// REQ-USR-003: 前端零依赖 CSV 导出(UTF-8 BOM + Blob + ,D-PLAN-1) import type { UserVO } from '../../../api/types'; /** 导出列定义:中文表头 + 从 UserVO 取值(与列定义语义一致,作废 0/1→否/是;不含序号列) */ const EXPORT_COLUMNS: { header: string; pick: (row: UserVO) => string }[] = [ { header: '用户名', pick: (r) => r.sUserName ?? '' }, { header: '员工名', pick: (r) => r.employeeName ?? '' }, { header: '用户号', pick: (r) => r.sUserNo ?? '' }, { header: '部门', pick: (r) => r.departmentName ?? '' }, { header: '用户类型', pick: (r) => r.sUserType ?? '' }, { header: '语言', pick: (r) => r.sLanguage ?? '' }, { header: '作废', pick: (r) => (r.iIsVoid === 1 ? '是' : '否') }, { header: '登录日期', pick: (r) => r.tLastLoginDate ?? '' }, { header: '制单人', pick: (r) => r.sCreator ?? '' }, { header: '制单日期', pick: (r) => r.tCreateDate ?? '' }, ]; /** CSV 单元转义:含逗号 / 引号 / 换行时用双引号包裹并转义内部引号 */ function escapeCell(value: string): string { if (/[",\n\r]/.test(value)) { return `"${value.replace(/"/g, '""')}"`; } return value; } /** 按列定义顺序与中文表头生成 CSV 文本(含表头行;空值→空串;作废 0/1→否/是) */ export function buildUserCsv(rows: UserVO[]): string { const header = EXPORT_COLUMNS.map((c) => escapeCell(c.header)).join(','); const body = rows.map((row) => EXPORT_COLUMNS.map((c) => escapeCell(c.pick(row))).join(','), ); return [header, ...body].join('\n'); } /** 前置 UTF-8 BOM → Blob → createObjectURL → 触发 下载 */ export function downloadCsv(filename: string, csv: string): void { const BOM = ''; const blob = new Blob([BOM + csv], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }