合同管理模块功能方案设计(v2 - 二次迭代版)
初版日期:2026-03-26 修订日期:2026-05-07(基于已落地实现重新整理,明确二次迭代目标) 模块名称:
yudao-module-contract文档用途:合同管理子系统的整体方案、当前实现状态、二次迭代待办清单
修订说明(与初版差异)
本次修订基于一阶段(v1)已落地代码 + 多个迭代计划文档(合同模块开发计划/合同全生命周期业务设计/合同全生命周期状态机/合同台账模块重设计/合同台账详情页改造/合同审批流程节点设计),对原方案做如下调整:
| 调整项 | 初版(v1)设计 | 二次迭代(v2)设计 |
|---|---|---|
| 功能拆分 | 「合同台账」单一入口管理全生命周期 | 拆分为 「合同起草」(status 0~2)+ 「合同台账」(status≥4),共用 contract_info 表 |
| 签署环节 | 状态字段预留「3 签署中」但无实现 | 新增独立流程单据 contract_sign(typeCode=203),起草审批通过后自动生成签署记录,签署确认审批通过才推进到「已生效」 |
| 签署可选 | 强约束必须签署 | 配置 sign_enabled 控制:开启=经签署确认才生效;关闭=审批通过直接生效 |
| 状态流转 | 仅 0→1→2 实现 | 完整 0→1→2→(3)→4→5→6/7→8 状态机闭环(含终止/归档/确认完成 API) |
| 合同文件版本 | 单字段 file_urls JSON 数组 | 三阶段独立存储:contract_file_urls(起草稿)+ signed_file_url(签署件)+ contract_change.file_urls(变更协议),台账详情聚合展示 |
| 甲乙方录入 | 直接填 partyA/partyB 信息 | 新增 our_role(我方甲/乙)+ counterparty_*(对方单位),后端按角色自动映射到 partyA/partyB 字段 |
| 跨业务关联 | 设计 biz_type + biz_id 通用字段 | 实际改为 counterparty_type(1-CRM 客户 / 2-ERP 供应商)+ counterparty_id,弱依赖 + 选择器组件直连 CRM/ERP |
| 变更回写 | 仅设计未实现 | (v2 待办)变更审批通过后回写主合同 + 协议文件追加到合同文件版本历史 |
| 台账列表 UI | 普通 CRUD 列表 | 顶部 Tabs(全部/已生效/履约中/已完成/已终止/已归档)+ 行操作按状态条件显示 |
| 台账详情 | 单页表单 | 多 Tab 视图(基本信息/合同文件/明细/收付款/履约/变更/附件)+ 顶栏操作按钮 |
| CRM 合同迁移 | 计划渐进迁移 | (延后)CRM 合同保持现状,新业务全部走 contract 模块 |
一、项目背景与目标
1.1 背景
宇擎(RuoYi Office)项目面向中小企业提供一体化办公管理平台。合同作为企业经营的核心法律文件,贯穿销售、采购、项目、人事等多个业务环节。CRM 模块虽已有一套销售合同能力,但局限明显:
- 强绑定 CRM:与客户/商机/CRM 数据权限深度耦合,无法复用于采购、租赁、劳动等场景
- 缺乏全生命周期:无模板、变更、补充协议、履约跟踪、归档等能力
- 流程框架未统一:CRM 用独立 Listener 模式,未复用项目统一的
FlowBillService框架
1.2 目标
参照泛微/蓝凌/Appian CLM 等主流方案,结合中小企业实际,建设独立的 yudao-module-contract 模块:
- 合同全生命周期闭环:起草 → 审批 → 签署 → 生效 → 履约 → 完成/终止 → 归档
- 统一所有合同类型:销售/采购/服务/租赁/劳动/框架协议
- 复用 OA 流程框架:
FlowBillService+BillCodeUtils+ 三通道回调 - 合同文件全程跟随:起草稿 → 签署件 → 变更协议三阶段独立管理 + 台账聚合
- 跨模块松耦合对接:通过
ContractInfoApiFeign 接口为 CRM/ERP/HRM 提供合同数据 - 覆盖 80% 中小企业场景:核心能力完备,复杂场景预留扩展接口
1.3 设计原则
| 原则 | 说明 |
|---|---|
| 统一规范 | 严格遵循后端分层、前端组件、流程集成等已有开发范式 |
| 面向扩展 | 合同分类、履约类型等通过字典/枚举驱动 |
| 适度简化 | 不内置电子签章/AI 审查/在线编辑器,保留接口预留 |
| 松耦合对接 | 通过 contract-api Feign 接口与其他模块交互 |
| 业务视角分离 | 起草(流程视角)与台账(资产视角)拆为两个菜单入口,复用同一张表 |
二、整体架构
2.1 模块依赖关系
┌──────────────────────────────┐
│ yudao-module-contract │
│ ┌────────────────────────┐ │
│ │ contract-api │ │ ← 对外暴露:枚举/DTO/Feign 接口
│ └────────────────────────┘ │
│ ┌────────────────────────┐ │
│ │ contract-server │ │ ← 业务实现
│ └────────────────────────┘ │
└──────────────┬───────────────┘
│ 依赖
┌──────────────────────┼──────────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ bpm-api │ │system-api│ │infra-api │
│(流程审批)│ │(用户/部门)│ │(文件服务)│
└──────────┘ └──────────┘ └──────────┘
│
contract-api 被调用方:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ CRM │ │ ERP │ │ HRM │ │ OA │
└──────────┘ └──────────┘ └──────────┘ └──────────┘2.2 业务全景
2.3 后端目录结构
cn.iocoder.yudao.module.contract
├── controller/admin/
│ ├── category/ # 合同分类
│ ├── template/ # 合同模板
│ ├── info/ # 合同台账(主)
│ ├── sign/ # 合同签署 ★ v2 新增
│ ├── payment/ # 收付款计划
│ ├── change/ # 合同变更
│ ├── performance/ # 合同履约
│ ├── stats/ # 统计分析
│ └── config/ # 合同配置
│
├── service/
│ ├── category/
│ ├── template/
│ ├── info/ # 实现 FlowBillService(contract_approve)
│ ├── sign/ # ★ v2 新增,实现 FlowBillService(contract_sign)
│ ├── payment/
│ ├── change/ # 实现 FlowBillService(contract_change)
│ ├── performance/ # 履约联动主合同状态推进
│ ├── stats/
│ ├── config/
│ └── ContractFlowBillServiceFactory.java
│
├── dal/dataobject/
│ ├── category/ template/ info/ item/ sign/(★) payment/ change/ performance/ config/
├── dal/mysql/ (Mapper 同上)
│
├── api/ # 对外 Feign 实现(ContractInfoApi)
├── framework/ # security/rpc 配置
├── process/ # 流程回调(mq/local/feign 三通道)
└── job/ # 定时任务(合同到期提醒)2.4 前端目录结构(apps/web-antd/src/)
api/contract/
├── category/ template/ info/ sign/(★) payment/ change/ performance/ stats/ config/
views/contract/
├── category/ # 合同分类(树表 CRUD)
├── template/ # 合同模板
├── draft/ # ★ v2 新增「合同起草」
│ └── list/ # 起草列表(status≤2)
├── info/
│ ├── list/ # 合同台账列表(status≥4,顶部 Tabs)★ v2 重构
│ ├── detail/ # 起草详情/编辑(流程表单)
│ ├── ledger/ # ★ v2 新增 台账详情(多 Tab 只读)
│ └── components/ # 共享组件(CounterpartySelectModal 等)
├── sign/ # ★ v2 新增「合同签署」
│ ├── list/ # 签署列表
│ └── info/ # 签署详情(含签署件上传 + 起草稿预览)
├── change/ # 合同变更
├── performance/ # 合同履约
├── stats/ # 统计分析
└── config/ # 合同配置(含签署开关 ★)2.5 移动端目录(UniApp)
ruoyi-office-uniapp/src/
├── pages-contract/ # 合同分包(v2 待办)
└── api/contract/三、数据模型
3.1 数据库表总览
| # | 表名 | 说明 | v1 状态 | v2 调整 |
|---|---|---|---|---|
| 1 | contract_category | 合同分类(树形) | 已有 | 不变 |
| 2 | contract_template | 合同模板 | 已有 | 不变 |
| 3 | contract_info | 合同主表(台账) | 已有 | 新增 7 字段(生命周期+签署件+起草稿) |
| 4 | contract_item | 合同明细行 | 已有 | 不变 |
| 5 | contract_payment_plan | 收付款计划 | 已有 | 不变 |
| 6 | contract_change | 合同变更 | 已有 | 新增 file_urls(变更协议文件) |
| 7 | contract_performance | 合同履约 | 已有 | 不变 |
| 8 | contract_config | 合同配置(每租户一条) | 已有 | 新增 sign_enabled |
| 9 | contract_sign | 合同签署记录 ★ | v2 新增 | 新表 |
3.2 contract_info(合同主表)
核心字段(已落地实现,注意与 v1 设计的差异):
CREATE TABLE `contract_info` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
-- 基本信息
`contract_code` VARCHAR(64) NOT NULL COMMENT '合同编号',
`contract_name` VARCHAR(255) NOT NULL COMMENT '合同名称',
`category_id` BIGINT DEFAULT NULL COMMENT '合同分类ID',
`contract_type` TINYINT NOT NULL COMMENT '合同类型',
`contract_nature` TINYINT NOT NULL DEFAULT 1 COMMENT '合同性质',
-- ★ v2 调整:签约主体(取代直接填写 partyA/partyB)
`our_company_id` BIGINT DEFAULT NULL COMMENT '我方主体ID(system_dept)',
`our_company_name` VARCHAR(255) DEFAULT NULL COMMENT '我方主体名称',
`our_role` TINYINT DEFAULT 1 COMMENT '我方角色(1甲方 2乙方)',
`counterparty_type` TINYINT DEFAULT NULL COMMENT '对方类型(1-CRM客户 2-ERP供应商)',
`counterparty_id` BIGINT DEFAULT NULL COMMENT '对方单位ID',
`counterparty_name` VARCHAR(255) DEFAULT NULL COMMENT '对方单位名称',
`counterparty_contact` VARCHAR(64) DEFAULT NULL COMMENT '对方联系人',
`counterparty_phone` VARCHAR(32) DEFAULT NULL COMMENT '对方联系电话',
`counterparty_address` VARCHAR(512) DEFAULT NULL COMMENT '对方地址',
-- 甲/乙方字段由 our_role 自动映射写入
`party_a_company_id` BIGINT DEFAULT NULL,
`party_a_company_name` VARCHAR(255) DEFAULT NULL,
`party_b_name` VARCHAR(255) DEFAULT NULL,
`party_b_contact` VARCHAR(64) DEFAULT NULL,
`party_b_phone` VARCHAR(32) DEFAULT NULL,
`party_b_address` VARCHAR(512) DEFAULT NULL,
-- 金额
`total_amount` DECIMAL(18,2) DEFAULT 0.00 COMMENT '合同总金额',
`performance_amount` DECIMAL(18,2) DEFAULT 0.00 COMMENT '累计已履约金额',
`performance_status` TINYINT DEFAULT 0 COMMENT '履约进度(0未 1部分 2完成)',
`currency` VARCHAR(16) DEFAULT 'CNY',
-- 日期
`sign_date` DATE DEFAULT NULL COMMENT '签订日期',
`start_date` DATE DEFAULT NULL COMMENT '生效日期',
`end_date` DATE DEFAULT NULL COMMENT '截止日期',
-- 状态 + 流程
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '合同状态(0~8)',
`process_instance_id` VARCHAR(64) DEFAULT NULL,
`process_status` TINYINT DEFAULT 0,
-- 组织
`owner_user_id` BIGINT DEFAULT NULL,
`owner_user_name` VARCHAR(64) DEFAULT NULL,
`dept_id` BIGINT DEFAULT NULL,
`dept_name` VARCHAR(128) DEFAULT NULL,
`company_id` BIGINT DEFAULT NULL,
`company_name` VARCHAR(255) DEFAULT NULL,
-- 关联
`parent_contract_id` BIGINT DEFAULT NULL COMMENT '主合同ID(补充协议)',
`biz_type` VARCHAR(32) DEFAULT NULL COMMENT '业务类型(保留扩展)',
`biz_id` BIGINT DEFAULT NULL COMMENT '业务ID(保留扩展)',
-- ★ v2 新增:合同文件(独立于 file_urls 附件)
`contract_file_urls` JSON DEFAULT NULL COMMENT '起草稿文件(JSON数组)',
`signed_file_url` VARCHAR(512) DEFAULT NULL COMMENT '正式签署件URL',
-- ★ v2 新增:生命周期字段
`effective_date` DATE DEFAULT NULL COMMENT '实际生效日期',
`terminate_reason` VARCHAR(500) DEFAULT NULL COMMENT '终止原因',
`terminate_date` DATE DEFAULT NULL COMMENT '终止日期',
`archive_date` DATE DEFAULT NULL COMMENT '归档日期',
`archive_remark` VARCHAR(500) DEFAULT NULL COMMENT '归档说明',
`complete_date` DATE DEFAULT NULL COMMENT '完成日期',
-- 附件 + 备注
`file_urls` JSON DEFAULT NULL COMMENT '通用附件(报价单等)',
`remark` TEXT DEFAULT NULL,
-- 标准字段...
PRIMARY KEY (`id`),
UNIQUE KEY `uk_contract_code` (`contract_code`, `tenant_id`),
KEY `idx_status` (`status`),
KEY `idx_end_date` (`end_date`),
KEY `idx_counterparty` (`counterparty_type`, `counterparty_id`)
);3.3 contract_sign(合同签署记录 ★ v2 新增)
CREATE TABLE `contract_sign` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
-- 单据基础
`bill_code` VARCHAR(50) NOT NULL COMMENT '签署编号',
`process_instance_id` VARCHAR(64) DEFAULT NULL COMMENT '流程实例ID',
`process_status` TINYINT DEFAULT 0 COMMENT '审批状态',
-- 关联合同
`contract_id` BIGINT NOT NULL COMMENT '合同ID',
`contract_code` VARCHAR(50) DEFAULT NULL COMMENT '合同编号(冗余)',
`contract_name` VARCHAR(200) DEFAULT NULL COMMENT '合同名称(冗余)',
-- 签署信息
`sign_method` TINYINT DEFAULT 1 COMMENT '签署方式(1线下 2电子)',
`sign_date` DATE DEFAULT NULL COMMENT '签署日期',
`sign_remark` VARCHAR(500) DEFAULT NULL COMMENT '签署说明',
-- 组织维度(标准)
`company_id` BIGINT DEFAULT NULL,
`company_name` VARCHAR(200) DEFAULT NULL,
`dept_id` BIGINT DEFAULT NULL,
`dept_name` VARCHAR(200) DEFAULT NULL,
`owner_user_id` BIGINT DEFAULT NULL COMMENT '经办人ID',
`owner_user_name` VARCHAR(30) DEFAULT NULL COMMENT '经办人姓名',
`remark` VARCHAR(500) DEFAULT NULL,
-- 标准字段...
PRIMARY KEY (`id`),
KEY `idx_contract_id` (`contract_id`)
);签署件文件通过
AttachmentService(bill_type=203)存储,不直接落字段;最终签署件 URL 在审批通过时回写到contract_info.signed_file_url。
3.4 contract_config(合同配置)
CREATE TABLE `contract_config` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`notify_enabled` BIT(1) DEFAULT b'1' COMMENT '是否开启到期提醒',
`notify_days` INT DEFAULT 30 COMMENT '提前提醒天数',
`code_prefix` VARCHAR(16) DEFAULT 'HT' COMMENT '编号前缀',
`code_date_format` VARCHAR(16) DEFAULT 'yyyyMMdd',
`code_seq_length` INT DEFAULT 4,
`sign_enabled` BIT(1) DEFAULT b'1' COMMENT '★ 是否启用签署环节',
-- 标准字段...
);3.5 contract_change(合同变更)
-- 在 v1 基础上新增(v2 待落地 SQL):
ALTER TABLE `contract_change`
ADD COLUMN `file_urls` JSON DEFAULT NULL COMMENT '变更协议文件';其余表(contract_category/contract_template/contract_item/contract_payment_plan/contract_performance)保持 v1 结构,详见初版方案附录。
四、合同状态机(v2 完整版)
4.1 状态枚举(ContractStatusEnum)
| 值 | 名称 | 标识 | 说明 | 进入方式 |
|---|---|---|---|---|
| 0 | 草稿 | DRAFT | 初始状态 | 创建 / 驳回 / 撤回 |
| 1 | 审批中 | APPROVING | 起草审批进行中 | 提交审批 |
| 2 | 已审批 | APPROVED | 起草审批通过待签署 | BPM 回调 |
| 3 | 签署中 | SIGNING | 等待双方签字盖章 + 签署确认审批 | 签署单提交审批 |
| 4 | 已生效 | EFFECTIVE | 合同正式生效 | 签署确认通过 / 直接生效(sign_enabled=false) |
| 5 | 履约中 | PERFORMING | 正在履约 | 登记首笔履约(自动推进) |
| 6 | 已完成 | COMPLETED | 履约完毕 | 手动确认完成 |
| 7 | 已终止 | TERMINATED | 合同被终止 | 手动终止(填原因) |
| 8 | 已归档 | ARCHIVED | 归档保存 | 手动归档(最终态) |
4.2 状态流转图
4.3 流转规则
| 规则 | 说明 |
|---|---|
| R1 签署可跳过 | contract_config.sign_enabled 控制:开启=审批通过自动生成签署记录,签署确认通过才生效;关闭=审批通过直接生效 |
| R2 签署经办人 | 系统在起草审批通过时自动生成签署记录,经办人 = 合同负责人 owner_user_id,单人线下完成后回到系统确认 |
| R3 履约推进 | 已生效合同登记首笔履约时自动推进 4→5;履约金额满额时仅更新 performance_status 为 2,不自动改 status,需用户手动确认完成 |
| R4 终止填原因 | 已审批/签署中/已生效/履约中可终止,必须填 terminate_reason,写入 terminate_date = today() |
| R5 归档为终态 | 已生效/已完成/已终止可归档,写入 archive_date、archive_remark,归档后只读 |
4.4 状态对应可用操作
| 状态 | 可用操作 | 操作位置 |
|---|---|---|
| 0 草稿 | 编辑、提交审批、删除 | 起草详情页 |
| 1 审批中 | 撤回 | 起草详情页 / 我的待办 |
| 2 已审批 | 终止、(自动进入签署或直接生效) | 起草详情页 |
| 3 签署中 | 签署确认(在签署单详情中)、终止 | 签署详情页 / 台账 |
| 4 已生效 | 登记履约、发起变更、终止、归档 | 台账列表 / 台账详情 |
| 5 履约中 | 登记履约、发起变更、确认完成、终止 | 台账列表 / 台账详情 |
| 6 已完成 | 归档 | 台账列表 / 台账详情 |
| 7 已终止 | 归档 | 台账列表 / 台账详情 |
| 8 已归档 | 仅查看 | 台账详情 |
五、流程集成
5.1 单据类型(ContractBillTypeEnum)
| typeCode | 名称 | processDefinitionKey | 状态 |
|---|---|---|---|
| 201 | 合同审批(起草) | contract_approve | v1 已实现 |
| 202 | 合同变更审批 | contract_change | v1 已实现 |
| 203 | 合同签署确认 | contract_sign | ★ v2 新增 |
⚠️ 当前代码 BUG:
ContractBillTypeEnum.java中CONTRACT_SIGN误写为("202", "合同变更审批", "contract_change"),需修复为("203", "合同签署确认", "contract_sign")。此为 v2 阶段必修项。
5.2 系统枚举
SystemEnum 已新增:
CONTRACT("CT", "合同管理")5.3 流程回调实现(已落地)
service/
├── ContractFlowBillServiceFactory.java # 工厂
├── info/ContractInfoServiceImpl.java # 实现 FlowBillService(contract_approve)
├── change/ContractChangeServiceImpl.java # 实现 FlowBillService(contract_change)
└── sign/ContractSignServiceImpl.java # ★ 实现 FlowBillService(contract_sign)
process/
├── mq/ContractMqNotificationConsumer.java # MQ 三通道
├── local/ContractLocalNotificationListener.java # 本地事件
└── feign/ContractFeignNotificationController.java # Feign HTTP5.4 三个流程单据生命周期钩子
| 钩子 | contract_approve(起草) | contract_change(变更) | contract_sign(签署) |
|---|---|---|---|
updateProcessStatus | 撤回/驳回时合同回 0 草稿 | 撤回/驳回时变更回草稿 | 撤回/驳回时主合同回 2 已审批 |
onProcessApproved | 1) 设状态 2 已审批 2) 读 sign_enabled:开启则生成签署记录;关闭则直接 4 已生效 + effective_date | (v2 待办) 回写主合同字段 + 协议文件追加到合同文件版本 | 1) 读签署件附件 2) 回写到 signed_file_url3) 主合同设 4 已生效 + effective_date |
onProcessRejected | 合同回 0 草稿 | 变更回草稿 | 主合同回 2 已审批 |
onProcessCancelled | 合同回 0 草稿 | 变更回草稿 | 主合同回 2 已审批 |
deleteBill | 删合同主表 + 明细 | 删变更记录 | 删签署记录 + 附件 |
5.5 BPM 流程模型设计
详见 合同审批流程节点设计.md:
contract_approve(起草审批)
发起人 → 部门负责人 → 合同专员审核 → 条件分支
├─ 金额≤10万 → 分管领导审批 → 结束
└─ 金额>10万 → 主要领导审批 → 结束contract_change(变更审批)
发起人 → 部门负责人 → 合同专员审核 → 分管领导审批 → 结束contract_sign(签署确认审批)★ v2 新增
发起人(经办人上传签署件) → 合同专员审核文件合规性 → 结束候选人岗位:
subLeader(分管领导)、mainLeader(主要领导)—— 已有CONTRACT_SPECIALIST(合同专员)—— v1 已新增
六、核心功能详细设计
6.1 合同分类管理
参照 v1 设计,已落地实现,无变化。
6.2 合同模板管理
参照 v1 设计,已落地实现,无变化。
6.3 合同起草(v2 新增菜单 / status≤2)
菜单:contract-draft-list,组件 ContractDraftList,路径 views/contract/draft/list/
列表页(仅展示自己起草、status≤2 的合同):
- 后端通过
ContractInfoPageReqVO.statusMax=2范围筛选 - 列:合同编号 / 名称 / 类型 / 金额 / 审批状态 / 操作
- 操作:编辑(草稿态)/ 删除(草稿态)/ 查看
- 顶部按钮:新建合同、导出
详情页(views/contract/info/detail/index.vue):
BasicForm+formSchema:基本信息(编号/名称/类型/性质/分类/我方主体/我方角色/对方类型/对方单位/金额/币种/三个日期/负责人/备注)- 子表区域:
- 合同明细行(
ContractItemTable) - 收款计划(
PaymentPlanGrid) - ★ v2 待办:合同文件(起草稿)独立卡片(绑定
contractFileUrls) - 附件列表(绑定
fileUrls)
- 合同明细行(
- 流程操作:保存草稿 / 提交审批 / 撤回 / 删除 / 关闭
6.4 合同签署(★ v2 新增)
菜单:contract-sign-list,详情 contract-sign-detail(隐藏菜单)
列表页(views/contract/sign/list/):
- 列:签署编号 / 关联合同编号 / 合同名称 / 经办人 / 签署状态 / 操作
- 操作:草稿态 = 编辑/删除/提交;其他 = 查看
详情页(views/contract/sign/info/index.vue):
BasicForm:签署编号(只读)/ 关联合同(只读链接)/ 签署方式 / 签署日期 / 签署说明#form-extension插槽:- 签署件上传(
AttachmentList,必须,PDF/扫描件,限制 5 个、50MB) - 合同起草稿(只读预览)(从
contractInfo.contractFileUrls加载)
- 签署件上传(
beforeApproval:动态字段权限驱动,校验通过自动保存- 提交前置:必须已上传签署件
6.5 合同台账(v2 重构 / status≥4)
菜单:contract-info-list(重定位为台账),详情 contract-ledger-detail(隐藏菜单)
6.5.1 列表页(views/contract/info/list/index.vue)
┌─────────────────────────────────────────────────────┐
│ Tabs: [全部] [已生效] [履约中] [已完成] [已终止] [已归档] │
│ 搜索: 编号 / 名称 / 类型 / 分类 / 对方单位 / 创建时间 │
│ Grid: │
│ 编号(链接到台账详情) / 名称 / 类型 / 对方 / 金额 │
│ / 状态(Tag) / 履约进度(Progress) / 负责人 │
│ / 生效日期 / 截止日期 / 操作 │
│ 行操作(按 status 显示): │
│ 4 已生效: 登记履约 / 发起变更 / 终止 / 归档 │
│ 5 履约中: 登记履约 / 发起变更 / 确认完成 / 终止 │
│ 6 已完成: 归档 │
│ 7 已终止: 归档 │
│ 8 已归档: 仅查看 │
└─────────────────────────────────────────────────────┘后端通过 ContractInfoPageReqVO.statusMin=4 + Tab 切换的精确 status 区分。
6.5.2 详情页(views/contract/info/ledger/index.vue)
┌─────────────────────────────────────────────────────┐
│ 顶栏: [返回列表] 编号 名称 [状态Tag] | 操作按钮区 │
│ 操作按钮按 status 动态显示: │
│ 4: [登记履约] [发起变更] [归档] [终止] │
│ 5: [登记履约] [发起变更] [确认完成] [终止] │
│ 6/7: [归档] │
├─────────────────────────────────────────────────────┤
│ Tabs: │
│ 1) 基本信息 - Descriptions 只读 + 生命周期信息 │
│ 2) 合同文件 - 聚合起草稿+签署件+变更协议三阶段 │
│ 3) 合同明细 - ContractItemTable 只读 │
│ 4) 收款计划 - PaymentPlanGrid 只读 │
│ 5) 履约记录 - VxeGrid │
│ 6) 变更记录 - VxeGrid │
│ 7) 附件信息 - AttachmentList 只读 │
└─────────────────────────────────────────────────────┘合同文件 Tab 聚合规则(前端 buildContractFiles()):
contract_file_urlsJSON 数组 → 每项标记为phase=draft, phaseLabel=起草稿signed_file_url字符串 → 标记为phase=signed, phaseLabel=签署件- 每条
contract_change.file_urls→ 标记为phase=change, phaseLabel=变更协议(变更编号)
6.6 合同变更(v2 增强)
当前已有:基本 CRUD + 提交审批 + 列表/详情。
v2 待办:
- 变更详情表单新增「变更协议文件」上传卡片(
AttachmentList或file_urls字段直接绑定) - 提交前校验:变更协议文件必须上传
onProcessApproved回写主合同(当前为 TODO):change_type=1 金额变更→ 更新contract_info.total_amountchange_type=2 期限变更→ 更新contract_info.end_date- 其他变更类型 → 写履历,不强制改字段
- 变更协议文件追加到
contract_info.contract_file_urls,便于在台账详情统一查看
6.7 合同履约(v2 增强已落地)
已实现:
- CRUD + 履约金额自动汇总(
syncContractPerformanceStats) - 履约状态推导(0 未/1 部分/2 完成)
v2 待办:
- 前置校验:
createPerformance中校验合同status ∈ [4, 5] - 首笔履约自动推进
status 4 → 5(当前syncContractPerformanceStats仅更新performance_status,未推进status) - 履约金额满额时返回前端提示("已达合同总金额,是否确认完成?")
6.8 收付款计划
参照 v1 设计,已落地实现。
6.9 合同配置(v2 增强)
已实现:编号规则(前缀+日期格式+流水位数)、到期提醒(开关+天数)、sign_enabled DO 字段。
v2 待办:前端 views/contract/config/index.vue 新增「签署环节开关」Switch 组件。
6.10 统计分析
参照 v1 设计,已落地实现 8 个概览指标 + 月度统计 + 分类统计。
v2 增强建议(可选):
- 合同生命周期分布(按 status 统计)
- 履约完成率 Top10 / Bottom10
- 即将到期合同列表(近 30 天
end_date< today + notify_days) - 收付款逾期统计
七、字典数据
| 字典类型 | 字典名称 | 字典值 | 状态 |
|---|---|---|---|
contract_type | 合同类型 | 1-销售 / 2-采购 / 3-服务 / 4-租赁 / 5-劳动 / 6-框架 / 99-其他 | 已有 |
contract_nature | 合同性质 | 1-收入 / 2-支出 / 3-无金额 | 已有 |
contract_status | 合同状态 | 0~8 | 已有(v2 完整使用) |
contract_change_type | 变更类型 | 1-金额 / 2-期限 / 3-条款 / 4-范围 / 99-其他 | 已有 |
contract_performance_type | 履约类型 | 1-交付 / 2-验收 / 3-开票 / 4-收款 / 5-付款 / 6-服务交付 / 99-其他 | 已有 |
contract_payment_status | 收付款状态 | 0-待 / 1-已 / 2-逾期 | 已有 |
contract_sign_method | 签署方式 | 1-线下 / 2-电子(预留) | v2 新增 |
contract_our_role | 我方角色 | 1-甲方 / 2-乙方 | v2 新增 |
contract_counterparty_type | 对方类型 | 1-CRM 客户 / 2-ERP 供应商 | v2 新增 |
八、跨模块对接
8.1 contract-api 已暴露接口
public interface ContractInfoApi {
ContractInfoDTO getContract(Long id);
List<ContractInfoDTO> getContractList(List<Long> ids);
List<ContractInfoDTO> getSimpleContractList();
}8.2 v2 待补充接口
// 履约汇总(CRM 回款页等场景使用)
ContractPerformanceSummaryDTO getPerformanceSummary(Long contractId);
// 跨模块新增履约记录(CRM 回款 / ERP 入库自动写入)
Long addPerformanceRecord(ContractPerformanceCreateReqDTO dto);
// 通过对方单位反查合同
List<ContractInfoDTO> getContractsByCounterparty(Integer counterpartyType, Long counterpartyId);8.3 与各业务模块对接
| 模块 | 对接方式 | 状态 |
|---|---|---|
| CRM | 创建销售合同时通过 CounterpartySelectModal 选择客户(counterparty_type=1) | 已实现 |
| ERP | 创建采购合同时通过 CounterpartySelectModal 选择供应商(counterparty_type=2) | 已实现 |
| CRM 回款 | 回款完成后通过 ContractInfoApi.addPerformanceRecord 自动写入履约 | v2 待办 |
| ERP 入库 | 入库时调用 addPerformanceRecord 写入交付记录 | v2 待办 |
| OA 用印 | 用印申请关联合同(用合同选择器) | v2 待办 |
| HRM 入职 | 自动创建劳动合同(contract_type=5) | v2 待办 |
九、合同文件全生命周期管理
9.1 文件三阶段独立存储
| 阶段 | 字段 | 存储方式 | 上传时机 |
|---|---|---|---|
| 起草稿 | contract_info.contract_file_urls(JSON) | 直接落表,多版本 | 起草草稿阶段(v2 待落地前端独立卡片) |
| 签署件 | contract_info.signed_file_url | 单字段 + 通过 AttachmentService(bill_type=203)管理上传 | 签署详情页提交前必须上传,审批通过自动回写 |
| 变更协议 | contract_change.file_urls(JSON) | 直接落表 | 变更提交前上传(v2 待落地校验) |
| 附件 | contract_info.file_urls(JSON) | 通用附件(报价单/需求文档等) | 起草任意阶段 |
| 履约凭证 | contract_performance.file_url | 单字段 | 登记履约时上传 |
9.2 台账详情聚合
台账详情「合同文件」Tab 自动聚合三个阶段的文件,列表展示 阶段 / 文件名 / 时间 / 操作,支持预览和下载。
9.3 预览策略(沿用项目统一方案)
| 文件类型 | PC 端 | 移动端 |
|---|---|---|
| iframe 内嵌 / KKFileView | uni.openDocument | |
| Word/Excel | @vue-office/docx excel / KKFileView | uni.openDocument |
| 图片 | Ant Design Vue Image | uni.previewImage |
| 其他 | KKFileView 或下载 | uni.openDocument |
十、二次迭代(v2)待办清单
阶段 A:BUG 修复 + 后端能力补齐(优先)
| # | 任务 | 涉及文件 | 优先级 |
|---|---|---|---|
| A1 | 修复 ContractBillTypeEnum.CONTRACT_SIGN 误用 202/contract_change 的 BUG | yudao-module-contract-api/.../ContractBillTypeEnum.java | ★★★ |
| A2 | ContractChangeServiceImpl.onProcessApproved 回写主合同:金额变更→更新 total_amount,期限变更→更新 end_date,并把变更协议追加到 contract_file_urls | service/change/ContractChangeServiceImpl.java | ★★★ |
| A3 | 履约前置校验 + 首笔履约自动推进 4→5 | service/performance/ContractPerformanceServiceImpl.java | ★★ |
| A4 | ContractInfoApi 补充 3 个跨模块接口(履约汇总/添加履约/按对方反查) | contract-api/.../ContractInfoApi.java + 实现 | ★★ |
| A5 | contract_change.file_urls SQL 字段(如尚未实际存在) | ruoyi-office-db/{今天}_update/alter_contract_change_file_urls.sql | ★★ |
阶段 B:前端补齐与体验优化
| # | 任务 | 涉及文件 | 优先级 |
|---|---|---|---|
| B1 | 起草详情页新增「合同文件(起草稿)」独立卡片,绑定 contractFileUrls | views/contract/info/detail/index.vue + data.ts | ★★★ |
| B2 | 合同配置页新增「签署环节开关」Switch(signEnabled) | views/contract/config/index.vue | ★★★ |
| B3 | 变更详情页新增「变更协议文件」上传卡片 + 提交校验 | views/contract/change/modules/form.vue + API | ★★ |
| B4 | API 类型补全:ContractInfoApi.ContractInfo 增加 effectiveDate / terminateReason / terminateDate / archiveDate / archiveRemark / completeDate / contractFileUrls / signedFileUrl | api/contract/info/index.ts | ★★ |
| B5 | 履约金额满额前端提示框 | views/contract/performance/modules/form.vue | ★ |
阶段 C:移动端
| # | 任务 | 涉及文件 | 优先级 |
|---|---|---|---|
| C1 | UniApp 合同台账列表(仅查看 status≥4) | pages-contract/index.vue | ★★ |
| C2 | UniApp 合同台账详情(多 Tab 风格简化) | pages-contract/detail/index.vue | ★★ |
| C3 | UniApp 合同审批接入(起草/变更/签署三个流程详情页) | pages-bpm/ 配置 + 三个 detail 页 | ★★ |
| C4 | API 层 api/contract/index.ts | 移动端工程 | ★★ |
阶段 D:BPM 流程模型部署
| # | 任务 | 涉及文件 | 优先级 |
|---|---|---|---|
| D1 | 在 BPM 设计器中创建并部署 contract_approve 模型(按金额分支) | BPM 后台 | ★★★ |
| D2 | 在 BPM 设计器中创建并部署 contract_change 模型 | BPM 后台 | ★★★ |
| D3 | ★ 在 BPM 设计器中创建并部署 contract_sign 模型 | BPM 后台 | ★★★ |
| D4 | 给关键候选岗位绑定用户(合同专员/分管领导/主要领导) | system_user_post | ★★ |
阶段 E:定时任务与运营
| # | 任务 | 涉及文件 | 优先级 |
|---|---|---|---|
| E1 | 合同到期提醒定时任务(按 notify_days 触发,未实现) | job/ContractExpireRemindJob.java | ★★ |
| E2 | 收付款逾期检查定时任务(更新 contract_payment_plan.status=2) | job/ContractPaymentOverdueJob.java | ★ |
阶段 F:跨模块对接落地
| # | 任务 | 模块 | 优先级 |
|---|---|---|---|
| F1 | CRM 回款完成后调用 addPerformanceRecord 自动写入履约 | yudao-module-crm | ★★ |
| F2 | ERP 入库/付款联动履约写入 | yudao-module-erp | ★★ |
| F3 | OA 用印申请增加合同选择器 | yudao-module-oa | ★ |
| F4 | HRM 入职流程触发劳动合同创建 | yudao-module-hrm | ★ |
阶段 G:统计分析增强(可选)
| # | 任务 | 优先级 |
|---|---|---|
| G1 | 合同生命周期分布饼图(按 status 统计) | ★ |
| G2 | 履约完成率排行 | ★ |
| G3 | 即将到期合同列表 | ★ |
十一、关键设计决策
11.1 为什么拆分「起草」和「台账」?
| 视角 | 起草(流程视角) | 台账(资产视角) |
|---|---|---|
| 关注点 | 我有哪些合同正在审批/拟稿 | 公司当前生效的合同资产 |
| 数据范围 | status ≤ 2 + 自己创建的 | status ≥ 4 + 全部数据权限范围 |
| 页面形态 | 列表 + 表单(可编辑) | 列表(顶部 Tabs)+ 多 Tab 详情(只读 + 操作按钮) |
| 入口 | 「合同起草」菜单 | 「合同台账」菜单 |
| 数据存储 | 共用 contract_info 表,通过 status 区分 |
11.2 为什么签署做成独立流程单据?
参照 OA「用车申请→还车确认」、「公文发文→收文」模式:
- 业务实质:起草是"申请合同生效",签署是"确认签署完成",是两个独立审批
- 审批人不同:起草由领导审批,签署由合同专员审核文件合规性
- 可选性:通过
sign_enabled配置开关,小企业可关闭签署直接生效 - 复用框架:与
contract_approve、contract_change完全对称地实现FlowBillService
11.3 为什么用 our_role + counterparty_* 取代直填 partyA/partyB?
- 业务直观:用户思维是"我方/对方",而不是"甲方/乙方"
- 自动联动:
our_role决定了甲乙方对应关系,前端不需要分别填两套 - 跨模块复用:
counterparty_type + counterparty_id可直接关联 CRM 客户 / ERP 供应商,避免手填错误 - 甲乙方仍保留:用于合同打印、对外展示等场景,由后端
mapPartyByOurRole()自动映射
11.4 为什么合同文件分三阶段独立存储?
- 审计需要:每个阶段的文件是不可变的历史记录
- 权限分离:起草稿可在草稿态修改,签署件审批通过后只读
- 统一聚合:台账详情通过前端聚合展示版本历史,无需后端额外建表
- 扩展性:未来加入电子签章时,只需在
signed_file_url旁加electronic_seal_url等字段
11.5 中小企业简化策略
| 简化项 | 当前做法 | 扩展预留 |
|---|---|---|
| 电子签章 | 不内置,附件上传盖章 PDF | 预留 sign_method=2 电子签署 枚举 |
| AI 合规检查 | 通过审批流程人工把关 | 未来可对接 AI 模块 |
| 在线编辑器 | 模板下载本地 Word/WPS 编辑 | 未来可集成 OnlyOffice |
| 多币种汇率 | 仅记录币种 | 预留 currency 字段 |
| 多级审批矩阵 | 用 BPM 标准条件分支 | BPM 自身支持 |
| 数据权限 | 标准租户 + 部门权限 | 未来加细粒度 |
十二、文档关联
| 相关文档 | 用途 |
|---|---|
| 合同审批流程节点设计.md | BPM 设计器配置参考 |
| 合同管理模块业务流程测试用例.md | 集成测试场景 |
ruoyi-office-prompt/cursor/plans/合同模块开发计划_f7cadc9e.plan.md | 一阶段(v1)开发计划 |
ruoyi-office-prompt/cursor/plans/合同全生命周期业务设计_78230c32.plan.md | v2 业务设计计划 |
ruoyi-office-prompt/cursor/plans/合同全生命周期状态机_74e6923e.plan.md | v2 状态机设计 |
ruoyi-office-prompt/cursor/plans/合同台账模块重设计_14a8a008.plan.md | v2 台账列表/详情重设计 |
ruoyi-office-prompt/cursor/plans/合同台账详情页改造_4db6bb73.plan.md | v2 台账详情多 Tab 改造 |
十三、版本历史
| 版本 | 日期 | 主要变更 |
|---|---|---|
| v1 | 2026-03-26 | 初版方案:8 张表、起草+审批+履约 |
| v1.1 | 2026-03-30 | 新增合同专员岗位 + 流程节点设计 |
| v2 | 2026-05-07 | 本次修订:起草/台账分离、签署独立流程、状态机闭环、合同文件三阶段、台账多 Tab UI、跨模块对接接口规划 |
附录 A:v2 已实现 vs 待办速览
✅ 已落地(v2 阶段)
- 9 张表(含
contract_sign)+ 全部 v2 新增字段 SQL ContractStatusEnum枚举类- 合同台账生命周期 API(terminate/archive/confirmComplete)
- 合同签署 Service/Controller + FlowBillService 实现
- 起草审批通过自动生成签署记录 / 直接生效(按
sign_enabled分流) - 签署审批通过回写
signed_file_url+ 推进 4 已生效 - 前端「合同起草」菜单 + 列表(
status≤2) - 前端「合同台账」列表重构(顶部 Tabs + 行操作按状态)
- 前端「合同台账详情」多 Tab(基本信息/合同文件/明细/收付款/履约/变更/附件)
- 前端「合同签署」菜单 + 列表 + 详情(含签署件上传 + 起草稿预览)
- 后端
ContractInfoPageReqVO增加statusMin/statusMax/processStatus - 合同文件三阶段聚合展示(起草稿+签署件+变更协议)
🔧 待办(v2 收尾)
- A1 修复
ContractBillTypeEnum.CONTRACT_SIGNBUG(最高优先级) - A2
ContractChangeServiceImpl.onProcessApproved实现回写主合同 - A3 履约前置校验 + 首笔自动推进
- A4
ContractInfoApi补充跨模块接口 - B1 起草详情页「合同文件(起草稿)」独立卡片
- B2 合同配置页「签署开关」前端
- B3 变更详情页「变更协议文件」上传
- B4 前端 API TypeScript 类型补全
- C1~C4 移动端 UniApp 全套
- D1~D4 BPM 流程模型在设计器中实际部署
- E1~E2 定时任务(到期提醒/收付款逾期)
- F1~F4 跨模块对接落地(CRM/ERP/OA/HRM)
- G1~G3 统计分析增强(可选)
