File size: 4,100 Bytes
793e953 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | /**
* CSV 导出工具
*
* 纯前端生成 CSV 文件并触发浏览器下载,无需后端参与。
* 自动处理中文编码(UTF-8 BOM),确保 Excel 能正确显示中文。
*/
import { formatDateStatic } from './dateUtils'
/**
* 将数据导出为 CSV 文件并触发下载
*
* @param filename - 下载文件名(不含扩展名)
* @param headers - CSV 表头行
* @param rows - CSV 数据行(二维数组)
*/
export function exportToCSV(
filename: string,
headers: string[],
rows: string[][],
): void {
// BOM 确保 Excel 正确识别 UTF-8 中文
const BOM = '\uFEFF'
// 转义单元格:如果包含逗号、引号或换行,用引号包裹
const escapeCell = (cell: string): string => {
const str = String(cell ?? '')
if (str.includes(',') || str.includes('"') || str.includes('\n') || str.includes('\r')) {
return `"${str.replace(/"/g, '""')}"`
}
return str
}
const headerLine = headers.map(escapeCell).join(',')
const dataLines = rows.map(row => row.map(escapeCell).join(','))
const csvContent = BOM + [headerLine, ...dataLines].join('\n')
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `${filename}.csv`
document.body.appendChild(a)
a.click()
a.remove()
URL.revokeObjectURL(url)
}
/** 患者导出所需的简要字段 */
export interface ExportPatient {
animal_name: string
species: string
breed: string
sex: string
age: string
owner_name: string
weight?: string
created_at: string
}
/**
* 导出患者列表为 CSV
*/
export function exportPatientsToCSV(patients: ExportPatient[], locale: string = 'zh'): void {
const headers = ['动物名', '物种', '品种', '性别', '年龄', '主人', '体重(kg)', '创建时间']
const rows = patients.map(p => [
p.animal_name ?? '',
p.species ?? '',
p.breed ?? '',
p.sex ?? '',
p.age ?? '',
p.owner_name ?? '',
p.weight ?? '',
p.created_at ? formatDateStatic(p.created_at, locale) : '',
])
const dateStr = new Date().toISOString().slice(0, 10)
exportToCSV(`患者档案_${dateStr}`, headers, rows)
}
/** 问诊导出所需的简要字段 */
export interface ExportConsultation {
animal_name: string
species: string
breed: string
owner_name: string
status: string
doctor_name: string
serial_number: string
created_at: string
}
/**
* 导出问诊列表为 CSV
*/
export function exportConsultationsToCSV(consultations: ExportConsultation[], locale: string = 'zh'): void {
const statusLabel = (s: string): string => {
const map: Record<string, string> = {
'draft': '草稿',
'final': '终稿',
'recording': '录音中',
'transcribing': '转写中',
'processing': '处理中',
'cancelled': '已取消',
}
return map[s] ?? s
}
const headers = ['动物名', '物种', '品种', '主人', '状态', '医师', '编号', '创建时间']
const rows = consultations.map(c => [
c.animal_name ?? '',
c.species ?? '',
c.breed ?? '',
c.owner_name ?? '',
statusLabel(c.status),
c.doctor_name ?? '',
c.serial_number ?? '',
c.created_at ? formatDateStatic(c.created_at, locale) : '',
])
const dateStr = new Date().toISOString().slice(0, 10)
exportToCSV(`问诊记录_${dateStr}`, headers, rows)
}
/**
* 导出图表数据为 CSV(通用)
*
* 适用于饼图、柱状图等简单 key-value 数据的导出。
* @param filename - 文件名(不含扩展名)
* @param labelHeader - 标签列标题
* @param valueHeader - 数值列标题
* @param data - 键值对数组
*/
export function exportChartDataToCSV(
filename: string,
labelHeader: string,
valueHeader: string,
data: Array<{ name: string; value: number }>,
): void {
const headers = [labelHeader, valueHeader]
const rows = data.map(d => [d.name, String(d.value)])
const dateStr = new Date().toISOString().slice(0, 10)
exportToCSV(`${filename}_${dateStr}`, headers, rows)
}
|