# 字段一致性开发指南 ## 问题背景 在前后端全链路开发中,一个字段需要同时出现在 **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"`