参考自下列文章

https://blog.csdn.net/u013558749/article/details/82257168 (element-ui 实现行合并) https://www.cnblogs.com/guwufeiyang/p/12850088.html (合并后样式的处理)

目标样式

table中表格合并 el-table纵向合并单元格(1)

合并后样式

来源数据

[ { "processId": "1499255834195238914", "currentProcessInfoId": "1499255834245570561", "flowType": "01", "userName": "xxx", "itcode": "xxx", "pernr": "xxx", "approveStatus": "01", "dimensionName": "重点-测试", "dimensionTag": "1499255834195238914重点-测试", "nature": "01", "name": "1212", "statusRemark": "1212", "scoreStand": "1212", "source": "1212", "weight": 0.3, "status": "Y", "remark": "-", "index": 1, "rowIndex": 0 }, { "processId": "1499255834195238914", "currentProcessInfoId": "1499255834245570561", "flowType": "01", "userName": "xxx", "itcode": "xxx", "pernr": "xxx", "approveStatus": "01", "dimensionName": "日常-测试", "dimensionTag": "1499255834195238914日常-测试", "nature": "01", "name": "TEST", "statusRemark": "100", "scoreStand": "100", "source": "100", "weight": 0.3, "status": "Y", "remark": "-", "index": 1, "rowIndex": 1 }, { "processId": "1499255834195238914", "currentProcessInfoId": "1499255834245570561", "flowType": "01", "userName": "xxx", "itcode": "xxx", "pernr": "xxx", "approveStatus": "01", "dimensionName": "日常-测试", "dimensionTag": "1499255834195238914日常-测试", "nature": "01", "name": "12", "statusRemark": "12", "scoreStand": "12", "source": "12", "weight": 0.3, "status": "Y", "remark": "-", "index": 1, "rowIndex": 2 }, { "processId": "1499255834195238914", "currentProcessInfoId": "1499255834245570561", "flowType": "01", "userName": "xxx", "itcode": "xxx", "pernr": "xxx", "approveStatus": "01", "dimensionName": "管理指标", "dimensionTag": "1499255834195238914管理指标", "nature": "02", "name": "12", "statusRemark": "12", "scoreStand": "12", "source": "12", "weight": 0.1, "status": "Y", "remark": "-", "index": 1, "rowIndex": 3 }, { "processId": "1499255834996350977", "currentProcessInfoId": null, "flowType": "02", "userName": "xxx", "itcode": "xxx", "pernr": "xxx", "approveStatus": "00", "dimensionName": "重点-测试", "dimensionTag": "1499255834996350977重点-测试", "nature": "01", "name": "1212", "statusRemark": "1212", "scoreStand": "1212", "source": "1212", "weight": 0.3, "status": "-", "remark": "-", "index": 2, "rowIndex": 4 }, { "processId": "1499255834996350977", "currentProcessInfoId": null, "flowType": "02", "userName": "xxx", "itcode": "xxx", "pernr": "xxx", "approveStatus": "00", "dimensionName": "日常-测试", "dimensionTag": "1499255834996350977日常-测试", "nature": "01", "name": "TEST", "statusRemark": "100", "scoreStand": "100", "source": "100", "weight": 0.3, "status": "-", "remark": "-", "index": 2, "rowIndex": 5 }, { "processId": "1499255834996350977", "currentProcessInfoId": null, "flowType": "02", "userName": "xxx", "itcode": "xxx", "pernr": "xxx", "approveStatus": "00", "dimensionName": "日常-测试", "dimensionTag": "1499255834996350977日常-测试", "nature": "01", "name": "12", "statusRemark": "12", "scoreStand": "12", "source": "12", "weight": 0.3, "status": "-", "remark": "-", "index": 2, "rowIndex": 6 }, { "processId": "1499255834996350977", "currentProcessInfoId": null, "flowType": "02", "userName": "xxx", "itcode": "xxx", "pernr": "xxx", "approveStatus": "00", "dimensionName": "管理指标", "dimensionTag": "1499255834996350977管理指标", "nature": "02", "name": "12", "statusRemark": "12", "scoreStand": "12", "source": "12", "weight": 0.1, "status": "-", "remark": "-", "index": 2, "rowIndex": 7 } ]

将数据按照字段[processId] [dimensionTag]进行处理

// 按照dimensionTag合并行 getDimensionNumber() { this.dimensionIndexArr = [] let DimensionObj = {} this.dataList.forEach((element, index) => { element.rowIndex = index if (DimensionObj[element.dimensionTag]) { DimensionObj[element.dimensionTag].push(index) } else { DimensionObj[element.dimensionTag] = [] DimensionObj[element.dimensionTag].push(index) } }) for (let k in DimensionObj) { if (DimensionObj[k].length > 1) { this.dimensionIndexArr.push(DimensionObj[k]) } } }, // 按照processId合并行 getRecordNumber() { this.recordIndexArr=[] let OrderObj = {} this.dataList.forEach((element, index) => { element.rowIndex = index if (OrderObj[element.processId]) { OrderObj[element.processId].push(index) } else { OrderObj[element.processId] = [] OrderObj[element.processId].push(index) } }) for (let k in OrderObj) { if (OrderObj[k].length > 1) { this.recordIndexArr.push(OrderObj[k]) } } },

根据页面展示需要,控制哪一些列上的数据需要进行合并

objectSpanMethod({row, column, rowIndex, columnIndex}) { if (columnIndex === 0 || columnIndex === 1 || columnIndex >= 9) { for (let i = 0; i < this.recordIndexArr.length; i ) { let element = this.recordIndexArr[i] for (let j = 0; j < element.length; j ) { let item = element[j] if (rowIndex == item) { if (j == 0) { return { rowspan: element.length, colspan: 1 } } else if (j != 0) { return { rowspan: 0, colspan: 0 } } } } } } if (columnIndex === 2) { for (let i = 0; i < this.dimensionIndexArr.length; i ) { let element = this.dimensionIndexArr[i] for (let j = 0; j < element.length; j ) { let item = element[j] if (rowIndex == item) { if (j == 0) { return { rowspan: element.length, colspan: 1 } } else if (j != 0) { return { rowspan: 0, colspan: 0 } } } } } } },

处理样式

table中表格合并 el-table纵向合并单元格(2)

样式错乱

<el-table ref="table" v-loading="dataListLoading" :data="dataList" border :span-method="objectSpanMethod" :row-class-name="tableRowClassName" @cell-mouse-enter="cellMouseEnter" @cell-mouse-leave="cellMouseLeave" style="width: 100%;margin-top: 16px" > ....... </el-table>

tableRowClassName({row, rowIndex}) { let arr = this.hoverOrderArr for (let i = 0; i < arr.length; i ) { if (rowIndex === arr[i]) { return 'success-row' } } }, cellMouseEnter(row, column, cell, event) { this.rowIndex = row.rowIndex this.hoverOrderArr = [] this.recordIndexArr.forEach((element) => { if (element.indexOf(this.rowIndex) >= 0) { this.hoverOrderArr = element } }) }, cellMouseLeave(row, column, cell, event) { this.rowIndex = '-1' this.hoverOrderArr = [] },

<style scoped> /deep/ .el-table .success-row { background: #ecf4fe; } </style>

完整代码

<template> <el-card> <div class="app-container"> <!--工具栏--> <div class="head-container"> <div> <!-- 搜索 --> <el-input v-model="queryParams.name" size="small" clearable placeholder="输入名称或者描述搜索" style="width: 200px;" class="filter-item" /> <span> <el-button class="filter-item" size="mini" type="success" icon="el-icon-search" @click="searchHandler" >搜索</el-button> <el-button class="filter-item" size="mini" type="warning" icon="el-icon-refresh-left" @click="resetHandler" >重置</el-button> <el-button class="filter-item" size="mini" icon="el-icon-plus" @click="addHandler" >新增</el-button> </span> </div> </div> <!-- 列表数据 --> <el-table ref="table" v-loading="dataListLoading" :data="dataList" border :span-method="objectSpanMethod" :row-class-name="tableRowClassName" @cell-mouse-enter="cellMouseEnter" @cell-mouse-leave="cellMouseLeave" style="width: 100%;margin-top: 16px" > <el-table-column label="序号" prop="index" width="50" align="center" /> <el-table-column :show-overflow-tooltip="true" prop="userName" header-align="center" align="center" label="人员" > <template slot-scope="scope"> <span v-if="scope.row.status!=='-'" style="color: #67c23a;font-weight: bold">{{scope.row.userName}}({{scope.row.pernr}})</span> <span v-if="scope.row.status==='N'" style="color: red;font-weight: bold">{{scope.row.userName}}({{scope.row.pernr}})</span> <span v-if="scope.row.status ==='-'"style="color: black;font-weight: bold">{{scope.row.userName}}({{scope.row.pernr}})</span> </template> </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="dimensionName" header-align="center" align="center" label="维度名称" > </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="nature" header-align="center" align="center" label="指标性质" > <template slot-scope="scope"> <el-tag v-if="scope.row.nature === '01'" type="success">定性</el-tag> <el-tag v-else type="warning">定量</el-tag> </template> </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="name" header-align="center" align="center" label="指标名称" > </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="statusRemark" header-align="center" align="center" label="目标值/状态描述" > </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="scoreStand" header-align="center" align="center" label="评分标准" > </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="source" header-align="center" align="center" label="数据来源" > </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="weight" header-align="center" align="center" label="权重" > </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="status" header-align="center" align="center" label="是否同意" > </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="remark" header-align="center" align="center" label="审批意见" > </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="flowType" header-align="center" align="center" label="流程类型" > <template slot-scope="scope"> <el-tag v-if="scope.row.flowType === '01'" type="success">目标流程</el-tag> <el-tag v-else type="warning">结果流程</el-tag> </template> </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="approveStatus" header-align="center" align="center" label="全局审批状态" > <template slot-scope="scope"> <el-tag v-if="scope.row.approveStatus === '00'" type="info">待审批</el-tag> <el-tag v-if="scope.row.approveStatus === '01'" type="warning">审批流转中</el-tag> <el-tag v-if="scope.row.approveStatus === '02'" type="success">已完成(同意)</el-tag> <el-tag v-if="scope.row.approveStatus === '03'" type="danger">已完成(驳回)</el-tag> </template> </el-table-column> <el-table-column fixed="right" align="center" width="150" label="操作" > <template slot-scope="scope"> <span v-if="scope.row.status==='-'"> <el-button type="text" @click="changeStatus(scope.row.processId,'Y')">同意</el-button> <el-button type="text" @click="changeStatus(scope.row.processId,'N')">不同意</el-button> </span> <el-button type="text" @click="fillInOpen(scope.row.currentProcessInfoId)">填写意见</el-button> <el-button type="text" @click="approveRecord(scope.row.processId)">审批记录</el-button> </template> </el-table-column> </el-table> <pagetool v-show="total>0" :total="total" :page.sync="queryParams.current" :limit.sync="queryParams.size" @pagination="searchHandler" /> <eForm ref="eForm" @finish="searchHandler"/> </div> </el-card> </template> <script> import eForm from './form' import kpi from "../../../../api/kpi/kpi"; export default { name: 'index', components: {eForm}, data() { return { visible: false, queryParams: { name: '', current: 1, size: 10 }, total: 0, dataList: [], recordIndexArr: [], dimensionIndexArr: [], hoverOrderArr: [], dataListLoading: false } }, created() { this.searchHandler() }, mounted() { this.searchHandler() }, methods: { searchHandler() { kpi.flowEmployeeApproveRecordPage(this.queryParams).then(({data}) => { let dataList = [] let index = 0 data.data.records.forEach(record => { let userName = record.userName // 用户名 let itcode = record.itcode // itcode let pernr = record.pernr // 员工编号 let status = record.status ? record.status : '-' // 审批状态-是否同意 let remark = record.remark ? record.remark : '-' // 审批意见 let processId = record.id // 流程ID let currentProcessInfoId = record.currentProcessInfoId // 当前激活的子流程ID let flowType = record.flowType // 流程类型 01:目标流程02:结果流程 let approveStatus = record.approveStatus // 全局审批状态 index = 1 /** 维度 **/ let dimensionList = record.dimensionList if (dimensionList && dimensionList.length) { dimensionList.forEach(dimension => { let dimensionName = dimension.name // 维度名称 let dimensionTag = processId dimensionName let userTargetList = dimension.userTargetList if (userTargetList && userTargetList.length) { userTargetList.forEach(userTarget => { // 指标性质 let nature = userTarget.nature // 指标名称 let name = userTarget.name // 目标值/状态描述 let statusRemark = userTarget.statusRemark // 评分标准 let scoreStand = userTarget.scoreStand // 数据来源 let source = userTarget.source // 权重 let weight = userTarget.weight let data = { processId, currentProcessInfoId, flowType, userName, itcode, pernr, approveStatus, dimensionName, dimensionTag, nature, name, statusRemark, scoreStand, source, weight, status, remark, index } dataList.push(data) }) } }) } }) this.dataList = dataList this.total = data.data.total this.getRecordNumber() this.getDimensionNumber() console.log(this.dataList) }) }, resetHandler() { }, addHandler() { }, fillInOpen(currentProcessInfoId){ this.$refs.eForm.init(currentProcessInfoId) }, changeStatus(id, status) { console.log(id, status) this.$confirm(`确定[${status === 'Y' ? '同意' : '拒绝'}]该流程?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { kpi.flowEmployeeChangeApproveRecordStatus(id, status).then(({data}) => { this.$message.success('操作成功') this.searchHandler() }) }).catch(() => { this.$message.info('已取消') }) }, delHandler(id) { }, getDimensionNumber() { let DimensionObj = {} this.dataList.forEach((element, index) => { element.rowIndex = index if (DimensionObj[element.dimensionTag]) { DimensionObj[element.dimensionTag].push(index) } else { DimensionObj[element.dimensionTag] = [] DimensionObj[element.dimensionTag].push(index) } }) for (let k in DimensionObj) { if (DimensionObj[k].length > 1) { this.dimensionIndexArr.push(DimensionObj[k]) } } }, getRecordNumber() { let OrderObj = {} this.dataList.forEach((element, index) => { element.rowIndex = index if (OrderObj[element.processId]) { OrderObj[element.processId].push(index) } else { OrderObj[element.processId] = [] OrderObj[element.processId].push(index) } }) for (let k in OrderObj) { if (OrderObj[k].length > 1) { this.recordIndexArr.push(OrderObj[k]) } } }, // 合并单元格 /** https://blog.csdn.net/u013558749/article/details/82257168 **/ objectSpanMethod({row, column, rowIndex, columnIndex}) { if (columnIndex === 0 || columnIndex === 1 || columnIndex >= 9) { for (let i = 0; i < this.recordIndexArr.length; i ) { let element = this.recordIndexArr[i] for (let j = 0; j < element.length; j ) { let item = element[j] if (rowIndex == item) { if (j == 0) { return { rowspan: element.length, colspan: 1 } } else if (j != 0) { return { rowspan: 0, colspan: 0 } } } } } } if (columnIndex === 2) { for (let i = 0; i < this.dimensionIndexArr.length; i ) { let element = this.dimensionIndexArr[i] for (let j = 0; j < element.length; j ) { let item = element[j] if (rowIndex == item) { if (j == 0) { return { rowspan: element.length, colspan: 1 } } else if (j != 0) { return { rowspan: 0, colspan: 0 } } } } } } }, tableRowClassName({row, rowIndex}) { let arr = this.hoverOrderArr for (let i = 0; i < arr.length; i ) { if (rowIndex === arr[i]) { return 'success-row' } } }, cellMouseEnter(row, column, cell, event) { this.rowIndex = row.rowIndex this.hoverOrderArr = [] this.recordIndexArr.forEach((element) => { if (element.indexOf(this.rowIndex) >= 0) { this.hoverOrderArr = element } }) }, cellMouseLeave(row, column, cell, event) { this.rowIndex = '-1' this.hoverOrderArr = [] }, } } </script> <style scoped> /deep/ .el-table .success-row { background: #ecf4fe; } </style>

,