excelParser.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. import type { SheetConfig } from '@/client/member/components/ExcelToJson/types';
  2. import * as XLSX from 'xlsx';
  3. import { performance } from 'node:perf_hooks'
  4. // Excel数据行类型
  5. export interface ExcelRow {
  6. [key: string]: string | number | null | undefined;
  7. _id?: string;
  8. tableIndex?: number;
  9. }
  10. // Excel原始数据类型
  11. type ExcelJsonData = Array<Array<string | number | null>>;
  12. /**
  13. * 服务器端Excel解析器
  14. * 从useExcelParser.ts中抽取的核心功能,移除了React和UI相关代码
  15. */
  16. export class ExcelParser {
  17. /**
  18. * 处理数据用于导出
  19. * @param data 原始数据行
  20. * @param sheetConfig 工作表配置
  21. * @param tableIndex 表格索引
  22. * @returns 处理后的数据
  23. */
  24. processDataForExport(
  25. data: ExcelRow[],
  26. sheetConfig: SheetConfig,
  27. tableIndex: number = 0
  28. ): ExcelRow[] {
  29. console.log(`[ExcelParser] 开始处理导出数据,数据行数: ${data.length},表格索引: ${tableIndex}`);
  30. // 记录exportFields和requiredFields配置
  31. console.log(`[ExcelParser] 导出字段配置: ${sheetConfig.exportFields.length} 个字段,必需字段: ${sheetConfig.requiredFields.length} 个`);
  32. const result = data
  33. .map((row, index) => {
  34. const processedRow: ExcelRow = {};
  35. processedRow._id = `table-${tableIndex}-row-${index}`;
  36. // 如果exportFields为空,保留所有原始字段
  37. if (sheetConfig.exportFields.length === 0) {
  38. console.log(`[ExcelParser] 导出字段为空,保留行 ${index} 的所有原始字段`);
  39. Object.keys(row).forEach(field => {
  40. processedRow[field] = row[field] ?? null;
  41. });
  42. } else {
  43. // 按照exportFields配置处理
  44. sheetConfig.exportFields.forEach(field => {
  45. const mappedField = sheetConfig.fieldMappings[field] || field;
  46. processedRow[mappedField] = row[field] ?? null;
  47. });
  48. }
  49. return processedRow;
  50. })
  51. .filter(row => {
  52. // 如果没有设置必需字段或exportFields为空,则不过滤
  53. if (sheetConfig.requiredFields.length === 0 || sheetConfig.exportFields.length === 0) {
  54. return true;
  55. }
  56. // 检查必需字段是否有值
  57. const isValid = sheetConfig.requiredFields.every(field => {
  58. const value = row[sheetConfig.fieldMappings[field] || field];
  59. return value !== null && value !== undefined && value !== '';
  60. });
  61. if (!isValid) {
  62. console.log(`[ExcelParser] 过滤掉不满足必需字段的行: ${row._id}`);
  63. }
  64. return isValid;
  65. });
  66. console.log(`[ExcelParser] 处理后的导出数据行数: ${result.length}`);
  67. return result;
  68. }
  69. /**
  70. * 处理所有字段数据
  71. * @param data 原始数据行
  72. * @param tableIndex 表格索引
  73. * @returns 处理后的数据
  74. */
  75. processAllFieldsData(
  76. data: ExcelRow[],
  77. tableIndex: number = 0
  78. ): ExcelRow[] {
  79. console.log(`[ExcelParser] 处理所有字段数据,数据行数: ${data.length},表格索引: ${tableIndex}`);
  80. const result = data.map((row, index) => ({
  81. ...row,
  82. _id: `table-${tableIndex}-row-${index}`
  83. }));
  84. return result;
  85. }
  86. /**
  87. * 获取每个工作表中的所有可用字段
  88. * @param data 工作表数据
  89. * @returns 按工作表分类的可用字段
  90. */
  91. getAllAvailableFields(data: { [key: string]: ExcelRow[] }): { [key: string]: string[] } {
  92. console.log(`[ExcelParser] 获取所有可用字段,工作表数: ${Object.keys(data).length}`);
  93. const result: { [key: string]: string[] } = {};
  94. // 遍历每个工作表的数据
  95. Object.keys(data).forEach(sheetName => {
  96. const sheetData = data[sheetName];
  97. if (sheetData.length === 0) {
  98. console.log(`[ExcelParser] 工作表 ${sheetName} 没有数据,返回空字段列表`);
  99. result[sheetName] = [];
  100. return;
  101. }
  102. // 获取该工作表中的所有唯一字段名
  103. const uniqueFields = new Set<string>();
  104. sheetData.forEach(row => {
  105. Object.keys(row).forEach(key => {
  106. // 排除特殊字段和空值
  107. if (key !== '_id' && key !== 'tableIndex') {
  108. uniqueFields.add(key);
  109. }
  110. });
  111. });
  112. // 转换为数组
  113. result[sheetName] = Array.from(uniqueFields);
  114. console.log(`[ExcelParser] 工作表 ${sheetName} 的可用字段数: ${result[sheetName].length}`);
  115. });
  116. return result;
  117. }
  118. /**
  119. * 解析单个表格数据
  120. */
  121. parseSingleTable(
  122. json: ExcelJsonData,
  123. headers: string[],
  124. startRow: number,
  125. endMarker: string,
  126. orderNumberRow: number,
  127. orderNumberCol: number,
  128. productNameRow?: number,
  129. productNameCol?: number
  130. ): { data: ExcelRow[]; endIndex: number } {
  131. console.log(`[ExcelParser] 开始解析单个表格,起始行: ${startRow},结束标记: ${endMarker || '无'}`);
  132. console.log(`[ExcelParser] 表头行数: ${headers.length},订单号位置: 行=${orderNumberRow}, 列=${orderNumberCol}`);
  133. if (productNameRow !== undefined && productNameCol !== undefined) {
  134. console.log(`[ExcelParser] 产品名称位置: 行=${productNameRow}, 列=${productNameCol}`);
  135. }
  136. const data: ExcelRow[] = [];
  137. let endIndex = json.length - 1;
  138. let orderNumber = '';
  139. let productName = '';
  140. // 获取订单号
  141. if (orderNumberRow >= 0 && orderNumberRow < json.length &&
  142. orderNumberCol >= 0 && orderNumberCol < (json[orderNumberRow]?.length || 0)) {
  143. orderNumber = String(json[orderNumberRow][orderNumberCol] || '');
  144. console.log(`[ExcelParser] 获取到订单号: ${orderNumber}`);
  145. } else {
  146. console.log(`[ExcelParser] 未获取到订单号,参数可能无效`);
  147. }
  148. // 获取产品名称(如果配置了产品名称行列号)
  149. if (productNameRow !== undefined && productNameCol !== undefined &&
  150. productNameRow >= 0 && productNameRow < json.length &&
  151. productNameCol >= 0 && productNameCol < (json[productNameRow]?.length || 0)) {
  152. productName = String(json[productNameRow][productNameCol] || '');
  153. console.log(`[ExcelParser] 获取到产品名称: ${productName}`);
  154. } else if (productNameRow !== undefined || productNameCol !== undefined) {
  155. console.log(`[ExcelParser] 未获取到产品名称,参数可能无效`);
  156. }
  157. // 找到结束标记行(如果有)
  158. if (endMarker && endMarker.trim() !== '') {
  159. console.log(`[ExcelParser] 搜索结束标记: ${endMarker}`);
  160. let found = false;
  161. for (let i = startRow; i < json.length; i++) {
  162. if (!json[i]) continue;
  163. const firstCell = json[i][0];
  164. if (firstCell && String(firstCell).includes(endMarker)) {
  165. endIndex = i - 1;
  166. found = true;
  167. console.log(`[ExcelParser] 找到结束标记,结束行索引: ${endIndex}`);
  168. break;
  169. }
  170. }
  171. if (!found) {
  172. console.log(`[ExcelParser] 未找到结束标记,将使用表格最后一行`);
  173. }
  174. }
  175. // 从起始行到结束行,提取数据并映射到列标题
  176. console.log(`[ExcelParser] 开始解析数据行,范围: ${startRow} - ${endIndex}`);
  177. let validRowCount = 0;
  178. for (let i = startRow; i <= endIndex; i++) {
  179. if (!json[i] || json[i].length === 0) {
  180. console.log(`[ExcelParser] 跳过空行: ${i}`);
  181. continue;
  182. }
  183. const row: ExcelRow = {};
  184. // 检查行是否有效(非空行)
  185. let hasValidData = false;
  186. // 映射列标题和值
  187. headers.forEach((header, columnIndex) => {
  188. if (header) {
  189. const value = json[i][columnIndex];
  190. row[header] = value ?? null;
  191. // 如果有任何一个单元格有值,则认为这行有效
  192. if (value !== null && value !== undefined && value !== '') {
  193. hasValidData = true;
  194. }
  195. }
  196. });
  197. // 添加订单号
  198. if (orderNumber) {
  199. row['订单号'] = orderNumber;
  200. }
  201. // 添加产品名称
  202. if (productName) {
  203. row['产品名称'] = productName;
  204. }
  205. // 只添加有效的行数据
  206. if (hasValidData) {
  207. data.push(row);
  208. validRowCount++;
  209. } else {
  210. console.log(`[ExcelParser] 跳过无效行: ${i} (没有有效数据)`);
  211. }
  212. }
  213. console.log(`[ExcelParser] 解析完成,有效数据行数: ${validRowCount}`);
  214. return { data, endIndex };
  215. }
  216. /**
  217. * 解析多表格数据
  218. */
  219. parseMultiTable(
  220. json: ExcelJsonData,
  221. sheetConfig: SheetConfig
  222. ): ExcelRow[][] {
  223. console.log(`[ExcelParser] 开始解析多表格数据,配置: 标题行=${sheetConfig.headerRowIndex}, 数据起始行=${sheetConfig.dataStartRow}`);
  224. const tableDataSets: ExcelRow[][] = [];
  225. let currentRow = sheetConfig.dataStartRow - 1;
  226. const {
  227. headerRowIndex,
  228. endMarker,
  229. multiTableHeaderOffset = 2,
  230. multiTableDataOffset = 1,
  231. multiTableOrderNumberOffset = -1,
  232. multiTableProductNameOffset = -1
  233. } = sheetConfig;
  234. console.log(`[ExcelParser] 多表格配置: headerOffset=${multiTableHeaderOffset}, dataOffset=${multiTableDataOffset}, orderNumberOffset=${multiTableOrderNumberOffset}`);
  235. if (sheetConfig.productNameRow !== undefined && sheetConfig.productNameCol !== undefined) {
  236. console.log(`[ExcelParser] 产品名称配置: productNameOffset=${multiTableProductNameOffset}`);
  237. }
  238. // 解析第一个表格
  239. console.log(`[ExcelParser] 开始解析第一个表格`);
  240. const { data: firstTableData, endIndex: firstEndIndex } = this.parseSingleTable(
  241. json,
  242. json[headerRowIndex - 1] as string[],
  243. currentRow,
  244. endMarker,
  245. sheetConfig.orderNumberRow - 1,
  246. sheetConfig.orderNumberCol - 1,
  247. sheetConfig.productNameRow !== undefined ? sheetConfig.productNameRow - 1 : undefined,
  248. sheetConfig.productNameCol !== undefined ? sheetConfig.productNameCol - 1 : undefined
  249. );
  250. if (firstTableData.length > 0) {
  251. tableDataSets.push(firstTableData);
  252. console.log(`[ExcelParser] 第一个表格解析完成,数据行数: ${firstTableData.length}`);
  253. } else {
  254. console.log(`[ExcelParser] 第一个表格没有有效数据`);
  255. }
  256. currentRow = firstEndIndex + 1;
  257. console.log(`[ExcelParser] 更新当前行索引: ${currentRow}`);
  258. // 继续解析后续表格
  259. let tableCount = 1;
  260. while (currentRow < json.length - 1 && currentRow + multiTableHeaderOffset < json.length) {
  261. tableCount++;
  262. console.log(`[ExcelParser] 开始解析表格 #${tableCount}`);
  263. const newHeaderRowIndex = currentRow + multiTableHeaderOffset;
  264. const newDataStartRowIndex = newHeaderRowIndex + multiTableDataOffset;
  265. const newOrderNumberRow = newHeaderRowIndex + multiTableOrderNumberOffset;
  266. console.log(`[ExcelParser] 表格 #${tableCount} 计算位置: 标题行=${newHeaderRowIndex}, 数据起始行=${newDataStartRowIndex}, 订单号行=${newOrderNumberRow}`);
  267. // 计算产品名称行(如果配置了产品名称行列号)
  268. let newProductNameRow = undefined;
  269. if (sheetConfig.productNameRow !== undefined && sheetConfig.productNameCol !== undefined) {
  270. newProductNameRow = newHeaderRowIndex + multiTableProductNameOffset;
  271. console.log(`[ExcelParser] 表格 #${tableCount} 产品名称行=${newProductNameRow}`);
  272. }
  273. if (newDataStartRowIndex >= json.length) {
  274. console.log(`[ExcelParser] 表格 #${tableCount} 数据起始行超出范围,停止解析`);
  275. break;
  276. }
  277. // 获取新表格的列标题
  278. const newHeaders = json[newHeaderRowIndex] as string[];
  279. if (!newHeaders || newHeaders.length === 0) {
  280. console.log(`[ExcelParser] 表格 #${tableCount} 无有效标题行,停止解析`);
  281. break;
  282. }
  283. console.log(`[ExcelParser] 表格 #${tableCount} 获取到标题列数: ${newHeaders.filter(Boolean).length}`);
  284. // 解析新表格
  285. const { data: tableData, endIndex } = this.parseSingleTable(
  286. json,
  287. newHeaders,
  288. newDataStartRowIndex,
  289. endMarker,
  290. newOrderNumberRow,
  291. sheetConfig.orderNumberCol - 1,
  292. newProductNameRow,
  293. sheetConfig.productNameCol !== undefined ? sheetConfig.productNameCol - 1 : undefined
  294. );
  295. if (tableData.length > 0) {
  296. tableDataSets.push(tableData);
  297. console.log(`[ExcelParser] 表格 #${tableCount} 解析完成,数据行数: ${tableData.length}`);
  298. } else {
  299. console.log(`[ExcelParser] 表格 #${tableCount} 没有有效数据`);
  300. }
  301. currentRow = endIndex + 1;
  302. console.log(`[ExcelParser] 更新当前行索引: ${currentRow}`);
  303. }
  304. console.log(`[ExcelParser] 多表格解析完成,共 ${tableDataSets.length} 个表格`);
  305. return tableDataSets;
  306. }
  307. /**
  308. * 解析Excel文件
  309. * @param buffer Excel文件的ArrayBuffer数据
  310. * @param sheetConfigs 工作表配置
  311. * @returns 解析结果
  312. */
  313. async parseExcelBuffer(buffer: ArrayBuffer, sheetConfigs: SheetConfig[]) {
  314. console.log(`[ExcelParser] 开始解析Excel文件,文件大小: ${buffer.byteLength} 字节,工作表配置数: ${sheetConfigs.length}`);
  315. try {
  316. const workbook = XLSX.read(buffer);
  317. console.log(`[ExcelParser] Excel文件读取成功,工作表数: ${workbook.SheetNames.length}`);
  318. console.log(`[ExcelParser] 工作表列表: ${workbook.SheetNames.join(', ')}`);
  319. const rawData: { [key: string]: ExcelRow[] } = {};
  320. const warnings: string[] = [];
  321. let totalTables = 0;
  322. // 处理每个配置的工作表
  323. for (const sheetConfig of sheetConfigs) {
  324. console.log(`[ExcelParser] 开始处理工作表: ${sheetConfig.sheetName}`);
  325. const worksheet = workbook.Sheets[sheetConfig.sheetName];
  326. if (!worksheet) {
  327. const warning = `未找到工作表: ${sheetConfig.sheetName}`;
  328. console.log(`[ExcelParser] 警告: ${warning}`);
  329. warnings.push(warning);
  330. continue;
  331. }
  332. console.log(`[ExcelParser] 转换工作表为JSON数据`);
  333. const json = XLSX.utils.sheet_to_json<string[]>(worksheet, { header: 1 }) as ExcelJsonData;
  334. console.log(`[ExcelParser] 转换完成,行数: ${json.length}`);
  335. const headers = json[sheetConfig.headerRowIndex - 1] as string[];
  336. if (!headers || headers.length === 0) {
  337. const warning = `工作表 ${sheetConfig.sheetName} 的表头数据无效`;
  338. console.log(`[ExcelParser] 警告: ${warning}`);
  339. warnings.push(warning);
  340. continue;
  341. }
  342. console.log(`[ExcelParser] 获取到表头,列数: ${headers.filter(Boolean).length}`);
  343. console.log(`[ExcelParser] 是否为多表格模式: ${sheetConfig.isMultiTable ? '是' : '否'}`);
  344. if (sheetConfig.isMultiTable) {
  345. // 处理多表格模式
  346. const tableDataSets = this.parseMultiTable(json, sheetConfig);
  347. if (tableDataSets.length > 0) {
  348. console.log(`[ExcelParser] 多表格模式解析完成,共 ${tableDataSets.length} 个表格`);
  349. // 保存所有原始字段数据
  350. rawData[sheetConfig.sheetName] = tableDataSets.flatMap((tableData, tableIndex) => {
  351. console.log(`[ExcelParser] 处理表格 #${tableIndex + 1} 的所有字段数据,行数: ${tableData.length}`);
  352. return this.processAllFieldsData(tableData, tableIndex + 1).map(row => ({
  353. ...row,
  354. tableIndex: tableIndex + 1,
  355. }));
  356. });
  357. totalTables += tableDataSets.length;
  358. console.log(`[ExcelParser] 工作表 ${sheetConfig.sheetName} 处理完成,原始数据行数: ${rawData[sheetConfig.sheetName].length}`);
  359. } else {
  360. const warning = `未在 "${sheetConfig.sheetName}" 中找到有效的数据表`;
  361. console.log(`[ExcelParser] 警告: ${warning}`);
  362. warnings.push(warning);
  363. }
  364. } else {
  365. // 处理单表格模式
  366. console.log(`[ExcelParser] 开始处理单表格模式`);
  367. const { data } = this.parseSingleTable(
  368. json,
  369. headers,
  370. sheetConfig.dataStartRow - 1,
  371. sheetConfig.endMarker,
  372. sheetConfig.orderNumberRow - 1,
  373. sheetConfig.orderNumberCol - 1,
  374. sheetConfig.productNameRow !== undefined ? sheetConfig.productNameRow - 1 : undefined,
  375. sheetConfig.productNameCol !== undefined ? sheetConfig.productNameCol - 1 : undefined
  376. );
  377. if (data.length > 0) {
  378. console.log(`[ExcelParser] 单表格模式解析完成,数据行数: ${data.length}`);
  379. // 保存所有原始字段数据
  380. rawData[sheetConfig.sheetName] = this.processAllFieldsData(data, 1);
  381. totalTables += 1;
  382. console.log(`[ExcelParser] 工作表 ${sheetConfig.sheetName} 处理完成,原始数据行数: ${rawData[sheetConfig.sheetName].length}`);
  383. } else {
  384. const warning = `未在 "${sheetConfig.sheetName}" 中找到有效数据`;
  385. console.log(`[ExcelParser] 警告: ${warning}`);
  386. warnings.push(warning);
  387. }
  388. }
  389. }
  390. // 生成导出数据
  391. console.log(`[ExcelParser] 开始生成导出数据`);
  392. const exportData = this.generateExportData(rawData, sheetConfigs);
  393. // 计算可用字段(按工作表分类)
  394. console.log(`[ExcelParser] 计算可用字段`);
  395. const availableFieldsBySheet = this.getAllAvailableFields(rawData);
  396. console.log(`[ExcelParser] Excel解析完成,总表格数: ${totalTables},警告数: ${warnings.length}`);
  397. return {
  398. rawData,
  399. exportData,
  400. availableFieldsBySheet,
  401. warnings,
  402. totalTables
  403. };
  404. } catch (error) {
  405. console.error(`[ExcelParser] Excel解析错误:`, error);
  406. throw error;
  407. }
  408. }
  409. /**
  410. * 从URL或base64字符串获取ArrayBuffer
  411. */
  412. async getBufferFromUrlOrBase64(input: string): Promise<ArrayBuffer> {
  413. console.log(`[ExcelParser] 开始从输入获取数据`);
  414. if (input.startsWith('data:')) {
  415. console.log(`[ExcelParser] 检测到Base64编码数据`);
  416. // 处理Base64编码
  417. const base64 = input.split(',')[1];
  418. if (!base64) {
  419. console.error(`[ExcelParser] Base64格式错误,无法提取数据部分`);
  420. throw new Error('Base64格式错误,无法提取数据部分');
  421. }
  422. console.log(`[ExcelParser] 正在解码Base64数据`);
  423. const binaryString = atob(base64);
  424. const len = binaryString.length;
  425. console.log(`[ExcelParser] Base64解码完成,二进制数据长度: ${len} 字节`);
  426. const bytes = new Uint8Array(len);
  427. for (let i = 0; i < len; i++) {
  428. bytes[i] = binaryString.charCodeAt(i);
  429. }
  430. console.log(`[ExcelParser] 成功获取ArrayBuffer,大小: ${bytes.buffer.byteLength} 字节`);
  431. return bytes.buffer;
  432. } else if (input.startsWith('http')) {
  433. console.log(`[ExcelParser] 检测到URL: ${input.substring(0, 50)}...`);
  434. // 处理URL
  435. try {
  436. const startTime = performance.now();
  437. console.log(`[ExcelParser] 开始从URL获取文件`);
  438. const response = await fetch(input);
  439. if (!response.ok) {
  440. console.error(`[ExcelParser] 获取文件失败: ${response.status} ${response.statusText}`);
  441. throw new Error(`获取文件失败: ${response.statusText}`);
  442. }
  443. const buffer = await response.arrayBuffer();
  444. const endTime = performance.now();
  445. const duration = (endTime - startTime).toFixed(2);
  446. console.log(`[ExcelParser] 成功从URL获取文件,大小: ${buffer.byteLength} 字节,耗时: ${duration}ms`);
  447. return buffer;
  448. } catch (error) {
  449. console.error(`[ExcelParser] 从URL获取文件时出错:`, error);
  450. throw new Error(`从URL获取文件时出错: ${error instanceof Error ? error.message : String(error)}`);
  451. }
  452. } else {
  453. console.error(`[ExcelParser] 不支持的输入格式: ${input.substring(0, 50)}...`);
  454. throw new Error('不支持的输入格式,请提供URL或Base64编码的数据');
  455. }
  456. }
  457. /**
  458. * 根据当前配置动态生成导出数据
  459. */
  460. generateExportData(
  461. allFieldsData: { [key: string]: ExcelRow[] },
  462. sheetConfigs: SheetConfig[]
  463. ): { [key: string]: ExcelRow[] } {
  464. console.log(`[ExcelParser] 开始生成导出数据,工作表数: ${Object.keys(allFieldsData).length}`);
  465. // 如果没有原始数据,直接返回空对象
  466. if (Object.keys(allFieldsData).length === 0) {
  467. console.log(`[ExcelParser] 没有原始数据,返回空导出数据`);
  468. return {};
  469. }
  470. const exportData: { [key: string]: ExcelRow[] } = {};
  471. // 处理每个工作表的数据
  472. for (const sheetConfig of sheetConfigs) {
  473. console.log(`[ExcelParser] 处理工作表 ${sheetConfig.sheetName} 的导出数据`);
  474. const rawDataForSheet = allFieldsData[sheetConfig.sheetName];
  475. if (!rawDataForSheet || rawDataForSheet.length === 0) {
  476. console.log(`[ExcelParser] 工作表 ${sheetConfig.sheetName} 没有原始数据,跳过处理`);
  477. continue;
  478. }
  479. // 根据当前配置处理数据
  480. // 使用exportSheetName作为导出的工作表名称,默认为sheetName
  481. const exportSheetName = sheetConfig.exportSheetName || sheetConfig.sheetName;
  482. exportData[exportSheetName] = this.processDataForExport(
  483. rawDataForSheet,
  484. sheetConfig,
  485. 1
  486. );
  487. console.log(`[ExcelParser] 工作表 ${sheetConfig.sheetName} 导出数据处理完成,行数: ${exportData[sheetConfig.sheetName].length}`);
  488. }
  489. console.log(`[ExcelParser] 导出数据生成完成,工作表数: ${Object.keys(exportData).length}`);
  490. return exportData;
  491. }
  492. }
  493. // 导出单例实例,便于服务端使用
  494. export const excelParser = new ExcelParser();