为减少仓库噪声和重复规则,整理当前开发入口并移除已废弃资料。 - 精简根 AGENTS,补充四个应用规则与 README,统一规范入口 - 归整部署文件、SOP 原稿和参考资源,修正迁移后的脚本路径 - 取消虚拟环境、工具状态、业务导出及备份的跟踪,本机所需原件保留 - 移除停用的 graphify 配置、脚本与产物 - 删除历史业务文档、执行计划、OpenSpec 业务变更和移动 UI 原型 - 清理失效引用,历史细胞产品导入改为必须显式指定 --file 验证:git diff --cached --check、OpenSpec 严格校验、导入参数隔离检查 3/3 通过; 迁移文件完整性和现行链接已核对。未执行部署、业务数据导入或服务启停。
105 lines
3.9 KiB
Markdown
105 lines
3.9 KiB
Markdown
# 字段一致性开发指南
|
||
|
||
## 问题背景
|
||
|
||
在前后端全链路开发中,一个字段需要同时出现在 **5 个位置** 才能完整打通:
|
||
|
||
```
|
||
前端 formData → API Schema (Pydantic) → API Handler 传参 → CRUD 函数签名 → ORM 赋值
|
||
```
|
||
|
||
任何一层遗漏都会导致字段**静默丢失**(Pydantic 默认忽略未定义字段,不报错),产生难以发现的 bug。
|
||
|
||
## 历史问题
|
||
|
||
| 时间 | 问题 | 根因 |
|
||
|------|------|------|
|
||
| 2026-05 | 耗材/试剂新增时 `warning_qty` 未保存 | Schema 缺字段 → Handler 没传 → CRUD 没接 |
|
||
| 2026-05 | 耗材/试剂新增时 `status` 未保存 | 同上 |
|
||
| 2026-05 | 变动记录筛选"出库"无效 | 前端 value 与后端期望值不匹配 |
|
||
|
||
## 开发纪律(MUST)
|
||
|
||
### 1. `_row_to_dict` 是单一真相源
|
||
|
||
CRUD 文件中的 `_row_to_dict` 函数定义了实体返回给前端的**所有可读字段**。它是字段一致性的基准。
|
||
|
||
### 2. 先写 `_row_to_dict`,再写 create/update
|
||
|
||
新增实体时:
|
||
1. 先定义 `_row_to_dict`,列出所有字段的读取逻辑
|
||
2. 根据 `_row_to_dict` 的字段列表,逐字段编写 CreateBody/UpdateBody
|
||
3. 根据 Schema 字段,逐字段编写 create/update 函数签名和 ORM 赋值
|
||
4. 根据后端字段列表,编写前端 formData
|
||
|
||
### 3. 排除只读字段
|
||
|
||
以下字段出现在 `_row_to_dict` 中但**不需要**出现在 CreateBody/UpdateBody 或 formData 中:
|
||
|
||
- `id` — 自动生成
|
||
- `createTime` / `updateTime` — 自动维护
|
||
- `stockQty` — 通过出入库操作维护,不可直接设置
|
||
- `tenantNo` — 从认证上下文获取
|
||
|
||
### 4. 每个字段必须检查的 5 个位置
|
||
|
||
以 `warningQty` 为例:
|
||
|
||
| 位置 | 代码 | 必须 |
|
||
|------|------|------|
|
||
| `_row_to_dict` | `"warningQty": _dec(c.warning_qty)` | ✅ 读取 |
|
||
| CreateBody | `warning_qty: Optional[float] = Field(0, alias="warningQty")` | ✅ 接收 |
|
||
| Handler | `warning_qty=body.warning_qty` | ✅ 传递 |
|
||
| create 函数签名 | `warning_qty: Optional[float] = None` | ✅ 接收 |
|
||
| create ORM 赋值 | `warning_qty=warning_qty if warning_qty is not None else 0` | ✅ 写入 |
|
||
|
||
### 5. 实现后验证
|
||
|
||
每个实体完成后运行:
|
||
|
||
```bash
|
||
python backend/scripts/check_field_consistency.py
|
||
```
|
||
|
||
检查项:
|
||
- `_row_to_dict` 中的可写字段是否都在 CreateBody/UpdateBody 中
|
||
- `_row_to_dict` 中的可写字段是否都在前端 formData 中
|
||
- 前后端字段值映射是否一致(如筛选条件 value 对应关系)
|
||
|
||
## 校验脚本
|
||
|
||
`backend/scripts/check_field_consistency.py` 自动扫描以下三层,输出 diff 报告:
|
||
|
||
1. **CRUD 层**:提取 `_row_to_dict` 的所有 camelCase key
|
||
2. **API 层**:提取 CreateBody/UpdateBody 的所有字段(含 alias)
|
||
3. **前端层**:提取 `formData` 的所有 key
|
||
|
||
### 使用方式
|
||
|
||
```bash
|
||
# 检查所有注册实体
|
||
python backend/scripts/check_field_consistency.py
|
||
|
||
# 检查单个实体
|
||
python backend/scripts/check_field_consistency.py --entity consumable
|
||
|
||
# JSON 格式输出
|
||
python backend/scripts/check_field_consistency.py --json
|
||
```
|
||
|
||
### 退出码
|
||
|
||
- `0`:所有检查通过
|
||
- `1`:发现字段不一致
|
||
|
||
## 常见陷阱
|
||
|
||
1. **alias 遗漏**:Schema 字段有 `alias="warningQty"` 但忘记写,Pydantic 只接受 snake_case 键名
|
||
2. **Handler 传参遗漏**:Schema 有字段但 Handler 没传给 CRUD,字段在 Schema 层就被丢弃
|
||
3. **CRUD 签名遗漏**:Handler 传了但 CRUD 函数签名没接收,Python 会报 unexpected keyword argument(运行时错误)
|
||
4. **前端 value 与后端不匹配**:如筛选条件下拉框的 value 是 `"use"` 但后端期望 `"out"`
|
||
|
||
## 当前检查器覆盖限制
|
||
|
||
检查器仅覆盖注册实体。`material (market)` 注册的 `web-admin/src/views/market/material/index.vue` 和 `qc_material` 注册的 `web-admin/src/views/quality/material/index.vue` 已失效;执行结果必须区分既有路径问题与本次改动,不能据检查器通过认定所有实体均已覆盖。
|