5.1 KiB
5.1 KiB
步骤四:后端 API 实现
前置条件:step-03 已完成。 实施依据:
docs/crm-migration/plans/{module}/06-steps.md中的后端实现步骤。 同步参考:ref-database-rules.md、ref-lessons-learned.md 模块方案:docs/crm-migration/plans/{module}/04-api-spec.md(API规格)、docs/crm-migration/plans/{module}/02-database.md(数据库)
核心原则
先理解 Java 业务逻辑,再写 Python 代码。 每个接口先读 Java 源码(Controller → Service → Mapper),用中文写出业务逻辑说明,再编码。
Java 快照(按需,SHALL)
写到哪一步,快照哪一步的 Java——不在方案阶段一次性拷贝整个模块。
- 打开
plans/{module}/06-steps.md,找到当前步骤的「Sub-step 0 快照」清单 - 执行
docs/crm-migration/scripts/snapshot-java.sh {module} <files...> - 只加载快照目录中本步文件 +
05-special.md,再写 Python
权威源:../shanxia/crm/backend/ruoyi-modules/ruoyi-crm/。快照目录:docs/crm-migration/reference/java/。
操作流程
1. 数据库先行
按 ref-database-rules.md 规范:
- 编写迁移后 DDL(业务字段与 sx.sql 一致,公共字段按适配规则调整)
- 编写 SQL 增量脚本保存到
docs/sql/ - 更新 SQLAlchemy Model(
backend/app/models/crm_models.py) - 导入字典数据(如需新建,从 sx.sql 筛选
crm_%字典)
2. Schema 层
创建 backend/app/schemas/crm/{module}.py:
- CreateBody、UpdateBody、ListBody 等 Pydantic v2 模型
- 使用
Field(..., alias="camelCase")实现命名转换 - 参考
backend/app/schemas/crm/product.py
3. CRUD 层
创建 backend/app/crud/crm/{module}.py:
_row_to_dict:ORM → camelCase dict(所有可读字段的单点真相)list_xxx:分页查询(租户隔离 + 软删除过滤 + create_time DESC)create_xxx:新增(UUID主键 + 编号生成 + 唯一校验 + 冗余字段写入)update_xxx:更新soft_delete_xxx:软删除(del_flag=1)- 参考
backend/app/crud/crm/product.py
4. API 路由层
在 backend/app/api/crm.py 中追加路由:
- 每个接口一个路由函数
Depends(require_admin_or_super_admin)认证- 路由路径与前端 API 调用一致
5. API 路径约定
| 操作 | 路径格式 | 示例 |
|---|---|---|
| 列表 | /web/crm/{module}/list |
POST,含 page/pageSize |
| 新增 | /web/crm/{module}/add |
POST |
| 编辑 | /web/crm/{module}/update |
POST |
| 删除 | /web/crm/{module}/delete |
POST |
| 详情 | /web/crm/{module}/detail |
POST |
| 下拉 | /web/crm/{module}/options |
POST |
| 导出 | /web/crm/{module}/export |
POST,返回 xlsx 流(非 JSON) |
| 导入模板 | /web/crm/{module}/importTemplate 或 /import-template |
POST,返回 xlsx 流 |
7. Excel 导出(CRM 集中字典翻译)
对齐 Java ExcelUtil.exportExcel + *Vo 的 @ExcelDictFormat:
- 列定义:在
backend/app/utils/crm_export_columns.py增加XXX_EXPORT_COLUMNS(ExportColumn(title, field, dict_type=...))。 - 字典对照:打开原 CRM
domain/vo/CrmXxxVo.java,逐字段核对dictType(如线索crm_clue_source、crm_clue_level)。 - 路由实现:查询列表数据后 只调用
export_rows_to_xlsx_response(db, tenant_no=..., columns=..., rows=..., filename_stem=...)。 - 禁止:在
crm.py内重复 openpyxl 表头/循环;禁止导出原始 dict code(除非该列 Java 也无@ExcelDictFormat)。 - 依赖:
openpyxl须在运行 venv 中安装(见ref-lessons-learned.md§30)。
参考实现:backend/app/utils/excel_export.py;已接入:线索/客户/产品/联系人/跟进/商机。
8. 定时任务 & 特殊场景
- 检查原 CRM 是否有定时任务,在
backend/app/tasks/中用 APScheduler 实现 - 在 API 路由中处理触发器逻辑(如统计字段同步更新)
常见业务场景处理
| 场景 | 处理方式 |
|---|---|
| 编号自动生成 | CRUD 层 create_xxx 中实现,参考 customer.py |
| 唯一性校验 | CRUD 层校验,del_flag=0 排除软删除 |
| 关联统计更新 | 新增/删除关联记录时同步更新主表 |
| 冗余字段写入 | create/update 时从主表获取写入 |
| 租户隔离 | 所有查询 WHERE 加 tenant_no |
| 数据权限 | 列表查询根据角色数据范围过滤 |
字段一致性
_row_to_dict是所有可读字段的单点真相- CreateBody/UpdateBody 的字段必须与
_row_to_dict中可写字段一一对应 - 前端
formData初始化必须包含 CreateBody 中的所有字段 - 可用
python scripts/check_field_consistency.py验证
完成标准
- DDL 已编写并保存到 docs/sql/
- Model、Schema、CRUD、API 路由全部实现
- 每个接口的业务逻辑与 Java 源码一致
- 字段一致性检查通过
- 若有导出:已在
crm_export_columns.py声明列与dict_type,并走export_rows_to_xlsx_response
下一步
完成后加载 step-05-verify.md。