涉及到行合并的el-table表格导出功能实现

开篇

因最近业务需求,需要实现表格的导出功能,正常表格导出很容易实现自不必提,这里的表格因为是高度定制化的,牵扯到了行的合并,以及配置项的动态列设置(也就是根据配置来增减某些列),以及每个单元格中也会分为三行内容,所以这里的导出会比较麻烦。

具体实现

表格部分代码(这里的单元格我只写了两列)

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';

导出效果

以上便是对于此处导出功能实现的全部逻辑。记录,以便日后使用。

感谢阅读!

相关推荐
MiyueFE22 分钟前
14 个逻辑驱动的 UI 设计技巧,助您改善任何界面
前端·设计
啃火龙果的兔子26 分钟前
前端单元测试覆盖率工具有哪些,分别有什么优缺点
前端·单元测试
「、皓子~1 小时前
后台管理系统的诞生 - 利用AI 1天完成整个后台管理系统的微服务后端+前端
前端·人工智能·微服务·小程序·go·ai编程·ai写作
就改了1 小时前
Ajax——在OA系统提升性能的局部刷新
前端·javascript·ajax
凌冰_1 小时前
Ajax 入门
前端·javascript·ajax
京东零售技术1 小时前
京东小程序JS API仓颉改造实践
前端
老A技术联盟1 小时前
从小白入门,基于Cursor开发一个前端小程序之Cursor 编程实践与案例分析
前端·小程序
风铃喵游1 小时前
构建引擎: 打造小程序编译器
前端·小程序·架构
sunbyte2 小时前
50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | ThemeClock(主题时钟)
前端·javascript·css·vue.js·前端框架·tailwindcss
小飞悟2 小时前
🎯 什么是模块化?CommonJS 和 ES6 Modules 到底有什么区别?小白也能看懂
前端·javascript·设计