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>
This commit is contained in:
kkfluous
2026-04-07 14:09:24 +08:00
parent da487c41d4
commit 573f8397a6
32 changed files with 3491 additions and 0 deletions

View File

@@ -0,0 +1,599 @@
# 车辆租赁合同模块实施计划
## 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 天**