feat: base 所有表格增加通用导出方法

This commit is contained in:
caoqianming 2025-11-02 00:22:29 +08:00
parent a0814191a7
commit 48ea04138b
2 changed files with 116 additions and 22 deletions

View File

@ -45,6 +45,14 @@
</el-button> </el-button>
<el-button v-if="!hideRefresh" @click="reload" icon="el-icon-refresh-right" circle style="margin-left: 15px"> <el-button v-if="!hideRefresh" @click="reload" icon="el-icon-refresh-right" circle style="margin-left: 15px">
</el-button> </el-button>
<el-popover v-if="!hideExport" placement="top" trigger="click" :hide-after="0">
<template #reference>
<el-button icon="el-icon-download" circle style="margin-left: 15px"></el-button>
</template>
<div><el-button type="primary" size="small" @click="exportExcel(0)">1导出本页数据</el-button></div>
<div style="margin-top: 2px;" v-if="hExportExcel"><el-button type="primary" size="small" @click="exportExcel(1)">2导出本页数据</el-button></div>
<div style="margin-top: 2px;" v-if="hExportExcel"><el-button type="primary" size="small" @click="exportExcel(2)">3导出全部数据</el-button></div>
</el-popover>
<el-popover v-if="column" placement="top" title="列设置" :width="500" trigger="click" :hide-after="0" <el-popover v-if="column" placement="top" title="列设置" :width="500" trigger="click" :hide-after="0"
@show="customColumnShow = true" @after-leave="customColumnShow = false"> @show="customColumnShow = true" @after-leave="customColumnShow = false">
@ -82,7 +90,7 @@
import config from "@/config/table"; import config from "@/config/table";
import columnSetting from "./columnSetting"; import columnSetting from "./columnSetting";
import { genTree } from "@/utils/verificate"; import { genTree } from "@/utils/verificate";
import { domToExcel } from "@/utils/exportExcel";
export default { export default {
name: "scTable", name: "scTable",
components: { components: {
@ -115,6 +123,8 @@ export default {
hideDo: { type: Boolean, default: false }, hideDo: { type: Boolean, default: false },
hideRefresh: { type: Boolean, default: false }, hideRefresh: { type: Boolean, default: false },
hideSetting: { type: Boolean, default: false }, hideSetting: { type: Boolean, default: false },
hideExport: { type: Boolean, default: false },
hExportExcel: { type: Function, default: null },
paginationLayout: { type: String, default: config.paginationLayout }, paginationLayout: { type: String, default: config.paginationLayout },
}, },
watch: { watch: {
@ -299,6 +309,35 @@ export default {
this.getData(); this.getData();
this.$emit("resetQuery"); this.$emit("resetQuery");
}, },
//
exportExcel(type=0) {
if (type === 0) {
try {
domToExcel(this.$refs.scTable.$el, "表格数据");
} catch (error) {
console.error('导出失败:', error);
this.$message.error("导出失败");
}
}
else if (type === 1) {
this.hExportExcel(this.tableData);
}else if (type === 2) {
var c = Object.assign({}, this.query, this.tableParams, {[this.orderStr]: this.order}, {page: 0})
let ElLoading = this.$loading({
lock: true,
text: '数据请求中,请稍后...',
background: 'rgba(0, 0, 0, 0)',
})
this.apiObj.req(c).then(res=>{
ElLoading.close();
this.hExportExcel(res);
}).catch(err=>{
ElLoading.close();
console.log(err)
this.$message.error("导出失败");
})
}
},
// //
columnSettingChange(userColumn) { columnSettingChange(userColumn) {
this.userColumn = userColumn; this.userColumn = userColumn;

View File

@ -1,4 +1,11 @@
import * as XLSX from 'xlsx'; import * as XLSX from 'xlsx';
export const domToExcel = (dom, name="data") => {
const worksheet = XLSX.utils.table_to_sheet(dom);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet);
XLSX.writeFile(workbook, `${name}.xlsx`);
}
/** /**
* eg: .columns = [ * eg: .columns = [
* { header: 'Id', key: 'id', wpx: 10 }, * { header: 'Id', key: 'id', wpx: 10 },
@ -10,35 +17,83 @@ import * as XLSX from 'xlsx';
* @param data 数据 * @param data 数据
* @param name 文件名 * @param name 文件名
*/ */
export const generateExcel = (columns = [], data = [], name = '') => { export const dataToExcel = (columns = [], data = [], name = 'data') => {
const headers = columns.map((item) => item.header); const headers = columns.map((item) => item.header);
const otherConfigs = columns.map(({ key, header, ...item }) => item);
const dataList = data.map((item) => { const dataList = data.map((item) => {
let obj = {}; let obj = {};
columns.forEach((col) => { columns.forEach(col => {
obj[col.header] = item[col.key]; obj[col.header] = getNestedValue(item, col.key) ?? '';
}); });
return obj; return obj;
}); });
const workbook = XLSX.utils.book_new(); const workbook = XLSX.utils.book_new();
workbook.SheetNames.push(name); // workbook.SheetNames.push(name);
const worksheet = XLSX.utils.json_to_sheet(dataList, { const worksheet = XLSX.utils.json_to_sheet(dataList, {
header: headers, header: headers,
}); });
worksheet['!cols'] = otherConfigs; // 自动计算列宽
workbook.Sheets[name] = worksheet; worksheet['!cols'] = calculateColumnWidths(columns, dataList);
// 生成Blob数据 // const otherConfigs = columns.map(({ key, header, ...item }) => item);
const excelData = XLSX.write(workbook, { type: 'array', bookType: 'xlsx' }); // worksheet['!cols'] = otherConfigs;
const blobData = new Blob([excelData], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); XLSX.utils.book_append_sheet(workbook, worksheet);
// 创建Blob URL XLSX.writeFile(workbook, `${name}.xlsx`);
const blobUrl = URL.createObjectURL(blobData); // workbook.Sheets[name] = worksheet;
// 创建一个隐藏的<a>标签并设置href属性为Blob URL // // 生成Blob数据
const link = document.createElement('a'); // const excelData = XLSX.write(workbook, { type: 'array', bookType: 'xlsx' });
link.href = blobUrl; // const blobData = new Blob([excelData], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
link.target = '_blank'; // // 创建Blob URL
link.download = `${name}.xlsx`; // const blobUrl = URL.createObjectURL(blobData);
// 触发点击操作,开始下载文件 // // 创建一个隐藏的<a>标签并设置href属性为Blob URL
link.click(); // const link = document.createElement('a');
// 释放Blob URL // link.href = blobUrl;
URL.revokeObjectURL(blobUrl); // link.target = '_blank';
// link.download = `${name}.xlsx`;
// // 触发点击操作,开始下载文件
// link.click();
// // 释放Blob URL
// URL.revokeObjectURL(blobUrl);
};
const getNestedValue = (obj, path, defaultValue = '') => {
if (!obj || !path) return defaultValue;
const keys = path.split('.');
let result = obj;
for (const key of keys) {
if (result === null || result === undefined) {
return defaultValue;
}
result = result[key];
}
return result !== undefined ? result : defaultValue;
};
const calculateColumnWidths = (columns, dataList) => {
// 确保 dataList 有数据
if (!dataList || dataList.length === 0) {
return columns.map(col => ({ wch: 15 })); // 返回默认宽度
}
return columns.map(col => {
// 固定宽度优先
if (col.wpx) return { wpx: col.wpx };
if (col.wch) return { wch: col.wch };
if (col.width) return { wch: col.width };
const header = col.header || '';
let maxWidth = header.length;
// 遍历数据计算最大宽度
for (let i = 0; i < Math.min(dataList.length, 100); i++) {
const item = dataList[i];
// 确保使用正确的键名
const value = item[header] !== undefined ? String(item[header]) : '';
if (value.length > maxWidth) {
maxWidth = value.length;
}
}
return { wch: Math.min(Math.max(maxWidth + 2, 8), 50) };
});
}; };