Files
ecm_sync_system/docs/enum_refactor/project.md
T
2026-03-18 11:34:02 +08:00

14 KiB
Raw Blame History

Project 领域重构指南

1. 范围

本文档只做 Project 领域的项目侧梳理。

必须覆盖两类字段:

  • 集团侧 enum_config 对应到 Project 的字段:project_typeproject_subtypesyxsstatus
  • depm 本地已经做成 enum / 类 enum,或者已经承担初始化、创建校验、业务分支职责的字段:progress_typekey_constraintsbuild_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 校验

项目侧取值范围:

  • 当前代码里的正式候选项是:photovoltaiconshore_windoffshore_windpumped_storagehydropowerthermal_powergas_turbine
  • app/common/enums.pyapp/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 白名单
  • 从代码看,它现在理论上就是任意字符串

项目侧可举例范围:

  • 目前只能借集团侧样例来猜测,例如光伏下可能是 centralizeddistributed

集团侧差异:

  • 集团侧至少给出了光伏下的两个候选项:centralizeddistributed
  • 项目侧目前一个正式值都没有落下来
  • 其它项目类型在集团侧也基本还是空占位,所以当前只能确认“项目侧缺正式范围,集团侧只给了局部样例”
  • 同步 schema 对应字段名是 sub_type,当前类型是 Optional[str],也还没有 enum 化

困难:

  • 项目侧没有正式定义源,无法从代码中反推出完整候选项集合
  • 集团侧除光伏外也没有给出有效值,导致现在只能列出局部范围,不能写成全项目类型完整表

结论:

  • 改为 field_config
  • 建议 keyproject.project_subtype

2.3 syxs

当前实现:

  • 模型里是 String
  • 当前 ProjectCreate / ProjectUpdate 里没有这个字段
  • 没看到本地正式 enum

当前使用:

  • 在 Project 模块内暂时没看到明确创建、初始化或校验使用点
  • 当前更像是“模型里已有字段,但项目侧链路尚未收敛”的状态

当前问题:

  • 有字段,但没有统一入口
  • 没有统一候选项来源
  • 没有统一校验

项目侧取值范围:

  • 目前列不出权威范围
  • 项目模型里有这个字段,但 Project 创建 schema 里没有该字段
  • 代码中也没找到项目侧正式 enum 或统一校验入口

项目侧可举例范围:

  • 当前只能参考集团侧海风场景,例如 hssylssy

集团侧差异:

  • 集团侧至少给出了海风下的两个候选项:hssylssy
  • 项目侧目前还没有正式范围、正式入口和正式校验
  • 其它项目类型在集团侧也基本还是空占位,所以当前差异主要是“集团侧有局部定义,项目侧还没落下来”
  • 同步 schema 中 syxs 当前也是 Optional[str],还没有 enum 化

困难:

  • 项目侧没有正式输入入口,也没有权威候选项定义
  • 集团侧只有海风场景给了有效值,因此暂时只能列局部范围

结论:

  • 改为 field_config
  • 建议 keyproject.syxs

2.4 status

当前实现:

  • app/modules/project/enums.py 里有 ProjectStatus
  • app/common/enums.py 里也有一套 ProjectStatus
  • 模型里是 String
  • 响应 schema 里是 str

当前使用:

  • ProjectService.change_project_status() 会根据 investment_decision_dateactual_construction_dateactual_production_dateactual_full_production_date 计算并写回 status

当前问题:

  • 定义重复
  • 模型层不是 enum
  • 当前状态值由服务逻辑推导,但接口层没有统一约束
  • 当前正式状态集合必须补上 early
  • 当前库里还存在 NULL,这说明状态机和历史数据都还没收口干净

项目侧取值范围:

  • 目标正式值应为:earlypreparationstartedpartially_connectedcompleted
  • 当前代码定义和服务推导还没有完整覆盖这 5 个值
  • 当前实际数据里还存在 NULL,这应视为待清理异常值,而不是正式取值

集团侧差异:

  • 项目侧最终也要纳入 early
  • 因此这个字段的目标差异不是“是否要 early”,而是“项目侧何时补齐 early 并清掉 NULL”
  • 同步 schema 里的 status 当前也是 Optional[str],没有正式 enum 类型

结论:

  • 保留为代码 enum
  • 正式状态集合按 earlypreparationstartedpartially_connectedcompleted 收口
  • NULL 不是正式值,必须通过数据修复和状态回填消除

2.5 progress_type

当前实现:

  • app/common/enums.pyapp/modules/project/enums.py 都定义了 ProgressType
  • 模型里是 SQLEnum(ProgressType)
  • ProjectInfoResponse 里使用 ProgressType
  • ProjectCreate 里仍是 str

当前使用:

  • 是 Project 主表正式字段
  • project_detail_data 初始化时会写入 progress_type
  • 列表筛选也会直接按它查询

当前问题:

  • 定义重复
  • 模型层已收紧,但创建入口还没收紧

项目侧取值范围:

  • 当前正式值是:ABC
  • app/common/enums.pyapp/modules/project/enums.py、初始化 dict_data.csv 当前是一致的

集团侧差异:

  • 集团侧同步 schema 中,progress_type 也是正式 enum
  • 同步 schema 的取值项是:ABC
  • 这一点和项目侧代码 enum 一致
  • 当前真正的差异不在取值范围,而在项目侧创建入口仍是 str,还没有像同步 schema 一样收紧到 enum 类型

困难:

  • 这个字段属于 depm 本地已枚举化字段,不是集团侧 Project 段直出字段
  • 因此这里只能写“项目侧权威范围明确,集团侧暂无直连字段”

结论:

  • 保留为代码 enum
  • 不迁到 field_config

2.6 key_constraints

当前实现:

  • app/common/enums.pyapp/modules/project/enums.py 都定义了 KeyConstraints
  • 两套定义已分叉:common 里有 OTHERproject 模块里没有
  • 模型里是 SQLEnum(KeyConstraints)
  • ProjectInfoResponse 里使用 KeyConstraints
  • ProjectSquareUpdate 里还是 str

当前使用:

  • 是 Project 主表正式字段
  • project_detail_data 初始化时会和 progress_type 一起写入
  • project_detail_data 审批回写时也会更新 Project 主表

当前问题:

  • 定义分叉
  • 主表是 enum,但部分接口入参仍是字符串
  • 项目侧正式口径应保留 OTHER

项目侧取值范围:

  • 项目侧正式值应为:NONELANDTRANSMISSIONBOTHOTHER
  • 当前 app/common/enums.py 和初始化 dict_data.csv 已包含这 5 个值
  • 当前 app/modules/project/enums.py 还少 OTHER

集团侧差异:

  • 集团侧同步 schema 中,key_constraints 也是正式 enum
  • 同步 schema 的取值项是:NONELANDTRANSMISSIONBOTHQT
  • 项目侧正式口径保留 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
  • 它会影响施工分支判断,例如 powermixednoneself

当前问题:

  • 模型层不是 enum
  • 创建入口不是 enum
  • 已经参与业务分支,但没有统一校验

项目侧取值范围:

  • 当前代码 enum 给出的值是:selfpowermixednone
  • 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_subtypesyxs 是典型的按项目类型变化字段,应迁到 field_config
  • progress_typekey_constraintsbuild_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_typestatusbuild_methods 是否要收紧为数据库 enum;如果暂不收紧,也要先统一 schema 校验。
  13. project_subtypesyxs 增加统一读取入口:get_field_options() / validate_field_value()
  14. 明确 status 的唯一来源:是继续由 change_project_status() 推导,还是允许手动写入。

5. 推荐落地顺序

  1. 先统一 ProjectTypeProgressTypeKeyConstraintsProjectStatus 的定义源。
  2. 再补 schema 层校验,把 project_typeprogress_typebuild_methodskey_constraints 的裸字符串入口收紧。
  3. 先补 status=early 和历史 NULL 清理,再把 project_subtypesyxs 迁到 field_config

6. 按本轮要求的改造落点

project 领域这轮要区分两类字段:

  • 固定语义枚举:继续保留代码 enum
  • 按项目类型变化的候选项:迁到 field config

6.1 初始化

Project 本身不直接批量初始化子表候选项,但 project_type 是整个初始化流程的路由键。

因此本轮在 project 领域的初始化要求是:

  • project_type 继续保留代码 enum,作为 config 路由键
  • project_subtypesyxs 如果进入初始化或默认值链路,应直接从 field config 读取

6.2 Create / Update 校验

这轮 project 领域要分开处理:

  • project_typestatusprogress_typekey_constraintsbuild_methods:继续按代码 enum 收紧
  • project_subtypesyxs:通过新的 config 工具校验

也就是说,project 领域不是“全部配置化”,而是“固定 enum 和 field config 分流后分别收紧”。

6.3 下拉列表

当前 project 领域里:

  • project_typeprogress_typekey_constraintsbuild_methods 更适合继续由代码 enum 提供候选项
  • project_subtypesyxs 后续如果提供前端下拉,应直接走 field config

本轮目标是明确边界,避免把本地固定枚举误迁到 config,也避免把按项目类型变化字段继续留成自由字符串。

6.4 清理项

project 领域本轮改造完成后,应清理:

  • 重复的 enum 定义源
  • 仍以裸字符串接收固定 enum 字段的入口
  • status 历史 NULL

7. 测试关注点

project 领域 service 层集成测试至少覆盖:

  1. project_typeprogress_typekey_constraintsbuild_methods 的合法/非法值校验。
  2. project_subtypesyxs 的 field config 读取与校验。
  3. status 状态推导补齐 early 且不再产生 NULL