java
// 先在请求处加上:
responseType: 'arraybuffer', // 指定响应类型为ArrayBuffer
java
const data = new Uint8Array(response.data); // 将ArrayBuffer转换为Uint8Array
const val = { columns: [], data: [] }
let offset = 0; // 用于跟踪当前解析到的位置
while (offset < data.length) {
// 确保当前偏移量可读取8个字节
if (offset + 8 > data.length) {
console.warn('字节数不足,无法读取偏移处的长度:', offset);
break; // 不够数据,退出循环
}
// 获取前8个字节,计算包长度
const lengthHex = String.fromCharCode.apply(null, data.slice(offset, offset + 8));
const packLength = parseInt(lengthHex, 16); // 转换为十进制
// 确保当前偏移量可读取完整的数据包
if (offset + 8 + packLength > data.length) {
console.warn('字节数不足,无法在偏移处读取数据包:', offset);
break; // 不够数据,退出循环
}
// 使用TextDecoder来处理JSON内容
const decoder = new TextDecoder('utf-8');
const jsonBody = decoder.decode(data.slice(offset + 8, offset + 8 + packLength)); // 获取JSON内容
// 解析并存储数据包
try {
const packetData = JSON.parse(jsonBody); // 解析JSON
if (offset == 0) {
val.columns = packetData.columns;
}
val.data.push(...packetData.data);
} catch (error) {
console.error('Error parsing JSON:', error, jsonBody);
}
// 更新偏移量
offset += 8 + packLength; // 移动到下一个包的起始位置
}
// 现在 allPackets 包含所有解析后的数据包
console.log('All parsed packets:', val);
const worker = new Worker(new URL('./export-worker.ts', import.meta.url), { type: 'module' });
worker.postMessage({ data: val });
worker.onmessage = (e) => {
if (e && e.data && e.data.t == "export") {
e.stopPropagation();
e.preventDefault();
// data will be the Uint8Array from the worker
const res = e.data.v;
downloadExcelFile(new Blob([res], { type: "application/octet-stream" }), row.TaskName + '-核查结果.xlsx');
window.$message?.success('导出成功!');
}
operateLoading.value = false;
worker.terminate(); // 终止 Worker
};
worker.onerror = (error) => {
console.error('Worker error:', error);
operateLoading.value = false;
worker.terminate(); // 终止 Worker
};
export-worker.ts
typescript
import * as XLSX_STYLE from 'xlsx-js-style';
interface Column {
name: string;
headerText: string;
}
interface Data {
columns: Column[];
data: any[][];
}
interface ExportMessage {
t: string;
v: any;
}
self.onmessage = async (event: MessageEvent) => {
const { data }: { data: Data } = event.data;
// 这里放置处理导出逻辑的代码
const highlightFields: string[][] = [];
const problemFieldsIndex: number = data.columns.findIndex(col => col.name === 'ProblemFields');
// 移除 ProblemFields 字段
if (problemFieldsIndex !== -1) {
data.columns.splice(problemFieldsIndex, 1);
}
const formattedData = data.data.map((row: any[]) => {
const problemFields = row[problemFieldsIndex];
highlightFields.push(problemFields.split(','));
row.splice(problemFieldsIndex, 1);
// const rowData: { [key: string]: any } = {};
// data.columns.forEach((col: Column, index: number) => {
// rowData[col.headerText] = row[index];
// });
return row;
});
const BATCH_SIZE = 30000; // 定义每批处理的数据大小
// 添加标题行
const header = data.columns.map(col => col.headerText);
// 设置样式
const headerCellStyle = {
font: { name: 'Arial', sz: 10, bold: true, color: { rgb: "FFFFFF" } }, // 白色字体
fill: { fgColor: { rgb: "808080" } }, // 灰色背景
alignment: { vertical: 'center', horizontal: 'center' }
};
const cellStyle = {
font: { name: 'Arial', sz: 10 },
alignment: { vertical: 'center', horizontal: 'center', wrapText: true }
};
const highlightStyle = {
fill: { fgColor: { rgb: "FFFF00" } }, // 黄色背景
font: { name: '宋体', sz: 11 },
alignment: { vertical: 'center', horizontal: 'center', wrapText: true },
border: {
top: { style: 'thin', color: { rgb: "C3CBDD" } },
bottom: { style: 'thin', color: { rgb: "C3CBDD" } },
left: { style: 'thin', color: { rgb: "C3CBDD" } },
right: { style: 'thin', color: { rgb: "C3CBDD" } }
}
};
const ws = [];
for (let i = 0; i < formattedData.length; i += BATCH_SIZE) {
const worksheet = XLSX_STYLE.utils.aoa_to_sheet([header], { origin: 'A1' }); // 创建一个空工作表
const batchData = formattedData.slice(i, i + BATCH_SIZE);
// 添加批量数据到工作表末尾
XLSX_STYLE.utils.sheet_add_aoa(worksheet, batchData, { skipHeader: true, origin: -1 });
// 设置列宽、行高和样式
// 设置每列的宽度(单位:字符)
const wsCols: { wch: number }[] = new Array(data.columns.length).fill({ wch: 30 });
worksheet['!cols'] = wsCols;
worksheet['!cols'][0] = { wch: 50 };
// 设置行高(单位:像素,通常建议设置为 20 或更高)
worksheet['!rows'] = new Array(batchData + 1).fill({ hpt: 50 });
worksheet['!rows'][0] = { hpt: 25 };
// 应用样式到表头和普通单元格
for (const col in worksheet) {
if (col[0] === '!') continue; // 跳过元数据
const cell = worksheet[col];
// 设置表头样式
if (data.columns.some(header => header.headerText === cell.v)) {
cell.s = headerCellStyle;
} else {
cell.s = cellStyle; // 设置普通单元格样式
}
}
// 根据 ProblemFields 高亮单元格
batchData.forEach((row, rowIndex) => {
const globalRowIndex = i + rowIndex; // 计算全局行索引
highlightFields[globalRowIndex].forEach(problemField => {
const colIndex = data.columns.findIndex(col => col.name === problemField); // 找到对应的列索引
if (colIndex !== -1) {
const cellRef = XLSX_STYLE.utils.encode_cell({ c: colIndex, r: rowIndex + 1 }); // 行号加1因为第一行为表头
if (worksheet[cellRef]) {
worksheet[cellRef].s = highlightStyle; // 应用高亮样式
}
}
});
});
ws.push(worksheet);
}
// const worksheet = XLSX_STYLE.utils.json_to_sheet(formattedData, { header: data.columns.map(col => col.headerText) });
const workbook = XLSX_STYLE.utils.book_new();
const min = formattedData.length > BATCH_SIZE ? BATCH_SIZE : formattedData.length;
ws.forEach((worksheet: any) => {
XLSX_STYLE.utils.book_append_sheet(workbook, worksheet);
});
console.log("准备写入")
const val = XLSX_STYLE.write(workbook, { type: "array", bookType: "xlsx", bookSST: true, compression: true });
console.log("写入完成")
self.postMessage({ t: "export", v: val } as ExportMessage);
};