tableToExcel.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /*
  2. * @Author: code4eat awesomedema@gmail.com
  3. * @Date: 2023-05-31 11:18:30
  4. * @LastEditors: code4eat awesomedema@gmail.com
  5. * @LastEditTime: 2024-09-10 10:31:52
  6. * @FilePath: /BudgetManaSystem/src/utils/tableToExcel.ts
  7. * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  8. */
  9. import * as XLSX from 'xlsx';
  10. import { saveAs } from 'file-saver';
  11. type DataType = { [key: string]: string | number | null };
  12. type Column = {
  13. title: string;
  14. dataIndex: string;
  15. key: string;
  16. children?: Column[];
  17. };
  18. type Merge = {
  19. s: { r: number; c: number };
  20. e: { r: number; c: number };
  21. };
  22. function getMerges(columns: Column[], startRow = 0, startCol = 0): Merge[] {
  23. let merges: Merge[] = [];
  24. let colIndex = startCol;
  25. for (const column of columns) {
  26. let endRow = startRow;
  27. let endCol = colIndex;
  28. if (column.children) {
  29. // 如果有子列,递归处理子列
  30. const childMerges = getMerges(column.children, startRow + 1, colIndex);
  31. merges = merges.concat(childMerges);
  32. // 计算结束列的位置
  33. endCol += column.children.length - 1;
  34. }
  35. // 添加合并项
  36. merges.push({ s: { r: startRow, c: colIndex }, e: { r: endRow, c: endCol } });
  37. // 更新列索引
  38. colIndex = endCol + 1;
  39. }
  40. return merges;
  41. }
  42. function exportTableToExcel(tableData: DataType[], columns: Column[], fileName = 'data') {
  43. // 获取列标题
  44. const columnHeaders = columns.map(column => column.title);
  45. // 将列标题和表格数据合并
  46. const allData = [columnHeaders as any].concat(
  47. tableData.map(row =>
  48. Object.values(row).map(value =>
  49. (typeof value === 'string' ? value : value)
  50. )
  51. )
  52. );
  53. // 获取合并项
  54. const merges = getMerges(columns);
  55. // 创建一个新的工作簿
  56. const wb = XLSX.utils.book_new();
  57. // 将数据转化为工作表
  58. const ws = XLSX.utils.aoa_to_sheet(allData);
  59. // 设置合并项
  60. ws['!merges'] = merges;
  61. // 自动计算列宽
  62. const colWidths = allData[0].map((col: any, index: number) => {
  63. const maxLength = allData.reduce((max, row) => {
  64. const cellValue = row[index] ? row[index].toString() : '';
  65. return Math.max(max, cellValue.length);
  66. }, 0);
  67. return { wch: maxLength + 2 }; // 加上额外的2个字符的宽度来提供一些空间
  68. });
  69. ws['!cols'] = colWidths; // 设置工作表的列宽
  70. // 将工作表添加到工作簿中
  71. XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
  72. // 将工作簿转化为blob
  73. const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
  74. const blob = new Blob([wbout], { type: 'application/octet-stream' });
  75. // 使用file-saver保存文件
  76. saveAs(blob, `${fileName}.xlsx`);
  77. }
  78. export default exportTableToExcel;