feat(platform): export history query results
This commit is contained in:
14
vehicle-data-platform/apps/web/src/domain/csvExport.test.ts
Normal file
14
vehicle-data-platform/apps/web/src/domain/csvExport.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { expect, test } from 'vitest';
|
||||
import { buildCsv } from './csvExport';
|
||||
|
||||
test('builds csv with escaping and json object values', () => {
|
||||
const csv = buildCsv(
|
||||
[
|
||||
{ title: 'VIN', value: (row: { vin: string; fields?: unknown }) => row.vin },
|
||||
{ title: '字段', value: (row) => row.fields }
|
||||
],
|
||||
[{ vin: 'VIN"001', fields: { speed: 42 } }]
|
||||
);
|
||||
|
||||
expect(csv).toBe('"VIN","字段"\n"VIN""001","{""speed"":42}"');
|
||||
});
|
||||
29
vehicle-data-platform/apps/web/src/domain/csvExport.ts
Normal file
29
vehicle-data-platform/apps/web/src/domain/csvExport.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
export type CsvColumn<T> = {
|
||||
title: string;
|
||||
value: (row: T) => unknown;
|
||||
};
|
||||
|
||||
function csvCell(value: unknown) {
|
||||
if (value == null) return '';
|
||||
const text = typeof value === 'object' ? JSON.stringify(value) : String(value);
|
||||
return `"${text.replace(/"/g, '""')}"`;
|
||||
}
|
||||
|
||||
export function buildCsv<T>(columns: CsvColumn<T>[], rows: T[]) {
|
||||
return [
|
||||
columns.map((item) => csvCell(item.title)).join(','),
|
||||
...rows.map((row) => columns.map((column) => csvCell(column.value(row))).join(','))
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
export function downloadCsv(filename: string, csv: string) {
|
||||
const blob = new Blob(['\uFEFF', csv], { type: 'text/csv;charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = filename;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
Reference in New Issue
Block a user