| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970 |
- // 1) 安全地把对象数组转成 CSV 文本
- export function toCSV<T extends Record<string, any>>(
- rows: T[],
- opts?: {
- headers?: string[] // 指定列顺序与表头;不传则用 rows[0] 的键
- delimiter?: string // 默认逗号 ","
- includeHeader?: boolean // 默认 true
- },
- ): string {
- const delimiter = opts?.delimiter ?? ','
- const includeHeader = opts?.includeHeader ?? true
- if (!rows?.length) return ''
- const headers = opts?.headers ?? Object.keys(rows[0])
- // 处理每个单元格:转为字符串、转义双引号、若含分隔符/换行/引号则整体再包一层引号
- const esc = (val: any) => {
- let s = val == null ? '' : String(val)
- s = s.replace(/"/g, '""')
- if (s.includes('"') || s.includes(delimiter) || s.includes('\n') || s.includes('\r')) {
- s = `"${s}"`
- }
- return s
- }
- const lines: string[] = []
- if (includeHeader) {
- lines.push(headers.map((h) => esc(h)).join(delimiter))
- }
- for (const row of rows) {
- lines.push(headers.map((h) => esc(row[h])).join(delimiter))
- }
- // Windows/Excel 友好:使用 \r\n 作为换行
- return lines.join('\r\n')
- }
- // 2) 触发浏览器下载(含 UTF-8 BOM,Excel 更稳)
- export function downloadCSV(filename: string, csv: string) {
- // 加 BOM,避免 Excel 中文乱码
- const BOM = '\uFEFF'
- 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.endsWith('.csv') ? filename : `${filename}.csv`
- document.body.appendChild(a)
- a.click()
- document.body.removeChild(a)
- URL.revokeObjectURL(url)
- }
- // 3) 使用示例
- // type Row = { id: number; name: string; note?: string };
- // const data: Row[] = [
- // { id: 1, name: "张三", note: "带,逗号" },
- // { id: 2, name: "李四", note: "含\"引号\"与换行\n第二行" },
- // ];
- // const csv = toCSV(data, {
- // headers: ["id", "name", "note"], // 指定列顺序(可选)
- // includeHeader: true,
- // });
- // downloadCSV("示例数据.csv", csv);
|