Files
zkxw/docs/dev-field-consistency.md
T
zlwu b220298f89 chore: 清理历史资料并规范工程目录与开发规则
为减少仓库噪声和重复规则,整理当前开发入口并移除已废弃资料。

- 精简根 AGENTS,补充四个应用规则与 README,统一规范入口
- 归整部署文件、SOP 原稿和参考资源,修正迁移后的脚本路径
- 取消虚拟环境、工具状态、业务导出及备份的跟踪,本机所需原件保留
- 移除停用的 graphify 配置、脚本与产物
- 删除历史业务文档、执行计划、OpenSpec 业务变更和移动 UI 原型
- 清理失效引用,历史细胞产品导入改为必须显式指定 --file

验证:git diff --cached --check、OpenSpec 严格校验、导入参数隔离检查 3/3 通过;
迁移文件完整性和现行链接已核对。未执行部署、业务数据导入或服务启停。
2026-10-29 23:08:29 +08:00

105 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 字段一致性开发指南
## 问题背景
在前后端全链路开发中,一个字段需要同时出现在 **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` 已失效;执行结果必须区分既有路径问题与本次改动,不能据检查器通过认定所有实体均已覆盖。