- Create user/ - User guides and configuration documentation - Create features/ - Feature specifications and business flows - Create debugging/ - Debug guides and quick references - Create testing/ - Test infrastructure, reports, and plans - Create internal/ - Internal plans, analyses, and templates - Move cleaner/*.md to cleaner/ directory - Move LOGGING_*.md to developer/guides/ Add docs/README.md as documentation index with category navigation and quick lookup guide. The reorganized structure makes it easier for users and developers to quickly locate relevant documentation.
928 lines
26 KiB
Markdown
928 lines
26 KiB
Markdown
# 系统设置保存按钮工作流程分析
|
||
|
||
# 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<br/>UI Component]
|
||
end
|
||
|
||
subgraph "Preload Script 预加载脚本"
|
||
BRIDGE[contextBridge API<br/>Security Boundary]
|
||
end
|
||
|
||
subgraph "Main Process 主进程"
|
||
IPC[settings-handler.ts<br/>IPC Handler]
|
||
SERVICE[ConfigManager.ts<br/>Configuration Service]
|
||
FILE[.env File<br/>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: 点击保存按钮<br/>Click Save Button
|
||
activate UI
|
||
|
||
UI->>UI: handleSaveSettings()
|
||
Note over UI: 检查是否修改<br/>Check isModified
|
||
|
||
UI->>Preload: window.electron.settings<br/>.saveSettings(settings)
|
||
activate Preload
|
||
|
||
Preload->>IPC: ipcRenderer.invoke<br/>('settings:saveSettings', settings)
|
||
activate IPC
|
||
|
||
IPC->>IPC: 验证用户类型<br/>Validate User Type
|
||
IPC->>Config: configManager<br/>.saveAllSettings(settings)
|
||
activate Config
|
||
|
||
Config->>Config: 更新内存缓存<br/>Update Cache
|
||
Note over Config: set('erp.url', value)<br/>set('erp.username', value)<br/>... (40+ fields)
|
||
|
||
Config->>File: fs.writeFileSync<br/>(.env, content)
|
||
activate File
|
||
File-->>Config: true/false
|
||
deactivate File
|
||
|
||
Config-->>IPC: Promise<boolean>
|
||
deactivate Config
|
||
|
||
IPC-->>Preload: {success, error?}
|
||
deactivate IPC
|
||
|
||
Preload-->>UI: Promise resolve
|
||
deactivate Preload
|
||
|
||
alt 保存成功 / Save Success
|
||
UI->>UI: setIsModified(false)
|
||
UI->>User: 显示成功消息<br/>Show Success Message
|
||
else 保存失败 / Save Failed
|
||
UI->>User: 显示错误消息<br/>Show Error Message
|
||
end
|
||
|
||
deactivate UI
|
||
```
|
||
|
||
### 数据转换流程 / Data Transformation Flow
|
||
|
||
```mermaid
|
||
graph LR
|
||
subgraph "UI State"
|
||
STATE[Settings Interface<br/>settings.erp.url = 'https://...']
|
||
end
|
||
|
||
subgraph "Type Conversion"
|
||
T1[SettingsData Object<br/>TypeScript Interface]
|
||
end
|
||
|
||
subgraph "IPC Transport"
|
||
JSON[JSON Serialization<br/>String Transfer]
|
||
end
|
||
|
||
subgraph "Service Layer"
|
||
CACHE[Config Cache<br/>Map<string, string>]
|
||
end
|
||
|
||
subgraph "File System"
|
||
ENV[.env File Format<br/>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<br/>Untrusted Context]
|
||
Preload[Preload Script<br/>Trusted Context]
|
||
Main[Main Process<br/>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<SaveSettingsResult> => {
|
||
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<string, string> // 内存缓存
|
||
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<boolean>
|
||
|
||
// 高级操作
|
||
public getAllSettings(): SettingsData
|
||
public async saveAllSettings(settings: SettingsData): Promise<boolean>
|
||
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 or 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<br/>渲染进程隔离]
|
||
L2[Layer 2: contextBridge<br/>受限 API 暴露]
|
||
L3[Layer 3: User Type Filtering<br/>基于角色的访问控制]
|
||
L4[Layer 4: File System Permissions<br/>.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: ⚠️ 安全风险:<br/>密码以明文形式持久化
|
||
```
|
||
|
||
---
|
||
|
||
## 技术实现细节 / 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<boolean> {
|
||
// 批量更新缓存 (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<boolean> {
|
||
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
|