Files
mileage-bonus/.claude_plans/lucky-churning-comet.md
kkfluous 573f8397a6 chore: 添加输入输出文件 + .claude记忆和计划
输入文件:
- 租赁任务考核_2026年{1,2,3}月.xlsx (考核源数据)
- {1,2}月.xlsx (客户盈亏表)
- 车辆里程考核与奖金发放规则(V.1.2).docx

输出文件:
- 里程任务考核_{1,2,3}月核算.xlsx (月度核算结果)
- 里程任务考核_Q1汇总.xlsx (含车辆台账)
- 3月客户盈亏表(待填写).xlsx (模版)

.claude_memory: 项目记忆(规则/偏好/架构/测试车辆)
.claude_plans: 历次计划文件

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:09:24 +08:00

600 lines
21 KiB
Markdown
Raw 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.
# 车辆租赁合同模块实施计划
## Context背景
### 为什么需要这个变更
车辆租赁业务是 OneOS 系统的核心业务模块,需要管理与客户签订的车辆租赁合同,包括合同信息、车辆订单、服务项目、被授权人、审批流程等。该模块需要与 BPM 工作流引擎深度集成,实现合同的审批流转。
### 问题或需求
1. **业务需求**:管理车辆租赁合同的全生命周期(创建→审批→执行→到期→续签/终止)
2. **审批流程**4级审批业务部主管→事业部主管→财务部→法务部
3. **复杂关联**:合同关联客户、车辆、服务项目、被授权人、附件等多个实体
4. **特殊业务**:续签合同、转正式合同、变更为三方合同、新增车辆等
5. **状态管理**:审批状态 × 合同状态的复杂状态机
### 预期结果
构建一个完整的车辆租赁合同管理模块,支持合同的 CRUD、审批流程、特殊业务操作并与现有的客户管理、车辆管理、BPM 工作流模块无缝集成。
---
## 架构设计
### 整体架构
```
Controller (REST API)
Service (业务逻辑)
├── Mapper (数据访问)
├── BpmProcessInstanceApi (流程启动)
└── FileApi (附件上传)
BpmProcessInstanceStatusEventListener (流程状态监听)
Service (更新合同状态)
```
### 模块结构
```
yudao-module-asset/yudao-module-asset-server/
├── controller/admin/contract/
│ └── ContractController.java
├── service/contract/
│ ├── ContractService.java
│ ├── ContractServiceImpl.java
│ └── listener/
│ └── ContractBpmListener.java
├── dal/
│ ├── dataobject/contract/
│ │ ├── ContractDO.java
│ │ ├── ContractVehicleDO.java
│ │ ├── ContractVehicleServiceDO.java
│ │ ├── ContractAuthorizedDO.java
│ │ ├── ContractAttachmentDO.java
│ │ └── ContractChangeHistoryDO.java
│ └── mysql/contract/
│ ├── ContractMapper.java
│ ├── ContractVehicleMapper.java
│ ├── ContractVehicleServiceMapper.java
│ ├── ContractAuthorizedMapper.java
│ ├── ContractAttachmentMapper.java
│ └── ContractChangeHistoryMapper.java
├── controller/admin/contract/vo/
│ ├── ContractBaseVO.java
│ ├── ContractSaveReqVO.java
│ ├── ContractRespVO.java
│ ├── ContractPageReqVO.java
│ ├── ContractDetailRespVO.java
│ ├── ContractVehicleVO.java
│ ├── ContractVehicleServiceVO.java
│ └── ContractAuthorizedVO.java
├── convert/contract/
│ └── ContractConvert.java
└── enums/
├── ContractTypeEnum.java
├── ContractApprovalStatusEnum.java
└── ContractStatusEnum.java
```
---
## 数据库表设计
### 1. asset_contract合同主表
```sql
CREATE TABLE `asset_contract` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
-- 合同基本信息
`contract_code` VARCHAR(50) NOT NULL COMMENT '合同编码',
`contract_type` TINYINT NOT NULL DEFAULT 1 COMMENT '合同类型1=试用 2=正式)',
`project_name` VARCHAR(200) NOT NULL COMMENT '项目名称',
`start_date` DATE NOT NULL COMMENT '生效日期',
`end_date` DATE NOT NULL COMMENT '结束日期',
`payment_method` VARCHAR(50) COMMENT '付款方式',
`payment_cycle` VARCHAR(50) COMMENT '付款周期',
`signing_company` VARCHAR(200) COMMENT '签约公司(乙方)',
`delivery_province` VARCHAR(50) COMMENT '交车省份',
`delivery_city` VARCHAR(50) COMMENT '交车城市',
`delivery_location` VARCHAR(255) COMMENT '交车地点',
`remark` VARCHAR(1000) COMMENT '备注',
-- 甲方客户信息(关联 asset_customer
`customer_id` BIGINT NOT NULL COMMENT '客户ID',
`customer_name` VARCHAR(200) NOT NULL COMMENT '客户名称(冗余)',
-- 丙方客户信息(三方合同,可选)
`third_party_enabled` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否三方合同',
`third_party_customer_id` BIGINT COMMENT '丙方客户ID',
`third_party_name` VARCHAR(200) COMMENT '丙方名称',
-- 业务信息
`business_dept_id` BIGINT NOT NULL COMMENT '业务部门ID',
`business_manager_id` BIGINT NOT NULL COMMENT '业务负责人ID',
-- 审批状态
`approval_status` TINYINT NOT NULL DEFAULT 0 COMMENT '审批状态0=草稿 1=审批中 2=审批通过 3=审批拒绝 4=已撤回)',
`bpm_instance_id` VARCHAR(64) COMMENT 'BPM流程实例ID',
-- 合同状态
`contract_status` TINYINT NOT NULL DEFAULT 0 COMMENT '合同状态0=草稿 1=待生效 2=进行中 3=已到期 4=已终止 5=已续签)',
`effective_time` DATETIME COMMENT '实际生效时间',
`terminate_time` DATETIME COMMENT '终止时间',
`terminate_reason` VARCHAR(500) COMMENT '终止原因',
-- 续签信息
`renewed_contract_id` BIGINT COMMENT '续签后的新合同ID',
`original_contract_id` BIGINT COMMENT '原合同ID如果是续签合同',
-- 系统字段
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_contract_code` (`contract_code`, `deleted`),
INDEX `idx_customer_id` (`customer_id`),
INDEX `idx_approval_status` (`approval_status`),
INDEX `idx_contract_status` (`contract_status`),
INDEX `idx_business_dept` (`business_dept_id`),
INDEX `idx_start_date` (`start_date`),
INDEX `idx_end_date` (`end_date`),
INDEX `idx_create_time` (`create_time`),
INDEX `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='车辆租赁合同表';
```
### 2. asset_contract_vehicle车辆租赁订单
```sql
CREATE TABLE `asset_contract_vehicle` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`contract_id` BIGINT NOT NULL COMMENT '合同ID',
`vehicle_id` BIGINT COMMENT '车辆ID关联 asset_vehicle_base',
`brand` VARCHAR(100) NOT NULL COMMENT '品牌',
`model` VARCHAR(100) NOT NULL COMMENT '型号',
`plate_no` VARCHAR(20) COMMENT '车牌号',
`vin` VARCHAR(50) COMMENT 'VIN码',
`month_rent` DECIMAL(10,2) NOT NULL COMMENT '月租金(元)',
`deposit` DECIMAL(10,2) NOT NULL COMMENT '保证金(元)',
`vehicle_status` TINYINT DEFAULT 0 COMMENT '车辆状态0=待交车 1=已交车 2=已退车)',
`actual_delivery_time` DATETIME COMMENT '实际交车时间',
`delivery_person` VARCHAR(50) COMMENT '交车人',
`remark` VARCHAR(500) COMMENT '备注',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
INDEX `idx_contract_id` (`contract_id`),
INDEX `idx_vehicle_id` (`vehicle_id`),
INDEX `idx_plate_no` (`plate_no`),
INDEX `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='合同车辆租赁订单表';
```
### 3. asset_contract_vehicle_service服务项目
```sql
CREATE TABLE `asset_contract_vehicle_service` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`contract_vehicle_id` BIGINT NOT NULL COMMENT '合同车辆ID',
`service_name` VARCHAR(100) NOT NULL COMMENT '服务项目名称',
`service_fee` DECIMAL(10,2) NOT NULL COMMENT '服务费用(元)',
`effective_date` DATE COMMENT '生效日期',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
INDEX `idx_contract_vehicle_id` (`contract_vehicle_id`),
INDEX `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='合同车辆服务项目表';
```
### 4. asset_contract_authorized被授权人
```sql
CREATE TABLE `asset_contract_authorized` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`contract_id` BIGINT NOT NULL COMMENT '合同ID',
`name` VARCHAR(50) NOT NULL COMMENT '姓名',
`phone` VARCHAR(20) NOT NULL COMMENT '电话',
`id_card` VARCHAR(18) NOT NULL COMMENT '身份证号',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
INDEX `idx_contract_id` (`contract_id`),
INDEX `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='合同被授权人表';
```
### 5. asset_contract_attachment合同附件
```sql
CREATE TABLE `asset_contract_attachment` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`contract_id` BIGINT NOT NULL COMMENT '合同ID',
`attachment_type` TINYINT NOT NULL COMMENT '附件类型1=合同原件 2=盖章合同)',
`file_id` BIGINT NOT NULL COMMENT '文件ID关联 infra_file',
`file_name` VARCHAR(255) NOT NULL COMMENT '文件名称',
`file_url` VARCHAR(500) NOT NULL COMMENT '文件URL',
`file_size` BIGINT COMMENT '文件大小(字节)',
`upload_time` DATETIME NOT NULL COMMENT '上传时间',
`uploader` VARCHAR(64) COMMENT '上传人',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
INDEX `idx_contract_id` (`contract_id`),
INDEX `idx_file_id` (`file_id`),
INDEX `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='合同附件表';
```
### 6. asset_contract_change_history变更历史
```sql
CREATE TABLE `asset_contract_change_history` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`contract_id` BIGINT NOT NULL COMMENT '合同ID',
`change_type` VARCHAR(50) NOT NULL COMMENT '变更类型(保存/提交审批/审批通过/审批驳回/撤回/终止/续签/转正式/变更三方/新增车辆等)',
`change_content` VARCHAR(1000) COMMENT '变更内容',
`operator` VARCHAR(64) NOT NULL COMMENT '操作人',
`operate_time` DATETIME NOT NULL COMMENT '操作时间',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`),
INDEX `idx_contract_id` (`contract_id`),
INDEX `idx_operate_time` (`operate_time`),
INDEX `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='合同变更历史表';
```
---
## BPM 集成方案
### 流程定义
- **流程定义 Key**: `rental_contract_approval`
- **流程名称**: 车辆租赁合同审批
- **审批节点**:
1. 业务部主管审批
2. 事业部主管审批
3. 财务部审批
4. 法务部审批(上传盖章合同)
### 流程变量
```java
Map<String, Object> variables = new HashMap<>();
variables.put("contractId", contractId);
variables.put("contractCode", contractCode);
variables.put("contractType", contractType);
variables.put("customerName", customerName);
variables.put("projectName", projectName);
variables.put("totalAmount", totalAmount);
variables.put("businessDeptId", businessDeptId);
variables.put("businessManagerId", businessManagerId);
```
### 候选人策略
- **业务部主管**: 根据 `businessDeptId` 动态分配(部门主管角色)
- **事业部主管**: 固定角色 `BUSINESS_DIRECTOR`
- **财务部**: 财务部角色 `FINANCE_DEPT`
- **法务部**: 法务部角色 `LEGAL_DEPT`
### 事件监听器
```java
@Component
public class ContractBpmListener {
@Resource
private ContractService contractService;
@EventListener
public void onProcessInstanceStatusChange(BpmProcessInstanceStatusEvent event) {
// 只处理租赁合同审批流程
if (!"rental_contract_approval".equals(event.getProcessDefinitionKey())) {
return;
}
Long contractId = Long.parseLong(event.getBusinessKey());
switch (event.getStatus()) {
case APPROVE: // 审批通过
contractService.handleApprovalApproved(contractId, event.getResult());
break;
case REJECT: // 审批驳回
contractService.handleApprovalRejected(contractId, event.getResult());
break;
case CANCEL: // 取消/撤回
contractService.handleApprovalCancelled(contractId);
break;
}
}
}
```
---
## API 接口设计
### 基础 CRUD 接口
```
POST /asset/contract/create - 创建合同
PUT /asset/contract/update - 更新合同
DELETE /asset/contract/delete - 删除合同
GET /asset/contract/get - 获取合同详情
GET /asset/contract/page - 分页查询合同
```
### 审批相关接口
```
POST /asset/contract/submit - 提交审批
POST /asset/contract/withdraw - 撤回合同
GET /asset/contract/approval-history - 审批历史
```
### 特殊业务接口
```
POST /asset/contract/terminate - 终止合同
POST /asset/contract/renew - 续签合同
POST /asset/contract/convert-formal - 转正式合同
POST /asset/contract/convert-tripartite - 变更为三方合同
POST /asset/contract/add-vehicle - 新增车辆
```
### 查询接口
```
GET /asset/contract/change-history - 变更历史
GET /asset/contract/vehicle/list - 合同车辆列表
GET /asset/contract/authorized/list - 被授权人列表
GET /asset/contract/attachment/list - 合同附件列表
```
---
## 状态机设计
### 审批状态approval_status
```
0 - 草稿DRAFT
1 - 审批中APPROVING
2 - 审批通过APPROVED
3 - 审批拒绝REJECTED
4 - 已撤回WITHDRAWN
```
### 合同状态contract_status
```
0 - 草稿DRAFT
1 - 待生效PENDING
2 - 进行中IN_PROGRESS
3 - 已到期EXPIRED
4 - 已终止TERMINATED
5 - 已续签RENEWED
```
### 状态流转规则
**审批状态流转:**
```
草稿 → 审批中 → 审批通过
↓ ↓
已撤回 审批拒绝
```
**合同状态流转:**
```
草稿 → 待生效 → 进行中 → 已到期 → 已续签
已终止
```
### 状态与操作关系矩阵
| 操作 | 草稿 | 审批中 | 审批通过 | 审批拒绝 | 已撤回 |
|------|------|--------|----------|----------|--------|
| 编辑 | ✓ | ✗ | ✗ | ✓ | ✓ |
| 删除 | ✓ | ✗ | ✗ | ✓ | ✓ |
| 提交审批 | ✓ | ✗ | ✗ | ✓ | ✓ |
| 撤回 | ✗ | ✓ | ✗ | ✗ | ✗ |
| 终止 | ✗ | ✗ | ✓ | ✗ | ✗ |
| 续签 | ✗ | ✗ | ✓ | ✗ | ✗ |
| 转正式 | ✗ | ✗ | ✓ | ✗ | ✗ |
| 变更三方 | ✗ | ✗ | ✓ | ✗ | ✗ |
| 新增车辆 | ✗ | ✗ | ✓ | ✗ | ✗ |
---
## 实现分阶段计划
### 阶段1基础合同管理不含审批
**目标**: 实现合同的基础 CRUD 功能
**关键文件**:
1. 数据库表创建脚本
2. DO 类6个
3. Mapper 接口6个
4. VO 类8个
5. Convert 接口
6. Service 接口和实现
7. Controller
8. 枚举类3个
**功能清单**:
- ✓ 创建合同(包含车辆订单、服务项目、被授权人)
- ✓ 更新合同
- ✓ 删除合同
- ✓ 查询合同详情
- ✓ 分页查询合同列表
- ✓ 查询变更历史
**验证方式**:
- 使用 Postman 测试所有 CRUD 接口
- 验证数据库数据正确性
- 验证多表关联查询
### 阶段2BPM 审批集成
**目标**: 集成 Flowable 工作流引擎,实现审批流程
**关键文件**:
1. BPM 流程定义文件BPMN 2.0 XML
2. ContractBpmListener.java事件监听器
3. 审批相关 Service 方法
4. 审批相关 Controller 接口
**功能清单**:
- ✓ 提交审批(启动 BPM 流程)
- ✓ 撤回审批
- ✓ 监听审批结果(通过/驳回)
- ✓ 更新合同审批状态
- ✓ 查询审批历史
**验证方式**:
- 创建合同并提交审批
- 在 BPM 管理界面审批
- 验证合同状态自动更新
- 验证审批历史记录
### 阶段3特殊业务流程
**目标**: 实现续签、转正式、变更三方、新增车辆等特殊业务
**关键文件**:
1. 特殊业务 Service 方法
2. 特殊业务 Controller 接口
3. 特殊业务 VO 类
**功能清单**:
- ✓ 终止合同
- ✓ 续签合同(创建新合同,关联原合同)
- ✓ 转正式合同(试用→正式)
- ✓ 变更为三方合同(增加丙方客户)
- ✓ 新增车辆(合同执行中新增车辆)
**验证方式**:
- 测试每个特殊业务流程
- 验证数据关联正确性
- 验证状态流转正确性
---
## 关键文件清单
### 数据库脚本
- `/Users/kkfluous/Projects/ai-coding/ln-oneos/oneos-backend/yudao-module-asset/sql/mysql/contract.sql`
### DO 类
- `ContractDO.java` - 合同主表
- `ContractVehicleDO.java` - 车辆订单
- `ContractVehicleServiceDO.java` - 服务项目
- `ContractAuthorizedDO.java` - 被授权人
- `ContractAttachmentDO.java` - 合同附件
- `ContractChangeHistoryDO.java` - 变更历史
### Mapper 接口
- `ContractMapper.java`
- `ContractVehicleMapper.java`
- `ContractVehicleServiceMapper.java`
- `ContractAuthorizedMapper.java`
- `ContractAttachmentMapper.java`
- `ContractChangeHistoryMapper.java`
### VO 类
- `ContractBaseVO.java` - 基础 VO
- `ContractSaveReqVO.java` - 创建/更新请求 VO
- `ContractRespVO.java` - 响应 VO
- `ContractPageReqVO.java` - 分页查询请求 VO
- `ContractDetailRespVO.java` - 详情响应 VO
- `ContractVehicleVO.java` - 车辆订单 VO
- `ContractVehicleServiceVO.java` - 服务项目 VO
- `ContractAuthorizedVO.java` - 被授权人 VO
### Service
- `ContractService.java` - Service 接口
- `ContractServiceImpl.java` - Service 实现
- `ContractBpmListener.java` - BPM 事件监听器
### Controller
- `ContractController.java` - REST API 控制器
### Convert
- `ContractConvert.java` - MapStruct 转换器
### 枚举类
- `ContractTypeEnum.java` - 合同类型枚举
- `ContractApprovalStatusEnum.java` - 审批状态枚举
- `ContractStatusEnum.java` - 合同状态枚举
### BPM 流程定义
- `rental_contract_approval.bpmn20.xml` - 租赁合同审批流程定义
---
## 注意事项
1. **数据一致性**: 合同、车辆订单、服务项目、被授权人等多表操作需要使用事务
2. **状态校验**: 每个操作前需要校验当前状态是否允许该操作
3. **权限控制**: 使用 `@PreAuthorize` 控制接口权限
4. **多租户**: 所有表都包含 `tenant_id` 字段,自动过滤
5. **软删除**: 使用 `deleted` 字段实现软删除
6. **审计字段**: 自动记录 `creator``create_time``updater``update_time`
7. **BPM 集成**: 流程实例 ID 需要保存到合同表,便于查询审批状态
8. **文件上传**: 使用 `FileApi` 上传附件,保存文件 ID 和 URL
9. **变更历史**: 每次重要操作都需要记录变更历史
10. **合同编码**: 自动生成格式HT-YYYY-NNNHT=合同YYYY=年份NNN=序号)
---
## 时间估算
- **阶段1**: 基础合同管理 - 2天
- 数据库表设计和创建 - 4小时
- DO/Mapper/VO/Convert - 4小时
- Service 实现 - 6小时
- Controller 实现 - 2小时
- 测试验证 - 2小时
- **阶段2**: BPM 审批集成 - 1天
- BPM 流程定义 - 2小时
- 事件监听器 - 2小时
- 审批相关接口 - 2小时
- 测试验证 - 2小时
- **阶段3**: 特殊业务流程 - 1天
- 续签/转正式/变更三方 - 4小时
- 新增车辆/终止合同 - 2小时
- 测试验证 - 2小时
**总计:约 4 天**