Files
mayfly-go/frontend/src/common/utils/export.ts

134 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import * as XLSX from 'xlsx';
/**
* 导出CSV文件
* @param filename 文件名
* @param columns 列信息
* @param datas 数据
*/
export function exportCsv(filename: string, columns: string[], datas: []) {
// 二维数组
const cvsData = [columns];
for (let data of datas) {
// 数据值组成的一维数组
let dataValueArr: any = [];
for (let column of columns) {
let val: any = data[column];
if (val == null || val == undefined) {
val = '';
} else if (val && typeof val == 'string') {
// 替换换行符
val = val.replace(/[\r\n]/g, '\\n');
// csv格式如果有逗号整体用双引号括起来如果里面还有双引号就替换成两个双引号这样导出来的格式就不会有问题了
if (val.indexOf(',') != -1) {
// 如果还有双引号,先将双引号转义,避免两边加了双引号后转义错误
if (val.indexOf('"') != -1) {
val = val.replace(/"/g, '""');
}
// 再将逗号转义
val = `"${val}"`;
}
}
dataValueArr.push(String(val));
}
cvsData.push(dataValueArr);
}
const csvString = cvsData.map((e) => e.join(',')).join('\n');
exportFile(`${filename}.csv`, csvString);
}
/**
* 导出文件
* @param filename 文件名
* @param content 文件内容
*/
export function exportFile(filename: string, content: string) {
// 导出
let link = document.createElement('a');
let exportContent = '\uFEFF';
let blob = new Blob([exportContent + content], {
type: 'text/plain;charset=utf-8',
});
link.id = 'download-file';
link.setAttribute('href', URL.createObjectURL(blob));
link.setAttribute('download', `${filename}`);
document.body.appendChild(link);
link.click();
document.body.removeChild(link); // 下载完成后移除元素
}
/**
* 计算字符串显示宽度(考虑中英文字符差异)
* @param str 要计算的字符串
* @returns 计算后的宽度值
*/
function getStringWidth(str: string): number {
if (!str) return 0;
// 统计中文字符数量(包括中文标点)
const chineseChars = str.match(/[\u4e00-\u9fa5\u3000-\u303f\uff00-\uffef]/g);
const chineseCount = chineseChars ? chineseChars.length : 0;
// 英文字符数量
const englishCount = str.length - chineseCount;
// 中文字符按2个单位宽度计算英文字符按1个单位宽度计算
return chineseCount * 2 + englishCount;
}
/**
* 导出Excel文件
* @param filename 文件名
* @param sheets 多个工作表数据,每个工作表包含名称、列信息和数据
* 示例: [{name: 'Sheet1', columns: ['列1', '列2'], datas: [{col1: '值1', col2: '值2'}]}]
*/
export function exportExcel(filename: string, sheets: { name: string; columns: string[]; datas: any[] }[]) {
// 创建工作簿
const wb = XLSX.utils.book_new();
// 处理每个工作表
sheets.forEach((sheet) => {
// 准备表头
const headers: any = {};
sheet.columns.forEach((col) => {
headers[col] = col;
});
// 准备数据
const data = [headers, ...sheet.datas];
// 创建工作表
const ws = XLSX.utils.json_to_sheet(data, { skipHeader: true });
// 设置列宽自适应
const colWidths: { wch: number }[] = [];
sheet.columns.forEach((col, index) => {
// 计算列宽:取表头和前几行数据的最大宽度
let maxWidth = getStringWidth(col); // 表头宽度
const checkCount = Math.min(sheet.datas.length, 10); // 只检查前10行数据
for (let i = 0; i < checkCount; i++) {
const cellData = sheet.datas[i][col];
const cellStr = cellData ? String(cellData) : '';
const cellWidth = getStringWidth(cellStr);
if (cellWidth > maxWidth) {
maxWidth = cellWidth;
}
}
// 设置最小宽度为8最大宽度为80
colWidths.push({ wch: Math.min(Math.max(maxWidth + 2, 8), 80) });
});
// 应用列宽设置
ws['!cols'] = colWidths;
// 添加工作表到工作簿
XLSX.utils.book_append_sheet(wb, ws, sheet.name);
});
// 导出文件
XLSX.writeFile(wb, `${filename}.xlsx`);
}