Files
xh-medical-sign-web/clinical-web/src/utils/csv-export.ts
T

68 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* CSV 生成与浏览器下载。
*
* 抽成公共实现的直接原因:签署记录查询与报表分析都要「按当前条件导出全量」,
* 两边各写一份 CSV 转义迟早会分叉 —— 一边处理了换行一边没处理,
* 导出的文件里就会多出一行被 Excel 解析成错位的数据,而且很难一眼看出来。
*
* ⚠️ 前端导出是**临时手段**:导出行为、导出人、导出范围都该写入审计日志,
* 浏览器里做不到。后端提供导出任务接口后,这里应整体替换为服务端导出。
*/
export interface CsvColumn<T> {
label: string
value: (row: T) => string
}
/** 含逗号、引号或换行的字段必须整体加引号,内部引号翻倍 */
export function escapeCsvField(value: string): string {
return /[",\n\r]/.test(value) ? `"${value.replace(/"/g, '""')}"` : value
}
/** 文件名时间戳:`YYYYMMDDHHmm` */
export function fileStamp(date = new Date()): string {
const pad = (value: number) => String(value).padStart(2, '0')
return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}${pad(date.getHours())}${pad(date.getMinutes())}`
}
/**
* 触发浏览器下载。
*
* 用 `setTimeout(revoke, 0)` 而不是立刻 revoke:立刻释放会让部分浏览器
* 来不及读取 blob 就中断下载。
*/
export function saveBlob(blob: Blob, fileName: string): void {
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = fileName
link.click()
window.setTimeout(() => URL.revokeObjectURL(url), 0)
}
/** 按列定义把行数据拼成 CSV 文本(含表头,行分隔用 CRLF) */
export function toCsv<T>(columns: readonly CsvColumn<T>[], rows: readonly T[]): string {
return [
columns.map((column) => escapeCsvField(column.label)).join(','),
...rows.map((row) => columns.map((column) => escapeCsvField(column.value(row))).join(',')),
].join('\r\n')
}
/**
* 生成并下载 CSV。
*
* 带 BOM:Excel 直接打开 UTF-8 CSV 时,没有 BOM 会把中文显示成乱码。
*/
export function downloadCsv<T>(
columns: readonly CsvColumn<T>[],
rows: readonly T[],
fileName: string,
): void {
saveBlob(
new Blob([`\uFEFF${toCsv(columns, rows)}`], { type: 'text/csv;charset=utf-8' }),
fileName,
)
}