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)
}