|
|
|
|
@ -5,7 +5,8 @@
|
|
|
|
|
<template #buttons>
|
|
|
|
|
<el-date-picker v-model="select.month" type="month" size="small" value-format="yyyy-MM" placeholder="月份"
|
|
|
|
|
format="yyyy-MM" />
|
|
|
|
|
<el-select style="width:250px;margin-left:6px" size="small" v-model="select.department_id" placeholder="请选择">
|
|
|
|
|
<el-select style="width:250px;margin-left:6px" size="small" @change="changeDepartment"
|
|
|
|
|
v-model="select.department_id" placeholder="请选择">
|
|
|
|
|
<el-option v-for="item in departments" :key="item.id" :label="item.name" :value="item.id">
|
|
|
|
|
</el-option>
|
|
|
|
|
</el-select>
|
|
|
|
|
@ -14,12 +15,12 @@
|
|
|
|
|
</template>
|
|
|
|
|
</vxe-toolbar>
|
|
|
|
|
<vxe-table ref="table" stripe :border='true' style="margin-top: 10px;" :loading="loading" :max-height="1400"
|
|
|
|
|
:min-height="400" :export-config="{type: 'xlsx'}" :print-config="{}" :column-config="{ resizable: true }"
|
|
|
|
|
:expand-config="{
|
|
|
|
|
:min-height="400" :export-config="{type: 'xlsx',filename:exportName,sheetName:exportName}" :print-config="{}"
|
|
|
|
|
:column-config="{ resizable: true }" :expand-config="{
|
|
|
|
|
visibleMethod: () => false,
|
|
|
|
|
trigger: 'manual'
|
|
|
|
|
}" :data="tableData" :span-method="spanMethods">
|
|
|
|
|
<!-- :span-method="spanMethods" :merge-cells="mergeCells"-->
|
|
|
|
|
}" :data="tableData" :merge-cells="mergeCells">
|
|
|
|
|
<!-- :span-method="spanMethods" -->
|
|
|
|
|
<vxe-column width="180" header-align="center" align="center" field="department_name" title="科室"></vxe-column>
|
|
|
|
|
<vxe-column width="180" header-align="center" align="center" field="name" title="姓名"></vxe-column>
|
|
|
|
|
<vxe-column width="180" header-align="center" align="center" field="kaishiriqi" title="日期">
|
|
|
|
|
@ -68,44 +69,9 @@
|
|
|
|
|
department_id: ''
|
|
|
|
|
},
|
|
|
|
|
departments: [],
|
|
|
|
|
mergeCells: [
|
|
|
|
|
// { row: 0, col: 2, rowspan: 1, colspan: 2 },
|
|
|
|
|
// { row: 2, col: 2, rowspan: 2, colspan: 1 }
|
|
|
|
|
],
|
|
|
|
|
columns: [{
|
|
|
|
|
field: 'department_name',
|
|
|
|
|
title: '科室'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
field: 'name',
|
|
|
|
|
title: '姓名'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
field: 'kaishiriqi',
|
|
|
|
|
title: '开始日期'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
field: 'yuanyinshuoming',
|
|
|
|
|
title: '加班事由'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
field: 'jiabanshijian',
|
|
|
|
|
title: '加班时间'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
field: 'yuanyinshuoming',
|
|
|
|
|
title: '加班事由'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
field: 'jiabanshichang',
|
|
|
|
|
title: '加班时长(h)'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
field: 'allDay',
|
|
|
|
|
title: '本月累计(d)'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
]
|
|
|
|
|
mergeCells: [],
|
|
|
|
|
exportName: '加班统计表',
|
|
|
|
|
dName: '全部科室'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
@ -115,9 +81,9 @@
|
|
|
|
|
const res = await overtimeList(this.select, false);
|
|
|
|
|
console.log(res);
|
|
|
|
|
let data = res?.users || [];
|
|
|
|
|
this.tableData = this.overtimeData(data)
|
|
|
|
|
console.log("this.tableData", this.tableData)
|
|
|
|
|
// this.setRowSpans()
|
|
|
|
|
this.tableData = this.overtimeData(data)
|
|
|
|
|
let date = this.$moment(this.select.month).format("YYYY年MM月")
|
|
|
|
|
this.exportName = `${date}${this.dName}加班统计表`
|
|
|
|
|
this.loading = false;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error(err);
|
|
|
|
|
@ -151,15 +117,20 @@
|
|
|
|
|
overtime
|
|
|
|
|
} = item;
|
|
|
|
|
const allDay = overtime.reduce((sum, overtimeItem) => sum + parseFloat(overtimeItem.day), 0);
|
|
|
|
|
|
|
|
|
|
overtime.forEach(overtimeItem => {
|
|
|
|
|
overtimeItem.pid = id;
|
|
|
|
|
overtimeItem.name = name;
|
|
|
|
|
overtimeItem.department_name = department.name
|
|
|
|
|
overtimeItem.sortnumber = department.sortnumber
|
|
|
|
|
overtimeItem.department_id = department.id
|
|
|
|
|
overtimeItem.allDay = parseFloat(allDay).toFixed(2);
|
|
|
|
|
result.push(overtimeItem);
|
|
|
|
|
});
|
|
|
|
|
result.sort((a, b) => {
|
|
|
|
|
return a.sortnumber - b.sortnumber
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
this.mergeCells = this.generateMergeCells(result)
|
|
|
|
|
return result;
|
|
|
|
|
},
|
|
|
|
|
exportjbMethod({
|
|
|
|
|
@ -167,112 +138,50 @@
|
|
|
|
|
}) {
|
|
|
|
|
return `${row.kaishiriqi?row.kaishiriqi.substring(11,row.kaishiriqi.length):''}-${row.kaishiriqi?row.jieshushijian.substring(11,row.jieshushijian.length):''}`
|
|
|
|
|
},
|
|
|
|
|
spanMethods({
|
|
|
|
|
row,
|
|
|
|
|
$rowIndex,
|
|
|
|
|
column,
|
|
|
|
|
data
|
|
|
|
|
}) {
|
|
|
|
|
let fields = ["department_name", "name", "allDay"]
|
|
|
|
|
let cellValue = row[column.property]
|
|
|
|
|
if (cellValue && fields.includes(column.property)) {
|
|
|
|
|
let prevRow = data[$rowIndex - 1]
|
|
|
|
|
let nextRow = data[$rowIndex + 1]
|
|
|
|
|
if (prevRow && prevRow[column.property] === cellValue) {
|
|
|
|
|
return {
|
|
|
|
|
rowspan: 0,
|
|
|
|
|
colspan: 0
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
let countRowspan = 1
|
|
|
|
|
while (nextRow && nextRow[column.property] === cellValue) {
|
|
|
|
|
nextRow = data[++countRowspan + $rowIndex]
|
|
|
|
|
changeDepartment(e) {
|
|
|
|
|
if (e) {
|
|
|
|
|
this.departments.map(item => {
|
|
|
|
|
if (item.id == e) {
|
|
|
|
|
this.dName = item.name
|
|
|
|
|
}
|
|
|
|
|
if (countRowspan > 1) {
|
|
|
|
|
return {
|
|
|
|
|
rowspan: countRowspan,
|
|
|
|
|
colspan: 1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
this.dName = '全部科室'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
// 合并单元格
|
|
|
|
|
setRowSpans() {
|
|
|
|
|
const options = {
|
|
|
|
|
list: this.tableData, // 表格数据
|
|
|
|
|
columns: this.columns, // 完整表头
|
|
|
|
|
merges: [ "name", "department_name"], // 需要合并的列
|
|
|
|
|
condition: ['pid'], // 合并条件
|
|
|
|
|
field: 'field' // 表头取值的字段
|
|
|
|
|
};
|
|
|
|
|
// 传入此配置项,是指将pid相等的相邻数据合并,如果两条数据不相邻即使pid相等也不会合并
|
|
|
|
|
this.mergeCells = this.setMergeCells(options);
|
|
|
|
|
console.log('this.mergeCells: ', this.mergeCells);
|
|
|
|
|
},
|
|
|
|
|
setMergeCells({
|
|
|
|
|
list = [],
|
|
|
|
|
columns = [],
|
|
|
|
|
merges = [],
|
|
|
|
|
condition = [],
|
|
|
|
|
field = 'field'
|
|
|
|
|
}) {
|
|
|
|
|
console.log("list",list)
|
|
|
|
|
const validMap = new Map(); // 有效合并配置项
|
|
|
|
|
for (let i = 0; i < list.length; i++) {
|
|
|
|
|
// 根据判断条件取出当前行对应的表格数据,生成唯一标识
|
|
|
|
|
console.log("list[i][field])",i,list[i]['pid'])
|
|
|
|
|
const hashKey = condition.map(field => list[i][field]).join('&&');
|
|
|
|
|
let flag = true;
|
|
|
|
|
let count = 1;
|
|
|
|
|
// 从当前索引i开始,往后找,数据相同的话,count自增,否则跳出while循环
|
|
|
|
|
while (flag && i + count < list.length) {
|
|
|
|
|
// 根据判断条件取出下一行的表格数据,生成唯一标识
|
|
|
|
|
const nextRow = condition.map(field => list[i + count][field]).join('&&');
|
|
|
|
|
if (hashKey === nextRow) {
|
|
|
|
|
// 数据相同,count自增
|
|
|
|
|
count++;
|
|
|
|
|
} else {
|
|
|
|
|
// 数据不同,跳出while循环
|
|
|
|
|
flag = false;
|
|
|
|
|
generateMergeCells(data) {
|
|
|
|
|
const columns = this.$refs.table.getColumns()
|
|
|
|
|
let mergeCells = [];
|
|
|
|
|
const columnsToMerge = ['department_name', 'name', 'allDay'];
|
|
|
|
|
columnsToMerge.forEach(key => {
|
|
|
|
|
const col = columns.findIndex(item => item['field'] === key);
|
|
|
|
|
if (col === -1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
|
|
|
let rowspan = 1;
|
|
|
|
|
const currentValue = data[i][key];
|
|
|
|
|
for (let j = i + 1; j < data.length; j++) {
|
|
|
|
|
if (data[j][key] === currentValue) {
|
|
|
|
|
rowspan++;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (rowspan > 1) {
|
|
|
|
|
mergeCells.push({
|
|
|
|
|
row: i,
|
|
|
|
|
col,
|
|
|
|
|
rowspan,
|
|
|
|
|
colspan: 1
|
|
|
|
|
});
|
|
|
|
|
i += rowspan - 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 将有效的合并配置项存入validMap
|
|
|
|
|
count > 1 && validMap.set(hashKey + '_' + i, {
|
|
|
|
|
row: i,
|
|
|
|
|
rowspan: count
|
|
|
|
|
});
|
|
|
|
|
// i 跳过已合并的行,减 1 是因为 i++
|
|
|
|
|
i += count - 1;
|
|
|
|
|
// 重置 while 循环标识
|
|
|
|
|
flag = true;
|
|
|
|
|
}
|
|
|
|
|
// 合并记录转换
|
|
|
|
|
const recordsList = [...validMap.values()];
|
|
|
|
|
console.log("recordsList",recordsList)
|
|
|
|
|
if (recordsList.length == 0) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
// 预处理列索引
|
|
|
|
|
const cols = merges.reduce((acc, mergeField) => {
|
|
|
|
|
const idx = columns.findIndex(item => item[field] === mergeField);
|
|
|
|
|
idx !== -1 && acc.push(idx);
|
|
|
|
|
return acc;
|
|
|
|
|
}, []);
|
|
|
|
|
console.log("cols",cols)
|
|
|
|
|
// 遍历列索引,生成合并单元格配置集合
|
|
|
|
|
const mergeCells = recordsList.flatMap(({
|
|
|
|
|
row,
|
|
|
|
|
rowspan
|
|
|
|
|
}) => cols.map(col => ({
|
|
|
|
|
row,
|
|
|
|
|
col,
|
|
|
|
|
rowspan,
|
|
|
|
|
colspan: 1
|
|
|
|
|
})));
|
|
|
|
|
});
|
|
|
|
|
return mergeCells;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
computed: {},
|
|
|
|
|
|