exporter.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /*
  2. * 导出相关工具(最小落地版)
  3. * 仅抽离现有 calcPageTemplate 的导出格式化逻辑,避免页面过重
  4. */
  5. import { ProColumns } from '@ant-design/pro-components';
  6. import exportTableToExcel from './tableToExcel';
  7. import { formatMoneyNumber, formatToPercentage } from './format';
  8. export interface ExportOptions {
  9. // 页面 key,用于处理特殊格式化
  10. calcPageKey?: string;
  11. // 是否为树形数据时需要缩进的列
  12. indentColumn?: string;
  13. }
  14. /**
  15. * 根据当前列与数据,进行必要的格式化与树形缩进,并导出为 Excel
  16. * 注意:本方法内的“wholeHospCostCalculate”逻辑与原实现保持一致,避免行为变化
  17. */
  18. export function exportCalcPageDataToExcel(
  19. columns: ProColumns[],
  20. totalData: any[],
  21. options: ExportOptions = {}
  22. ) {
  23. const { calcPageKey, indentColumn } = options;
  24. // 生成表头
  25. const headers: { [key: string]: any } = {};
  26. columns.forEach((a: any) => {
  27. headers[`${a.dataIndex}`] = a.title;
  28. });
  29. // 列配置索引,便于判断数值列
  30. const columnMap = new Map<string, any>();
  31. (columns as any[])?.forEach?.((c) => {
  32. if (c && c.dataIndex) columnMap.set(String(c.dataIndex), c);
  33. });
  34. // 递归处理数据(支持 children),并为 indentColumn 添加缩进
  35. const data: any[] = [];
  36. const processData = (items: any[], level: number = 0) => {
  37. items.forEach(item => {
  38. const row: { [key: string]: any } = {};
  39. Object.keys(headers).forEach(key => {
  40. if (indentColumn && key === indentColumn) {
  41. // 使用 Unicode 不可见空格来缩进
  42. row[`${key}`] = `${'\u00A0'.repeat(level * 4)}${item[`${key}`]}`;
  43. } else if (item.children && item.children.length > 0 && (calcPageKey !== 'wholeHospCostCalculate')) {
  44. // 非全院损益时,有 children 的父节点导出为空字符串
  45. row[`${key}`] = '';
  46. } else {
  47. if (calcPageKey === 'wholeHospCostCalculate') {
  48. if (key === 'amount') {
  49. const { decimalPlace, permil, dataType, children, calcType } = item;
  50. if (children && children.length > 0 && calcType === '0') {
  51. row[`${key}`] = '';
  52. } else if (dataType === 2) {
  53. row[`${key}`] = typeof item[`${key}`] === 'number' && !isNaN(item[`${key}`])
  54. ? `${(item[`${key}`] * 100).toFixed(decimalPlace || 2)}%`
  55. : item[`${key}`];
  56. } else {
  57. const formatOptions = {
  58. decimalPlaces: decimalPlace !== undefined ? decimalPlace : 2,
  59. useThousandSeparator: permil === 1,
  60. };
  61. row[`${key}`] = formatMoneyNumber(item[`${key}`], formatOptions);
  62. }
  63. } else if (key === 'percent') {
  64. const { children, calcType } = item;
  65. row[`${key}`] = (children && children.length > 0 && calcType === '0')
  66. ? ''
  67. : formatToPercentage(item[`${key}`]);
  68. } else {
  69. row[`${key}`] = item[`${key}`];
  70. }
  71. } else if (calcPageKey === 'deptDirectMedicalCost' || calcPageKey === 'deptFullDirectCost' || calcPageKey === 'hospitalVisitCostComposition' || calcPageKey === 'hospitalDeptVisitCost' || calcPageKey === 'deptCostAllocationSummary' || calcPageKey === 'hospitalBedDayCostComposition') {
  72. // 这两个页面导出需要默认启用千分号,并按行的 decimalPlace 控制小数位
  73. const col = columnMap.get(key);
  74. const isNumericColumn = col && (col.align === 'right');
  75. if (isNumericColumn) {
  76. const decimalPlaces = (typeof item?.decimalPlace === 'number') ? item.decimalPlace : 2;
  77. row[`${key}`] = formatMoneyNumber(item[`${key}`], { decimalPlaces, useThousandSeparator: true });
  78. } else {
  79. row[`${key}`] = item[`${key}`];
  80. }
  81. } else {
  82. row[`${key}`] = item[`${key}`];
  83. }
  84. }
  85. });
  86. data.push(row);
  87. if (item.children && item.children.length > 0) {
  88. processData(item.children, level + 1);
  89. }
  90. });
  91. };
  92. processData(totalData);
  93. // 根据页面 key 设定导出文件名
  94. const fileNameMap: Record<string, string> = {
  95. wholeHospCostCalculate: '全院损益报表',
  96. projectCostCalc: '项目成本计算',
  97. deptDirectMedicalCost: '医院科室直接成本表(医疗成本)',
  98. deptFullDirectCost: '医院科室直接成本表(全成本)',
  99. clinicalDeptMedicalCost: '临床服务类科室全成本(医疗成本)',
  100. clinicalDeptFullCost: '临床服务类科室全成本(全成本)',
  101. clinicalDeptFullCostAnalysis: '临床服务类科室全成本构成分析表',
  102. deptCostAllocationSummary: '医院科室成本分摊汇总表',
  103. hospitalVisitCostComposition: '医院诊次成本构成表',
  104. hospitalBedDayCostComposition: '医院床日成本构成表',
  105. };
  106. const fileName = (calcPageKey && fileNameMap[calcPageKey]) ? fileNameMap[calcPageKey] : '项目成本计算';
  107. exportTableToExcel(data, columns as any[], fileName);
  108. }