feat: Add mermaid-fixer skill for automatic Mermaid syntax error correction
- Add skill that uses check-mermaid.js to validate Mermaid diagrams - Skill guides Claude to parse error reports and apply intelligent fixes - Fixes common Mermaid parser bugs (parentheses, brackets, braces in labels) - Include demo scripts with test Markdown file for validation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
482
demo_scripts/demo.md
Normal file
482
demo_scripts/demo.md
Normal file
@@ -0,0 +1,482 @@
|
||||
# Admin 用户物料清理数据流说明文档
|
||||
|
||||
## 概述
|
||||
|
||||
本文档详细说明 ERPAuto 系统中,Admin 用户执行物料清理操作时,被清理物料的完整获取流程、数据来源和处理链路。
|
||||
|
||||
## 核心结论
|
||||
|
||||
**Admin 用户清理的物料来源**:被清理的物料代码从数据库表 `dbo.MaterialsToBeDeleted` 中获取,根据 Admin 用户在 UI 界面选择的负责人(Manager)进行过滤。
|
||||
|
||||
---
|
||||
|
||||
## 数据流总览
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant UI as CleanerPage (UI)
|
||||
participant Hook as useCleaner Hook
|
||||
participant API as Renderer API
|
||||
participant IPC as IPC Channel
|
||||
participant Service as ValidationService
|
||||
participant DB as Database
|
||||
|
||||
UI->>Hook: handleExecuteDeletion()
|
||||
Hook->>API: runCleanerExecution()
|
||||
API->>IPC: validation.getCleanerData({selectedManagers})
|
||||
|
||||
IPC->>Service: getCleanerData(userInfo, selectedManagers)
|
||||
|
||||
alt Admin User
|
||||
Service->>Service: loadMaterialCodesForCleaner()
|
||||
Service->>DB: SELECT MaterialCode FROM dbo.MaterialsToBeDeleted<br/>WHERE ManagerName IN (selectedManagers)
|
||||
DB-->>Service: materialCodes[]
|
||||
Service-->>IPC: {orderNumbers[], materialCodes[]}
|
||||
else Regular User
|
||||
Service->>DB: SELECT MaterialCode FROM dbo.MaterialsToBeDeleted<br/>WHERE ManagerName = username
|
||||
DB-->>Service: materialCodes[]
|
||||
Service-->>IPC: {orderNumbers[], materialCodes[]}
|
||||
end
|
||||
|
||||
IPC-->>API: cleanerData
|
||||
API->>IPC: cleaner.runCleaner({orderNumbers, materialCodes})
|
||||
IPC->>Service: CleanerApplicationService.runCleaner()
|
||||
Service->>UI: 执行清理 (ERP 删除)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 架构分层
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "渲染进程 (Renderer)"
|
||||
UI[CleanerPage.tsx]
|
||||
HOOK[useCleaner.ts]
|
||||
RAPI[renderer/api.ts]
|
||||
end
|
||||
|
||||
subgraph "主进程 (Main)"
|
||||
IPC_VAL[IPC: validation.getCleanerData]
|
||||
IPC_CLEAN[IPC: cleaner.runCleaner]
|
||||
VAS[ValidationApplicationService]
|
||||
CAS[CleanerApplicationService]
|
||||
ERP["CleanerService (ERP)"]
|
||||
end
|
||||
|
||||
subgraph "数据库 (Database)"
|
||||
MTBD[(dbo.MaterialsToBeDeleted)]
|
||||
DMPD[(dbo.DiscreteMaterialPlanData)]
|
||||
MTTD[(dbo.MaterialsTypeToBeDeleted)]
|
||||
end
|
||||
|
||||
UI --> HOOK
|
||||
HOOK --> RAPI
|
||||
RAPI --> IPC_VAL
|
||||
RAPI --> IPC_CLEAN
|
||||
IPC_VAL --> VAS
|
||||
IPC_CLEAN --> CAS
|
||||
VAS --> MTBD
|
||||
VAS --> DMPD
|
||||
VAS --> MTTD
|
||||
CAS --> ERP
|
||||
|
||||
style MTBD fill:#f9f,stroke:#333
|
||||
style MTTD fill:#f9f,stroke:#333
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 关键数据表
|
||||
|
||||
### 1. `dbo.MaterialsToBeDeleted` (核心来源表)
|
||||
|
||||
**作用**:存储所有被标记为待删除的物料代码及其负责人。
|
||||
|
||||
**表结构**:
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `ID` | int | 主键 |
|
||||
| `MaterialCode` | varchar | **物料代码 (被清理的目标)** |
|
||||
| `ManagerName` | varchar | 负责人姓名 |
|
||||
|
||||
**Admin 获取物料的 SQL 查询**:
|
||||
|
||||
```sql
|
||||
SELECT MaterialCode
|
||||
FROM dbo.MaterialsToBeDeleted
|
||||
WHERE ManagerName IN (@manager0, @manager1, ...)
|
||||
AND MaterialCode IS NOT NULL
|
||||
```
|
||||
|
||||
### 2. `dbo.MaterialsTypeToBeDeleted` (物料类型配置表)
|
||||
|
||||
**作用**:定义物料名称关键词与负责人的映射关系,用于自动分配负责人。
|
||||
|
||||
**表结构**:
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `MaterialName` | varchar | 物料名称关键词 |
|
||||
| `ManagerName` | varchar | 对应的负责人 |
|
||||
|
||||
**示例**:
|
||||
| MaterialName | ManagerName |
|
||||
|-------------|-------------|
|
||||
| "电阻" | "张三" |
|
||||
| "电容" | "李四" |
|
||||
|
||||
### 3. `dbo.DiscreteMaterialPlanData` (物料计划数据表)
|
||||
|
||||
**作用**:存储从 ERP 提取的完整物料计划数据,用于校验和展示物料详情。
|
||||
|
||||
**关键字段**:
|
||||
|
||||
- `MaterialCode` - 物料代码
|
||||
- `MaterialName` - 物料名称
|
||||
- `Specification` - 规格
|
||||
- `Model` - 型号
|
||||
- `SourceNo` - 订单号
|
||||
|
||||
---
|
||||
|
||||
## Admin 用户完整数据流
|
||||
|
||||
### 阶段 1: 校验 (Validation)
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph "步骤 1: 用户触发的数据来源"
|
||||
A1[Admin 点击'数据校验']
|
||||
end
|
||||
|
||||
subgraph "步骤 2: 数据获取模式"
|
||||
A2{校验模式?}
|
||||
A21[Full Mode<br/>全量数据]
|
||||
A22[Filtered Mode<br/>筛选数据]
|
||||
end
|
||||
|
||||
subgraph "步骤 3: 数据库查询"
|
||||
A3[DiscreteMaterialPlanDAO]
|
||||
A31["queryAllDistinctByMaterialCode()"]
|
||||
A32["queryBySourceNumbersDistinct(orderNumbers)"]
|
||||
end
|
||||
|
||||
subgraph "步骤 4: 数据增强"
|
||||
A4[加载负责人信息]
|
||||
A41[加载 MaterialsTypeToBeDeleted<br/>关键词匹配]
|
||||
A42[加载 MaterialsToBeDeleted<br/>已标记记录]
|
||||
end
|
||||
|
||||
subgraph "结果"
|
||||
A5["ValidationResult[]<br/>包含 isMarkedForDeletion 标志"]
|
||||
end
|
||||
|
||||
A1 --> A2
|
||||
A2 -->|Full| A21
|
||||
A2 -->|Filtered| A22
|
||||
A21 --> A31
|
||||
A22 --> A32
|
||||
A31 --> A4
|
||||
A32 --> A4
|
||||
A4 --> A41
|
||||
A4 --> A42
|
||||
A4 --> A5
|
||||
|
||||
style A5 fill:#9f9,stroke:#333
|
||||
```
|
||||
|
||||
**Admin 特殊逻辑**:
|
||||
|
||||
- Admin 可以看到**所有负责人**的物料
|
||||
- UI 会显示 Manager 列下拉筛选器
|
||||
- Admin 默认选中所有 Manager
|
||||
|
||||
### 阶段 2: 保存删除计划 (可选)
|
||||
|
||||
用户在 UI 上勾选物料 → 点击"确认删除" → 数据写入 `MaterialsToBeDeleted` 表:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant UI as 用户界面
|
||||
participant DAO as MaterialsToBeDeletedDAO
|
||||
participant DB as Database
|
||||
|
||||
UI->>DAO: upsertBatch(materials[])
|
||||
|
||||
loop 对每个物料
|
||||
DAO->>DB: MERGE INTO dbo.MaterialsToBeDeleted<br/>ON MaterialCode<br/>WHEN MATCHED UPDATE<br/>WHEN NOT MATCHED INSERT
|
||||
end
|
||||
|
||||
DB-->>DAO: 成功/失败统计
|
||||
DAO-->>UI: { total, success, failed }
|
||||
```
|
||||
|
||||
**SQL 逻辑**(MERGE UPSERT):
|
||||
|
||||
```sql
|
||||
MERGE INTO dbo.MaterialsToBeDeleted AS target
|
||||
USING (VALUES (@MaterialCode, @ManagerName)) AS source (MaterialCode, ManagerName)
|
||||
ON target.MaterialCode = source.MaterialCode
|
||||
WHEN MATCHED THEN
|
||||
UPDATE SET ManagerName = source.ManagerName
|
||||
WHEN NOT MATCHED THEN
|
||||
INSERT (MaterialCode, ManagerName) VALUES (source.MaterialCode, source.ManagerName);
|
||||
```
|
||||
|
||||
### 阶段 3: 执行清理 (关键步骤)
|
||||
|
||||
这是 Admin 用户执行实际删除操作的核心流程:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "Renderer 层"
|
||||
S1["handleExecuteDeletion()"]
|
||||
S1-->S2["runCleanerExecution {selectedManagers}"]
|
||||
end
|
||||
|
||||
subgraph "获取清理数据 (主进程)"
|
||||
S2-->S3[ValidationApplicationService.getCleanerData]
|
||||
S3-->S4{用户类型?}
|
||||
|
||||
S4-->|Admin + selectedManagers| S5[loadMaterialCodesForCleaner<br/>Admin With Managers]
|
||||
S5-->S6[SELECT FROM MaterialsToBeDeleted<br/>WHERE ManagerName IN selectedManagers]
|
||||
|
||||
S4-->|Admin no managers| S7[Admin Without Managers]
|
||||
S7-->S8[SELECT FROM DiscreteMaterialPlanData<br/>WHERE SourceNo IN orderNumbers]
|
||||
|
||||
S4-->|普通用户 | S9[SELECT FROM MaterialsToBeDeleted<br/>WHERE ManagerName = username]
|
||||
end
|
||||
|
||||
subgraph "执行清理"
|
||||
S6-->S10["返回 materialCodes[]"]
|
||||
S8-->S10
|
||||
S9-->S10
|
||||
S10-->S11[CleanerApplicationService.runCleaner]
|
||||
S11-->S12[CleanerService.clean<br/>连接 ERP 执行删除]
|
||||
end
|
||||
|
||||
S12-->S13[清理完成报告]
|
||||
|
||||
style S5 fill:#ff9,stroke:#333
|
||||
style S6 fill:#f96,stroke:#333
|
||||
style S12 fill:#f99,stroke:#333
|
||||
```
|
||||
|
||||
**关键代码路径**:
|
||||
|
||||
```typescript
|
||||
// src/main/services/validation/validation-application-service.ts
|
||||
// loadMaterialCodesForCleaner() 方法
|
||||
|
||||
// Admin with selected managers:
|
||||
if (isAdmin && selectedManagers && selectedManagers.length > 0) {
|
||||
const materialCodes = await this.queryMaterialCodesByManagers(
|
||||
dbService,
|
||||
markedTableName, // dbo.MaterialsToBeDeleted
|
||||
selectedManagers
|
||||
)
|
||||
return materialCodes
|
||||
}
|
||||
|
||||
// Admin without selected managers (fallback):
|
||||
if (isAdmin) {
|
||||
if (orderNumbers.length === 0) {
|
||||
return [] // 无数据可处理
|
||||
}
|
||||
const materialDao = new DiscreteMaterialPlanDAO()
|
||||
const records = await materialDao.queryBySourceNumbersDistinct(orderNumbers)
|
||||
const materialCodes = [...new Set(records.map((r) => r.MaterialCode as string).filter(Boolean))]
|
||||
return materialCodes
|
||||
}
|
||||
```
|
||||
|
||||
### 阶段 4: ERP 删除执行
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant CAS as CleanerApplicationService
|
||||
participant Cleaner as CleanerService
|
||||
participant ERP as ERP System
|
||||
|
||||
CAS->>Cleaner: clean({orderNumbers, materialCodes})
|
||||
|
||||
loop 每个订单号
|
||||
Cleaner->>ERP: 登录 (一次)
|
||||
loop 每个物料代码
|
||||
Cleaner->>ERP: 查询物料计划
|
||||
alt 物料存在
|
||||
Cleaner->>ERP: 执行删除
|
||||
ERP-->>Cleaner: 删除结果
|
||||
else 物料不存在
|
||||
Cleaner-->>Cleaner: 跳过
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Cleaner-->>CAS: CleanerResult
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Admin 用户的数据来源路径
|
||||
|
||||
整理出 Admin 用户获取物料的完整路径:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
Start[Admin 点击执行清理] --> Check{有 selectedManagers?}
|
||||
|
||||
Check -->|Yes| Path1[路径 1: MaterialsToBeDeleted 表]
|
||||
Path1 --> Q1["SELECT MaterialCode FROM MaterialsToBeDeleted<br/>WHERE ManagerName IN (selectedManagers)"]
|
||||
Q1 --> Merge[合并所有物料代码]
|
||||
|
||||
Check -->|No| Path2[路径 2: DiscreteMaterialPlanData 表]
|
||||
Path2 --> NeedProd{有共享 Production ID?}
|
||||
NeedProd -->|Yes| GetOrder[从共享 ID 解析订单号]
|
||||
GetOrder --> Q2["SELECT DISTINCT MaterialCode FROM DiscreteMaterialPlanData<br/>WHERE SourceNo IN (orderNumbers)"]
|
||||
Q2 --> Merge
|
||||
|
||||
NeedProd -->|No| Empty[返回空数组<br/>无法执行清理]
|
||||
|
||||
Merge --> Execute[传递给 CleanerService<br/>执行 ERP 删除]
|
||||
|
||||
style Path1 fill:#9f9,stroke:#333,stroke-width:2px
|
||||
style Path2 fill:#ff9,stroke:#333,stroke-width:2px
|
||||
style Empty fill:#f99,stroke:#333
|
||||
style Execute fill:#f96,stroke:#333,stroke-width:3px
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 关键代码位置参考
|
||||
|
||||
### 渲染层 (Renderer)
|
||||
|
||||
| 文件 | 函数 | 说明 |
|
||||
| ---------------------------------------- | ----------------------- | -------------------------- |
|
||||
| `src/renderer/src/pages/CleanerPage.tsx` | `handleExecuteDeletion` | 清理入口 |
|
||||
| `src/renderer/src/hooks/useCleaner.ts` | `handleExecuteDeletion` | 调用 `runCleanerExecution` |
|
||||
| `src/renderer/src/hooks/cleaner/api.ts` | `runCleanerExecution` | 先获取数据再执行清理 |
|
||||
|
||||
### 主进程层 (Main)
|
||||
|
||||
| 文件 | 类/函数 | 说明 |
|
||||
| ---------------------------------------------------------------- | ----------------------------------------------- | ---------------- |
|
||||
| `src/main/ipc/validation-handler.ts` | `VALIDATION_GET_CLEANER_DATA` | IPC 入口 |
|
||||
| `src/main/services/validation/validation-application-service.ts` | `getCleanerData`, `loadMaterialCodesForCleaner` | **核心逻辑** |
|
||||
| `src/main/services/cleaner/cleaner-application-service.ts` | `runCleaner` | 执行 ERP 清理 |
|
||||
| `src/main/services/erp/cleaner.ts` | `CleanerService.clean` | ERP 浏览器自动化 |
|
||||
|
||||
### 数据库层 (DAO)
|
||||
|
||||
| 文件 | 类 | 说明 |
|
||||
| ----------------------------------------------------------- | ------------------------- | ---------------------------- |
|
||||
| `src/main/services/database/materials-to-be-deleted-dao.ts` | `MaterialsToBeDeletedDAO` | `MaterialsToBeDeleted`表操作 |
|
||||
| `src/main/services/database/discrete-material-plan-dao.ts` | `DiscreteMaterialPlanDAO` | 物料计划数据查询 |
|
||||
|
||||
---
|
||||
|
||||
## 数据流状态图
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 物料录入:用户在 UI 输入物料
|
||||
物料录入 --> 待校验:保存到 MaterialsToBeDeleted 表
|
||||
|
||||
待校验 --> 校验中:点击"数据校验"
|
||||
校验中 --> 已标记:通过关键词匹配负责人
|
||||
已标记 --> 待清理:用户勾选物料
|
||||
|
||||
待清理 --> 清理执行中:点击"执行清理"
|
||||
清理执行中 --> 清理完成:ERP 删除成功
|
||||
清理执行中 --> 部分失败:部分物料删除失败
|
||||
|
||||
清理完成 --> [*]
|
||||
部分失败 --> [*]
|
||||
|
||||
note right of 待清理
|
||||
Admin 可以查看和选择
|
||||
所有负责人的物料
|
||||
end note
|
||||
|
||||
note right of 清理执行中
|
||||
从 MaterialsToBeDeleted 表
|
||||
根据 selectedManagers 过滤
|
||||
获取要删除的物料代码
|
||||
end note
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 数据流对比:Admin vs 普通用户
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Admin 用户"
|
||||
A1[勾选多个 Manager]
|
||||
A2[SELECT FROM MaterialsToBeDeleted<br/>WHERE ManagerName IN selectedManagers]
|
||||
A3[获取所有选中负责人的物料]
|
||||
end
|
||||
|
||||
subgraph "普通用户"
|
||||
B1[只能看到自己的物料]
|
||||
B2[SELECT FROM MaterialsToBeDeleted<br/>WHERE ManagerName = username]
|
||||
B3[只能删除自己的物料]
|
||||
end
|
||||
|
||||
A1 --> A2 --> A3 --> Exec[执行清理]
|
||||
B1 --> B2 --> B3 --> Exec
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题解答
|
||||
|
||||
### Q1: **物料代码是如何被录入到 `MaterialsToBeDeleted` 表的?**
|
||||
|
||||
**A**: 有三种方式:
|
||||
|
||||
1. **用户手动勾选** → 在 CleanerPage 勾选物料 → 点击"确认删除" → `upsertBatch`
|
||||
2. **关键词自动匹配** → 校验时根据 `MaterialsTypeToBeDeleted` 配置自动分配负责人和标记
|
||||
3. **API 直接写入** → 其他服务调用 `materials.upsertBatch` IPC
|
||||
|
||||
### Q2: **Admin 如果不选 Manager 会怎样?**
|
||||
|
||||
**A**: Admin 可以不选 Manager,此时:
|
||||
|
||||
- 系统会尝试从"共享 Production ID"解析订单号
|
||||
- 然后从 `DiscreteMaterialPlanData` 表查询所有物料代码(不经过 `MaterialsToBeDeleted` 过滤)
|
||||
- 如果没有共享 Production ID,则返回空数组,无法执行清理
|
||||
|
||||
### Q3: **物料代码会在清理后被自动删除吗?**
|
||||
|
||||
**A**:
|
||||
|
||||
- ✅ **干运行模式**:不删除 ERP 数据,但会保留 UI 状态
|
||||
- ✅ **正式执行**:
|
||||
- ERP 中的物料计划被删除
|
||||
- `MaterialsToBeDeleted` 表中记录**不会被自动删除**(需要手动清理)
|
||||
|
||||
### Q4: **如何清理已删除的物料记录?**
|
||||
|
||||
**A**: Admin 可以在物料管理界面:
|
||||
|
||||
- 按 Manager 筛选
|
||||
- 批量删除已处理的物料记录
|
||||
- 调用 `materials.delete` IPC 接口
|
||||
|
||||
---
|
||||
|
||||
## 总结
|
||||
|
||||
Admin 用户执行清理时,被清理物料的来源路径:
|
||||
|
||||
1. **主要来源**: `dbo.MaterialsToBeDeleted` 表
|
||||
2. **过滤条件**: `ManagerName IN (selectedManagers)`
|
||||
3. **执行流程**:
|
||||
- 从数据库查询物料代码
|
||||
- 结合订单号列表
|
||||
- 通过 Playwright 连接 ERP 系统
|
||||
- 逐个物料执行删除操作
|
||||
|
||||
**关键点**:被清理的物料**必须**先在 `MaterialsToBeDeleted` 表中存在记录,并且其 `ManagerName` 与 Admin 选择的负责人匹配。
|
||||
Reference in New Issue
Block a user