Files
2026-03-18 11:34:02 +08:00

400 lines
14 KiB
Markdown
Raw Permalink 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.
# Project 领域重构指南
## 1. 范围
本文档只做 Project 领域的项目侧梳理。
必须覆盖两类字段:
- 集团侧 `enum_config` 对应到 Project 的字段:`project_type``project_subtype``syxs``status`
- depm 本地已经做成 enum / 类 enum,或者已经承担初始化、创建校验、业务分支职责的字段:`progress_type``key_constraints``build_methods`
本文重点只回答四件事:
- 当前有几种实现
- 模型层怎么存
- 是否真的用到了
- 创建、校验、初始化时怎么取值,以及下一步怎么改
## 2. 字段盘点
### 2.1 `project_type`
当前实现:
- `app/common/enums.py` 有一套 `ProjectType`
- `app/modules/project/enums.py` 又有一套 `ProjectType`
- `Project` 模型里是 `String`
- `ProjectCreate` / `ProjectUpdate` 里是 `str`
当前使用:
- `ProjectService.init_project_data)` 用它作为初始化路由键,去取 `preparation_{project_type}``production_{project_type}``power_{project_type}` 等配置
- construction 模块的部分接口和工具也直接复用 `ProjectType`
当前问题:
- 定义重复
- 模型层不是 enum
- 创建 / 更新入口没有真正按 enum 校验
项目侧取值范围:
- 当前代码里的正式候选项是:`photovoltaic``onshore_wind``offshore_wind``pumped_storage``hydropower``thermal_power``gas_turbine`
- `app/common/enums.py``app/modules/project/enums.py`、初始化 `dict_data.csv` 当前三处是一致的
集团侧差异:
- 当前未看到和项目侧不同的取值项
- 这个字段目前可视为两边一致
- 但同步 schema 里的 `project_type` 字段当前仍写成 `str`,并没有直接收紧成 `ProjectType`
结论:
- 保留为代码 enum
- 它是核心路由字段,不迁到 `field_config`
### 2.2 `project_subtype`
当前实现:
- 模型里是 `String`
- `ProjectCreate` / `ProjectUpdate` 里是 `str`
- 没看到本地正式 enum
当前使用:
- 当前主要是项目主表字段
- 在 Project 模块内没看到稳定初始化使用点
当前问题:
- 没有统一候选项来源
- 没有统一校验
- 现在只是“字符串字段”
项目侧取值范围:
- 目前列不出权威范围
- 当前项目侧没有正式 enum、没有 `field_config`、没有 schema 白名单
- 从代码看,它现在理论上就是任意字符串
项目侧可举例范围:
- 目前只能借集团侧样例来猜测,例如光伏下可能是 `centralized``distributed`
集团侧差异:
- 集团侧至少给出了光伏下的两个候选项:`centralized``distributed`
- 项目侧目前一个正式值都没有落下来
- 其它项目类型在集团侧也基本还是空占位,所以当前只能确认“项目侧缺正式范围,集团侧只给了局部样例”
- 同步 schema 对应字段名是 `sub_type`,当前类型是 `Optional[str]`,也还没有 enum 化
困难:
- 项目侧没有正式定义源,无法从代码中反推出完整候选项集合
- 集团侧除光伏外也没有给出有效值,导致现在只能列出局部范围,不能写成全项目类型完整表
结论:
- 改为 `field_config`
- 建议 key`project.project_subtype`
### 2.3 `syxs`
当前实现:
- 模型里是 `String`
- 当前 `ProjectCreate` / `ProjectUpdate` 里没有这个字段
- 没看到本地正式 enum
当前使用:
- 在 Project 模块内暂时没看到明确创建、初始化或校验使用点
- 当前更像是“模型里已有字段,但项目侧链路尚未收敛”的状态
当前问题:
- 有字段,但没有统一入口
- 没有统一候选项来源
- 没有统一校验
项目侧取值范围:
- 目前列不出权威范围
- 项目模型里有这个字段,但 Project 创建 schema 里没有该字段
- 代码中也没找到项目侧正式 enum 或统一校验入口
项目侧可举例范围:
- 当前只能参考集团侧海风场景,例如 `hssy``lssy`
集团侧差异:
- 集团侧至少给出了海风下的两个候选项:`hssy``lssy`
- 项目侧目前还没有正式范围、正式入口和正式校验
- 其它项目类型在集团侧也基本还是空占位,所以当前差异主要是“集团侧有局部定义,项目侧还没落下来”
- 同步 schema 中 `syxs` 当前也是 `Optional[str]`,还没有 enum 化
困难:
- 项目侧没有正式输入入口,也没有权威候选项定义
- 集团侧只有海风场景给了有效值,因此暂时只能列局部范围
结论:
- 改为 `field_config`
- 建议 key`project.syxs`
### 2.4 `status`
当前实现:
- `app/modules/project/enums.py` 里有 `ProjectStatus`
- `app/common/enums.py` 里也有一套 `ProjectStatus`
- 模型里是 `String`
- 响应 schema 里是 `str`
当前使用:
- `ProjectService.change_project_status()` 会根据 `investment_decision_date``actual_construction_date``actual_production_date``actual_full_production_date` 计算并写回 `status`
当前问题:
- 定义重复
- 模型层不是 enum
- 当前状态值由服务逻辑推导,但接口层没有统一约束
- 当前正式状态集合必须补上 `early`
- 当前库里还存在 `NULL`,这说明状态机和历史数据都还没收口干净
项目侧取值范围:
- 目标正式值应为:`early``preparation``started``partially_connected``completed`
- 当前代码定义和服务推导还没有完整覆盖这 5 个值
- 当前实际数据里还存在 `NULL`,这应视为待清理异常值,而不是正式取值
集团侧差异:
- 项目侧最终也要纳入 `early`
- 因此这个字段的目标差异不是“是否要 early”,而是“项目侧何时补齐 early 并清掉 NULL”
- 同步 schema 里的 `status` 当前也是 `Optional[str]`,没有正式 enum 类型
结论:
- 保留为代码 enum
- 正式状态集合按 `early``preparation``started``partially_connected``completed` 收口
- `NULL` 不是正式值,必须通过数据修复和状态回填消除
### 2.5 `progress_type`
当前实现:
- `app/common/enums.py``app/modules/project/enums.py` 都定义了 `ProgressType`
- 模型里是 `SQLEnum(ProgressType)`
- `ProjectInfoResponse` 里使用 `ProgressType`
- `ProjectCreate` 里仍是 `str`
当前使用:
- 是 Project 主表正式字段
- `project_detail_data` 初始化时会写入 `progress_type`
- 列表筛选也会直接按它查询
当前问题:
- 定义重复
- 模型层已收紧,但创建入口还没收紧
项目侧取值范围:
- 当前正式值是:`A``B``C`
- `app/common/enums.py``app/modules/project/enums.py`、初始化 `dict_data.csv` 当前是一致的
集团侧差异:
- 集团侧同步 schema 中,`progress_type` 也是正式 enum
- 同步 schema 的取值项是:`A``B``C`
- 这一点和项目侧代码 enum 一致
- 当前真正的差异不在取值范围,而在项目侧创建入口仍是 `str`,还没有像同步 schema 一样收紧到 enum 类型
困难:
- 这个字段属于 depm 本地已枚举化字段,不是集团侧 `Project` 段直出字段
- 因此这里只能写“项目侧权威范围明确,集团侧暂无直连字段”
结论:
- 保留为代码 enum
- 不迁到 `field_config`
### 2.6 `key_constraints`
当前实现:
- `app/common/enums.py``app/modules/project/enums.py` 都定义了 `KeyConstraints`
- 两套定义已分叉:common 里有 `OTHER`project 模块里没有
- 模型里是 `SQLEnum(KeyConstraints)`
- `ProjectInfoResponse` 里使用 `KeyConstraints`
- `ProjectSquareUpdate` 里还是 `str`
当前使用:
- 是 Project 主表正式字段
- `project_detail_data` 初始化时会和 `progress_type` 一起写入
- `project_detail_data` 审批回写时也会更新 Project 主表
当前问题:
- 定义分叉
- 主表是 enum,但部分接口入参仍是字符串
- 项目侧正式口径应保留 `OTHER`
项目侧取值范围:
- 项目侧正式值应为:`NONE``LAND``TRANSMISSION``BOTH``OTHER`
- 当前 `app/common/enums.py` 和初始化 `dict_data.csv` 已包含这 5 个值
- 当前 `app/modules/project/enums.py` 还少 `OTHER`
集团侧差异:
- 集团侧同步 schema 中,`key_constraints` 也是正式 enum
- 同步 schema 的取值项是:`NONE``LAND``TRANSMISSION``BOTH``QT`
- 项目侧正式口径保留 `OTHER`
- 这里需要备注的差异只有一条:集团侧用 `QT`,项目侧用 `OTHER`
结论:
- 保留为代码 enum
- 项目侧按 `OTHER` 收口
- 在同步和推送链路上单独备注 `OTHER/QT` 差异
- 同时补齐 project 模块那套缺失的 `OTHER`
### 2.7 `build_methods`
当前实现:
- `app/modules/project/enums.py` 里有 `BuildMethod`
- 模型里是 `String`
- `ProjectCreate` 里是 `str`
- 响应 schema 通过 `enum_to_build_method_name` 做名称映射
当前使用:
- construction 服务里确实使用了 `project.build_methods`
- 它会影响施工分支判断,例如 `power``mixed``none``self`
当前问题:
- 模型层不是 enum
- 创建入口不是 enum
- 已经参与业务分支,但没有统一校验
项目侧取值范围:
- 当前代码 enum 给出的值是:`self``power``mixed``none`
- construction 分支判断当前也确实在使用这 4 个值
集团侧差异:
- 集团侧同步 schema 里没有 `build_methods` 这个名字,对应字段是 `scgc_type`
- `scgc_type` 当前在同步 schema 里是 `Optional[str]`
- 目前没有看到同步 schema 中为 `scgc_type` 定义正式 enum
也就是说:
- 语义上两边大概率是在说同一个字段
- 但集团侧当前还没有把它收紧成正式 enum
- 因此这个字段更像“项目侧本地先有 enum,集团侧 schema 还停留在字符串字段”
困难:
- 这是项目侧本地业务字段,不是集团侧 `Project` 段直出字段
- 项目侧虽然已有 enum,但模型和 schema 还没完全收紧
结论:
- 保留为代码 enum
- 不迁到 `field_config`
- 需要把模型层和 schema 层一起收紧
## 3. 重点结论
- `project_type` 是初始化路由键,必须保留为代码 enum。
- `project_subtype``syxs` 是典型的按项目类型变化字段,应迁到 `field_config`
- `progress_type``key_constraints``build_methods` 都已经在项目侧真实使用,不是可忽略字段;它们应保留为代码 enum,但当前实现没有收紧干净。
- `status` 也应保留为代码 enum,正式集合必须包含 `early`,并且要清掉历史 `NULL`
- `key_constraints` 项目侧正式口径保留 `OTHER`,只需要在文档和同步链路上备注集团侧使用 `QT`
## 4. 待修改项清单
1. 统一 `ProjectType` 定义,只保留一套正式 enum。
2. 统一 `ProjectStatus` 定义,并把 `early` 纳入正式状态集合。
3. 统一 `ProgressType` 定义,只保留一套正式 enum。
4. 统一 `KeyConstraints` 定义,项目侧正式保留 `OTHER`
5.`project.project_subtype` 改为字段级配置,放入 `field_config`
6.`project.syxs` 改为字段级配置,放入 `field_config`
7.`project_type` 在 schema 层增加正式 enum 校验,不再使用裸 `str`
8.`progress_type` 在创建入口增加正式 enum 校验。
9.`build_methods` 在 schema 层增加正式 enum 校验。
10.`key_constraints` 在仍使用字符串入参的接口上补 enum 校验。
11. 清理 `Project.status` 的历史 `NULL` 数据,并补状态回填逻辑,确保 `NULL` 不再出现。
12. 评估 `Project` 模型中的 `project_type``status``build_methods` 是否要收紧为数据库 enum;如果暂不收紧,也要先统一 schema 校验。
13.`project_subtype``syxs` 增加统一读取入口:`get_field_options()` / `validate_field_value()`
14. 明确 `status` 的唯一来源:是继续由 `change_project_status()` 推导,还是允许手动写入。
## 5. 推荐落地顺序
1. 先统一 `ProjectType``ProgressType``KeyConstraints``ProjectStatus` 的定义源。
2. 再补 schema 层校验,把 `project_type``progress_type``build_methods``key_constraints` 的裸字符串入口收紧。
3. 先补 `status=early` 和历史 `NULL` 清理,再把 `project_subtype``syxs` 迁到 `field_config`
## 6. 按本轮要求的改造落点
project 领域这轮要区分两类字段:
- 固定语义枚举:继续保留代码 enum
- 按项目类型变化的候选项:迁到 field config
### 6.1 初始化
Project 本身不直接批量初始化子表候选项,但 `project_type` 是整个初始化流程的路由键。
因此本轮在 project 领域的初始化要求是:
- `project_type` 继续保留代码 enum,作为 config 路由键
- `project_subtype``syxs` 如果进入初始化或默认值链路,应直接从 field config 读取
### 6.2 Create / Update 校验
这轮 project 领域要分开处理:
- `project_type``status``progress_type``key_constraints``build_methods`:继续按代码 enum 收紧
- `project_subtype``syxs`:通过新的 config 工具校验
也就是说,project 领域不是“全部配置化”,而是“固定 enum 和 field config 分流后分别收紧”。
### 6.3 下拉列表
当前 project 领域里:
- `project_type``progress_type``key_constraints``build_methods` 更适合继续由代码 enum 提供候选项
- `project_subtype``syxs` 后续如果提供前端下拉,应直接走 field config
本轮目标是明确边界,避免把本地固定枚举误迁到 config,也避免把按项目类型变化字段继续留成自由字符串。
### 6.4 清理项
project 领域本轮改造完成后,应清理:
- 重复的 enum 定义源
- 仍以裸字符串接收固定 enum 字段的入口
- `status` 历史 `NULL`
## 7. 测试关注点
project 领域 service 层集成测试至少覆盖:
1. `project_type``progress_type``key_constraints``build_methods` 的合法/非法值校验。
2. `project_subtype``syxs` 的 field config 读取与校验。
3. `status` 状态推导补齐 `early` 且不再产生 `NULL`