一. 需求
对指定月份间的项目信息进行合计
- 指定月份内可能存在多个项目
- 一个项目里面有多个人员
- 一个人员可能会存在多个任务
- 需要统计1级项目的合计,2级项目的小计,3级项目的小计
二. 前台html
:data
=> 数据源:row-class-name
=> 表格行的样式:cell-style
=> 表格单元格的样式:span-method
=> 合并行或列的计算方法
<template>
<el-container>
<el-header class="appMain" style="width: 100%"></el-header>
<el-main>
<el-row>
<el-col :span="24">
<el-table
:data="listDate"
tooltip-effect="dark"
border
highlight-current-row
:row-class-name="tabRowClassName"
:cell-style="cellStyleChange"
:span-method="cellMerge"
style="width: 100%"
>
<el-table-column label="项目编号" prop="ordercd" align="left" min-width="55%">
<template slot-scope="scope">
{{ scope.row.ordercd }}
</template>
</el-table-column>
<el-table-column label="项目名称" prop="ordernm" align="left" :show-overflow-tooltip = "true">
<template slot-scope="scope">{{ scope.row.ordernm }}</template>
</el-table-column>
<el-table-column label="项目经理" prop="kanribangou" header-align="center" align="left" min-width="55%">
<template slot-scope="scope">{{ scope.row.kanribangou }}</template>
</el-table-column>
<el-table-column label="人员编号" prop="employeeid" header-align="center" align="left" min-width="55%">
<template slot-scope="scope">{{ scope.row.employeeid }}</template>
</el-table-column>
<el-table-column label="人员姓名" prop="name" header-align="center" align="left" min-width="55%">
<template slot-scope="scope">{{ scope.row.name }}</template>
</el-table-column>
<el-table-column label="1级任务" prop="bigitemnm" header-align="center" align="left" :show-overflow-tooltip = "true">
<template slot-scope="scope">
<span>{{ scope.row.bigitemnm }}</span>
</template>
</el-table-column>
<el-table-column label="2级任务" prop="mediumitemnm" header-align="center" align="left" :show-overflow-tooltip = "true">
<template slot-scope="scope">
<span>{{scope.row.mediumitemnm}}</span>
</template>
</el-table-column>
<el-table-column label="3级任务" prop="orderitemnm" header-align="center" align="left" :show-overflow-tooltip = "true">
<template slot-scope="scope">
<span>{{ scope.row.orderitemnm }}</span>
</template>
</el-table-column>
<el-table-column label="加班时间(H)" prop="sagyotime" header-align="center" align="right">
<template slot-scope="scope">{{ scope.row.sagyotime }}</template>
</el-table-column>
<el-table-column label="合计时间(H)" prop="sagyotime" header-align="center" align="right">
<template slot-scope="scope">{{ scope.row.sagyotime }}</template>
</el-table-column>
<el-table-column label="折合人日(D)" prop="percentage" header-align="center" align="right">
<template slot-scope="scope">{{ scope.row.percentage }}</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
</el-main>
</el-container>
</template>
三. 前台JS
- 每一个row对象都对应着后端的一个实体类
- statisticsFlag为实体类中的属性,用于标识该行是否为合计行
- 列的合并,是通过比较上下两个值是否一致,如果完全一致则进行合并
- 行的合并为伪合并,通过去除表格之间的线,从而在视觉上看起来是合并了
// mock的测试数据
import testTableData from '../../../mock/projectStandardGatherStaffDetail'
// 单元格的index和名称的映射关系
const columnIndexMap = new Map([
[0, 'ordercd'],
[1, 'ordernm'],
[2, 'kanribangou'],
[3, 'employeeid'],
[4, 'name'],
[5, 'bigitemnm'],
[6, 'mediumitemnm']
]);
// 获取所有的合并栏的index
const mergeColumnIndexList = [...columnIndexMap.keys()];
// 1级任务栏的index
const oneTaskColumnList = [5, 6, 7];
// 2级任务栏的index
const towTaskColumnList = [6, 7];
// 3级任务栏的index
const threeTaskColumnList = [7];
export default {
name: "CustomTable",
data() {
return {
// 表格数据
listDate: [],
// 表格合并所涉及到的列
tableDataMerge: {
// 订单号
ordercd: {
ordercdList: [],
ordercdPositon: 0
},
// 订单名称
ordernm: {
ordernmList: [],
ordernmPositon: 0
},
// 项目经理
kanribangou: {
kanribangouList: [],
kanribangouPositon: 0
},
// 员工ID
employeeid: {
employeeidList: [],
employeeidPositon: 0
},
// 员工姓名
name: {
nameList: [],
namePositon: 0
},
// 1级任务
bigitemnm: {
bigitemnmList: [],
bigitemnmPositon: 0
},
// 2级任务
mediumitemnm: {
mediumitemnmList: [],
mediumitemnmPositon: 0
}
}
};
},
created() {
// 将测试数据添加到表格的数据源中
this.listDate = testTableData;
// 单元格合并
Object.keys(this.tableDataMerge).forEach((item) => this.getMergeColumnCellData(item));
},
methods: {
// 自定义斑马纹
tabRowClassName({ row, rowIndex }) {
const index = rowIndex + 1;
if (index % 2 == 0) {
return "warning-row";
}
},
// 修改单元格的样式
cellStyleChange({row, column, rowIndex, columnIndex}) {
/*
如果是合计栏的话,字体加粗居右
statisticsFlag 是row对象中的一个自定义属性,用于标识该行是否为统计行
*/
if (row.statisticsFlag === true) {
// 合计单元格的共通样式
const cellStyle = {
'text-align': 'right',
'font-weight': 'bolder',
}
// 1级合计相关单元格样式
if (row.bigitemnm == "1级合计" && oneTaskColumnList.includes(columnIndex)) {
cellStyle['background-color'] = '#a3a4ae';
// 清除1,2,3级任务之间的右表格线
if (columnIndex == 5 || columnIndex == 6) {
cellStyle['border-right'] = 'none';
}
return cellStyle;
}
// 2级小计相关单元格样式
if (row.mediumitemnm == "2级小计" && towTaskColumnList.includes(columnIndex)) {
cellStyle['background-color'] = '#c4c9cc';
// 清除2,3级任务之间的右表格线
if (columnIndex == 6) {
cellStyle['border-right'] = 'none';
}
return cellStyle;
}
// 3级小计相关单元格样式
if (row.orderitemnm == "3级小计" && threeTaskColumnList.includes(columnIndex)) {
cellStyle['background-color'] = '#dbe1e4';
return cellStyle;
}
return cellStyle;
}
// 如果当前栏是单元格合并栏
if (mergeColumnIndexList.includes(columnIndex)) {
// 如果是合并栏的话,字体居顶部
return {
'vertical-align': 'top',
}
}
},
// 获取要合并单元格的相关数据
getMergeColumnCellData(columnName) {
// 数据库获取到的数据
const data = this.listDate;
for (let i = 0; i < data.length; i++) {
if (i === 0) {
// 设置table表格行号、设置合并参数,以便相同参数合并
this.tableDataMerge[columnName][`${columnName}List`].push(1);
this.tableDataMerge[columnName][`${columnName}Positon`] = 0;
continue;
}
// 判断当前元素与上一个元素是否相同
if (data[i][columnName].trim() == data[i - 1][columnName].trim()) {
const positon = this.tableDataMerge[columnName][`${columnName}Positon`];
this.tableDataMerge[columnName][`${columnName}List`][positon] += 1;
this.tableDataMerge[columnName][`${columnName}List`].push(0);
continue;
}
this.tableDataMerge[columnName][`${columnName}List`].push(1);
this.tableDataMerge[columnName][`${columnName}Positon`] = i;
}
},
// 表格合并方法
cellMerge({row, column, rowIndex, columnIndex}) {
// 获取要合并的表格名称
const colunmName = columnIndexMap.get(columnIndex);
if(!colunmName) {
return;
}
// 获取要合并的单元格数据
const _row = this.tableDataMerge[colunmName][`${colunmName}List`][rowIndex];
const _col = _row > 0 ? 1 : 0;
// 返回要合并的单元格
return {
rowspan: _row
,colspan: _col
}
},
},
};