diff --git a/.gitignore b/.gitignore
index 2cab9ab..a7bd664 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,4 +22,7 @@ tests/debug/
tests/manual/
test-*.mjs
test-*.js
-compare_*.js
\ No newline at end of file
+compare_*.js
+
+# logs
+logs
\ No newline at end of file
diff --git a/docs/extractor-start-button-flow.md b/docs/extractor-start-button-flow.md
new file mode 100644
index 0000000..e889969
--- /dev/null
+++ b/docs/extractor-start-button-flow.md
@@ -0,0 +1,657 @@
+# 数据提取界面 - 开始按钮工作流程详解
+
+> **文档版本**: 1.0
+> **创建日期**: 2026-03-03
+> **适用范围**: ERPAuto v1.0+
+> **相关文件**:
+> - `src/renderer/src/pages/ExtractorPage.tsx` (UI层)
+> - `src/main/ipc/extractor-handler.ts` (IPC处理层)
+> - `src/main/services/erp/extractor.ts` (业务逻辑层)
+> - `src/main/services/erp/order-resolver.ts` (订单号解析服务)
+> - `src/main/services/erp/erp-auth.ts` (ERP认证服务)
+
+## 目录
+
+1. [系统架构概览](#系统架构概览)
+2. [完整执行流程](#完整执行流程)
+3. [状态管理流程](#状态管理流程)
+4. [错误处理机制](#错误处理机制)
+5. [数据流转过程](#数据流转过程)
+6. [关键代码引用](#关键代码引用)
+
+---
+
+## 系统架构概览
+
+```mermaid
+graph TB
+ subgraph "Renderer Process (UI层)"
+ A[ExtractorPage.tsx]
+ B[React State Management]
+ C[用户输入: 订单号列表]
+ D[开始按钮]
+ end
+
+ subgraph "IPC Bridge (通信桥梁)"
+ E[electron.extractor.runExtractor]
+ F[extractor:run Channel]
+ end
+
+ subgraph "Main Process (主进程)"
+ G[extractor-handler.ts]
+ H[OrderNumberResolver]
+ I[ErpAuthService]
+ J[ExtractorService]
+ end
+
+ subgraph "External Services (外部服务)"
+ K[(MySQL Database)]
+ L[ERP Web System]
+ M[Playwright Browser]
+ end
+
+ A -->|用户点击| D
+ D -->|调用API| E
+ E -->|IPC通信| F
+ F -->|接收请求| G
+ G -->|解析订单号| H
+ H -->|查询数据| K
+ G -->|登录认证| I
+ I -->|自动化操作| M
+ M -->|访问页面| L
+ G -->|执行提取| J
+ J -->|使用| I
+ J -->|返回结果| G
+ G -->|IPC响应| F
+ F -->|更新UI| A
+ B -->|管理状态| A
+
+ style A fill:#e1f5ff
+ style G fill:#fff4e1
+ style K fill:#e8f5e9
+ style L fill:#f3e5f5
+```
+
+### 架构说明
+
+- **Renderer Process**: 负责UI展示和用户交互,使用React管理状态
+- **IPC Bridge**: 安全的进程间通信桥梁,通过preload脚本暴露
+- **Main Process**: 处理业务逻辑、数据库操作、浏览器自动化
+- **External Services**: MySQL数据库和ERP Web系统
+
+---
+
+## 完整执行流程
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant User as 👤 用户
+ participant UI as ExtractorPage.tsx
+ participant IPC as electron API
+ participant Handler as extractor-handler.ts
+ participant Resolver as OrderNumberResolver
+ participant MySQL as MySQL Database
+ participant Auth as ErpAuthService
+ participant Extractor as ExtractorService
+ participant Browser as Playwright Browser
+ participant ERP as ERP Web System
+
+ User->>UI: 1. 输入订单号列表
(每行一个)
+ User->>UI: 2. 点击"开始提取"按钮
+
+ Note over UI: 前端验证与准备
+ UI->>UI: 3. 验证订单号非空
+ UI->>UI: 4. 设置isRunning=true
+ UI->>UI: 5. 清空之前的结果和错误
+ UI->>UI: 6. 存储Production IDs到共享状态
+ UI->>IPC: 7. 调用electron.extractor.runExtractor()
+
+ Note over IPC,Handler: IPC通信
+ IPC->>Handler: 8. 发送IPC消息 'extractor:run'
+
+ Note over Handler: 环境配置检查
+ Handler->>Handler: 9. 读取.env配置
(ERP_URL, USERNAME, PASSWORD)
+ Handler->>Handler: 10. 验证配置完整性
+ alt 配置不完整
+ Handler-->>UI: 返回ValidationError
+ UI->>UI: 显示错误提示
+ UI->>UI: 设置isRunning=false
+ end
+
+ Note over Handler,MySQL: 订单号解析阶段
+ Handler->>MySQL: 11. 连接MySQL数据库
+ alt MySQL连接失败
+ Handler-->>UI: 返回DatabaseQueryError
+ end
+
+ Handler->>Resolver: 12. 创建OrderNumberResolver
+ Handler->>Resolver: 13. 调用resolve(orderNumbers)
+ Resolver->>MySQL: 14. 查询生产订单号映射
+ MySQL-->>Resolver: 15. 返回映射结果
+ Resolver-->>Handler: 16. 返回映射结果
(包含有效订单号和警告)
+
+ alt 没有有效订单号
+ Handler-->>UI: 返回ValidationError
+ UI->>UI: 显示错误: "没有有效的生产订单号"
+ end
+
+ Note over Handler,Browser: ERP认证阶段
+ Handler->>Auth: 17. 创建ErpAuthService
+ Handler->>Auth: 18. 调用login()
+ Auth->>Browser: 19. 启动Playwright浏览器
+ Browser->>ERP: 20. 访问ERP登录页面
+ Browser->>ERP: 21. 填写用户名密码
+ Browser->>ERP: 22. 点击登录按钮
+ ERP-->>Browser: 23. 登录成功
+ Browser-->>Auth: 24. 返回session对象
+ Auth-->>Handler: 25. 登录成功
+ alt 登录失败
+ Auth-->>Handler: 抛出异常
+ Handler-->>UI: 返回ErpConnectionError
+ end
+
+ Note over Extractor,ERP: 数据提取阶段
+ Handler->>Extractor: 26. 创建ExtractorService
+ Handler->>Extractor: 27. 调用extract()
传入有效订单号
+ Extractor->>Browser: 28. 使用已有session
+ Extractor->>ERP: 29. 导航到离散备料计划维护页面
+ Extractor->>ERP: 30. 设置查询界面
(订单号查询, 全部标签, 限制5000)
+
+ loop 批处理循环 (每批最多100个订单)
+ Extractor->>Extractor: 31. 创建批次
(按batchSize分组)
+ Extractor->>UI: 32. 发送进度更新
onProgress(message, progress%)
+ UI->>UI: 33. 更新进度条和日志
+
+ Extractor->>ERP: 34. 填充订单号到搜索框
+ Extractor->>ERP: 35. 点击搜索按钮
+ Extractor->>ERP: 36. 等待加载完成
+ Extractor->>ERP: 37. 点击第一行复选框
+ Extractor->>ERP: 38. 悬停并点击"更多"
+ Extractor->>ERP: 39. 点击"输出"
+ Extractor->>ERP: 40. 设置行数阈值为300000
+ Extractor->>ERP: 41. 点击"确定(Y)"
+
+ Browser->>Browser: 42. 监听下载事件
+ ERP->>Browser: 43. 触发文件下载
+ Browser->>Browser: 44. 保存文件到downloads目录
+ Browser-->>Extractor: 45. 返回文件路径
+ Extractor->>Extractor: 46. 记录下载文件路径
+ end
+
+ Extractor->>Extractor: 47. 汇总结果
(文件列表, 记录数, 错误)
+ Extractor-->>Handler: 48. 返回ExtractorResult
+ Handler->>Handler: 49. 添加解析警告到错误列表
+
+ Note over Handler,IPC: 清理阶段
+ Handler->>Browser: 50. 关闭浏览器
+ Handler->>MySQL: 51. 断开数据库连接
+
+ Note over Handler,UI: 响应阶段
+ Handler-->>IPC: 52. 返回IPC响应
(success: true, data: result)
+ IPC-->>UI: 53. 返回response
+ UI->>UI: 54. 设置result状态
+ UI->>UI: 55. 设置isRunning=false
+ UI->>UI: 56. 清空进度状态
+ UI->>User: 57. 显示提取结果
(文件数, 记录数, 错误数)
+
+ alt 发生任何错误
+ Handler-->>UI: 返回error响应
+ UI->>UI: 设置error状态
+ UI->>UI: 设置isRunning=false
+ UI->>User: 显示错误信息
+ end
+```
+
+---
+
+## 状态管理流程
+
+```mermaid
+stateDiagram-v2
+ [*] --> Idle: 初始状态
+
+ Idle --> Validating: 用户点击开始按钮
+ Validating --> Idle: 验证失败
(订单号为空)
+ Validating --> Running: 验证通过
+
+ Running --> Processing: 调用IPC API
+ Processing --> Progress: 收到进度更新
+ Progress --> Processing: 继续处理
+
+ Processing --> Success: 提取成功
+ Processing --> Error: 提取失败
+
+ Success --> Idle: 用户清空或重新输入
+ Error --> Idle: 用户修正后重试
+
+ note right of Validating
+ 前端验证阶段:
+ - 检查orderNumbers非空
+ - 解析订单号列表
+ - 存储到sessionStorage
+ - 存储到共享状态
+ end note
+
+ note right of Processing
+ 后端处理阶段:
+ - 环境配置检查
+ - 订单号解析
+ - ERP登录
+ - 批量数据提取
+ - 资源清理
+ end note
+
+ note right of Progress
+ 进度更新:
+ - 更新进度条百分比
+ - 添加日志到控制台
+ - 保持isRunning=true
+ end note
+
+ note right of Success
+ 成功状态:
+ - 显示下载文件数
+ - 显示记录总数
+ - 显示错误数
+ - isRunning=false
+ end note
+
+ note right of Error
+ 错误状态:
+ - 显示错误信息
+ - isRunning=false
+ - 保留用户输入
+ end note
+```
+
+### 状态变量说明
+
+| 状态变量 | 类型 | 说明 | 持久化 |
+|---------|------|------|--------|
+| `orderNumbers` | string | 用户输入的订单号列表 | ✅ sessionStorage |
+| `batchSize` | number | 每批处理的订单数量 (默认100) | ✅ sessionStorage |
+| `isRunning` | boolean | 是否正在执行提取 | ❌ 内存状态 |
+| `progress` | ExtractorProgress \| null | 当前进度信息 | ❌ 内存状态 |
+| `result` | ExtractorResult \| null | 提取结果 | ❌ 内存状态 |
+| `error` | string \| null | 错误信息 | ❌ 内存状态 |
+| `logs` | string[] | 执行日志列表 | ❌ 内存状态 |
+
+---
+
+## 错误处理机制
+
+```mermaid
+flowchart TD
+ Start([用户点击开始]) --> Validate{前端验证}
+ Validate -->|订单号为空| ShowEmptyError[显示错误:
请输入至少一个订单号]
+ Validate -->|验证通过| CallIPC[调用IPC API]
+
+ CallIPC --> ConfigCheck{环境配置检查}
+ ConfigCheck -->|配置不完整| ConfigError[返回ValidationError:
ERP配置不完整]
+ ConfigCheck -->|配置完整| ConnectMySQL[连接MySQL]
+
+ ConnectMySQL --> MySQLCheck{连接成功?}
+ MySQLCheck -->|失败| MySQLError[返回DatabaseQueryError:
MySQL连接失败]
+ MySQLCheck -->|成功| ResolveOrders[解析订单号]
+
+ ResolveOrders --> ValidOrders{有有效订单号?}
+ ValidOrders -->|无| NoOrdersError[返回ValidationError:
没有有效的生产订单号]
+ ValidOrders -->|有| LoginERP[ERP登录]
+
+ LoginERP --> LoginCheck{登录成功?}
+ LoginCheck -->|失败| LoginError[返回ErpConnectionError:
ERP登录失败]
+ LoginCheck -->|成功| ExtractData[执行数据提取]
+
+ ExtractData --> BatchLoop[批处理循环]
+ BatchLoop --> BatchError{批次成功?}
+ BatchError -->|失败| RecordError[记录错误到result.errors]
+ BatchError -->|成功| SaveFile[保存文件]
+ RecordError --> NextBatch{还有批次?}
+ SaveFile --> NextBatch
+
+ NextBatch -->|是| BatchLoop
+ NextBatch -->|否| Cleanup[清理资源]
+
+ Cleanup --> CheckWarnings{有警告?}
+ CheckWarnings -->|是| AddWarnings[添加警告到errors]
+ CheckWarnings -->|否| ReturnSuccess[返回成功结果]
+ AddWarnings --> ReturnSuccess
+
+ ShowEmptyError --> ResetState1[设置isRunning=false]
+ ConfigError --> ResetState2[设置isRunning=false]
+ MySQLError --> ResetState3[设置isRunning=false]
+ NoOrdersError --> ResetState4[设置isRunning=false]
+ LoginError --> ResetState5[设置isRunning=false]
+
+ ResetState1 --> End1([结束])
+ ResetState2 --> End2([结束])
+ ResetState3 --> End3([结束])
+ ResetState4 --> End4([结束])
+ ResetState5 --> End5([结束])
+ ReturnSuccess --> End6([显示结果])
+
+ style ShowEmptyError fill:#ffcccc
+ style ConfigError fill:#ffcccc
+ style MySQLError fill:#ffcccc
+ style NoOrdersError fill:#ffcccc
+ style LoginError fill:#ffcccc
+ style RecordError fill:#fff4cc
+ style ReturnSuccess fill:#ccffcc
+```
+
+### 错误类型与处理策略
+
+| 错误类型 | 触发条件 | 用户反馈 | 恢复策略 |
+|---------|---------|---------|---------|
+| `ValidationError` | 订单号为空、配置不完整、无有效订单号 | 显示红色错误消息 | 修正输入后重试 |
+| `DatabaseQueryError` | MySQL连接失败 | 显示数据库连接错误 | 检查数据库配置 |
+| `ErpConnectionError` | ERP登录失败 | 显示ERP登录错误 | 检查ERP凭据 |
+| `BatchError` | 单个批次处理失败 | 记录到错误列表,继续处理 | 查看错误详情 |
+| `SystemError` | 未知系统错误 | 显示通用错误消息 | 查看日志 |
+
+---
+
+## 数据流转过程
+
+```mermaid
+flowchart LR
+ subgraph "Input (用户输入)"
+ A1[原始输入
订单号列表]
+ A2[批次大小
batchSize=100]
+ end
+
+ subgraph "Transformation (数据转换)"
+ B1[行解析
按换行符分割]
+ B2[去空白
trim每行]
+ B3[过滤空行
移除空字符串]
+ B4[存储共享状态
Production IDs]
+ end
+
+ subgraph "Resolution (订单号解析)"
+ C1[查询MySQL
查找映射关系]
+ C2[提取生产订单号
获取有效值]
+ C3[收集警告
记录未映射项]
+ end
+
+ subgraph "Processing (批量处理)"
+ D1[批次分组
按batchSize切分]
+ D2[批次迭代
逐批处理]
+ D3[订单拼接
逗号连接]
+ end
+
+ subgraph "Output (结果输出)"
+ E1[下载文件列表
downloadedFiles数组]
+ E2[合并文件
mergedFile TODO]
+ E3[记录总数
recordCount]
+ E4[错误列表
errors数组]
+ end
+
+ A1 --> B1
+ B1 --> B2
+ B2 --> B3
+ B3 --> B4
+ B4 --> C1
+ A2 --> D1
+ C1 --> C2
+ C2 --> D1
+ C3 --> E4
+ D1 --> D2
+ D2 --> D3
+ D3 --> E1
+ E1 --> E3
+
+ style A1 fill:#e3f2fd
+ style A2 fill:#e3f2fd
+ style E1 fill:#e8f5e9
+ style E2 fill:#e8f5e9
+ style E3 fill:#e8f5e9
+ style E4 fill:#fff3e0
+```
+
+### 数据转换详情
+
+**阶段1: 用户输入 → Production IDs**
+```
+输入: "PO-20231024-001\nPO-20231024-002\nPO-20231024-003"
+ ↓ 分割 + trim + 过滤
+结果: ["PO-20231024-001", "PO-20231024-002", "PO-20231024-003"]
+ ↓ 存储到共享状态
+共享状态: Production IDs (供清理模块使用)
+```
+
+**阶段2: Production IDs → 生产订单号**
+```
+输入: ["PO-20231024-001", "PO-20231024-002", "INVALID"]
+ ↓ MySQL查询 (production_order表)
+映射结果: {
+ "PO-20231024-001": "MO-20231024-001",
+ "PO-20231024-002": "MO-20231024-002",
+ "INVALID": null
+}
+ ↓ 提取有效值
+有效订单号: ["MO-20231024-001", "MO-20231024-002"]
+警告: ["INVALID: 未找到对应的生产订单号"]
+```
+
+**阶段3: 生产订单号 → 批次**
+```
+输入: ["MO-001", "MO-002", ..., "MO-250"] (250个)
+批次大小: 100
+ ↓ 分组
+批次1: ["MO-001", ..., "MO-100"]
+批次2: ["MO-101", ..., "MO-200"]
+批次3: ["MO-201", ..., "MO-250"]
+```
+
+**阶段4: 批次 → ERP查询字符串**
+```
+批次: ["MO-001", "MO-002", "MO-003"]
+ ↓ 逗号连接
+查询字符串: "MO-001,MO-002,MO-003"
+ ↓ 填充到ERP搜索框
+ERP操作: 填入搜索框并点击搜索
+```
+
+---
+
+## 关键代码引用
+
+### 1. 前端开始按钮处理 (ExtractorPage.tsx:52-90)
+
+```typescript
+const handleExtract = async () => {
+ // 1. 前端验证
+ if (!orderNumbers.trim()) {
+ setError('请输入至少一个订单号')
+ return
+ }
+
+ // 2. 设置运行状态
+ setIsRunning(true)
+ setProgress(null)
+ setResult(null)
+ setError(null)
+
+ try {
+ // 3. 解析订单号列表
+ const orderNumberList = orderNumbers
+ .split('\n')
+ .map((line) => line.trim())
+ .filter((line) => line.length > 0)
+
+ // 4. 存储到共享状态
+ await window.electron.validation.setSharedProductionIds(orderNumberList)
+
+ // 5. 调用后端API
+ const response = await window.electron.extractor.runExtractor({
+ orderNumbers: orderNumberList,
+ batchSize
+ })
+
+ // 6. 处理响应
+ if (response.success && response.data) {
+ setResult(response.data)
+ } else {
+ setError(response.error || '提取失败')
+ }
+ } catch (err) {
+ setError(err instanceof Error ? err.message : '发生未知错误')
+ } finally {
+ // 7. 重置状态
+ setIsRunning(false)
+ setProgress(null)
+ }
+}
+```
+
+### 2. IPC处理器核心逻辑 (extractor-handler.ts:17-154)
+
+```typescript
+ipcMain.handle('extractor:run', async (_event, input: ExtractorInput) => {
+ return withErrorHandling(async () => {
+ // 1. 环境配置检查
+ const erpUrl = process.env.ERP_URL || ''
+ const erpUsername = process.env.ERP_USERNAME || ''
+ const erpPassword = process.env.ERP_PASSWORD || ''
+
+ if (!erpUrl || !erpUsername || !erpPassword) {
+ throw new ValidationError('ERP 配置不完整')
+ }
+
+ // 2. 订单号解析
+ const mysqlService = new MySqlService(mysqlConfig)
+ await mysqlService.connect()
+
+ const resolver = new OrderNumberResolver(mysqlService)
+ const mappings = await resolver.resolve(input.orderNumbers)
+ const validOrderNumbers = resolver.getValidOrderNumbers(mappings)
+
+ if (validOrderNumbers.length === 0) {
+ throw new ValidationError('没有有效的生产订单号可处理')
+ }
+
+ // 3. ERP登录
+ const authService = new ErpAuthService({...})
+ await authService.login()
+
+ // 4. 执行提取
+ const extractor = new ExtractorService(authService)
+ const result = await extractor.extract({
+ ...input,
+ orderNumbers: validOrderNumbers
+ })
+
+ // 5. 资源清理
+ await authService.close()
+ await mysqlService.disconnect()
+
+ return result
+ }, 'extractor:run')
+})
+```
+
+### 3. 提取服务批处理逻辑 (extractor.ts:43-67)
+
+```typescript
+// 批处理循环
+const batches = this.createBatches(input.orderNumbers, batchSize)
+
+for (let i = 0; i < batches.length; i++) {
+ const batch = batches[i]
+ const progress = ((i + 1) / batches.length) * 100
+
+ // 发送进度更新
+ input.onProgress?.(`Processing batch ${i + 1}/${batches.length}`, progress)
+
+ try {
+ const filePath = await this.downloadBatch(
+ session, popupPage, workFrame, batch, i, batches.length
+ )
+ result.downloadedFiles.push(filePath)
+ } catch (error) {
+ // 记录错误但继续处理
+ result.errors.push(`Batch ${i + 1}: ${error.message}`)
+ }
+}
+```
+
+### 4. 浏览器自动化单批次处理 (extractor.ts:151-194)
+
+```typescript
+private async downloadBatch(...): Promise {
+ // 1. 填充订单号
+ const textbox = workFrame.getByRole('textbox', { name: '来源生产订单号' })
+ await textbox.fill(orderNumbers.join(','))
+
+ // 2. 点击搜索
+ await workFrame.locator('.search-component-searchBtn').click()
+
+ // 3. 等待加载
+ await this.waitForLoading(workFrame)
+
+ // 4. 选择第一行
+ await workFrame.getByRole('row', { name: '序号' }).getByLabel('').click()
+
+ // 5. 点击更多 -> 输出
+ await workFrame.getByRole('button', { name: '更多' }).hover()
+ await workFrame.getByText('输出', { exact: true }).click()
+
+ // 6. 设置阈值
+ await thresholdBox.fill('300000')
+
+ // 7. 等待下载
+ const downloadPromise = popupPage.waitForEvent('download')
+ await workFrame.getByRole('button', { name: '确定(Y)' }).click()
+ const download = await downloadPromise
+
+ // 8. 保存文件
+ const downloadPath = path.join(this.downloadDir, `temp_batch_${batchIndex + 1}.xlsx`)
+ await download.saveAs(downloadPath)
+
+ return downloadPath
+}
+```
+
+---
+
+## 总结
+
+### 流程关键点
+
+1. **三层验证机制**:
+ - 前端验证: 非空检查
+ - 配置验证: 环境变量完整性
+ - 数据验证: 订单号有效性
+
+2. **资源管理策略**:
+ - 使用try-finally确保资源清理
+ - 浏览器在使用后立即关闭
+ - 数据库连接在使用后断开
+
+3. **错误容错设计**:
+ - 单个批次失败不影响其他批次
+ - 警告信息独立收集,不影响主流程
+ - 详细错误信息返回给前端展示
+
+4. **用户体验优化**:
+ - sessionStorage持久化用户输入
+ - 实时进度反馈
+ - 共享状态支持跨页面数据传递
+ - 详细的日志记录
+
+### 性能考虑
+
+- **批处理**: 默认每批100个订单,平衡性能与稳定性
+- **异步并发**: 使用async/await处理异步操作
+- **进度反馈**: 避免长时间无响应的用户体验
+
+### 扩展性
+
+- **配置化**: batchSize可配置
+- **模块化**: 服务独立,易于测试和维护
+- **错误类型化**: 使用自定义错误类型便于精确处理
+
+---
+
+**文档维护**: 如代码逻辑变更,请及时更新本文档和相关流程图。
diff --git a/docs/settings-save-button-flow.md b/docs/settings-save-button-flow.md
new file mode 100644
index 0000000..66235df
--- /dev/null
+++ b/docs/settings-save-button-flow.md
@@ -0,0 +1,913 @@
+# 系统设置保存按钮工作流程分析
+# System Settings Save Button Workflow Analysis
+
+## 文档概述 / Document Overview
+
+本文档详细分析了 ERPAuto 系统设置界面中保存按钮的完整工作流程,包括架构设计、数据流转、技术实现细节以及错误处理机制。
+
+This document provides a comprehensive analysis of the save button workflow in the ERPAuto system settings interface, including architecture design, data flow, technical implementation details, and error handling mechanisms.
+
+---
+
+## 目录 / Table of Contents
+
+1. [架构概览](#架构概览)
+2. [数据流程图](#数据流程图)
+3. [组件详解](#组件详解)
+4. [数据结构](#数据结构)
+5. [错误处理机制](#错误处理机制)
+6. [安全考虑](#安全考虑)
+7. [技术实现细节](#技术实现细节)
+
+---
+
+## 架构概览 / Architecture Overview
+
+### 系统架构 / System Architecture
+
+系统设置保存功能采用典型的 Electron 三层架构模式:
+
+The system settings save functionality follows the classic Electron three-tier architecture pattern:
+
+```mermaid
+graph TB
+ subgraph "Renderer Process 渲染进程"
+ UI[SettingsPage.tsx
UI Component]
+ end
+
+ subgraph "Preload Script 预加载脚本"
+ BRIDGE[contextBridge API
Security Boundary]
+ end
+
+ subgraph "Main Process 主进程"
+ IPC[settings-handler.ts
IPC Handler]
+ SERVICE[ConfigManager.ts
Configuration Service]
+ FILE[.env File
Persistent Storage]
+ end
+
+ UI -->|IPC Invoke| BRIDGE
+ BRIDGE -->|Secure Channel| IPC
+ IPC -->|Business Logic| SERVICE
+ SERVICE -->|Write| FILE
+ FILE -->|Confirm| SERVICE
+ SERVICE -->|Result| IPC
+ IPC -->|Response| BRIDGE
+ BRIDGE -->|Promise Resolve| UI
+
+ style UI fill:#e1f5ff
+ style BRIDGE fill:#fff4e1
+ style IPC fill:#ffe1f5
+ style SERVICE fill:#e1ffe1
+ style FILE fill:#f5f5f5
+```
+
+### 核心设计模式 / Core Design Patterns
+
+1. **单向数据流**:数据从 UI → Main Process → File,响应沿相反路径返回
+2. **安全隔离**:Preload 脚本作为安全桥梁,通过 `contextBridge` 暴露受限 API
+3. **单例模式**:ConfigManager 使用单例确保配置一致性
+4. **缓存优先**:配置读取优先从内存缓存获取,写入时同步到磁盘
+
+---
+
+## 数据流程图 / Data Flow Diagrams
+
+### 完整保存流程 / Complete Save Flow
+
+```mermaid
+sequenceDiagram
+ actor User as 用户 User
+ participant UI as SettingsPage.tsx
+ participant Preload as preload/index.ts
+ participant IPC as settings-handler.ts
+ participant Config as ConfigManager.ts
+ participant File as .env File
+
+ User->>UI: 点击保存按钮
Click Save Button
+ activate UI
+
+ UI->>UI: handleSaveSettings()
+ Note over UI: 检查是否修改
Check isModified
+
+ UI->>Preload: window.electron.settings
.saveSettings(settings)
+ activate Preload
+
+ Preload->>IPC: ipcRenderer.invoke
('settings:saveSettings', settings)
+ activate IPC
+
+ IPC->>IPC: 验证用户类型
Validate User Type
+ IPC->>Config: configManager
.saveAllSettings(settings)
+ activate Config
+
+ Config->>Config: 更新内存缓存
Update Cache
+ Note over Config: set('erp.url', value)
set('erp.username', value)
... (40+ fields)
+
+ Config->>File: fs.writeFileSync
(.env, content)
+ activate File
+ File-->>Config: true/false
+ deactivate File
+
+ Config-->>IPC: Promise
+ deactivate Config
+
+ IPC-->>Preload: {success, error?}
+ deactivate IPC
+
+ Preload-->>UI: Promise resolve
+ deactivate Preload
+
+ alt 保存成功 / Save Success
+ UI->>UI: setIsModified(false)
+ UI->>User: 显示成功消息
Show Success Message
+ else 保存失败 / Save Failed
+ UI->>User: 显示错误消息
Show Error Message
+ end
+
+ deactivate UI
+```
+
+### 数据转换流程 / Data Transformation Flow
+
+```mermaid
+graph LR
+ subgraph "UI State"
+ STATE[Settings Interface
settings.erp.url = 'https://...']
+ end
+
+ subgraph "Type Conversion"
+ T1[SettingsData Object
TypeScript Interface]
+ end
+
+ subgraph "IPC Transport"
+ JSON[JSON Serialization
String Transfer]
+ end
+
+ subgraph "Service Layer"
+ CACHE[Config Cache
Map]
+ end
+
+ subgraph "File System"
+ ENV[.env File Format
KEY=VALUE]
+ end
+
+ STATE -->|Object| T1
+ T1 -->|JSON.stringify| JSON
+ JSON -->|Deserialize| T1
+ T1 -->|set key-value| CACHE
+ CACHE -->|Format| ENV
+
+ style STATE fill:#e1f5ff
+ style JSON fill:#fff4e1
+ style CACHE fill:#e1ffe1
+ style ENV fill:#f5f5f5
+```
+
+---
+
+## 组件详解 / Component Details
+
+### 1. 渲染进程 / Renderer Process
+
+#### SettingsPage.tsx (`src/renderer/src/pages/SettingsPage.tsx`)
+
+**主要职责 / Main Responsibilities:**
+- 用户界面渲染和交互
+- 本地状态管理(settings, isModified, message)
+- 调用 IPC 通信
+
+**关键函数 / Key Functions:**
+
+```typescript
+// 第 61-73 行 / Lines 61-73
+const handleSaveSettings = async () => {
+ try {
+ const result = await window.electron.settings.saveSettings(settings as any)
+ if (result.success) {
+ setIsModified(false) // 清除修改标记
+ showMessage('success', '设置保存成功')
+ } else {
+ showMessage('error', result.error || '保存失败')
+ }
+ } catch (error) {
+ showMessage('error', '保存设置时发生错误')
+ }
+}
+```
+
+**状态管理 / State Management:**
+
+| 状态变量 | 类型 | 用途 |
+|---------|------|------|
+| `settings` | `Settings` | 当前配置数据,结构为 `{ erp: { url, username, password } }` |
+| `isModified` | `boolean` | 标记配置是否已修改,控制保存按钮启用状态 |
+| `isLoading` | `boolean` | 加载状态,显示加载动画 |
+| `message` | `object \| null` | 临时消息,3秒后自动消失 |
+
+**UI 交互逻辑 / UI Interaction Logic:**
+
+```mermaid
+stateDiagram-v2
+ [*] --> Loading: 组件挂载
+ Loading --> Ready: loadSettings()
+ Ready --> Modified: updateSettings()
+ Modified --> Modified: 继续修改
+ Modified --> Ready: 保存成功
+ Modified --> Error: 保存失败
+ Error --> Modified: 用户继续操作
+ Ready --> [*]: 组件卸载
+
+ note right of Modified
+ 保存按钮启用
+ Save Button Enabled
+ end note
+
+ note right of Ready
+ 保存按钮禁用
+ Save Button Disabled
+ end note
+```
+
+### 2. 预加载脚本 / Preload Script
+
+#### preload/index.ts (`src/preload/index.ts`)
+
+**主要职责 / Main Responsibilities:**
+- 安全桥梁,暴露受限 API 到渲染进程
+- 类型安全的 IPC 通道定义
+
+**关键代码 / Key Code:**
+
+```typescript
+// 第 89-97 行 / Lines 89-97
+settings: {
+ getUserType: () => ipcRenderer.invoke('settings:getUserType'),
+ getSettings: () => ipcRenderer.invoke('settings:getSettings'),
+ saveSettings: (settings: SettingsData) =>
+ ipcRenderer.invoke('settings:saveSettings', settings),
+ resetDefaults: () => ipcRenderer.invoke('settings:resetDefaults'),
+ testErpConnection: () => ipcRenderer.invoke('settings:testErpConnection'),
+ testDbConnection: () => ipcRenderer.invoke('settings:testDbConnection')
+}
+```
+
+**安全隔离机制 / Security Isolation:**
+
+```mermaid
+graph TB
+ Renderer[Renderer Process
Untrusted Context]
+ Preload[Preload Script
Trusted Context]
+ Main[Main Process
Trusted Context]
+
+ Renderer -->|window.electron| Preload
+ Preload -->|ipcRenderer.invoke| Main
+ Main -->|Validation| Preload
+ Preload -->|Return Promise| Renderer
+
+ style Renderer fill:#ffe1e1
+ style Preload fill:#e1ffe1
+ style Main fill:#e1e1ff
+```
+
+### 3. 主进程 / Main Process
+
+#### settings-handler.ts (`src/main/ipc/settings-handler.ts`)
+
+**主要职责 / Main Responsibilities:**
+- IPC 通道注册和处理
+- 权限验证(基于用户类型)
+- 业务逻辑协调
+
+**保存设置处理函数 / Save Settings Handler:**
+
+```typescript
+// 第 83-102 行 / Lines 83-102
+ipcMain.handle(
+ 'settings:saveSettings',
+ async (_event, settings: SettingsData): Promise => {
+ try {
+ log.info('Saving settings')
+ const success = await configManager.saveAllSettings(settings)
+ if (success) {
+ log.info('Settings saved successfully')
+ return { success: true }
+ } else {
+ log.warn('Failed to save settings')
+ return { success: false, error: '保存设置失败' }
+ }
+ } catch (error) {
+ const message = error instanceof Error ? error.message : 'Unknown error'
+ log.error('Error saving settings', { error: message })
+ return { success: false, error: `保存设置失败:${message}` }
+ }
+ }
+)
+```
+
+**用户类型过滤 / User Type Filtering:**
+
+```typescript
+// 第 31-54 行 / Lines 31-54
+function filterSettingsByUserType(settings: SettingsData, userType: UserType): SettingsData {
+ if (userType === 'Admin') {
+ return settings // Admin 获取完整配置
+ }
+
+ // User 用户获取受限配置
+ return {
+ erp: {
+ username: settings.erp.username,
+ password: settings.erp.password,
+ headless: settings.erp.headless,
+ url: settings.erp.url,
+ ignoreHttpsErrors: settings.erp.ignoreHttpsErrors,
+ autoCloseBrowser: settings.erp.autoCloseBrowser
+ },
+ paths: settings.paths,
+ execution: settings.execution,
+ database: settings.database,
+ extraction: settings.extraction,
+ validation: settings.validation,
+ ui: settings.ui
+ }
+}
+```
+
+**权限控制矩阵 / Permission Control Matrix:**
+
+| 功能 / Feature | Admin | User | Guest |
+|---------------|-------|------|-------|
+| 查看所有设置 | ✅ | ⚠️ 部分 | ❌ |
+| 保存设置 | ✅ | ✅ | ❌ |
+| 恢复默认值 | ✅ | ❌ | ❌ |
+| 测试 ERP 连接 | ✅ | ✅ | ❌ |
+| 测试数据库连接 | ✅ | ✅ | ❌ |
+
+### 4. 配置管理服务 / Configuration Manager Service
+
+#### config-manager.ts (`src/main/services/config/config-manager.ts`)
+
+**主要职责 / Main Responsibilities:**
+- .env 文件读写
+- 配置缓存管理
+- 默认值管理
+- 类型转换和验证
+
+**类结构 / Class Structure:**
+
+```typescript
+export class ConfigManager {
+ private static instance: ConfigManager | null = null // 单例模式
+ private envPath: string // .env 文件路径
+ private configCache: Map // 内存缓存
+ private initialized: boolean = false // 初始化标记
+
+ // 单例获取方法
+ public static getInstance(): ConfigManager
+
+ // 配置读取
+ public get(key: string, defaultValue?: string): string | undefined
+ public getBoolean(key: string, defaultValue?: boolean): boolean
+ public getNumber(key: string, defaultValue?: number): number
+
+ // 配置写入
+ public set(key: string, value: string | number | boolean): void
+
+ // 持久化
+ public async save(): Promise
+
+ // 高级操作
+ public getAllSettings(): SettingsData
+ public async saveAllSettings(settings: SettingsData): Promise
+ public resetToDefaults(): SettingsData
+}
+```
+
+**保存详细流程 / Save Detailed Flow:**
+
+```mermaid
+graph TD
+ START[saveAllSettings] --> STEP1[更新 ERP 配置 6 字段]
+ STEP1 --> STEP2[更新数据库配置 7 字段]
+ STEP2 --> STEP3[更新路径配置 3 字段]
+ STEP3 --> STEP4[更新提取配置 5 字段]
+ STEP4 --> STEP5[更新校验配置 5 字段]
+ STEP5 --> STEP6[更新 UI 配置 3 字段]
+ STEP6 --> STEP7[更新执行配置 1 字段]
+ STEP7 --> SAVE[调用 save 方法]
+ SAVE --> BUILD[构建 .env 内容]
+ BUILD --> WRITE[写入文件系统]
+ WRITE --> CHECK{检查结果}
+ CHECK -->|成功| SUCCESS[返回 true]
+ CHECK -->|失败| FAILURE[返回 false]
+```
+
+**.env 文件格式 / .env File Format:**
+
+```bash
+# ===========================
+# ERP 系统配置
+# ===========================
+ERP_URL=https://68.11.34.30:8082/
+ERP_USERNAME=
+ERP_PASSWORD=
+ERP_HEADLESS=true
+ERP_IGNORE_HTTPS_ERRORS=true
+ERP_AUTO_CLOSE_BROWSER=true
+
+# ===========================
+# 数据库配置 - MySQL
+# ===========================
+DB_TYPE=mysql
+DB_NAME=BLD_DB
+DB_USERNAME=remote_user
+DB_PASSWORD=
+DB_MYSQL_HOST=192.168.31.83
+DB_MYSQL_PORT=3306
+DB_MYSQL_CHARSET=utf8mb4
+
+# ===========================
+# 路径配置
+# ===========================
+PATH_DATA_DIR=D:/python/playwrite/data/
+PATH_DEFAULT_OUTPUT=离散备料计划维护_合并.xlsx
+PATH_VALIDATION_OUTPUT=物料状态校验结果.xlsx
+
+# ... 更多配置节
+```
+
+---
+
+## 数据结构 / Data Structures
+
+### SettingsData 接口 / Interface Definition
+
+**类型定义位置 / Type Definition Location:**
+`src/main/types/settings.types.ts` (第 136-151 行)
+
+```typescript
+export interface SettingsData {
+ erp: ErpConfig
+ database: DatabaseConfig
+ paths: PathsConfig
+ extraction: ExtractionConfig
+ validation: ValidationConfig
+ ui: UiConfig
+ execution: ExecutionConfig
+}
+```
+
+### 完整数据结构树 / Complete Data Structure Tree
+
+```mermaid
+graph TB
+ Settings[SettingsData]
+
+ Settings --> Erp[ErpConfig]
+ Erp --> Erp1[url: string]
+ Erp --> Erp2[username: string]
+ Erp --> Erp3[password: string]
+ Erp --> Erp4[headless: boolean]
+ Erp --> Erp5[ignoreHttpsErrors: boolean]
+ Erp --> Erp6[autoCloseBrowser: boolean]
+
+ Settings --> DB[DatabaseConfig]
+ DB --> DB1[dbType: 'mysql'|'sqlserver']
+ DB --> DB2[server: string]
+ DB --> DB3[mysqlHost: string]
+ DB --> DB4[mysqlPort: number]
+ DB --> DB5[database: string]
+ DB --> DB6[username: string]
+ DB --> DB7[password: string]
+
+ Settings --> Paths[PathsConfig]
+ Paths --> Paths1[dataDir: string]
+ Paths --> Paths2[defaultOutput: string]
+ Paths --> Paths3[validationOutput: string]
+
+ Settings --> Extract[ExtractionConfig]
+ Extract --> Extract1[batchSize: number]
+ Extract --> Extract2[verbose: boolean]
+ Extract --> Extract3[autoConvert: boolean]
+ Extract --> Extract4[mergeBatches: boolean]
+ Extract --> Extract5[enableDbPersistence: boolean]
+
+ Settings --> Valid[ValidationConfig]
+ Valid --> Valid1[dataSource: ValidationDataSource]
+ Valid --> Valid2[batchSize: number]
+ Valid --> Valid3[matchMode: MatchMode]
+ Valid --> Valid4[enableCrud: boolean]
+ Valid --> Valid5[defaultManager: string]
+
+ Settings --> UI[UiConfig]
+ UI --> UI1[fontFamily: string]
+ UI --> UI2[fontSize: number]
+ UI --> UI3[productionIdInputWidth: number]
+
+ Settings --> Exec[ExecutionConfig]
+ Exec --> Exec1[dryRun: boolean]
+
+ style Settings fill:#e1f5ff
+ style Erp fill:#ffe1f5
+ style DB fill:#e1ffe1
+ style Paths fill:#fff4e1
+ style Extract fill:#f5e1ff
+ style Valid fill:#ffe1e1
+ style UI fill:#e1f5ff
+ style Exec fill:#f5f5f5
+```
+
+### IPC 通信数据格式 / IPC Communication Data Format
+
+**请求格式 / Request Format:**
+```json
+{
+ "erp": {
+ "url": "https://68.11.34.30:8082/",
+ "username": "admin",
+ "password": "password123",
+ "headless": true,
+ "ignoreHttpsErrors": true,
+ "autoCloseBrowser": true
+ },
+ "database": { ... },
+ "paths": { ... },
+ "extraction": { ... },
+ "validation": { ... },
+ "ui": { ... },
+ "execution": { ... }
+}
+```
+
+**响应格式 / Response Format:**
+```json
+// 成功 / Success
+{
+ "success": true
+}
+
+// 失败 / Failure
+{
+ "success": false,
+ "error": "保存设置失败:Access denied"
+}
+```
+
+---
+
+## 错误处理机制 / Error Handling Mechanism
+
+### 错误处理层次 / Error Handling Layers
+
+```mermaid
+graph TB
+ subgraph "UI Layer"
+ UI_TRY[try-catch in handleSaveSettings]
+ UI_MSG[showMessage display]
+ end
+
+ subgraph "IPC Layer"
+ IPC_TRY[try-catch in handler]
+ IPC_LOG[Structured logging]
+ IPC_RETURN[Return error object]
+ end
+
+ subgraph "Service Layer"
+ SVC_TRY[try-catch in save]
+ SVC_LOG[Console error log]
+ SVC_RETURN[Return false]
+ end
+
+ subgraph "File System"
+ FS_CHECK[File exists check]
+ FS_WRITE[Write with error handling]
+ end
+
+ UI_TRY -->|Catch| UI_MSG
+ IPC_TRY -->|Catch| IPC_LOG --> IPC_RETURN
+ SVC_TRY -->|Catch| SVC_LOG --> SVC_RETURN
+ FS_WRITE -->|Error| SVC_TRY
+
+ style UI_TRY fill:#ffe1e1
+ style IPC_TRY fill:#ffe1e1
+ style SVC_TRY fill:#ffe1e1
+```
+
+### 错误场景分析 / Error Scenario Analysis
+
+| 错误场景 / Error Scenario | 触发位置 / Location | 处理方式 / Handling | 用户反馈 / User Feedback |
+|--------------------------|-------------------|-------------------|----------------------|
+| IPC 通信失败 | Renderer | try-catch | 显示"保存设置时发生错误" |
+| 权限不足 | Main Process | 检查 UserType | 返回权限错误信息 |
+| 文件写入失败 | ConfigManager | fs.writeFileSync 捕获 | 返回"保存设置失败" |
+| 无效数据类型 | IPC Handler | TypeScript 类型检查 | 返回验证错误 |
+| 磁盘空间不足 | File System | OS 异常捕获 | 返回系统错误信息 |
+
+### 日志记录策略 / Logging Strategy
+
+```typescript
+// Main Process 结构化日志 / Structured Logging
+log.info('Saving settings')
+log.info('Settings saved successfully')
+log.warn('Failed to save settings')
+log.error('Error saving settings', { error: message })
+```
+
+**日志级别使用 / Log Level Usage:**
+- `info`: 正常操作流程
+- `warn`: 潜在问题(如保存失败但未崩溃)
+- `error`: 严重错误(如异常抛出)
+
+---
+
+## 安全考虑 / Security Considerations
+
+### 安全机制层级 / Security Layers
+
+```mermaid
+graph TB
+ L1[Layer 1: Context Isolation
渲染进程隔离]
+ L2[Layer 2: contextBridge
受限 API 暴露]
+ L3[Layer 3: User Type Filtering
基于角色的访问控制]
+ L4[Layer 4: File System Permissions
.env 文件保护]
+
+ L1 --> L2 --> L3 --> L4
+
+ style L1 fill:#e1f5ff
+ style L2 fill:#fff4e1
+ style L3 fill:#e1ffe1
+ style L4 fill:#ffe1f5
+```
+
+### 关键安全措施 / Key Security Measures
+
+1. **密码明文存储风险 / Password Storage Risk**
+ - ⚠️ 当前:密码以明文形式存储在 .env 文件中
+ - 🔒 建议:实现加密存储机制
+
+2. **用户权限隔离 / User Permission Isolation**
+ - ✅ 实现:基于用户类型过滤可见配置
+ - ✅ 实现:Guest 用户无法访问设置页面
+
+3. **IPC 通信安全 / IPC Communication Security**
+ - ✅ 实现:使用 `contextBridge` 而非直接暴露
+ - ✅ 实现:类型安全的 TypeScript 接口
+
+4. **文件系统访问 / File System Access**
+ - ✅ 实现:.env 文件仅主进程可访问
+ - ⚠️ 风险:文件权限取决于操作系统
+
+### 敏感数据流向 / Sensitive Data Flow
+
+```mermaid
+sequenceDiagram
+ participant User as 用户输入
+ participant UI as UI State (内存)
+ participant IPC as IPC Channel
+ participant Cache as Config Cache
+ participant File as .env File
+
+ User->>UI: password = "secret123"
+ UI->>IPC: JSON 传输 (未加密)
+ IPC->>Cache: Map.set('erp.password', 'secret123')
+ Cache->>File: 写入明文到磁盘
+
+ Note over File: ⚠️ 安全风险:
密码以明文形式持久化
+```
+
+---
+
+## 技术实现细节 / Technical Implementation Details
+
+### 文件位置索引 / File Location Index
+
+| 组件 / Component | 文件路径 / File Path | 关键行数 / Key Lines |
+|-----------------|---------------------|-------------------|
+| UI 组件 | `src/renderer/src/pages/SettingsPage.tsx` | 61-73 (保存处理) |
+| 预加载脚本 | `src/preload/index.ts` | 89-97 (API 定义) |
+| IPC 处理器 | `src/main/ipc/settings-handler.ts` | 83-102 (保存处理) |
+| 配置管理器 | `src/main/services/config/config-manager.ts` | 437-483 (保存方法) |
+| 类型定义 | `src/main/types/settings.types.ts` | 136-171 (接口定义) |
+| IPC 注册 | `src/main/ipc/index.ts` | 导入 settings-handler |
+
+### 性能特性 / Performance Characteristics
+
+1. **异步操作 / Async Operations**
+ - 所有 IPC 调用使用 `async/await` 模式
+ - 避免阻塞主进程事件循环
+
+2. **内存优化 / Memory Optimization**
+ - 使用 Map 缓存配置,减少文件读取
+ - 按需加载配置项
+
+3. **写入策略 / Write Strategy**
+ - 每次保存完整重写 .env 文件
+ - 原子写入(writeFileSync)
+
+### 依赖关系图 / Dependency Graph
+
+```mermaid
+graph TD
+ A[SettingsPage.tsx] -->|imports| B[lucide-react]
+ A -->|uses| C[window.electron.settings]
+
+ C -->|exposed by| D[preload/index.ts]
+ D -->|imports| E[electron API]
+ D -->|imports| F[SettingsData Type]
+
+ G[settings-handler.ts] -->|imports| H[ipcMain]
+ G -->|imports| I[ConfigManager]
+ G -->|imports| J[SessionManager]
+ G -->|imports| K[Logger]
+
+ I -->|imports| L[fs/path]
+ I -->|imports| M[SettingsData Type]
+ I -->|imports| N[DEFAULT_SETTINGS]
+
+ style A fill:#e1f5ff
+ style D fill:#fff4e1
+ style G fill:#ffe1f5
+ style I fill:#e1ffe1
+```
+
+### 关键代码片段分析 / Key Code Snippet Analysis
+
+**1. 状态更新逻辑 / State Update Logic**
+
+```typescript
+// SettingsPage.tsx 第 50-59 行
+const updateSettings = (category: string, key: string, value: any) => {
+ setSettings((prev) => ({
+ ...prev,
+ [category]: {
+ ...(prev as any)[category],
+ [key]: value
+ }
+ }))
+ setIsModified(true) // 标记为已修改
+}
+```
+
+**设计要点 / Design Points:**
+- 不可变更新模式(Immutable Update Pattern)
+- 使用展开运算符保持对象引用
+- 自动启用保存按钮
+
+**2. 配置保存逻辑 / Configuration Save Logic**
+
+```typescript
+// config-manager.ts 第 437-483 行
+public async saveAllSettings(settings: SettingsData): Promise {
+ // 批量更新缓存 (40+ 字段)
+ this.set('erp.url', settings.erp.url)
+ this.set('erp.username', settings.erp.username)
+ // ... 更多字段
+
+ // 同步写入文件
+ return this.save()
+}
+```
+
+**设计要点 / Design Points:**
+- 先更新内存,后写入磁盘
+- 失败时缓存保持不变
+- 返回布尔值表示成功/失败
+
+**3. .env 文件生成逻辑 / .env File Generation**
+
+```typescript
+// config-manager.ts 第 179-345 行
+public async save(): Promise {
+ const lines: string[] = []
+
+ // 构建格式化的 .env 内容
+ lines.push('# ===========================')
+ lines.push('# ERP 系统配置')
+ lines.push('# ===========================')
+ lines.push(`ERP_URL=${this.configCache.get('erp.url') || DEFAULT_SETTINGS.erp.url}`)
+
+ const content = lines.join('\n')
+ fs.writeFileSync(this.envPath, content, 'utf-8')
+ return true
+}
+```
+
+**设计要点 / Design Points:**
+- 添加注释分隔符提高可读性
+- 使用默认值作为后备
+- 同步写入确保一致性
+
+---
+
+## 扩展与改进建议 / Extension and Improvement Suggestions
+
+### 短期改进 / Short-term Improvements
+
+1. **输入验证 / Input Validation**
+ - 添加 URL 格式验证
+ - 密码强度检查
+ - 端口号范围验证
+
+2. **用户体验 / User Experience**
+ - 添加保存进度指示器
+ - 实现自动保存功能
+ - 添加配置导入/导出
+
+3. **错误处理 / Error Handling**
+ - 更详细的错误消息
+ - 错误恢复建议
+ - 错误日志导出
+
+### 长期改进 / Long-term Improvements
+
+1. **安全性增强 / Security Enhancement**
+ ```typescript
+ // 建议实现密码加密
+ interface SecureSettingsData extends SettingsData {
+ erp: {
+ ...ErpConfig
+ encryptedPassword: string // 替代明文密码
+ }
+ }
+ ```
+
+2. **配置版本控制 / Configuration Versioning**
+ - 实现配置历史记录
+ - 支持回滚到之前版本
+ - 配置变更审计日志
+
+3. **实时配置重载 / Live Config Reload**
+ - 监听 .env 文件变化
+ - 自动重载配置
+ - 通知相关服务更新
+
+---
+
+## 测试建议 / Testing Recommendations
+
+### 单元测试 / Unit Tests
+
+```typescript
+// 测试用例示例
+describe('ConfigManager', () => {
+ it('should save settings successfully', async () => {
+ const manager = ConfigManager.getInstance()
+ const settings: SettingsData = { /* mock data */ }
+ const result = await manager.saveAllSettings(settings)
+ expect(result).toBe(true)
+ })
+
+ it('should handle file write errors', async () => {
+ // Mock fs.writeFileSync to throw error
+ const result = await manager.saveAllSettings(settings)
+ expect(result).toBe(false)
+ })
+})
+```
+
+### 集成测试 / Integration Tests
+
+```typescript
+describe('Settings Save Flow', () => {
+ it('should complete full save cycle', async () => {
+ // 1. User modifies settings
+ // 2. Clicks save button
+ // 3. Verifies .env file updated
+ // 4. Confirms UI feedback
+ })
+})
+```
+
+---
+
+## 附录 / Appendix
+
+### 完整配置字段列表 / Complete Configuration Field List
+
+| 类别 / Category | 字段数 / Field Count | 字段列表 / Field List |
+|---------------|---------------------|-------------------|
+| ERP | 6 | url, username, password, headless, ignoreHttpsErrors, autoCloseBrowser |
+| Database | 7 | dbType, server, mysqlHost, mysqlPort, database, username, password |
+| Paths | 3 | dataDir, defaultOutput, validationOutput |
+| Extraction | 5 | batchSize, verbose, autoConvert, mergeBatches, enableDbPersistence |
+| Validation | 5 | dataSource, batchSize, matchMode, enableCrud, defaultManager |
+| UI | 3 | fontFamily, fontSize, productionIdInputWidth |
+| Execution | 1 | dryRun |
+| **总计 / Total** | **30** | |
+
+### 相关文档 / Related Documentation
+
+- [Electron Security Guidelines](https://www.electronjs.org/docs/latest/tutorial/security)
+- [IPC 通信最佳实践](https://www.electronjs.org/docs/latest/tutorial/ipc)
+- [环境变量管理规范](.env.example)
+
+### 版本历史 / Version History
+
+| 版本 / Version | 日期 / Date | 变更 / Changes |
+|---------------|------------|--------------|
+| 1.0 | 2025-03-03 | 初始版本 / Initial version |
+
+---
+
+**文档生成时间 / Document Generated:** 2025-03-03
+**最后更新 / Last Updated:** 2025-03-03
+**维护者 / Maintainer:** ERPAuto Development Team