开篇
因最近业务需求,需要实现表格的导出功能,正常表格导出很容易实现自不必提,这里的表格因为是高度定制化的,牵扯到了行的合并,以及配置项的动态列设置(也就是根据配置来增减某些列),以及每个单元格中也会分为三行内容,所以这里的导出会比较麻烦。
具体实现
表格部分代码(这里的单元格我只写了两列)
javascript
<el-table
:data="currTableData"
border
style="width: 100%;"
:max-height="getMaxHeight()"
:cell-style="CellStyle"
@cell-click="handleCellClick"
>
<!--姓名列-->
<el-table-column
style="background-color: #fff;"
:align="'center'"
prop="userName"
label="姓名"
fixed/>
<!--工号-->
<el-table-column
v-for="(item, index) in filteredCfgColumns"
:key="index"
style="background-color: #fff;"
:align="'center'"
:prop="item.prop"
:label="item.label"
/>
<!--
这一块牵扯到合并列及周期模式切换后的动态展示
需要特殊处理,不要写死
-->
<el-table-column
v-for="(date, index) in dateHeaders"
:key="index"
:align="'center'"
:class-name="isWeekend(date)"
:label-class-name="isWeekend(date)"
>
<!--星期几/日期-->
<template #header>
<div>{{ getWeekDay(date) }}</div>
<div>{{ parseDate(date) }}</div>
</template>
<!--表格内容 -->
<template #default="{row}">
<div
class="cell-content"
v-if="row[date]"
:data-cell-content="JSON.stringify(row[date])"
:class="`${row[date].cellKey}`"
>
<!-- 第一行 -->
<div v-if="pageSettingList.includes('显示附加班')" class="row"
style="font-size: 8px;min-height: 12px; display: flex; align-items: center;">
<el-row style="width: 100%;">
<el-col :span="24" style="color: red;font-weight: 600;text-align: right;">
{{ row[date]?.attchDetail || '' }}
</el-col>
</el-row>
</div>
<!-- 第二行 -->
<div class="row"
style="font-size: 12px;min-height: 20px; display: flex; align-items: center;">
<el-row style="width: 100%;">
<el-col :span="24" style="font-weight: 600;text-align: center;">
<StyledText :colorAndSchedules="colorAndSchedules"
:styledTexts="row[date]?.mainDetail || ''" />
</el-col>
</el-row>
</div>
</div>
</template>
</el-table-column>
</el-table>
如上图,这里不仅牵扯到了行的合并,而且每个单元格中的内容也比较复杂。
导出功能实现
javascript
const handleExportExcel = async () => {
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('表格数据');
// 动态生成表头映射
const colsMapping = [{ name: '姓名', key: 'userName' }];
filteredCfgColumns.value.forEach(item => {
colsMapping.push({ name: item.label, key: item.prop });
});
// 根据表格动态生成日期列
const dateHeaders = props.dateHeaders.map(date => ({
weekDay: getWeekDay(date),
date: parseDate(date),
key: date,
}));
// 生成第1行和第2行的表头内容
const headerRow1 = colsMapping.map(col => col.name).concat(dateHeaders.map(date => date.weekDay));
const headerRow2 = colsMapping.map(() => '').concat(dateHeaders.map(date => date.date));
worksheet.addRow(headerRow1);
worksheet.addRow(headerRow2);
// 设置第一行和第二行的样式
worksheet.getRow(1).alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
worksheet.getRow(2).alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
// 合并表头的姓名列单元格(动态合并)
colsMapping.forEach((col, index) => {
const cellAddress = String.fromCharCode(65 + index) + '1';
const mergeRange = `${cellAddress}:${String.fromCharCode(65 + index)}2`;
worksheet.mergeCells(mergeRange);
const headerCell = worksheet.getCell(cellAddress);
headerCell.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
});
// 添加数据行
currTableData.value.forEach(row => {
const rowData = colsMapping.map(col => row[col.key]);
const details = dateHeaders.map(date => {
const cellData = row[date.key] || {};
return [
cellData.attchDetail || '',
cellData.mainDetail || '',
cellData.applyDetail || ''
];
});
for (let i = 0; i < 3; i++) {
const rowCells = rowData.map((value, index) => index === 0 && i === 0 ? value : '');
details.forEach(detail => {
rowCells.push(detail[i]);
});
worksheet.addRow(rowCells);
}
});
// 合并姓名列的单元格并设置样式
let rowIndex = 3;
currTableData.value.forEach(() => {
colsMapping.forEach((col, index) => {
const cellAddress = String.fromCharCode(65 + index) + rowIndex;
const mergeRange = `${cellAddress}:${String.fromCharCode(65 + index)}${rowIndex + 2}`;
worksheet.mergeCells(mergeRange);
const cell = worksheet.getCell(cellAddress);
cell.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
});
rowIndex += 3;
});
// 设置列宽
colsMapping.forEach((_, index) => {
worksheet.getColumn(index + 1).width = 20;
});
// 导出Excel文件
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'table-data.xlsx';
link.click();
};
- 这里用到了一个三方库
"exceljs": "^4.4.0",
...
import ExcelJS from 'exceljs';
导出效果
注
以上便是对于此处导出功能实现的全部逻辑。记录,以便日后使用。
感谢阅读!