feat: 实现测试数据生成器完整功能
- 添加类型定义 (FieldConfig, DataRule, GeneratorDefinition 等) - 实现 21 个数据生成器 (个人信息/业务数据/技术数据/基础类型) - 实现 Web Worker 后台数据生成引擎 - 实现规则存储与管理功能 - 实现 JSON/CSV 数据导出功能 - 开发完整 UI 组件 (字段管理/生成器选择/数据预览/导出面板等) - 集成到应用功能配置,添加国际化支持 功能特性: - 实时预览生成的数据 - 字段配置 (名称/描述/必填/空值率/唯一性约束) - 规则管理 (保存/加载/搜索/导入导出) - Web Worker 后台生成,支持进度显示和取消 - 响应式布局,支持多种设备 docs: 更新 TASKS.md 所有子任务复选框为已完成状态
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* 数据导出工具
|
||||
* 实现 JSON 和 CSV 格式的数据导出
|
||||
*/
|
||||
|
||||
import type { ExportFile } from '@/types/testDataGenerator';
|
||||
|
||||
/**
|
||||
* 数据导出器
|
||||
*/
|
||||
export class DataExporter {
|
||||
/**
|
||||
* 将数据转换为 JSON 字符串
|
||||
*/
|
||||
static toJSON(data: Record<string, unknown>[], pretty = true): string {
|
||||
return JSON.stringify(data, null, pretty ? 2 : undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据转换为 CSV 字符串
|
||||
*/
|
||||
static toCSV(data: Record<string, unknown>[]): string {
|
||||
if (data.length === 0) return '';
|
||||
|
||||
// 获取所有列名
|
||||
const headers = Array.from(new Set(data.flatMap((row) => Object.keys(row))));
|
||||
|
||||
// 构建 CSV 内容
|
||||
const rows = [
|
||||
headers.map((h) => this.escapeCSV(h)).join(','),
|
||||
...data.map((row) => headers.map((h) => this.escapeCSV(String(row[h] ?? ''))).join(',')),
|
||||
];
|
||||
|
||||
return rows.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* 转义 CSV 字段
|
||||
*/
|
||||
private static escapeCSV(value: string): string {
|
||||
// 如果包含逗号、引号、换行符,需要用引号包裹
|
||||
if (value.includes(',') || value.includes('"') || value.includes('\n')) {
|
||||
return `"${value.replace(/"/g, '""')}"`;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据格式导出数据
|
||||
*/
|
||||
static exportByFormat(data: Record<string, unknown>[], format: 'json' | 'csv'): string {
|
||||
if (format === 'csv') {
|
||||
return this.toCSV(data);
|
||||
}
|
||||
return this.toJSON(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出为多个文件
|
||||
*/
|
||||
static toMultipleFiles(
|
||||
data: Record<string, unknown>[],
|
||||
formats: ('json' | 'csv')[],
|
||||
filename = 'test-data',
|
||||
): ExportFile[] {
|
||||
return formats.map((format) => ({
|
||||
filename,
|
||||
content: this.exportByFormat(data, format),
|
||||
mimeType: this.getMimeType(format),
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出为单个文件
|
||||
*/
|
||||
static toSingleFile(
|
||||
data: Record<string, unknown>[],
|
||||
format: 'json' | 'csv',
|
||||
filename = 'test-data',
|
||||
): ExportFile {
|
||||
return {
|
||||
filename,
|
||||
content: this.exportByFormat(data, format),
|
||||
mimeType: this.getMimeType(format),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 MIME 类型
|
||||
*/
|
||||
private static getMimeType(format: string): string {
|
||||
const mimeTypes: Record<string, string> = {
|
||||
json: 'application/json',
|
||||
csv: 'text/csv',
|
||||
};
|
||||
return mimeTypes[format] || 'application/octet-stream';
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*/
|
||||
static download(file: ExportFile): void {
|
||||
const blob = new Blob([file.content], { type: file.mimeType });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `${file.filename}.${file.mimeType === 'application/json' ? 'json' : 'csv'}`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载多个文件
|
||||
*/
|
||||
static downloadMultiple(files: ExportFile[]): void {
|
||||
files.forEach((file) => this.download(file));
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制到剪贴板
|
||||
*/
|
||||
static async copyToClipboard(content: string): Promise<boolean> {
|
||||
try {
|
||||
await navigator.clipboard.writeText(content);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('[DataExporter] 复制失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user