import type { VehicleListItem } from './types'; export type ExportRow = Record; /** Use complete filtered groups, never the progressively rendered slice. Repeat parent labels for Excel filtering. */ export function statisticsExportRows(labels: string[], groups: { values: string[]; count: number; extra?: ExportRow }[], total: number, unit = '台'): ExportRow[] { return groups.map(group => ({ ...Object.fromEntries(labels.length ? labels.map((label, index) => [label, group.values[index]]) : [['统计范围', '当前筛选结果']]), [`数量(${unit})`]: group.count, ...group.extra, '占比(%)': total ? Number((group.count / total * 100).toFixed(1)) : 0, })); } export function vehicleExportRows(vehicles: VehicleListItem[]): ExportRow[] { const status: Record = { Abnormal: '异动', Pending: '待交车', Inventory: '在库', Operating: '运营中' }; const operation: Record = { '1': '租赁', '2': '自营', '3': '可运营', '4': '待运营' }; const hasPending = vehicles.some(v => v.pendingDelivery); const hasMovement = vehicles.some(v => v.abnormalMove); return vehicles.map(v => ({ 车牌: v.plateNumber, VIN: v.vin, 品牌: v.brandLabel, 车型: v.type, 型号: v.model, 省份: v.province, 城市: v.city || v.location, 状态: status[v.status] || v.status, 运营状态: operation[v.operationStatus || ''] || v.operationStatus, 客户: v.customerName, 签约公司: v.orgName, 部门: v.departmentName, 业务负责人: v.customerManager, 所属公司: v.subjectOrg, 合同: v.contractNo, ...(hasPending ? { 待交车合同: v.pendingDelivery?.contractNo, 待交车客户: v.pendingDelivery?.customerName } : {}), ...(hasMovement ? { 异动类型: v.abnormalMove?.type, 审批通过时间: v.abnormalMove?.approvalPassedAt, '已异动时长(天)': v.abnormalMove?.elapsedDays == null ? null : Number(v.abnormalMove.elapsedDays.toFixed(1)), 具体工作: v.abnormalMove?.work, 申请人: v.abnormalMove?.applicant, 预计完成时间: v.abnormalMove?.targetCompletionTime, 实际完成时间: v.abnormalMove?.actualCompletionTime || (v.abnormalMove?.status === '待结束' ? '未完成' : null), } : {}), })); } async function analysisSheets(statistics: ExportRow[], details: ExportRow[]) { const { buildJsonSheet } = await import('../../shared/xlsx'); return ([['统计表', statistics], ['详情表', details]] as const).map(([name, rows]) => { const sheet = buildJsonSheet(rows.map(row => Object.fromEntries(Object.entries(row).map(([key, value]) => [key, value ?? '—'])))); sheet['!cols'] = Object.keys(rows[0] || {}).map(label => ({ wch: /时间|合同|项目|工作/.test(label) ? 28 : 18 })); if (sheet['!ref']) sheet['!autofilter'] = { ref: sheet['!ref'] }; return { name, sheet }; }); } export async function createAnalysisWorkbook(statistics: ExportRow[], details: ExportRow[]) { const { createWorkbook } = await import('../../shared/xlsx'); return createWorkbook(await analysisSheets(statistics, details)); } export async function downloadAnalysisWorkbook(statistics: ExportRow[], details: ExportRow[], title: string) { const { writeWorkbook } = await import('../../shared/xlsx'); const safeTitle = title.replace(/[\\/:*?"<>|\x00-\x1f]/g, '-').slice(0, 120); writeWorkbook(await analysisSheets(statistics, details), `${safeTitle}.xlsx`, { compression: true }); }