feat: add theme toggle component and theme store for light/dark mode support
- Implemented ThemeToggle component for switching between light, dark, and system themes. - Created themeStore for managing theme state and persisting user preferences in localStorage. - Added utility functions for error message sanitization to prevent sensitive data leakage. - Developed proxy utility functions for API requests, including template variable replacement. - Enhanced layout with dark mode styles and smooth transitions for theme changes. - Updated main layout and page components to integrate theme toggle and improve accessibility. - Added server-side proxy handling with validation and error sanitization for API requests.
This commit is contained in:
163
demands/DEMAND-proxy.md
Normal file
163
demands/DEMAND-proxy.md
Normal file
@@ -0,0 +1,163 @@
|
||||
这是一个为您准备的 **v3.0 版本需求文档**。
|
||||
|
||||
这份文档的核心目标是**“收口”**:将之前零散开发的“前端代理 (Proxy)”功能正式集成到主流程中,确立 **“混合模式 (Hybrid Mode)”** 的架构策略。
|
||||
|
||||
即:**前端负责实时测试和预览(利用 Proxy),后端/脚本负责全量执行(利用 Job Bundle)。**
|
||||
|
||||
---
|
||||
|
||||
### 复制下面的内容发送给 Claude:
|
||||
|
||||
---
|
||||
|
||||
**Role:** 资深全栈架构师 (SvelteKit + TypeScript)
|
||||
|
||||
**Project Context:**
|
||||
我们正在开发 "Excel2JSON ETL Blueprint Generator"。
|
||||
目前我们已经具备了:
|
||||
|
||||
1. **前端:** Excel 解析、映射配置、JSON 预览。
|
||||
2. **后端能力:** 一个 `/api/proxy` 端点 (SvelteKit Endpoint),可以绕过 CORS 转发请求。
|
||||
3. **输出:** `job_bundle.json` 用于给 Python 脚本跑全量数据。
|
||||
|
||||
**Current Goal (Phase 3 Integration):**
|
||||
我们需要正式集成 `/api/proxy`,实现 **“所见即所得”** 的 API 调试体验。
|
||||
用户在配置 API 字段时,可以直接点击“测试”,前端调用 Proxy 立即拿回数据并展示,确保配置无误后再导出。
|
||||
|
||||
### Phase 3: 在线调试与混合执行架构需求文档
|
||||
|
||||
#### 1. 核心架构策略:混合模式 (Hybrid Execution)
|
||||
|
||||
为了平衡**用户体验**与**系统性能**,我们采用以下策略:
|
||||
|
||||
* **调试/预览阶段 (Online Mode):**
|
||||
* 使用 SvelteKit 后端代理 (`/api/proxy`)。
|
||||
* **作用:** 让用户在配置界面就能实时验证 "URL 填得对不对"、"JSON Path 提取得对不对"。
|
||||
* **限制:** 仅用于**单条数据**测试或**小批量 (前10条)** 预览。
|
||||
|
||||
|
||||
* **生产/执行阶段 (Offline Mode):**
|
||||
* 使用 `job_bundle.json` + Python 脚本。
|
||||
* **作用:** 处理成千上万行数据的全量抓取和入库。
|
||||
* **优势:** 无超时限制,无浏览器崩溃风险。
|
||||
|
||||
|
||||
|
||||
#### 2. UI/UX 交互升级
|
||||
|
||||
##### 2.1 API 配置面板 (Enrichment Config Modal)
|
||||
|
||||
在 `ApiConfigModal.svelte` 中增加 **"Test Connection" (测试连接)** 功能区。
|
||||
|
||||
* **输入区:** (已有的 URL, Method, Headers, Body 配置)
|
||||
* **测试上下文 (Test Context):**
|
||||
* 显示当前 Excel 的 **第一行数据** 作为测试样本。
|
||||
* *示例:* `User ID: 101`, `Name: Alice`。
|
||||
* 用户可以手动修改这些样本值来测试不同情况。
|
||||
|
||||
|
||||
* **操作:** 点击 **[Test Request]** 按钮。
|
||||
* **逻辑:**
|
||||
1. 前端将 URL 模板中的 `{{Variables}}` 替换为测试样本值。
|
||||
2. 发送 POST 请求给本站的 `/api/proxy`。
|
||||
3. 等待响应。
|
||||
|
||||
|
||||
* **反馈区:**
|
||||
* **Status:** 显示 HTTP 状态码 (e.g., `200 OK`, `404 Not Found`)。
|
||||
* **Response Preview:** 显示原始返回的 JSON (带语法高亮)。
|
||||
* **Extracted Result:** 根据用户配置的 `Response Path` (e.g., `data.balance`),显示最终提取到的值。
|
||||
* *交互:* 如果提取结果为 `undefined`,高亮提示用户检查 Path 配置。
|
||||
|
||||
|
||||
|
||||
##### 2.2 主界面实时预览 (Enriched Preview)
|
||||
|
||||
在主界面的右侧 JSON 预览区,增加一个 **"Preview Enrichment" (预览增强数据)** 开关。
|
||||
|
||||
* **默认状态 (Off):** 仅展示静态映射后的数据(API 字段显示为 `null` 或占位符)。
|
||||
* **开启状态 (On):**
|
||||
* **限制:** 仅对前 **5 行** 数据生效。
|
||||
* **加载:** 显示 Loading 骨架屏。
|
||||
* **并发:** 并发调用 `/api/proxy` (限制并发数为 3)。
|
||||
* **展示:** 成功获取后,JSON 预览中的相关字段会被真实数据填充并高亮显示。
|
||||
* **警告:** 在开关旁显示小字提示 *"Live preview limited to first 5 rows to prevent API abuse."*
|
||||
|
||||
|
||||
|
||||
#### 3. 数据流与接口定义 (Data Flow)
|
||||
|
||||
##### 3.1 前端代理调用函数
|
||||
|
||||
封装一个通用的 `proxyFetch` 工具函数,用于前端组件调用:
|
||||
|
||||
```typescript
|
||||
// src/lib/utils/proxy.ts
|
||||
|
||||
interface ProxyOptions {
|
||||
url: string;
|
||||
method: string;
|
||||
headers: Record<string, string>;
|
||||
body?: any;
|
||||
}
|
||||
|
||||
export async function proxyFetch(options: ProxyOptions): Promise<any> {
|
||||
// 1. 调用我们自己的 SvelteKit 后端
|
||||
const response = await fetch('/api/proxy', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(options)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Proxy Error: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
##### 3.2 变量替换逻辑 (Template Interpolation)
|
||||
|
||||
确保前端和后端(Python)使用一致的变量替换逻辑。建议实现一个简单的 `renderTemplate` 函数:
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* 将 "https://api.com/users/{{id}}" 使用 { id: 123 } 替换为 "https://api.com/users/123"
|
||||
*/
|
||||
export function renderTemplate(template: string, context: Record<string, any>): string {
|
||||
return template.replace(/\{\{\s*(\w+)\s*\}\}/g, (_, key) => {
|
||||
return context[key] !== undefined ? String(context[key]) : '';
|
||||
});
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### 4. 安全性与限流 (Security & Constraints)
|
||||
|
||||
为了防止 `/api/proxy` 被滥用或导致服务器卡死,请在服务端 (`src/routes/api/proxy/+server.ts`) 增加以下保护:
|
||||
|
||||
1. **超时控制:** 设置 `AbortController`,如果目标接口 10 秒未响应,强制中断并返回 504。
|
||||
2. **错误屏蔽:** 如果目标接口返回敏感信息(如 Stack Trace),后端应进行脱敏处理后再返回给前端。
|
||||
|
||||
#### 5. 开发任务清单
|
||||
|
||||
1. **工具库:** 实现 `src/lib/utils/proxy.ts` 和 `renderTemplate`。
|
||||
2. **组件升级:**
|
||||
* 改造 `ApiConfigModal`:加入测试按钮和结果展示面板。
|
||||
* 改造 `JsonPreview`:集成“实时预览”开关和并发请求逻辑。
|
||||
|
||||
|
||||
3. **流程集成:** 确保在导出 `job_bundle.json` 时,不需要改动任何逻辑(导出依然是纯配置)。
|
||||
|
||||
---
|
||||
|
||||
### 给 AI 的提示 (Prompt Tip)
|
||||
|
||||
* **Focus on State:** 提醒 Claude 注意 Svelte 的状态管理。在测试 API 时,不要阻塞主 UI 的渲染。建议使用 `async/await` 配合局部 loading 状态变量。
|
||||
* **Error Handling:** 强调错误处理。如果用户填的 API URL 是错的(比如 404),前端不应该报错崩溃,而是应该优雅地在“测试结果”面板里显示红色错误信息。
|
||||
|
||||
---
|
||||
|
||||
**请先实现 `src/lib/utils/proxy.ts` 和 `ApiConfigModal` 的测试功能。**
|
||||
137
demands/DEMAND-queryFiled.md
Normal file
137
demands/DEMAND-queryFiled.md
Normal file
@@ -0,0 +1,137 @@
|
||||
|
||||
|
||||
**Role:** 资深前端架构师 (Svelte 5 + TypeScript)
|
||||
|
||||
**Project Pivot (重大架构调整):**
|
||||
我们将 "Excel2JSON Mapper" 升级为一个 **"ETL 配置生成器 (ETL Blueprint Generator)"**。
|
||||
前端的任务是生成一个包含 **[源数据 + 处理逻辑]** 的 **Job Bundle (JSON 文件)**,用户将使用该文件配合 Python 脚本在后端执行实际的数据抓取和入库。
|
||||
|
||||
### Phase 2: ETL 配置生成器需求文档
|
||||
|
||||
#### 1. 项目概述
|
||||
|
||||
这是一个基于 Svelte 5 的单页应用。用户上传 Excel,配置字段映射规则(包含静态重命名和动态 API 获取规则),最后导出为一个标准化的 JSON 任务包 (`job_bundle.json`)。
|
||||
|
||||
#### 2. 用户界面与交互 (UI/UX)
|
||||
|
||||
##### 2.1 顶部工具栏
|
||||
|
||||
* **导入/导出配置:** 支持保存当前所有的映射规则。
|
||||
* **导出任务包 (Export Job Bundle):** 這是核心操作。点击后下载 `job_bundle.json` 文件(包含数据+配置)。
|
||||
* **提交设置 (Submission Settings):** 一个模态框,配置最终数据推送到哪里。
|
||||
* `Target URL`: 最终数据接收接口 (e.g., `https://api.db.com/bulk-insert`).
|
||||
* `Method`: POST / PUT.
|
||||
* `Batch Size`: 批次大小 (默认 50).
|
||||
|
||||
|
||||
|
||||
##### 2.2 主体区域 (左右分栏)
|
||||
|
||||
* **左侧 (Source):** Excel 表格预览。
|
||||
* **右侧 (Preview):** 静态映射后的 JSON 预览(仅展示前 20 条以保证性能)。
|
||||
|
||||
##### 2.3 核心功能:列配置 (Column Configuration)
|
||||
|
||||
在左侧表格区域,除了点击现有表头修改映射外,新增 **"添加计算列 (Add Computed Column)"** 功能。
|
||||
|
||||
**新增类型:`API_FETCH` (动态 API 字段)**
|
||||
当用户选择此类型时,弹出一个详细配置面板:
|
||||
|
||||
1. **Target Key:** 最终生成的 JSON 字段名 (例如 `user_balance`)。
|
||||
2. **Request URL (支持模板变量):**
|
||||
* 允许使用 `{{ColumnName}}` 语法引用当前行的 Excel 数据。
|
||||
* *示例:* `https://api.example.com/users/{{用户ID}}/detail`
|
||||
* *UI 交互:* 输入框旁应有“插入变量”按钮,点击列出所有可用 Excel 表头。
|
||||
|
||||
|
||||
3. **Request Method:** 下拉选择 `GET` (默认) 或 `POST`。
|
||||
4. **Headers:** Key-Value 编辑器 (用于传 `Authorization`, `Content-Type` 等)。
|
||||
5. **Request Body (仅 POST):**
|
||||
* 多行文本域,支持 JSON 格式。
|
||||
* 同样支持 `{{ColumnName}}` 模板变量替换。
|
||||
|
||||
|
||||
6. **Response Extractor (取值路径):**
|
||||
* 指定从接口返回的 JSON 中提取哪个字段。
|
||||
* 支持 `lodash.get` 风格的点号路径。
|
||||
* *示例:* 接口返回 `{ "data": { "balance": 100 } }`,用户填 `data.balance`。
|
||||
|
||||
|
||||
|
||||
#### 3. 核心输出:Job Bundle 数据结构
|
||||
|
||||
请严格按照以下 TypeScript 接口定义生成导出的 JSON 文件:
|
||||
|
||||
```typescript
|
||||
// 1. 静态映射规则
|
||||
interface StaticRule {
|
||||
type: 'static';
|
||||
source: string; // Excel 原表头
|
||||
target: string; // JSON 目标 Key
|
||||
dataType: 'string' | 'number' | 'boolean' | 'date';
|
||||
format?: string; // 日期格式化字符串
|
||||
}
|
||||
|
||||
// 2. 动态 API 获取规则 (本次新增核心)
|
||||
interface ApiEnrichmentRule {
|
||||
type: 'api_fetch';
|
||||
target_key: string; // JSON 目标 Key
|
||||
url_template: string; // "https://api.com/{{id}}"
|
||||
method: 'GET' | 'POST';
|
||||
headers?: Record<string, string>;
|
||||
body_template?: string; // POST body 模板
|
||||
response_path: string; // "data.result.value"
|
||||
fallback_value?: any; // 默认值 (null/0)
|
||||
}
|
||||
|
||||
// 3. 提交配置
|
||||
interface SubmissionConfig {
|
||||
target_url: string;
|
||||
method: 'POST' | 'PUT';
|
||||
batch_size: number;
|
||||
}
|
||||
|
||||
// 4. 最终导出的 Job Bundle 结构
|
||||
interface JobBundle {
|
||||
meta: {
|
||||
version: string;
|
||||
generated_at: string;
|
||||
};
|
||||
config: {
|
||||
static_rules: StaticRule[];
|
||||
enrichment_rules: ApiEnrichmentRule[];
|
||||
submission: SubmissionConfig;
|
||||
};
|
||||
source_data: Record<string, any>[]; // 经过静态映射后的基础数据列表
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### 4. 开发任务清单
|
||||
|
||||
1. **Store 设计:** 更新 Svelte Store 以存储 `enrichmentRules` 和 `submissionConfig`。
|
||||
2. **UI 组件:**
|
||||
* 开发 `ApiConfigModal.svelte`: 用于录入 URL、Headers、Body 等复杂信息。
|
||||
* 实现变量插入辅助功能 (点击列名自动插入 `{{...}}`)。
|
||||
|
||||
|
||||
3. **导出逻辑:** 编写 `generateJobBundle` 函数。
|
||||
* **步骤 1:** 根据 `static_rules` 转换 Excel 原始数据,生成基础 JSON 数组。
|
||||
* **步骤 2:** 将基础数据、API 规则、提交配置组装成 `JobBundle` 格式。
|
||||
* **步骤 3:** 触发浏览器下载 `job_bundle.json`。
|
||||
|
||||
|
||||
|
||||
#### 5. 特别说明 (给 AI 的提示)
|
||||
|
||||
* **No Runtime Fetch:** 前端代码 **不需要** 执行 `fetch` 去调用用户配置的 API(避免 CORS)。前端只负责把 URL 字符串保存到 JSON 里。
|
||||
* **Template Validation:** 在 UI 上简单校验 URL 模板格式(检查是否包含 `{}`),但不做逻辑校验。
|
||||
* **Preview Limitations:** 右侧预览仅展示静态映射的结果。对于 API 字段,可以在预览中显示一个占位符(如 `[Pending API Fetch]`)。
|
||||
|
||||
---
|
||||
|
||||
### 后续步骤
|
||||
|
||||
Claude 完成这个前端代码后,你可以再发一条指令让它写对应的 Python 执行脚本:
|
||||
|
||||
> "前端已经完成了。现在请帮我写一个 Python 脚本 (`executor.py`)。它读取上面定义的 `job_bundle.json`,使用 http请求 执行 `enrichment_rules` 里的请求(注意替换 URL 中的 {{变量}}),最后把结果推送到 `submission` 定义的接口。"
|
||||
162
demands/DEMAND-字典映射.md
Normal file
162
demands/DEMAND-字典映射.md
Normal file
@@ -0,0 +1,162 @@
|
||||
|
||||
|
||||
这次更新加入了 **“字典映射 (Dictionary Mapping)”** 功能,允许用户对有限的枚举值进行转换(如“是/否”转“Y/N”)。
|
||||
|
||||
我特别在文档中强调了**“自动扫描”**功能——让 UI 自动读取 Excel 列中的前几十行去重数据,自动列出所有可能的选项,用户只需要填右边的目标值即可,极大提升体验。
|
||||
|
||||
---
|
||||
|
||||
### 复制下面的内容发送给 Claude:
|
||||
|
||||
---
|
||||
|
||||
**Role:** 资深前端架构师 (Svelte 5 + TypeScript)
|
||||
|
||||
**Project Context:**
|
||||
我们正在开发 "Excel2JSON ETL Blueprint Generator"。
|
||||
前端负责解析 Excel、配置映射规则(含静态重命名、字典转换、动态 API)、生成预览,并最终导出包含 **[处理后的基础数据 + API 执行逻辑]** 的 `job_bundle.json`。
|
||||
|
||||
**Current Task:**
|
||||
我们需要在 **v2.0 (API Enrichment)** 的基础上,新增 **v2.1 (Dictionary/Enum Mapping)** 功能。
|
||||
|
||||
### Phase 2.1: 字典映射与高级 ETL 配置需求文档
|
||||
|
||||
#### 1. 核心功能变更
|
||||
|
||||
在静态字段映射(Static Mapping)阶段,新增 **"值映射 (Value Map)"** 功能。
|
||||
|
||||
* **场景:** Excel 中某列是状态词(如 "开/关", "男/女"),目标 JSON 需要代码(如 `1/0`, `M/F`)。
|
||||
* **逻辑:** 解析 Excel -> **字典替换** -> 类型转换 -> 生成基础 JSON -> (后续由 Python 处理 API).
|
||||
|
||||
#### 2. 用户界面与交互 (UI/UX)
|
||||
|
||||
##### 2.1 列配置面板升级
|
||||
|
||||
点击 Excel 表头配置时,除了修改 `Target Key` 和 `Data Type`,新增一个 **"Value Mapping" (值映射)** 开关/折叠面板。
|
||||
|
||||
**面板内容:**
|
||||
|
||||
1. **自动扫描 (Auto-Scan):**
|
||||
* UI 自动读取该列的前 50 行数据,提取所有**唯一值 (Unique Values)**。
|
||||
* 显示一个“映射表”:左侧是 `Source Value` (Excel 原值),右侧是 `Target Value` (输入框)。
|
||||
|
||||
|
||||
2. **手动添加:** 允许用户手动增加新的映射对(防止前 50 行没覆盖到所有情况)。
|
||||
3. **默认值 (Fallback):**
|
||||
* 如果单元格的值不在映射表中,怎么处理?
|
||||
* 选项: `Keep Original` (保留原值) / `Set to Null` / `Custom Value` (自定义默认值)。
|
||||
|
||||
|
||||
|
||||
##### 2.2 预览逻辑 (Preview Logic)
|
||||
|
||||
* 右侧 JSON 预览必须**实时反映**字典映射的结果。
|
||||
* *示例:* 用户在左侧把 "是" 映射为 `true` (Boolean),右侧预览中原本的 "是" 应立即变为 `true`。
|
||||
|
||||
#### 3. 核心数据结构 (Updated Interfaces)
|
||||
|
||||
请更新 TypeScript 接口以支持新的映射逻辑:
|
||||
|
||||
```typescript
|
||||
// 字典映射项
|
||||
interface ValueMapItem {
|
||||
source: string | number; // Excel 里的原始值 (e.g., "是")
|
||||
target: any; // JSON 里的目标值 (e.g., true, "Y", 1)
|
||||
}
|
||||
|
||||
// 静态映射规则 (升级版)
|
||||
interface StaticRule {
|
||||
type: 'static';
|
||||
source_column: string; // Excel 原表头
|
||||
target_key: string; // JSON 目标 Key
|
||||
data_type: 'string' | 'number' | 'boolean' | 'date' | 'array'; // 目标类型
|
||||
|
||||
// v2.1 新增: 字典映射配置
|
||||
use_dictionary: boolean; // 是否启用字典映射
|
||||
value_mapping?: ValueMapItem[];
|
||||
mapping_fallback?: 'keep' | 'null' | any; // 没匹配到时的默认值
|
||||
|
||||
// v2.0 已有
|
||||
format?: string; // 日期格式
|
||||
separator?: string; // 数组分隔符
|
||||
}
|
||||
|
||||
// 动态 API 规则 (保持 v2.0 不变)
|
||||
interface ApiEnrichmentRule {
|
||||
type: 'api_fetch';
|
||||
target_key: string;
|
||||
url_template: string; // "https://api.com/{{id}}"
|
||||
method: 'GET' | 'POST';
|
||||
headers?: Record<string, string>;
|
||||
body_template?: string;
|
||||
response_path: string; // "data.result"
|
||||
}
|
||||
|
||||
// 提交配置 (保持 v2.0 不变)
|
||||
interface SubmissionConfig {
|
||||
target_url: string;
|
||||
method: 'POST' | 'PUT';
|
||||
batch_size: number;
|
||||
}
|
||||
|
||||
// 最终导出的 Job Bundle
|
||||
interface JobBundle {
|
||||
meta: { version: string; generated_at: string };
|
||||
config: {
|
||||
// static_rules 仅用于前端回显,Python 脚本其实只需要 enrichment 和 submission
|
||||
// 但为了以后能在前端重新导入编辑,建议保留完整配置
|
||||
static_rules: StaticRule[];
|
||||
enrichment_rules: ApiEnrichmentRule[];
|
||||
submission: SubmissionConfig;
|
||||
};
|
||||
// 注意: source_data 是前端已经应用了 "StaticRule" (包括字典映射) 后的干净数据
|
||||
source_data: Record<string, any>[];
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### 4. 处理流程 (Processing Pipeline)
|
||||
|
||||
前端在生成 `source_data` 时,必须严格按照以下顺序处理每一单元格:
|
||||
|
||||
1. **Extract:** 读取 Excel 单元格原始值。
|
||||
2. **Map (字典映射):**
|
||||
* 如果启用了 `use_dictionary`:查找映射表。
|
||||
* 找到 -> 替换为 Target Value。
|
||||
* 没找到 -> 应用 `mapping_fallback` 策略。
|
||||
|
||||
|
||||
3. **Cast (类型转换):**
|
||||
* 将上一步的结果转换为 `data_type` 指定的类型 (e.g., String -> Boolean, String -> Number)。
|
||||
* *注意:* 如果字典映射的目标值已经是正确的类型(如 `true`),则跳过此步或确保不会再次转为字符串 "true"。
|
||||
|
||||
|
||||
4. **Format:** (如果是日期或数组) 应用格式化规则。
|
||||
|
||||
#### 5. 开发任务清单
|
||||
|
||||
1. **组件开发:**
|
||||
* 修改 `ColumnConfigPanel.svelte` (或类似组件)。
|
||||
* 新增 `DictionaryMapper` 子组件:包含“自动扫描”按钮和“键值对”编辑表格。
|
||||
|
||||
|
||||
2. **逻辑核心:**
|
||||
* 更新 `processRow` 函数,在类型转换前插入字典查找逻辑。
|
||||
* 实现 `scanUniqueValues(columnData)` 函数,用于快速提取 Excel 列的去重值。
|
||||
|
||||
|
||||
3. **预览同步:** 确保右侧 JSON 预览能实时响应字典配置的变更。
|
||||
4. **导出验证:** 导出 `job_bundle.json`,检查 `source_data` 中的值是否已成功转换为映射后的值(例如 "Y" 而不是 "是")。
|
||||
|
||||
---
|
||||
|
||||
### 给 AI 的提示 (Prompt Tip)
|
||||
|
||||
* **性能注意:** 自动扫描 `scanUniqueValues` 时,如果 Excel 数据量极大(>10万行),不要全量扫描。只扫描前 1000 行即可,并提示用户“仅扫描了前 1000 行,如有遗漏请手动添加”。
|
||||
* **交互细节:** 字典映射的 Target Value 输入框,应该能智能识别类型。如果用户输入 `true`,应该被识别为 Boolean 而不是字符串 "true"。
|
||||
|
||||
---
|
||||
|
||||
### 执行步骤
|
||||
|
||||
请先基于上述文档,更新 **数据类型定义 (Interfaces)** 和 **核心处理逻辑 (`processRow` 函数)**。
|
||||
145
demands/DEMAND-样式.md
Normal file
145
demands/DEMAND-样式.md
Normal file
@@ -0,0 +1,145 @@
|
||||
|
||||
**Role:** 资深 UI/UX 工程师 & Svelte 专家
|
||||
|
||||
**Current Context:**
|
||||
我们已经完成了 "Excel2JSON ETL Blueprint Generator" 的核心功能(Excel 解析、API 配置、JSON 导出)。
|
||||
目前的界面比较原始。现在需要进行 **Phase 3: UI/UX Overhaul & Theming**。
|
||||
|
||||
**Goal:**
|
||||
全面优化应用样式,引入 **Dark Mode (夜间模式)** 支持,提升视觉层级和交互体验。目标风格是 **"Modern SaaS"** (类似 Vercel/Linear/Shadcn 的风格)。
|
||||
|
||||
### Phase 3: UI/UX 优化与多主题需求文档
|
||||
|
||||
#### 1. 技术方案 (Technical Approach)
|
||||
|
||||
* **Tailwind CSS Dark Mode:** 使用 `class` 策略(通过在 `<html>` 标签添加 `class="dark"` 来切换)。
|
||||
* **State Management:** 创建一个 `themeStore.ts` (Svelte Store),用于管理 `light` | `dark` | `system` 状态,并持久化到 `localStorage`。
|
||||
* **CSS Variables:** 建议在 `app.css` 中定义语义化的 CSS 变量 (如 `--bg-primary`, `--text-secondary`),或者直接使用 Tailwind 的 `slate` 色系作为主轴。
|
||||
|
||||
#### 2. 设计规范 (Design System Specs)
|
||||
|
||||
请严格遵循以下配色逻辑,确保深色模式下的对比度和可读性。
|
||||
|
||||
##### 2.1 基础色盘 (Color Palette)
|
||||
|
||||
* **Primary Brand:** Indigo-600 (Light) / Indigo-500 (Dark)
|
||||
* **Background (Canvas):**
|
||||
* Light: `bg-white` (Main), `bg-slate-50` (Sidebar/Header)
|
||||
* Dark: `bg-slate-950` (Main), `bg-slate-900` (Sidebar/Header)
|
||||
|
||||
|
||||
* **Surface (Cards/Modals):**
|
||||
* Light: `bg-white` + `shadow-sm` + `border-slate-200`
|
||||
* Dark: `bg-slate-900` + `shadow-none` + `border-slate-800`
|
||||
|
||||
|
||||
* **Text (Typography):**
|
||||
* Primary: `text-slate-900` (Light) / `text-slate-50` (Dark)
|
||||
* Secondary: `text-slate-500` (Light) / `text-slate-400` (Dark)
|
||||
* Muted: `text-slate-400` (Light) / `text-slate-500` (Dark)
|
||||
|
||||
|
||||
* **Borders:** `border-slate-200` (Light) / `border-slate-800` (Dark)
|
||||
|
||||
##### 2.2 交互反馈 (Interactive States)
|
||||
|
||||
* **Buttons:**
|
||||
* Primary: Solid Indigo background. Hover: `hover:bg-indigo-700` (Light) / `hover:bg-indigo-400` (Dark).
|
||||
* Ghost/Secondary: Transparent background. Hover: `hover:bg-slate-100` (Light) / `hover:bg-slate-800` (Dark).
|
||||
|
||||
|
||||
* **Inputs:**
|
||||
* Default: `bg-transparent border border-slate-300 dark:border-slate-700`.
|
||||
* Focus: `ring-2 ring-indigo-500/20 border-indigo-500`.
|
||||
|
||||
|
||||
|
||||
#### 3. 组件级优化详情
|
||||
|
||||
##### 3.1 顶部导航栏 (Header)
|
||||
|
||||
* **布局:** Flexbox,高度 `h-14` or `h-16`。
|
||||
* **功能区:**
|
||||
* 左侧: Logo + Title (Bold, Tracking-tight)。
|
||||
* 右侧: [Export Button] [Settings Icon] [Theme Toggle]。
|
||||
|
||||
|
||||
* **Theme Toggle:** 实现一个图标按钮,点击在 🌞 (Sun) / 🌙 (Moon) / 💻 (System) 之间切换。切换时添加平滑的 `transition-colors` 动画。
|
||||
|
||||
##### 3.2 Excel 表格区域 (Left Panel)
|
||||
|
||||
* **容器:** 卡片式设计,圆角 `rounded-lg`,带边框。
|
||||
* **表头 (Thead):**
|
||||
* Light: `bg-slate-50`
|
||||
* Dark: `bg-slate-900`
|
||||
* 文字: `text-xs font-semibold uppercase tracking-wider text-slate-500`.
|
||||
|
||||
|
||||
* **单元格 (Td):**
|
||||
* 必须有边框:`border-r border-b border-slate-200 dark:border-slate-800`。
|
||||
* 斑马纹 (Zebra Striping): 偶数行在 Dark mode 下给予微弱的背景色 `dark:even:bg-slate-900/50` 增加可读性。
|
||||
|
||||
|
||||
* **列配置按钮:** 表头上的“设置图标”在 Hover 时才显示,保持界面整洁。
|
||||
|
||||
##### 3.3 JSON 预览区域 (Right Panel)
|
||||
|
||||
* **容器:** 模拟 IDE/终端外观。
|
||||
* **背景:**
|
||||
* Light: `bg-slate-50` (或者纯白)
|
||||
* Dark: `bg-[#0d1117]` (GitHub Dark Dimmed 风格) 或 `bg-slate-950`.
|
||||
|
||||
|
||||
* **代码高亮:**
|
||||
* **关键点:** 语法高亮需要根据主题动态切换。
|
||||
* 如果没有引入重的 highlighter 库,请手动为 Key/String/Number/Boolean 定义两套颜色。
|
||||
* *Example:* Keys (Blue-600/Blue-400), Strings (Green-600/Green-400), Numbers (Orange-600/Orange-400).
|
||||
|
||||
|
||||
* **Copy 按钮:** 悬浮在右上角的绝对定位按钮,点击后显示 "Copied!" 提示。
|
||||
|
||||
##### 3.4 模态框 (Modals - API & Dictionary Config)
|
||||
|
||||
* **背景遮罩 (Backdrop):** `bg-black/50` (Light) / `bg-black/80` (Dark) with `backdrop-blur-sm`.
|
||||
* **弹窗本体:** `bg-white dark:bg-slate-900`,边框 `dark:border-slate-700`。
|
||||
* **表单元素:** 输入框在 Dark Mode 下背景应为 `bg-slate-950` 或深灰色,避免过亮。
|
||||
|
||||
##### 3.5 滚动条 (Scrollbars)
|
||||
|
||||
* 请自定义 Webkit 滚动条样式,使其不再是默认的丑陋灰色条。
|
||||
* Track: Transparent.
|
||||
* Thumb: `bg-slate-300 dark:bg-slate-700`,圆角 `rounded-full`。
|
||||
|
||||
#### 4. 开发任务清单 (Action Plan)
|
||||
|
||||
1. **基础建设:**
|
||||
* 在 `app.css` 中配置 Tailwind 的 `@apply` 基础样式。
|
||||
* 实现 `themeStore.ts` 并处理 `onMount` 时的系统偏好检测。
|
||||
* 在 `App.svelte` 根节点绑定 `class:dark={$themeStore === 'dark'}`。
|
||||
|
||||
|
||||
2. **组件重构:**
|
||||
* 重写 `Header.svelte`,加入主题切换器。
|
||||
* 重构 `ExcelTable.svelte` 的 class,全面加入 `dark:` 修饰符。
|
||||
* 重构 `JsonPreview.svelte`,优化配色和字体 (使用 Monospace 字体)。
|
||||
* 优化 `Modal` 和 `Drawer` 组件的阴影和边框。
|
||||
|
||||
|
||||
3. **细节打磨:**
|
||||
* 为所有可点击元素添加 `transition-all duration-200`。
|
||||
* 确保 Loading 状态(骨架屏或 Spinner)在深色模式下不可见度正常。
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 给 AI 的提示 (Prompt Tip)
|
||||
|
||||
* **Syntax Highlighting:** 告诉 Claude,如果目前的 JSON 预览只是纯文本 `pre` 标签,请帮我写一个简单的 `syntaxHighlight(json)` 函数,通过正则把 HTML 标签包进去,并用 Tailwind 的颜色类(如 `text-blue-600 dark:text-blue-400`)来控制颜色,从而实现轻量级的双模式高亮。
|
||||
|
||||
---
|
||||
|
||||
### 你可以期待的效果
|
||||
|
||||
有了这份文档,Claude 会帮你把界面做得像 **VS Code** 或 **GitHub** 一样专业。
|
||||
左边是清爽的表格,右边是极客风的代码预览,切换开关时,整个页面会平滑过渡(如果不做 transition 就是瞬间切换,做了就是渐变,建议做 transition)。
|
||||
126
demands/DEMAND.md
Normal file
126
demands/DEMAND.md
Normal file
@@ -0,0 +1,126 @@
|
||||
项目需求文档 (PRD): Excel 转 JSON 可视化映射工具
|
||||
1. 项目概述
|
||||
|
||||
我们需要开发一个基于 Svelte 的单页应用。该应用允许用户上传 Excel 文件,在左侧预览数据,在右侧实时预览转换后的 JSON 数据。核心功能是用户可以自定义“Excel列”到“JSON字段”的映射规则、处理空值逻辑以及格式化特定数据类型(如日期),并支持将这些配置导出为模板,以便下次复用。
|
||||
2. 技术栈要求
|
||||
|
||||
框架: Svelte (推荐使用 Svelte 5 或 SvelteKit) + TypeScript
|
||||
|
||||
样式: TailwindCSS (用于快速构建左右分栏布局)
|
||||
|
||||
Excel 处理: xlsx (SheetJS) 或类似的轻量级库
|
||||
|
||||
图标库: Lucide-svelte (可选)
|
||||
|
||||
3. 界面布局 (UI Layout)
|
||||
|
||||
页面主要分为 顶部工具栏 和 主体内容区。
|
||||
|
||||
顶部工具栏 (Header):
|
||||
|
||||
文件上传按钮 (支持拖拽上传 Excel)。
|
||||
|
||||
模板操作区:[导入配置模板]、[导出当前配置]。
|
||||
|
||||
全局操作:[下载 JSON]、[复制 JSON]。
|
||||
|
||||
主体内容区 (Main Split View):
|
||||
|
||||
左侧 (Source Panel - 50%): 显示 Excel 解析后的表格数据。
|
||||
|
||||
关键交互: 表头应包含“设置”功能。用户点击表头或表头旁边的图标,可以弹出/展开该列的映射配置面板。
|
||||
|
||||
右侧 (Target Panel - 50%): 显示转换后的 JSON 代码预览(支持语法高亮)。
|
||||
|
||||
4. 核心功能细节
|
||||
4.1 Excel 导入与展示
|
||||
|
||||
支持 .xlsx, .xls, .csv 格式。
|
||||
|
||||
读取 Excel 的第一行作为默认表头(Key)。
|
||||
|
||||
数据以表格形式展示在左侧。
|
||||
|
||||
4.2 字段映射配置 (Mapping Logic)
|
||||
|
||||
这是本应用的核心。每一列都需要一个配置对象,包含以下属性:
|
||||
|
||||
Original Header (源字段): Excel 原始表头名称 (只读)。
|
||||
|
||||
Target Key (目标字段): 映射到 JSON 中的 Key 名称 (用户可修改)。
|
||||
|
||||
示例: Excel 中是 "姓名",用户输入 "userName",生成的 JSON 为 {"userName": "..."}。
|
||||
|
||||
Data Type (数据类型):
|
||||
|
||||
String (默认)
|
||||
|
||||
Number
|
||||
|
||||
Boolean
|
||||
|
||||
Date
|
||||
|
||||
Format Rules (格式化规则 - 仅针对特定类型):
|
||||
|
||||
如果是 Date 类型,提供格式化选项 (如 YYYY-MM-DD, YYYY/MM/DD HH:mm, Unix Timestamp)。需要引入 dayjs 或类似库处理。
|
||||
|
||||
Null Handling (空值处理):
|
||||
|
||||
开关选项:Exclude if Empty (如果该单元格为空,则在生成的 JSON 对象中完全移除该 Key)。
|
||||
|
||||
默认值:如果未勾选“移除”,可设置一个默认值 (Default Value)。
|
||||
|
||||
4.3 JSON 实时预览
|
||||
|
||||
当用户修改映射配置(如修改 Key 名称、切换日期格式、改变空值策略)时,右侧的 JSON 预览应 实时 (Reactive) 更新。
|
||||
|
||||
4.4 模板系统 (Configuration Persistence)
|
||||
|
||||
导出模板: 将当前的映射规则数组导出为 .json 文件。
|
||||
|
||||
数据结构示例:
|
||||
JSON
|
||||
|
||||
[
|
||||
{ "source": "A", "target": "AAA", "type": "string", "excludeIfEmpty": false },
|
||||
{ "source": "入职日期", "target": "joinDate", "type": "date", "format": "YYYY-MM-DD" }
|
||||
]
|
||||
|
||||
导入模板: 上传上述格式的 JSON 文件,应用自动匹配当前 Excel 的表头。如果 Excel 包含模板中定义的 source 字段,则自动应用对应的规则。
|
||||
|
||||
5. 交互流程 (User Story)
|
||||
|
||||
用户打开页面,拖入 staff_data.xlsx。
|
||||
|
||||
左侧显示表格。用户发现“出生日期”这一列解析出来是数字(Excel 时间戳)。
|
||||
|
||||
用户点击“出生日期”列的设置,将类型改为 Date,格式选择 YYYY-MM-DD。
|
||||
|
||||
用户发现有一列“备注”很多是空的,点击设置,勾选 Exclude if Empty。
|
||||
|
||||
用户将“姓名”列的 Target Key 改为 full_name。
|
||||
|
||||
右侧 JSON 实时变成了期望的格式。
|
||||
|
||||
用户点击“导出配置”,保存为 staff_mapping.json。
|
||||
|
||||
下周,用户上传新的 Excel,并点击“导入配置”选择 staff_mapping.json,所有规则自动应用,直接复制右侧 JSON。
|
||||
|
||||
请执行以下任务:
|
||||
|
||||
数据结构设计: 定义 MappingConfig 和 RowData 的 TypeScript 接口。
|
||||
|
||||
核心逻辑实现: 编写一个 convertData 函数,根据映射配置将 Excel 原始数据转换为最终 JSON。
|
||||
|
||||
组件编写:
|
||||
|
||||
App.svelte: 主布局和状态管理。
|
||||
|
||||
ExcelTable.svelte: 左侧表格,包含列头配置 UI。
|
||||
|
||||
JsonPreview.svelte: 右侧展示。
|
||||
|
||||
请确保代码不仅能运行,而且具有良好的错误处理(例如文件解析失败)。
|
||||
|
||||
支持嵌套对象: 如果 Target Key 包含点号(例如 user.address.city),生成的 JSON 应当自动构建对应的嵌套对象结构,而不是生成一个带点的字符串键名。
|
||||
Reference in New Issue
Block a user