Files
shanxia2.0/docs/crm-migration/plans/contract/04-api-spec.md
T
2026-06-01 08:21:21 +08:00

14 KiB
Raw Blame History

合同管理 — 04 API 规格(重写移植版)

步骤 1 产出 | 日期:2026-05-31
权威源:shanxia/crm/backend/ruoyi-modules/ruoyi-crm/ + 快照 docs/crm-migration/reference/java/contract/
状态:后端 ✅ 已重写(2026-06-01);前端 ✅ Fresh Mint 适配完成
验收清单:08-verify.md HTTP 约定:对齐原 CRM(GET/PUT/DELETE/POST 与 Java Controller 一致),不采用旧门户「全 POST」包装


0. 路径与响应约定

0.1 原 CRM(Java / RuoYi)

项 值
Controller 前缀 /crm/contract(及 /crm/contract/approval 等子模块)
网关前缀 前端 request 通常走 /prod-api,完整路径如 /prod-api/crm/contract/list
列表分页入参 Query:CrmContractBo 字段 + pageNum / pageSize
列表分页出参 TableDataInfo:{ rows, total }
单条出参 R<T>:{ code, msg, data }
详情 GET GET /crm/contract/{id} → data 为 CrmContractVo(含 products、canApprove)

0.2 shanxia2.0 Python 目标

项 值
Router 挂载 APIRouter(prefix="/web/crm") → 完整前缀 /api/web/crm
子路径 与 Java 相同(如 GET .../contract/list,不是 POST .../contract/list)
租户 所有查询/写入带 tenant_no(Java 靠 TenantEntity;Python 从当前用户上下文取)
主键 VARCHAR(64) UUID(Java 为 Long;API 层接受 string,避免前端精度问题)
列表响应 兼容 RuoYi:{ rows/list, total } 包在统一 success_response 的 data 内
导出 POST .../export,响应 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

0.3 前端(已拷贝 CRM)实际请求路径

拷贝页调用 /crm/contract/...(非 /web/crm)。步骤 7 机械适配时二选一:

  1. 推荐:Vite 增加 proxy:/crm → {backend}/api/web/crm(保留原 URL + 原 HTTP 动词)
  2. 或改 http 的 baseURL,仍保持各函数 method: 'get'|'put' 与 Java 一致

1. 合同主模块 — CrmContractController

Java:@RequestMapping("/crm/contract")
Service:ICrmContractService / CrmContractServiceImpl

# HTTP 路径 Java Service 方法 请求体 / Query 响应 data 前端函数 后端
C01 GET /list queryPageList Query: CrmContractBo + pageNum, pageSize { rows, total } listContract ❌
C02 GET /{id} queryById Path: id CrmContractVo getContract ❌
C03 POST / insertByBo Body: CrmContractBo(AddGroup) 新合同 id addContract ❌
C04 PUT / updateByBo Body: CrmContractBo(EditGroup) — updateContract ❌
C05 DELETE /{ids} deleteWithValidByIds Path: 逗号或单 id — delContract ❌
C06 PUT /submitApproval submitApproval { id, approverIds[], remark? } — submitApproval ❌
C07 PUT /batchSubmitApproval batchSubmitApproval { ids[], approverIds[], remark? } 成功条数 int batchSubmitApproval ❌
C08 POST /saveTemplate saveTemplate { id, templateContent, settlementClauseDrafts? } — saveTemplate ❌
C09 GET /getTemplate/{id} getTemplate Path: id 富文本 HTML 字符串 getTemplate ❌
C10 PUT /withdrawApproval withdrawApproval { id, remark? } — withdrawApproval ❌
C11 PUT /startExecute startExecute { id, remark? } — startExecute / executeContract ❌
C12 PUT /finish finishContract { id, remark? } — finishContract / completeContract ❌
C13 PUT /invalid invalidContract { id, invalidReason, remark? } — invalidContract ❌
C14 POST /uploadFile uploadFile { id, fileUrl } — uploadFile ❌
C15 POST /uploadAttachments uploadAttachments / uploadAttachmentsWithCategory { id, attachments[]? | ossIds? } — uploadAttachments ❌
C16 POST /export queryList + Excel Body/Query: CrmContractBo xlsx 流 exportContract ❌
C17 GET /statistics/overview statisticsOverview Query: ownerUserId?, beginTime?, endTime? Map 统计 getStatisticsOverview ❌
C18 GET /statistics/status statisticsByStatus — List Map getStatisticsByStatus ❌
C19 GET /statistics/type statisticsByType — List Map getStatisticsByType ❌
C20 GET /statistics/trend statisticsTrend Query: type=month, beginTime?, endTime? List Map getStatisticsTrend ❌
C21 GET /statistics/expiring queryExpiring Query: days=30 List<CrmContractVo> getExpiringContracts ❌
C22 POST /renew/{parentContractId} renewContract Path + Body: CrmContractBo 新合同 id renewContract ❌
C23 POST /createFromOpportunity/{opportunityId} createFromOpportunity Path + Body — createFromOpportunity ❌
C24 POST /createFromQuote/{quoteId} createFromQuote Path + Body — createFromQuote ❌
C25 PUT /sign signContract { id, actualSignDate, contractFile, remark? } — (form 页可能用) ❌
C26 PUT /batch/assign batchAssignOwner { ids[], ownerUserId, remark? } — (列表批量分配) ❌
C27 GET /download/{id} downloadContractPdf Path: id 文件路径/URL 字符串 (详情下载) ❌

1.1 CrmContractBo 列表/筛选字段(Query)

与前端 ContractQuery 对齐:

字段 说明
contractNo, contractName, customerName 分别 like;三者同值时 OR 联合搜索
customerId, opportunityId, quoteId 精确
contractType, status, approvalStatus 精确
excludeStatus ne status(列表默认排除 invalid)
ownerUserId Tab「我的合同」
pendingApprovalUserId Tab「待审批」→ 子查询 crm_contract_approval
approvedByUserId Tab「已审批」→ 历史审批记录反查 contract_id
minAmount, maxAmount 金额区间(Java 在 params 中)
signDateBegin, signDateEnd 签订日期
beginTime, endTime 创建时间
pageNum, pageSize 分页

1.2 CrmContractVo 关键返回字段

列表/详情需包含:canApprove(列表逐行计算)、products(详情)、supplierName(详情 enrichment)、回款/开票金额字段、attachmentFiles(JSON 或逗号 ossId)。

1.3 列表页统计卡片说明

index.vue 未调用 C17;Tab 顶栏统计由当前页列表数据前端聚合(loadStatistics)。C17–C21 仍须在 Service 层实现(其它页/报表可能使用)。


2. 合同审批 — CrmContractApprovalController

Java:@RequestMapping("/crm/contract/approval")
Service:ICrmContractApprovalService

# HTTP 路径 Service 方法 请求 前端 后端
A01 GET /list queryPageList Query: CrmContractApprovalBo + 分页 listApproval ❌
A02 GET /{id} queryById Path: id getApproval ❌
A03 GET /flow/{contractId} queryListByContractId Path: contractId listContractApproval / getContractApprovalFlow ❌
A04 POST /pass approvePass { id, approvalOpinion? } approvePass ❌
A05 POST /reject approveReject { id, approvalOpinion } approveReject ❌
A06 POST /transfer approveTransfer { id, targetApproverId, transferReason } approveTransfer ❌
A07 POST /export queryList + Excel Query/Bo exportApproval ❌
A08 POST / approveContractByContractId { id: contractId, approvalResult, approvalOpinion, attachments?, remark? } approveContract / rejectContract ❌
A09 POST /refreshNames refreshApproverNames { contractId? } refreshApproverNames ❌

注意:列表页 ApprovalDialog 使用 A08(按 合同 id + approvalResult);独立审批页可用 A04/A05(按 审批记录 id)。


3. 合同变更 — CrmContractChangeController

Java:@RequestMapping("/crm/contract/change")
Service:ICrmContractChangeService

# HTTP 路径 Service 方法 前端 后端
H01 GET /list queryPageList listChange ❌
H02 GET /{id} queryById getChange ❌
H03 POST / insertByBo addChange ❌
H04 PUT / updateByBo updateChange ❌
H05 DELETE /{ids} deleteWithValidByIds delChange ❌
H06 POST /submitApproval (Controller TODO 空实现) submitChangeApproval ❌
H07 PUT /withdraw/{id} withdrawChange withdrawChange ❌
H08 PUT /execute/{id} executeChange executeChange ❌
H09 POST /export queryList + Excel exportChange ❌

4. 合同模板库 — CrmContractTemplateController

Java:@RequestMapping("/crm/contract/template")
与 C08/C09 区别:此处是 模板主数据;C08/C09 是 单份合同实例 的富文本内容。

# HTTP 路径 Service 方法 前端 后端
T01 GET /list queryPageList listTemplate ❌
T02 GET /{id} queryById getTemplate(template.ts) ❌
T03 POST / insertByBo addTemplate ❌
T04 PUT / updateByBo updateTemplate ❌
T05 DELETE /{ids} deleteWithValidByIds delTemplate ❌
T06 PUT /enable/{id} enableTemplate enableTemplate ❌
T07 PUT /disable/{id} disableTemplate disableTemplate ❌
T08 POST /export queryList + Excel exportTemplate ❌

5. 合同产品 — ICrmContractProductService(无独立 Controller)

产品随合同 Bo 的 products[] 在 C03/C04 中批量写入;Service 另提供:

Service 方法 用途 后端
queryListByContractId 详情/列表展开行 ❌(合入 C02)
insertByBo / updateByBo / deleteByIds 产品 CRUD ❌
updateDeliveryStatus 交付进度 ❌

框架合同 调价区间 crm_contract_product_price_tier 在 insertByBo / 提交审批校验中处理(见 ServiceImpl)。


6. Service 层无 Controller 入口(内部 / 跨模块)

Service 方法 调用方 说明 后端
updateReceivedAmount(contractId) 回款 Service 回写 received_amount / unreceived_amount ❌
updateInvoiceAmount(contractId) 开票 Service 回写 invoice_amount / uninvoice_amount ❌
generateContractNo(supplierId, signDate) insertByBo 内部 供方 + 日期规则编号 ❌
createFromTemplate(templateId, bo) 无 Controller 若前端后续需要再暴露 ❌
queryList(bo) C16 导出 同 C01 条件无分页 ❌

定时任务:合同模块 无 专用 cron;到期提醒走 C21 查询接口。


7. 前端跨模块依赖(非 contract Controller)

用途 HTTP 路径 使用页面
操作日志 GET /monitor/operlog/list detail.vue
OSS 批量 GET /resource/oss/listByIds/{ids} index / form / detail / Upload
OSS 下载 GET /resource/oss/download/{ossId} 附件预览下载
商机名 GET /crm/opportunity/{id} index 详情抽屉 / form
报价单号 GET /crm/quote/{id} index 详情抽屉 / form

shanxia2.0 需确认上述路由是否已有 Python 等价实现或需同步移植。


8. Python 实现映射(计划)

层 目标文件
路由 backend/app/api/crm_contract_routes.py
子路由 backend/app/api/crm_contract_sub_routes.py(approval / change / template)
CRUD backend/app/crud/crm/contract.py
审批 backend/app/crud/crm/contract_approval.py
产品 backend/app/crud/crm/contract_product.py
变更 backend/app/crud/crm/contract_change.py
模板库 backend/app/crud/crm/contract_template.py
Schema backend/app/schemas/crm/contract.py 等
导出列 backend/app/utils/crm_export_columns.py(CONTRACT_*_EXPORT_COLUMNS 已存在)
注册 backend/app/api/crm.py 末尾 register_contract_routes

翻译顺序(对应断点步骤 15–26):C01+C02 → C03–C05 → C06–C07+A* → C10–C15 → C16–C21 → C22–C27 → H* / T* → 恢复 quote.to_contract → C24。


9. 权限码(Java 注释,实现时可对接 menuCode)

权限 接口组
crm:contract:list C01, C17–C21
crm:contract:query C02, C09, C27
crm:contract:add C03, C23, C24
crm:contract:edit C04, C08, C10, C14–C15
crm:contract:remove C05
crm:contract:submit C06–C07
crm:contract:execute C11–C12
crm:contract:invalid C13
crm:contract:export C16
crm:contract:renew C22
crm:contract:sign C25
crm:contract:assign C26
crm:contract:approval:* A01–A09
crm:contract:change:* H01–H09
crm:contract:template:* T01–T08

10. 完成标准(重写后勾选)

  • 27 个主接口 C01–C27 HTTP 动词与 Java 一致
  • 9 个审批接口 A01–A09
  • 9 个变更接口 H01–H09(H06 与 Java 行为对齐或明确实现)
  • 8 个模板接口 T01–T08
  • 内部方法 updateReceivedAmount / updateInvoiceAmount 可供回款/开票模块调用
  • createFromQuote 恢复报价转合同
  • 前端拷贝页在 proxy 配置下可直接调用,无需改为全 POST

变更记录

日期 说明
2026-05-31 步骤 1:自 Java Controller + Service 接口全量梳理;废弃旧「全 POST 门户」规格