Compare commits
6 Commits
main
...
04f0599efa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04f0599efa | ||
|
|
b93ea71174 | ||
|
|
46485289a2 | ||
|
|
1dca703caa | ||
|
|
d5c3ed373f | ||
|
|
072196aad4 |
1263
docs/superpowers/plans/2026-03-13-rental-full-chain.md
Normal file
1263
docs/superpowers/plans/2026-03-13-rental-full-chain.md
Normal file
File diff suppressed because it is too large
Load Diff
587
docs/superpowers/specs/2026-03-13-rental-full-chain-design.md
Normal file
587
docs/superpowers/specs/2026-03-13-rental-full-chain-design.md
Normal file
@@ -0,0 +1,587 @@
|
|||||||
|
# 租赁业务全链路设计规格
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
实现租赁业务全链路(合同 → 备车 → 交车 → 替换车 → 还车)生产可用,包括:模块功能补全、跨模块状态联动、BPM 审批流程部署、共享验车模板系统。
|
||||||
|
|
||||||
|
## 架构决策
|
||||||
|
|
||||||
|
- **方案选择**:方案 C — 轻量模板表 + 记录表,模块内引用
|
||||||
|
- **验车模板**:共享表(`asset_inspection_template` + `asset_inspection_record`),放在 asset 模块
|
||||||
|
- **流转机制**:克隆 + 预填,各业务持有独立 `inspection_record_id`
|
||||||
|
- **事件驱动**:Spring Event 解耦跨模块状态变更
|
||||||
|
- **BPM 集成**:继承现有 `BpmProcessInstanceStatusEventListener` 模式
|
||||||
|
- **表名前缀**:统一使用 `asset_` 前缀,与现有 `asset_return_order`、`asset_delivery_order` 等保持一致
|
||||||
|
- **BPM 字段名**:统一使用 `bpm_instance_id`,与现有 `ContractDO`、`ReturnOrderDO` 保持一致
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第一部分:共享验车模板系统
|
||||||
|
|
||||||
|
### 数据库表
|
||||||
|
|
||||||
|
#### `asset_inspection_template`(模板定义)
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | bigint | 主键 |
|
||||||
|
| code | varchar(50) | 模板编码,如 `TPL-BC-001` |
|
||||||
|
| name | varchar(100) | 模板名称,如"氢能车备车检查模板" |
|
||||||
|
| biz_type | tinyint | 适用业务:1=备车 2=交车 3=还车(一个模板可适用多种业务) |
|
||||||
|
| vehicle_type | varchar(50) | 适用车辆类型(如"氢能车"、"电动车",nullable 表示通用) |
|
||||||
|
| status | tinyint | 0=禁用 1=启用 |
|
||||||
|
| remark | varchar(500) | 备注 |
|
||||||
|
| + BaseDO 字段 | | creator, create_time, updater, update_time, deleted, tenant_id |
|
||||||
|
|
||||||
|
**模板匹配规则**:创建验车记录时,先按 `biz_type` + `vehicle_type` 精确匹配,无结果则按 `biz_type` + `vehicle_type IS NULL` 匹配通用模板。
|
||||||
|
|
||||||
|
#### `asset_inspection_template_item`(模板检查项)
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | bigint | 主键 |
|
||||||
|
| template_id | bigint | 关联模板 |
|
||||||
|
| category | varchar(50) | 分类,如"制动系统"、"外观检查" |
|
||||||
|
| item_name | varchar(100) | 检查项名称 |
|
||||||
|
| item_code | varchar(50) | 检查项编码,如 `BRAKE-001` |
|
||||||
|
| input_type | varchar(20) | 输入类型:`checkbox`(合格/不合格)、`number`(数值)、`text`(文本) |
|
||||||
|
| sort | int | 排序 |
|
||||||
|
| required | tinyint | 是否必填:0=否 1=是 |
|
||||||
|
| + BaseDO | | |
|
||||||
|
|
||||||
|
#### `asset_inspection_record`(验车记录实例)
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | bigint | 主键 |
|
||||||
|
| record_code | varchar(50) | 记录编码,如 `BC-V001-20260313-001` |
|
||||||
|
| template_id | bigint | 使用的模板 |
|
||||||
|
| source_type | tinyint | 来源:1=备车 2=交车 3=还车 |
|
||||||
|
| source_id | bigint | 来源业务ID |
|
||||||
|
| vehicle_id | bigint | 车辆ID |
|
||||||
|
| inspector_name | varchar(50) | 检查人 |
|
||||||
|
| inspection_time | datetime | 检查时间 |
|
||||||
|
| status | tinyint | 0=待检查 1=检查中 2=已完成 |
|
||||||
|
| overall_result | tinyint | 总结果:1=合格 2=不合格 |
|
||||||
|
| remark | varchar(500) | 总备注 |
|
||||||
|
| cloned_from_id | bigint | 克隆来源记录ID(nullable) |
|
||||||
|
| + BaseDO | | |
|
||||||
|
|
||||||
|
#### `asset_inspection_record_item`(逐项检查结果)
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | bigint | 主键 |
|
||||||
|
| record_id | bigint | 关联记录 |
|
||||||
|
| item_code | varchar(50) | 检查项编码(与模板 item 对应) |
|
||||||
|
| category | varchar(50) | 分类(冗余,便于展示) |
|
||||||
|
| item_name | varchar(100) | 检查项名称(冗余) |
|
||||||
|
| input_type | varchar(20) | 输入类型(冗余,便于前端渲染) |
|
||||||
|
| result | tinyint | 1=合格 2=不合格 3=不适用 |
|
||||||
|
| value | varchar(200) | 数值/文本类型的输入值 |
|
||||||
|
| remark | varchar(500) | 该项备注 |
|
||||||
|
| image_urls | varchar(2000) | 图片URL,JSON数组 |
|
||||||
|
| + BaseDO | | |
|
||||||
|
|
||||||
|
### 克隆流转机制
|
||||||
|
|
||||||
|
```
|
||||||
|
备车完成(record status=已完成)
|
||||||
|
↓ 交车时,查找该 vehicleId 最近的备车 record
|
||||||
|
↓ InspectionRecordService.cloneRecord(sourceRecordId, DELIVERY, newSourceId)
|
||||||
|
↓ 生成新 record + 复制所有 item(result/value 保留,可修改)
|
||||||
|
↓ cloned_from_id = 源 record.id
|
||||||
|
交车完成
|
||||||
|
↓ 还车时同理克隆交车 record
|
||||||
|
```
|
||||||
|
|
||||||
|
### 后端结构
|
||||||
|
|
||||||
|
```
|
||||||
|
asset-server/
|
||||||
|
├── dal/dataobject/inspection/
|
||||||
|
│ ├── InspectionTemplateDO.java
|
||||||
|
│ ├── InspectionTemplateItemDO.java
|
||||||
|
│ ├── InspectionRecordDO.java
|
||||||
|
│ └── InspectionRecordItemDO.java
|
||||||
|
├── dal/mysql/inspection/
|
||||||
|
│ ├── InspectionTemplateMapper.java
|
||||||
|
│ ├── InspectionTemplateItemMapper.java
|
||||||
|
│ ├── InspectionRecordMapper.java
|
||||||
|
│ └── InspectionRecordItemMapper.java
|
||||||
|
├── service/inspection/
|
||||||
|
│ ├── InspectionTemplateService.java
|
||||||
|
│ ├── InspectionTemplateServiceImpl.java
|
||||||
|
│ ├── InspectionRecordService.java
|
||||||
|
│ └── InspectionRecordServiceImpl.java
|
||||||
|
├── controller/admin/inspection/
|
||||||
|
│ ├── InspectionTemplateController.java (模板 CRUD)
|
||||||
|
│ └── InspectionRecordController.java (记录查询)
|
||||||
|
└── convert/inspection/
|
||||||
|
└── InspectionConvert.java
|
||||||
|
```
|
||||||
|
|
||||||
|
### 核心 Service 方法
|
||||||
|
|
||||||
|
```java
|
||||||
|
public interface InspectionRecordService {
|
||||||
|
// 根据模板创建空白验车记录
|
||||||
|
Long createRecord(Long templateId, Integer sourceType, Long sourceId, Long vehicleId);
|
||||||
|
|
||||||
|
// 克隆已有记录(跨模块流转)
|
||||||
|
Long cloneRecord(Long sourceRecordId, Integer newSourceType, Long newSourceId);
|
||||||
|
|
||||||
|
// 更新检查项结果
|
||||||
|
void updateRecordItem(Long recordItemId, Integer result, String value, String remark, String imageUrls);
|
||||||
|
|
||||||
|
// 完成验车
|
||||||
|
void completeRecord(Long recordId, String inspectorName);
|
||||||
|
|
||||||
|
// 查询记录详情(含所有 item)
|
||||||
|
InspectionRecordDetailVO getRecordDetail(Long recordId);
|
||||||
|
|
||||||
|
// 查找车辆最近的某类型验车记录
|
||||||
|
InspectionRecordDO getLatestRecord(Long vehicleId, Integer sourceType);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第二部分:备车模块精简
|
||||||
|
|
||||||
|
### 现状
|
||||||
|
|
||||||
|
`VehiclePrepareDO` 有 ~30 个字段,其中 `checkList`(JSON) 存储检查数据。需精简为纯业务字段 + `inspection_record_id` 关联。
|
||||||
|
|
||||||
|
### 精简后 `asset_vehicle_prepare` 字段
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | bigint | 主键 |
|
||||||
|
| vehicle_id | bigint | 车辆ID |
|
||||||
|
| plate_no | varchar(20) | 车牌号(冗余) |
|
||||||
|
| vin | varchar(50) | VIN码(冗余) |
|
||||||
|
| vehicle_model_id | bigint | 车型ID |
|
||||||
|
| brand | varchar(50) | 品牌(冗余) |
|
||||||
|
| model | varchar(50) | 型号(冗余) |
|
||||||
|
| vehicle_type | varchar(50) | 车辆类型(冗余) |
|
||||||
|
| parking_lot | varchar(100) | 停车场 |
|
||||||
|
| preparation_type | varchar(50) | 备车类型 |
|
||||||
|
| mileage | int | 里程数 |
|
||||||
|
| hydrogen_remaining | decimal(10,2) | 剩余氢量 |
|
||||||
|
| hydrogen_unit | varchar(10) | 氢量单位 |
|
||||||
|
| battery_remaining | decimal(10,2) | 剩余电量 |
|
||||||
|
| has_body_ad | tinyint | 是否有车身广告 |
|
||||||
|
| body_ad_photos | varchar(2000) | 车身广告照片(JSON) |
|
||||||
|
| has_tail_lift | tinyint | 是否有尾板 |
|
||||||
|
| spare_tire_depth | decimal(5,2) | 备胎深度 |
|
||||||
|
| spare_tire_photo | varchar(500) | 备胎照片 |
|
||||||
|
| trailer_plate_no | varchar(20) | 挂车车牌 |
|
||||||
|
| defect_photos | varchar(2000) | 缺陷照片(JSON) |
|
||||||
|
| inspection_record_id | bigint | **新增:关联验车记录** |
|
||||||
|
| remark | varchar(500) | 备注 |
|
||||||
|
| status | tinyint | 0=待检查 1=已完成 |
|
||||||
|
| complete_time | datetime | 完成时间 |
|
||||||
|
| + BaseDO | | |
|
||||||
|
|
||||||
|
**移除字段**:`check_list`(JSON)、`contract_id`、`contract_code`、`enlarged_text_photo`
|
||||||
|
|
||||||
|
**关键变更**:
|
||||||
|
- 移除 `contract_id` / `contract_code` — 备车与合同解耦,备车是运维常态
|
||||||
|
- 移除 `check_list` JSON — 验车数据统一走 `inspection_record`
|
||||||
|
- 新增 `inspection_record_id` — 关联共享验车记录
|
||||||
|
|
||||||
|
**数据迁移**:现有 `asset_vehicle_prepare` 表中 `contract_id`、`contract_code`、`check_list`、`enlarged_text_photo` 字段标记为废弃(ALTER TABLE DROP COLUMN),现有数据通过脚本迁移 `check_list` JSON 到 `asset_inspection_record` + `asset_inspection_record_item`。若现有数据量小或尚未投产,可直接删除旧列无需迁移。
|
||||||
|
|
||||||
|
### 备车创建流程
|
||||||
|
|
||||||
|
1. 用户选择车辆 → 创建备车单
|
||||||
|
2. 系统根据 `biz_type=1(备车)` + 车辆的 `vehicleType` 匹配验车模板 → 调用 `InspectionRecordService.createRecord()` 生成记录
|
||||||
|
3. 备车人员逐项检查填写(前端动态渲染 inspection_record_item,按 category 分组,根据 input_type 渲染不同输入控件)
|
||||||
|
4. 提交 → 调用 `InspectionRecordService.completeRecord()` → 备车单 status=已完成
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第三部分:交车模块增强
|
||||||
|
|
||||||
|
### 数据库变更
|
||||||
|
|
||||||
|
`asset_delivery_order` 表变更:
|
||||||
|
|
||||||
|
| 操作 | 字段 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 新增 | inspection_record_id (bigint) | 关联验车记录 |
|
||||||
|
| 保留 | cost_list (JSON) | 费用列表保持原样,不做改动 |
|
||||||
|
|
||||||
|
**关于 `inspection_data`**:现有 JSON 字段标记为废弃,新数据不再写入。验车数据统一通过 `inspection_record_id` 关联。待确认无历史依赖后可 DROP COLUMN。
|
||||||
|
|
||||||
|
### 交车验车流程
|
||||||
|
|
||||||
|
1. 创建交车单时,查找该车最近的备车 `inspection_record`
|
||||||
|
2. 调用 `InspectionRecordService.cloneRecord()` 克隆为交车记录
|
||||||
|
3. 预填备车检查结果,交车人员逐项确认/修改
|
||||||
|
4. 提交验车 → 记录状态=已完成
|
||||||
|
|
||||||
|
### 操作列扩展
|
||||||
|
|
||||||
|
交车管理页面已完成的交车单,操作列新增:
|
||||||
|
|
||||||
|
| 按钮 | 条件 | 行为 |
|
||||||
|
|------|------|------|
|
||||||
|
| 还车 | status=已完成 | 弹窗选择该交车单关联的车辆(可多选),调用 `POST /return-order/create-from-delivery`,跳转还车单详情 |
|
||||||
|
| 替换车 | status=已完成 | 弹窗选择该交车单关联的某辆车,路由跳转替换车新建页,携带 `contractId`, `vehicleId`, `deliveryOrderId` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第四部分:替换车模块(从零构建)
|
||||||
|
|
||||||
|
### 数据库表
|
||||||
|
|
||||||
|
#### `asset_vehicle_replacement`
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | bigint | 主键 |
|
||||||
|
| replacement_code | varchar(50) | 替换单编码,如 `TH-20260313-001` |
|
||||||
|
| replacement_type | tinyint | 1=临时替换 2=永久替换 |
|
||||||
|
| contract_id | bigint | 合同ID |
|
||||||
|
| contract_code | varchar(50) | 合同编号(冗余) |
|
||||||
|
| customer_id | bigint | 客户ID |
|
||||||
|
| customer_name | varchar(100) | 客户名称(冗余) |
|
||||||
|
| delivery_order_id | bigint | 来源交车单ID(从交车页面触发时记录) |
|
||||||
|
| original_vehicle_id | bigint | 原车ID |
|
||||||
|
| original_plate_no | varchar(20) | 原车车牌号(冗余) |
|
||||||
|
| original_vin | varchar(50) | 原车VIN(冗余) |
|
||||||
|
| new_vehicle_id | bigint | 新车ID |
|
||||||
|
| new_plate_no | varchar(20) | 新车车牌号(冗余) |
|
||||||
|
| new_vin | varchar(50) | 新车VIN(冗余) |
|
||||||
|
| replacement_reason | varchar(500) | 替换原因 |
|
||||||
|
| expected_date | date | 预计替换日期 |
|
||||||
|
| actual_date | date | 实际替换日期 |
|
||||||
|
| return_date | date | 临时替换预计归还日期 |
|
||||||
|
| actual_return_date | date | 临时替换实际归还日期 |
|
||||||
|
| status | tinyint | 业务状态(见状态流转) |
|
||||||
|
| approval_status | tinyint | 审批状态 |
|
||||||
|
| bpm_instance_id | varchar(64) | BPM流程实例ID |
|
||||||
|
| remark | varchar(500) | 备注 |
|
||||||
|
| + BaseDO | | |
|
||||||
|
|
||||||
|
**说明**:冗余字段使用 `plate_no`(车牌号)而非 `vehicleCode`,因为现有 DO 中车辆标识统一使用 `plateNo` + `vin`。
|
||||||
|
|
||||||
|
### 状态流转
|
||||||
|
|
||||||
|
```
|
||||||
|
草稿(0) → 审批中(1) → 审批通过(2) → 执行中(3) → 已完成(4)
|
||||||
|
→ 审批驳回(5)
|
||||||
|
→ 已撤回(6)
|
||||||
|
```
|
||||||
|
|
||||||
|
- 审批通过 + 永久替换 → 自动创建原车还车单壳子,状态进入"执行中"
|
||||||
|
- 审批通过 + 临时替换 → 状态进入"执行中"
|
||||||
|
- 执行中 + 临时替换 → 确认换回 → "已完成"
|
||||||
|
- 执行中 + 永久替换 → 原车还车单完成后 → "已完成"
|
||||||
|
|
||||||
|
### 从交车页面快捷触发
|
||||||
|
|
||||||
|
交车管理操作列"替换车"按钮 → 路由跳转:
|
||||||
|
```
|
||||||
|
/asset/vehicle-replacement/create?contractId=xx&vehicleId=xx&deliveryOrderId=xx
|
||||||
|
```
|
||||||
|
替换车表单自动填充合同信息、原车信息(只读),用户只需选择新车、填写原因。
|
||||||
|
|
||||||
|
### 后端结构
|
||||||
|
|
||||||
|
```
|
||||||
|
asset-server/
|
||||||
|
├── dal/dataobject/replacement/
|
||||||
|
│ └── VehicleReplacementDO.java
|
||||||
|
├── dal/mysql/replacement/
|
||||||
|
│ └── VehicleReplacementMapper.java
|
||||||
|
├── service/replacement/
|
||||||
|
│ ├── VehicleReplacementService.java
|
||||||
|
│ ├── VehicleReplacementServiceImpl.java
|
||||||
|
│ └── listener/
|
||||||
|
│ └── ReplacementBpmListener.java
|
||||||
|
├── controller/admin/replacement/
|
||||||
|
│ ├── VehicleReplacementController.java
|
||||||
|
│ └── vo/
|
||||||
|
│ ├── VehicleReplacementSaveReqVO.java
|
||||||
|
│ ├── VehicleReplacementRespVO.java
|
||||||
|
│ └── VehicleReplacementPageReqVO.java
|
||||||
|
└── convert/replacement/
|
||||||
|
└── VehicleReplacementConvert.java
|
||||||
|
```
|
||||||
|
|
||||||
|
### 接口设计
|
||||||
|
|
||||||
|
| 端点 | 方法 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| POST /asset/vehicle-replacement/create | create | 创建替换申请 |
|
||||||
|
| PUT /asset/vehicle-replacement/update | update | 更新(草稿/驳回) |
|
||||||
|
| DELETE /asset/vehicle-replacement/delete | delete | 删除(草稿) |
|
||||||
|
| GET /asset/vehicle-replacement/get | get | 获取详情 |
|
||||||
|
| GET /asset/vehicle-replacement/page | page | 分页查询 |
|
||||||
|
| POST /asset/vehicle-replacement/submit | submit | 提交BPM审批 |
|
||||||
|
| POST /asset/vehicle-replacement/withdraw | withdraw | 撤回审批 |
|
||||||
|
| POST /asset/vehicle-replacement/confirm-return | confirmReturn | 临时替换确认换回 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第五部分:还车模块完善
|
||||||
|
|
||||||
|
### 现有架构
|
||||||
|
|
||||||
|
还车模块采用主子表结构:
|
||||||
|
- **`asset_return_order`**(主表):还车单基本信息、合同/客户关联、审批状态
|
||||||
|
- **`asset_return_order_vehicle`**(子表):每辆车的还车详情,含里程、氢量差、各项费用、`checkList`(JSON)
|
||||||
|
|
||||||
|
### 数据库变更
|
||||||
|
|
||||||
|
#### `asset_return_order`(主表)新增字段
|
||||||
|
|
||||||
|
| 字段 | 操作 | 类型 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| source_type | 新增 | tinyint | 来源:1=手动(从交车触发) 2=替换车触发 |
|
||||||
|
| source_id | 新增 | bigint | 来源业务ID(替换车申请ID 或 交车单ID) |
|
||||||
|
| delivery_order_id | 新增 | bigint | 关联交车单ID(追溯来源) |
|
||||||
|
|
||||||
|
#### `asset_return_order_vehicle`(子表)变更
|
||||||
|
|
||||||
|
| 字段 | 操作 | 类型 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| inspection_record_id | 新增 | bigint | 关联验车记录(每辆车独立验车记录) |
|
||||||
|
| check_list | 废弃 | JSON | 不再写入新数据,验车统一走 inspection_record |
|
||||||
|
|
||||||
|
**关键设计**:`inspection_record_id` 放在子表 `asset_return_order_vehicle` 上(而非主表),因为一个还车单可包含多辆车,每辆车有独立的验车记录。
|
||||||
|
|
||||||
|
### 状态流转
|
||||||
|
|
||||||
|
还车单状态(`status` 字段)保持现有值域不变:
|
||||||
|
|
||||||
|
```
|
||||||
|
待验车(0) → 验车完成(1) → 已结算(2)
|
||||||
|
```
|
||||||
|
|
||||||
|
审批通过 `approval_status` 字段(已有)独立管理:
|
||||||
|
|
||||||
|
```
|
||||||
|
待审批(0) → 审批中(1) → 审批通过(2) → 审批驳回(3) → 已撤回(4)
|
||||||
|
```
|
||||||
|
|
||||||
|
**完整流程**:待验车 → 逐车验车 → 全部验车完成(status=1) → 提交审批(approvalStatus=1) → 审批通过(approvalStatus=2)
|
||||||
|
|
||||||
|
费用结算(status=2)暂不纳入本期。
|
||||||
|
|
||||||
|
### 触发方式
|
||||||
|
|
||||||
|
1. **从交车管理操作列触发**:用户在交车单操作列点"还车"→ 弹窗选择车辆 → `POST /return-order/create-from-delivery` → 创建还车单壳子(含选中的车辆子记录)→ 跳转还车单详情页
|
||||||
|
2. **永久替换审批通过自动创建**:事件监听器创建,source_type=2,自动创建一条主记录 + 一条车辆子记录
|
||||||
|
|
||||||
|
### 验车流程
|
||||||
|
|
||||||
|
1. 用户进入还车单详情 → 选择某辆车 → 点击"开始验车"
|
||||||
|
2. 系统查找该车最近的交车 inspection_record → 克隆为还车 record
|
||||||
|
3. 预填交车检查结果,用户逐项确认/修改
|
||||||
|
4. 提交单车验车 → 该车辆子记录的 `inspection_record_id` 更新
|
||||||
|
5. 所有车辆验车完成 → 还车单 status=1(验车完成) → 可提交审批
|
||||||
|
|
||||||
|
### 接口设计
|
||||||
|
|
||||||
|
| 端点 | 方法 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| POST /asset/return-order/create | create | 手动创建 |
|
||||||
|
| POST /asset/return-order/create-from-delivery | createFromDelivery | 从交车记录创建壳子(参数:deliveryOrderId + vehicleIds[]) |
|
||||||
|
| PUT /asset/return-order/update | update | 更新 |
|
||||||
|
| DELETE /asset/return-order/delete | delete | 删除(待验车) |
|
||||||
|
| GET /asset/return-order/get | get | 获取详情(含车辆子表) |
|
||||||
|
| GET /asset/return-order/page | page | 分页查询 |
|
||||||
|
| POST /asset/return-order/start-inspection | startInspection | 开始单车验车(参数:returnOrderVehicleId),克隆交车record |
|
||||||
|
| POST /asset/return-order/complete-inspection | completeInspection | 完成单车验车 |
|
||||||
|
| POST /asset/return-order/submit | submit | 提交BPM审批(验车完成后) |
|
||||||
|
| POST /asset/return-order/withdraw | withdraw | 撤回审批 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第六部分:BPM 审批流程
|
||||||
|
|
||||||
|
### 需要审批的业务
|
||||||
|
|
||||||
|
| 业务 | 流程Key | 触发时机 | 审批通过后动作 |
|
||||||
|
|------|---------|---------|---------------|
|
||||||
|
| 租赁合同 | `asset_contract` | 已有,无需新建 | 合同状态→已审批 |
|
||||||
|
| 替换车申请 | `asset_vehicle_replacement` | 替换申请提交 | 临时→执行中;永久→执行中+创建还车单壳子 |
|
||||||
|
| 还车 | `asset_return_order` | 验车完成后提交 | 还车单 approvalStatus→审批通过 |
|
||||||
|
|
||||||
|
### BPM 集成模式
|
||||||
|
|
||||||
|
继承现有 `BpmProcessInstanceStatusEventListener`:
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 替换车审批监听
|
||||||
|
@Component
|
||||||
|
public class ReplacementBpmListener extends BpmProcessInstanceStatusEventListener {
|
||||||
|
public static final String PROCESS_KEY = "asset_vehicle_replacement";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getProcessDefinitionKey() { return PROCESS_KEY; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onEvent(BpmProcessInstanceStatusEvent event) {
|
||||||
|
replacementService.updateApprovalStatus(
|
||||||
|
Long.parseLong(event.getBusinessKey()), event.getStatus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 还车审批监听
|
||||||
|
@Component
|
||||||
|
public class ReturnOrderBpmListener extends BpmProcessInstanceStatusEventListener {
|
||||||
|
public static final String PROCESS_KEY = "asset_return_order";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getProcessDefinitionKey() { return PROCESS_KEY; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onEvent(BpmProcessInstanceStatusEvent event) {
|
||||||
|
returnOrderService.updateApprovalStatus(
|
||||||
|
Long.parseLong(event.getBusinessKey()), event.getStatus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### BPMN XML 文件
|
||||||
|
|
||||||
|
新增两个流程定义,放在 `resources/processes/`:
|
||||||
|
|
||||||
|
**`asset_vehicle_replacement.bpmn20.xml`** — 带网关:发起 → 部门主管 → (永久替换?) → 总经理审批 → 完成
|
||||||
|
|
||||||
|
**`asset_return_order.bpmn20.xml`** — 简单串行:发起 → 部门主管审批 → 完成
|
||||||
|
|
||||||
|
命名规则与现有 `asset_contract.bpmn20.xml` 一致。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第七部分:事件驱动 & 跨模块联动
|
||||||
|
|
||||||
|
### 事件清单
|
||||||
|
|
||||||
|
| 事件类 | 发布者 | 监听者 | 动作 |
|
||||||
|
|--------|--------|--------|------|
|
||||||
|
| `DeliveryCompletedEvent` | DeliveryOrderService | VehicleStatusListener | 车辆状态→已交付 |
|
||||||
|
| `ReplacementApprovedEvent` | ReplacementBpmListener | ReturnOrderEventListener | 永久替换→创建还车单壳子 |
|
||||||
|
| `ReplacementReturnConfirmedEvent` | ReplacementService | VehicleStatusListener | 临时替换换回→恢复原车状态 |
|
||||||
|
| `ReturnApprovedEvent` | ReturnOrderBpmListener | VehicleStatusListener | 还车审批通过→车辆状态→可用 |
|
||||||
|
|
||||||
|
### 事件监听实现
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Component
|
||||||
|
public class VehicleStatusEventListener {
|
||||||
|
|
||||||
|
@TransactionalEventListener
|
||||||
|
public void onDeliveryCompleted(DeliveryCompletedEvent event) {
|
||||||
|
vehicleService.updateStatus(event.getVehicleId(), VehicleStatus.DELIVERED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TransactionalEventListener
|
||||||
|
public void onReturnApproved(ReturnApprovedEvent event) {
|
||||||
|
// 还车单有多辆车,逐辆更新
|
||||||
|
for (Long vehicleId : event.getVehicleIds()) {
|
||||||
|
vehicleService.updateStatus(vehicleId, VehicleStatus.AVAILABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TransactionalEventListener
|
||||||
|
public void onReplacementReturnConfirmed(ReplacementReturnConfirmedEvent event) {
|
||||||
|
vehicleService.updateStatus(event.getOriginalVehicleId(), VehicleStatus.AVAILABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ReturnOrderEventListener {
|
||||||
|
|
||||||
|
// 使用 @EventListener 而非 @TransactionalEventListener,
|
||||||
|
// 确保还车单创建在同一事务中,避免审批已提交但还车单创建失败的不一致
|
||||||
|
@EventListener
|
||||||
|
public void onReplacementApproved(ReplacementApprovedEvent event) {
|
||||||
|
if (event.getReplacementType() == ReplacementType.PERMANENT) {
|
||||||
|
returnOrderService.createFromReplacement(
|
||||||
|
event.getReplacementId(),
|
||||||
|
event.getContractId(),
|
||||||
|
event.getOriginalVehicleId()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**关于事务安全**:`ReturnOrderEventListener.onReplacementApproved()` 使用 `@EventListener`(非 `@TransactionalEventListener`),确保还车单创建与替换车状态更新在同一事务内完成。`@TransactionalEventListener` 默认 `AFTER_COMMIT`,会导致还车单创建在事务外执行,失败时无法回滚。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 前端变更概要
|
||||||
|
|
||||||
|
### 共享验车组件
|
||||||
|
|
||||||
|
创建通用验车表单组件 `InspectionForm.vue`:
|
||||||
|
- 按 category 分组展示检查项
|
||||||
|
- 根据 `input_type` 渲染不同控件:`checkbox` → Radio(合格/不合格/不适用);`number` → InputNumber;`text` → Input
|
||||||
|
- 每项支持:备注 + 图片上传
|
||||||
|
- 只读模式(查看历史记录)和编辑模式
|
||||||
|
- 被备车/交车/还车表单复用
|
||||||
|
|
||||||
|
### 替换车前端
|
||||||
|
|
||||||
|
新建 `views/asset/vehicle-replacement/`:
|
||||||
|
- `index.vue` — 列表页(分页、筛选、操作列)
|
||||||
|
- `modules/form.vue` — 表单(create/edit/view 三模式)
|
||||||
|
- `data.ts` — 搜索/列/常量定义
|
||||||
|
|
||||||
|
### 备车前端改造
|
||||||
|
|
||||||
|
- 移除硬编码 `checkList` 表单
|
||||||
|
- 改用 `InspectionForm.vue` 组件动态渲染
|
||||||
|
|
||||||
|
### 交车/还车前端改造
|
||||||
|
|
||||||
|
- 交车表单中验车区域改用 `InspectionForm.vue`
|
||||||
|
- 交车列表操作列增加"还车"和"替换车"按钮
|
||||||
|
- 还车表单中每辆车增加"开始验车"按钮 + `InspectionForm.vue`
|
||||||
|
|
||||||
|
### 新增 API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// inspection.ts
|
||||||
|
export function getInspectionRecord(id: number)
|
||||||
|
export function updateInspectionRecordItem(data: {...})
|
||||||
|
export function completeInspection(recordId: number, inspectorName: string)
|
||||||
|
|
||||||
|
// vehicle-replacement.ts
|
||||||
|
export function createReplacement(data: VehicleReplacementSaveReqVO)
|
||||||
|
export function updateReplacement(data: VehicleReplacementSaveReqVO)
|
||||||
|
export function deleteReplacement(id: number)
|
||||||
|
export function getReplacement(id: number)
|
||||||
|
export function getReplacementPage(params: VehicleReplacementPageReqVO)
|
||||||
|
export function submitReplacement(id: number)
|
||||||
|
export function withdrawReplacement(id: number)
|
||||||
|
export function confirmReplacementReturn(id: number)
|
||||||
|
|
||||||
|
// return-order.ts (补充)
|
||||||
|
export function createFromDelivery(deliveryOrderId: number, vehicleIds: number[])
|
||||||
|
export function startVehicleInspection(returnOrderVehicleId: number)
|
||||||
|
export function completeVehicleInspection(returnOrderVehicleId: number)
|
||||||
|
export function submitReturnOrder(id: number)
|
||||||
|
export function withdrawReturnOrder(id: number)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 实施顺序
|
||||||
|
|
||||||
|
1. **共享验车模板** — SQL建表 → DO/Mapper → Service → Controller → 前端组件
|
||||||
|
2. **备车精简** — 移除旧字段 → 对接 inspection_record → 前端改造
|
||||||
|
3. **交车增强** — 新增 inspection_record_id → 废弃 inspection_data → 操作列扩展 → 前端改造
|
||||||
|
4. **替换车模块** — 全套新建(DO → VO → Mapper → Service → BPM listener → Controller → 前端)
|
||||||
|
5. **还车完善** — 新增字段 → 对接验车模板(子表级别) → 从交车/替换车触发 → BPM listener → 前端改造
|
||||||
|
6. **BPM 部署** — 创建 BPMN XML → 部署到引擎
|
||||||
|
7. **事件驱动** — 事件类 → 监听器 → 车辆状态同步
|
||||||
|
8. **端到端验证** — `mvn compile` + `pnpm run build:antd` + 全链路测试
|
||||||
3
sql/2026-03-13-delivery-order-inspection.sql
Normal file
3
sql/2026-03-13-delivery-order-inspection.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
-- 交车单表增加验车记录关联字段
|
||||||
|
ALTER TABLE asset_delivery_order
|
||||||
|
ADD COLUMN inspection_record_id bigint DEFAULT NULL COMMENT '关联验车记录';
|
||||||
3
sql/2026-03-13-prepare-simplify.sql
Normal file
3
sql/2026-03-13-prepare-simplify.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
-- 备车表增加验车记录关联字段
|
||||||
|
ALTER TABLE asset_vehicle_prepare
|
||||||
|
ADD COLUMN inspection_record_id bigint DEFAULT NULL COMMENT '关联验车记录' AFTER defect_photos;
|
||||||
9
sql/2026-03-13-return-order-enhance.sql
Normal file
9
sql/2026-03-13-return-order-enhance.sql
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
-- 还车单增强:添加来源类型、来源ID、关联交车单ID
|
||||||
|
ALTER TABLE asset_return_order
|
||||||
|
ADD COLUMN source_type tinyint DEFAULT NULL COMMENT '来源:1=手动 2=替换车触发',
|
||||||
|
ADD COLUMN source_id bigint DEFAULT NULL COMMENT '来源业务ID',
|
||||||
|
ADD COLUMN delivery_order_id bigint DEFAULT NULL COMMENT '关联交车单ID';
|
||||||
|
|
||||||
|
-- 还车车辆增强:添加验车记录关联
|
||||||
|
ALTER TABLE asset_return_order_vehicle
|
||||||
|
ADD COLUMN inspection_record_id bigint DEFAULT NULL COMMENT '关联验车记录';
|
||||||
32
sql/2026-03-13-vehicle-replacement.sql
Normal file
32
sql/2026-03-13-vehicle-replacement.sql
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS `asset_vehicle_replacement` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`replacement_code` varchar(50) NOT NULL COMMENT '替换单编码',
|
||||||
|
`replacement_type` tinyint NOT NULL COMMENT '1=临时 2=永久',
|
||||||
|
`contract_id` bigint NOT NULL,
|
||||||
|
`contract_code` varchar(50) DEFAULT NULL,
|
||||||
|
`customer_id` bigint DEFAULT NULL,
|
||||||
|
`customer_name` varchar(100) DEFAULT NULL,
|
||||||
|
`delivery_order_id` bigint DEFAULT NULL COMMENT '来源交车单ID',
|
||||||
|
`original_vehicle_id` bigint NOT NULL,
|
||||||
|
`original_plate_no` varchar(20) DEFAULT NULL,
|
||||||
|
`original_vin` varchar(50) DEFAULT NULL,
|
||||||
|
`new_vehicle_id` bigint DEFAULT NULL,
|
||||||
|
`new_plate_no` varchar(20) DEFAULT NULL,
|
||||||
|
`new_vin` varchar(50) DEFAULT NULL,
|
||||||
|
`replacement_reason` varchar(500) DEFAULT NULL,
|
||||||
|
`expected_date` date DEFAULT NULL,
|
||||||
|
`actual_date` date DEFAULT NULL,
|
||||||
|
`return_date` date DEFAULT NULL COMMENT '临时替换预计归还日期',
|
||||||
|
`actual_return_date` date DEFAULT NULL,
|
||||||
|
`status` tinyint NOT NULL DEFAULT 0 COMMENT '0=草稿 1=审批中 2=审批通过 3=执行中 4=已完成 5=审批驳回 6=已撤回',
|
||||||
|
`approval_status` tinyint NOT NULL DEFAULT 0,
|
||||||
|
`bpm_instance_id` varchar(64) DEFAULT NULL,
|
||||||
|
`remark` varchar(500) DEFAULT NULL,
|
||||||
|
`creator` varchar(64) DEFAULT '',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updater` varchar(64) DEFAULT '',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
`deleted` bit(1) NOT NULL DEFAULT b'0',
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB COMMENT='替换车申请';
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
-- =============================================
|
||||||
|
-- 验车模板与验车记录表
|
||||||
|
-- 创建时间: 2026-03-13
|
||||||
|
-- =============================================
|
||||||
|
|
||||||
|
-- 验车模板
|
||||||
|
CREATE TABLE IF NOT EXISTS `asset_inspection_template` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`code` varchar(50) NOT NULL COMMENT '模板编码',
|
||||||
|
`name` varchar(100) NOT NULL COMMENT '模板名称',
|
||||||
|
`biz_type` tinyint NOT NULL COMMENT '业务类型(1=备车 2=交车 3=还车)',
|
||||||
|
`vehicle_type` varchar(50) DEFAULT NULL COMMENT '车辆类型',
|
||||||
|
`status` tinyint DEFAULT 1 COMMENT '状态(0=禁用 1=启用)',
|
||||||
|
`remark` varchar(500) DEFAULT 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`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='验车模板';
|
||||||
|
|
||||||
|
-- 验车模板检查项
|
||||||
|
CREATE TABLE IF NOT EXISTS `asset_inspection_template_item` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`template_id` bigint NOT NULL COMMENT '模板ID',
|
||||||
|
`category` varchar(50) NOT NULL COMMENT '分类',
|
||||||
|
`item_name` varchar(100) NOT NULL COMMENT '检查项名称',
|
||||||
|
`item_code` varchar(50) NOT NULL COMMENT '检查项编码',
|
||||||
|
`input_type` varchar(20) DEFAULT 'checkbox' COMMENT '输入类型',
|
||||||
|
`sort` int DEFAULT 0 COMMENT '排序',
|
||||||
|
`required` tinyint DEFAULT 1 COMMENT '是否必填(0=否 1=是)',
|
||||||
|
`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_template_id` (`template_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='验车模板检查项';
|
||||||
|
|
||||||
|
-- 验车记录
|
||||||
|
CREATE TABLE IF NOT EXISTS `asset_inspection_record` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`record_code` varchar(50) NOT NULL COMMENT '记录编码',
|
||||||
|
`template_id` bigint NOT NULL COMMENT '模板ID',
|
||||||
|
`source_type` tinyint NOT NULL COMMENT '来源类型(1=备车 2=交车 3=还车)',
|
||||||
|
`source_id` bigint NOT NULL COMMENT '来源ID',
|
||||||
|
`vehicle_id` bigint NOT NULL COMMENT '车辆ID',
|
||||||
|
`inspector_name` varchar(50) DEFAULT NULL COMMENT '检查人',
|
||||||
|
`inspection_time` datetime DEFAULT NULL COMMENT '检查时间',
|
||||||
|
`status` tinyint DEFAULT 0 COMMENT '状态(0=待检 1=检查中 2=已完成)',
|
||||||
|
`overall_result` tinyint DEFAULT NULL COMMENT '总体结果(1=通过 2=不通过 3=不适用)',
|
||||||
|
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
`cloned_from_id` bigint DEFAULT NULL 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`),
|
||||||
|
INDEX `idx_vehicle_source` (`vehicle_id`, `source_type`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='验车记录';
|
||||||
|
|
||||||
|
-- 验车记录检查项
|
||||||
|
CREATE TABLE IF NOT EXISTS `asset_inspection_record_item` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`record_id` bigint NOT NULL COMMENT '记录ID',
|
||||||
|
`item_code` varchar(50) NOT NULL COMMENT '检查项编码',
|
||||||
|
`category` varchar(50) NOT NULL COMMENT '分类',
|
||||||
|
`item_name` varchar(100) NOT NULL COMMENT '检查项名称',
|
||||||
|
`input_type` varchar(20) DEFAULT 'checkbox' COMMENT '输入类型',
|
||||||
|
`result` tinyint DEFAULT NULL COMMENT '检查结果(1=通过 2=不通过 3=不适用)',
|
||||||
|
`value` varchar(200) DEFAULT NULL COMMENT '检查值',
|
||||||
|
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
`image_urls` varchar(2000) DEFAULT NULL COMMENT '图片URL列表',
|
||||||
|
`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_record_id` (`record_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='验车记录检查项';
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.enums.inspection;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车结果枚举
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum InspectionResultEnum {
|
||||||
|
|
||||||
|
PASS(1, "通过"),
|
||||||
|
FAIL(2, "不通过"),
|
||||||
|
NA(3, "不适用");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结果
|
||||||
|
*/
|
||||||
|
private final Integer result;
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static InspectionResultEnum valueOf(Integer result) {
|
||||||
|
return Arrays.stream(values())
|
||||||
|
.filter(item -> item.getResult().equals(result))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.enums.inspection;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车来源类型枚举
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum InspectionSourceTypeEnum {
|
||||||
|
|
||||||
|
PREPARE(1, "备车"),
|
||||||
|
DELIVERY(2, "交车"),
|
||||||
|
RETURN(3, "还车");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
private final Integer type;
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static InspectionSourceTypeEnum valueOf(Integer type) {
|
||||||
|
return Arrays.stream(values())
|
||||||
|
.filter(item -> item.getType().equals(type))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.enums.inspection;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车状态枚举
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum InspectionStatusEnum {
|
||||||
|
|
||||||
|
PENDING(0, "待检"),
|
||||||
|
IN_PROGRESS(1, "检查中"),
|
||||||
|
COMPLETED(2, "已完成");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private final Integer status;
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static InspectionStatusEnum valueOf(Integer status) {
|
||||||
|
return Arrays.stream(values())
|
||||||
|
.filter(item -> item.getStatus().equals(status))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.enums.replacement;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车状态枚举
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum ReplacementStatusEnum {
|
||||||
|
|
||||||
|
DRAFT(0, "草稿"),
|
||||||
|
APPROVING(1, "审批中"),
|
||||||
|
APPROVED(2, "审批通过"),
|
||||||
|
EXECUTING(3, "执行中"),
|
||||||
|
COMPLETED(4, "已完成"),
|
||||||
|
REJECTED(5, "审批驳回"),
|
||||||
|
WITHDRAWN(6, "已撤回");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private final Integer status;
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static ReplacementStatusEnum valueOf(Integer status) {
|
||||||
|
return Arrays.stream(values())
|
||||||
|
.filter(item -> item.getStatus().equals(status))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.enums.replacement;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车类型枚举
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum ReplacementTypeEnum {
|
||||||
|
|
||||||
|
TEMPORARY(1, "临时替换"),
|
||||||
|
PERMANENT(2, "永久替换");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
private final Integer type;
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static ReplacementTypeEnum valueOf(Integer type) {
|
||||||
|
return Arrays.stream(values())
|
||||||
|
.filter(item -> item.getType().equals(type))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.delivery.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 交车单 Response VO")
|
||||||
|
@Data
|
||||||
|
public class DeliveryOrderRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "交车单编码")
|
||||||
|
private String orderCode;
|
||||||
|
|
||||||
|
@Schema(description = "交车任务ID")
|
||||||
|
private Long taskId;
|
||||||
|
|
||||||
|
@Schema(description = "任务编码")
|
||||||
|
private String taskCode;
|
||||||
|
|
||||||
|
@Schema(description = "合同ID")
|
||||||
|
private Long contractId;
|
||||||
|
|
||||||
|
@Schema(description = "合同编码")
|
||||||
|
private String contractCode;
|
||||||
|
|
||||||
|
@Schema(description = "项目名称")
|
||||||
|
private String projectName;
|
||||||
|
|
||||||
|
@Schema(description = "客户ID")
|
||||||
|
private Long customerId;
|
||||||
|
|
||||||
|
@Schema(description = "客户名称")
|
||||||
|
private String customerName;
|
||||||
|
|
||||||
|
@Schema(description = "交车日期")
|
||||||
|
private LocalDateTime deliveryDate;
|
||||||
|
|
||||||
|
@Schema(description = "交车人")
|
||||||
|
private String deliveryPerson;
|
||||||
|
|
||||||
|
@Schema(description = "交车地点")
|
||||||
|
private String deliveryLocation;
|
||||||
|
|
||||||
|
@Schema(description = "被授权人姓名")
|
||||||
|
private String authorizedPersonName;
|
||||||
|
|
||||||
|
@Schema(description = "被授权人电话")
|
||||||
|
private String authorizedPersonPhone;
|
||||||
|
|
||||||
|
@Schema(description = "E签宝状态")
|
||||||
|
private Integer esignStatus;
|
||||||
|
|
||||||
|
@Schema(description = "交车照片")
|
||||||
|
private String deliveryPhotos;
|
||||||
|
|
||||||
|
@Schema(description = "司机姓名")
|
||||||
|
private String driverName;
|
||||||
|
|
||||||
|
@Schema(description = "司机身份证")
|
||||||
|
private String driverIdCard;
|
||||||
|
|
||||||
|
@Schema(description = "司机手机号")
|
||||||
|
private String driverPhone;
|
||||||
|
|
||||||
|
@Schema(description = "交检清单JSON")
|
||||||
|
private String inspectionData;
|
||||||
|
|
||||||
|
@Schema(description = "费用信息JSON")
|
||||||
|
private String costList;
|
||||||
|
|
||||||
|
@Schema(description = "关联验车记录ID")
|
||||||
|
private Long inspectionRecordId;
|
||||||
|
|
||||||
|
@Schema(description = "状态")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "车辆列表")
|
||||||
|
private List<DeliveryOrderVehicleVO> vehicles;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionRecordDetailVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionRecordItemUpdateReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.inspection.InspectionRecordService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车记录 Controller
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Tag(name = "管理后台 - 验车记录管理")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/asset/inspection-record")
|
||||||
|
@Validated
|
||||||
|
public class InspectionRecordController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionRecordService inspectionRecordService;
|
||||||
|
|
||||||
|
@GetMapping("/get")
|
||||||
|
@Operation(summary = "获得验车记录详情")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:inspection-record:query')")
|
||||||
|
public CommonResult<InspectionRecordDetailVO> getRecordDetail(@RequestParam("id") Long id) {
|
||||||
|
return success(inspectionRecordService.getRecordDetail(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/update-item")
|
||||||
|
@Operation(summary = "更新验车记录检查项")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:inspection-record:update')")
|
||||||
|
public CommonResult<Boolean> updateRecordItem(@Valid @RequestBody InspectionRecordItemUpdateReqVO updateReqVO) {
|
||||||
|
inspectionRecordService.updateRecordItem(updateReqVO);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/complete")
|
||||||
|
@Operation(summary = "完成验车记录")
|
||||||
|
@Parameter(name = "id", description = "记录ID", required = true, example = "1")
|
||||||
|
@Parameter(name = "inspectorName", description = "检查人", required = true, example = "张三")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:inspection-record:update')")
|
||||||
|
public CommonResult<Boolean> completeRecord(@RequestParam("id") Long id,
|
||||||
|
@RequestParam("inspectorName") String inspectorName) {
|
||||||
|
inspectionRecordService.completeRecord(id, inspectorName);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.asset.convert.inspection.InspectionConvert;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionTemplateDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.inspection.InspectionTemplateService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车模板 Controller
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Tag(name = "管理后台 - 验车模板管理")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/asset/inspection-template")
|
||||||
|
@Validated
|
||||||
|
public class InspectionTemplateController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionTemplateService inspectionTemplateService;
|
||||||
|
|
||||||
|
@PostMapping("/create")
|
||||||
|
@Operation(summary = "创建验车模板")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:inspection-template:create')")
|
||||||
|
public CommonResult<Long> createTemplate(@Valid @RequestBody InspectionTemplateSaveReqVO createReqVO) {
|
||||||
|
return success(inspectionTemplateService.createTemplate(createReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/update")
|
||||||
|
@Operation(summary = "更新验车模板")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:inspection-template:update')")
|
||||||
|
public CommonResult<Boolean> updateTemplate(@Valid @RequestBody InspectionTemplateSaveReqVO updateReqVO) {
|
||||||
|
inspectionTemplateService.updateTemplate(updateReqVO);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/delete")
|
||||||
|
@Operation(summary = "删除验车模板")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:inspection-template:delete')")
|
||||||
|
public CommonResult<Boolean> deleteTemplate(@RequestParam("id") Long id) {
|
||||||
|
inspectionTemplateService.deleteTemplate(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get")
|
||||||
|
@Operation(summary = "获得验车模板详情")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:inspection-template:query')")
|
||||||
|
public CommonResult<InspectionTemplateRespVO> getTemplate(@RequestParam("id") Long id) {
|
||||||
|
return success(inspectionTemplateService.getTemplate(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
@Operation(summary = "获得验车模板分页")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:inspection-template:query')")
|
||||||
|
public CommonResult<PageResult<InspectionTemplateRespVO>> getTemplatePage(@Valid InspectionTemplatePageReqVO pageReqVO) {
|
||||||
|
PageResult<InspectionTemplateDO> pageResult = inspectionTemplateService.getTemplatePage(pageReqVO);
|
||||||
|
return success(InspectionConvert.INSTANCE.convertPage(pageResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.inspection.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车记录详情 Response VO
|
||||||
|
*/
|
||||||
|
@Schema(description = "管理后台 - 验车记录详情 Response VO")
|
||||||
|
@Data
|
||||||
|
public class InspectionRecordDetailVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键ID", example = "1")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "记录编码", example = "BC-20260313-001")
|
||||||
|
private String recordCode;
|
||||||
|
|
||||||
|
@Schema(description = "模板ID", example = "1")
|
||||||
|
private Long templateId;
|
||||||
|
|
||||||
|
@Schema(description = "来源类型(1=备车 2=交车 3=还车)", example = "1")
|
||||||
|
private Integer sourceType;
|
||||||
|
|
||||||
|
@Schema(description = "来源ID", example = "1")
|
||||||
|
private Long sourceId;
|
||||||
|
|
||||||
|
@Schema(description = "车辆ID", example = "1")
|
||||||
|
private Long vehicleId;
|
||||||
|
|
||||||
|
@Schema(description = "检查人", example = "张三")
|
||||||
|
private String inspectorName;
|
||||||
|
|
||||||
|
@Schema(description = "检查时间")
|
||||||
|
private LocalDateTime inspectionTime;
|
||||||
|
|
||||||
|
@Schema(description = "状态(0=待检 1=检查中 2=已完成)", example = "0")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "总体结果(1=通过 2=不通过 3=不适用)", example = "1")
|
||||||
|
private Integer overallResult;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "克隆来源记录ID", example = "1")
|
||||||
|
private Long clonedFromId;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "检查项列表")
|
||||||
|
private List<InspectionRecordItemVO> items;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车记录检查项 VO
|
||||||
|
*/
|
||||||
|
@Schema(description = "验车记录检查项 VO")
|
||||||
|
@Data
|
||||||
|
public static class InspectionRecordItemVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键ID", example = "1")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "检查项编码", example = "BODY_PAINT")
|
||||||
|
private String itemCode;
|
||||||
|
|
||||||
|
@Schema(description = "分类", example = "外观检查")
|
||||||
|
private String category;
|
||||||
|
|
||||||
|
@Schema(description = "检查项名称", example = "车身漆面")
|
||||||
|
private String itemName;
|
||||||
|
|
||||||
|
@Schema(description = "输入类型", example = "checkbox")
|
||||||
|
private String inputType;
|
||||||
|
|
||||||
|
@Schema(description = "检查结果(1=通过 2=不通过 3=不适用)", example = "1")
|
||||||
|
private Integer result;
|
||||||
|
|
||||||
|
@Schema(description = "检查值", example = "正常")
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "图片URL列表")
|
||||||
|
private String imageUrls;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.inspection.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车记录检查项更新 Request VO
|
||||||
|
*/
|
||||||
|
@Schema(description = "管理后台 - 验车记录检查项更新 Request VO")
|
||||||
|
@Data
|
||||||
|
public class InspectionRecordItemUpdateReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@NotNull(message = "主键ID不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "检查结果(1=通过 2=不通过 3=不适用)", example = "1")
|
||||||
|
private Integer result;
|
||||||
|
|
||||||
|
@Schema(description = "检查值", example = "正常")
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "图片URL列表")
|
||||||
|
private String imageUrls;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.inspection.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车模板检查项 VO
|
||||||
|
*/
|
||||||
|
@Schema(description = "管理后台 - 验车模板检查项 VO")
|
||||||
|
@Data
|
||||||
|
public class InspectionTemplateItemVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键ID", example = "1")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "外观检查")
|
||||||
|
@NotBlank(message = "分类不能为空")
|
||||||
|
private String category;
|
||||||
|
|
||||||
|
@Schema(description = "检查项名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "车身漆面")
|
||||||
|
@NotBlank(message = "检查项名称不能为空")
|
||||||
|
private String itemName;
|
||||||
|
|
||||||
|
@Schema(description = "检查项编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "BODY_PAINT")
|
||||||
|
@NotBlank(message = "检查项编码不能为空")
|
||||||
|
private String itemCode;
|
||||||
|
|
||||||
|
@Schema(description = "输入类型", example = "checkbox")
|
||||||
|
private String inputType;
|
||||||
|
|
||||||
|
@Schema(description = "排序", example = "0")
|
||||||
|
private Integer sort;
|
||||||
|
|
||||||
|
@Schema(description = "是否必填(0=否 1=是)", example = "1")
|
||||||
|
private Integer required;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.inspection.vo;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车模板分页查询 Request VO
|
||||||
|
*/
|
||||||
|
@Schema(description = "管理后台 - 验车模板分页查询 Request VO")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class InspectionTemplatePageReqVO extends PageParam {
|
||||||
|
|
||||||
|
@Schema(description = "模板编码", example = "TPL-BC-001")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@Schema(description = "模板名称", example = "备车检查模板")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "业务类型(1=备车 2=交车 3=还车)", example = "1")
|
||||||
|
private Integer bizType;
|
||||||
|
|
||||||
|
@Schema(description = "车辆类型", example = "重卡")
|
||||||
|
private String vehicleType;
|
||||||
|
|
||||||
|
@Schema(description = "状态(0=禁用 1=启用)", example = "1")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.inspection.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车模板 Response VO
|
||||||
|
*/
|
||||||
|
@Schema(description = "管理后台 - 验车模板 Response VO")
|
||||||
|
@Data
|
||||||
|
public class InspectionTemplateRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键ID", example = "1")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "模板编码", example = "TPL-BC-001")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@Schema(description = "模板名称", example = "备车检查模板")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "业务类型(1=备车 2=交车 3=还车)", example = "1")
|
||||||
|
private Integer bizType;
|
||||||
|
|
||||||
|
@Schema(description = "车辆类型", example = "重卡")
|
||||||
|
private String vehicleType;
|
||||||
|
|
||||||
|
@Schema(description = "状态(0=禁用 1=启用)", example = "1")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "备注", example = "备车检查模板")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "检查项列表")
|
||||||
|
private List<InspectionTemplateItemVO> items;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.inspection.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车模板创建/更新 Request VO
|
||||||
|
*/
|
||||||
|
@Schema(description = "管理后台 - 验车模板创建/更新 Request VO")
|
||||||
|
@Data
|
||||||
|
public class InspectionTemplateSaveReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键ID", example = "1")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "TPL-BC-001")
|
||||||
|
@NotBlank(message = "模板编码不能为空")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "备车检查模板")
|
||||||
|
@NotBlank(message = "模板名称不能为空")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "业务类型(1=备车 2=交车 3=还车)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@NotNull(message = "业务类型不能为空")
|
||||||
|
private Integer bizType;
|
||||||
|
|
||||||
|
@Schema(description = "车辆类型", example = "重卡")
|
||||||
|
private String vehicleType;
|
||||||
|
|
||||||
|
@Schema(description = "状态(0=禁用 1=启用)", example = "1")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "备注", example = "备车检查模板")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "检查项列表")
|
||||||
|
@Valid
|
||||||
|
private List<InspectionTemplateItemVO> items;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.prepare.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 备车记录 Response VO")
|
||||||
|
@Data
|
||||||
|
public class VehiclePrepareRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "车辆ID")
|
||||||
|
private Long vehicleId;
|
||||||
|
|
||||||
|
@Schema(description = "车牌号")
|
||||||
|
private String plateNo;
|
||||||
|
|
||||||
|
@Schema(description = "VIN码")
|
||||||
|
private String vin;
|
||||||
|
|
||||||
|
@Schema(description = "车型ID")
|
||||||
|
private Long vehicleModelId;
|
||||||
|
|
||||||
|
@Schema(description = "品牌")
|
||||||
|
private String brand;
|
||||||
|
|
||||||
|
@Schema(description = "型号")
|
||||||
|
private String model;
|
||||||
|
|
||||||
|
@Schema(description = "车辆类型")
|
||||||
|
private String vehicleType;
|
||||||
|
|
||||||
|
@Schema(description = "停车场")
|
||||||
|
private String parkingLot;
|
||||||
|
|
||||||
|
@Schema(description = "合同ID")
|
||||||
|
private Long contractId;
|
||||||
|
|
||||||
|
@Schema(description = "合同编码")
|
||||||
|
private String contractCode;
|
||||||
|
|
||||||
|
@Schema(description = "整备类型")
|
||||||
|
private String preparationType;
|
||||||
|
|
||||||
|
@Schema(description = "里程(km)")
|
||||||
|
private Integer mileage;
|
||||||
|
|
||||||
|
@Schema(description = "剩余氢量")
|
||||||
|
private BigDecimal hydrogenRemaining;
|
||||||
|
|
||||||
|
@Schema(description = "氢量单位")
|
||||||
|
private String hydrogenUnit;
|
||||||
|
|
||||||
|
@Schema(description = "剩余电量(%)")
|
||||||
|
private BigDecimal batteryRemaining;
|
||||||
|
|
||||||
|
@Schema(description = "是否有车身广告")
|
||||||
|
private Boolean hasBodyAd;
|
||||||
|
|
||||||
|
@Schema(description = "广告照片")
|
||||||
|
private String bodyAdPhotos;
|
||||||
|
|
||||||
|
@Schema(description = "放大字照片")
|
||||||
|
private String enlargedTextPhoto;
|
||||||
|
|
||||||
|
@Schema(description = "是否有尾板")
|
||||||
|
private Boolean hasTailLift;
|
||||||
|
|
||||||
|
@Schema(description = "备胎胎纹深度(mm)")
|
||||||
|
private BigDecimal spareTireDepth;
|
||||||
|
|
||||||
|
@Schema(description = "备胎照片")
|
||||||
|
private String spareTirePhoto;
|
||||||
|
|
||||||
|
@Schema(description = "挂车牌号")
|
||||||
|
private String trailerPlateNo;
|
||||||
|
|
||||||
|
@Schema(description = "瑕疵照片")
|
||||||
|
private String defectPhotos;
|
||||||
|
|
||||||
|
@Schema(description = "关联验车记录ID")
|
||||||
|
private Long inspectionRecordId;
|
||||||
|
|
||||||
|
@Schema(description = "检查清单JSON")
|
||||||
|
private String checkList;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "状态")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "完成时间")
|
||||||
|
private LocalDateTime completeTime;
|
||||||
|
|
||||||
|
@Schema(description = "创建者")
|
||||||
|
private String creator;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.replacement;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.replacement.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.asset.convert.replacement.VehicleReplacementConvert;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.replacement.VehicleReplacementDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.replacement.VehicleReplacementService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车申请 Controller
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Tag(name = "管理后台 - 替换车管理")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/asset/vehicle-replacement")
|
||||||
|
@Validated
|
||||||
|
public class VehicleReplacementController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private VehicleReplacementService replacementService;
|
||||||
|
|
||||||
|
@PostMapping("/create")
|
||||||
|
@Operation(summary = "创建替换车申请")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:vehicle-replacement:create')")
|
||||||
|
public CommonResult<Long> createReplacement(@Valid @RequestBody VehicleReplacementSaveReqVO createReqVO) {
|
||||||
|
return success(replacementService.createReplacement(createReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/update")
|
||||||
|
@Operation(summary = "更新替换车申请")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:vehicle-replacement:update')")
|
||||||
|
public CommonResult<Boolean> updateReplacement(@Valid @RequestBody VehicleReplacementSaveReqVO updateReqVO) {
|
||||||
|
replacementService.updateReplacement(updateReqVO);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/delete")
|
||||||
|
@Operation(summary = "删除替换车申请")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:vehicle-replacement:delete')")
|
||||||
|
public CommonResult<Boolean> deleteReplacement(@RequestParam("id") Long id) {
|
||||||
|
replacementService.deleteReplacement(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get")
|
||||||
|
@Operation(summary = "获得替换车申请详情")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:vehicle-replacement:query')")
|
||||||
|
public CommonResult<VehicleReplacementRespVO> getReplacement(@RequestParam("id") Long id) {
|
||||||
|
VehicleReplacementDO replacement = replacementService.getReplacement(id);
|
||||||
|
return success(VehicleReplacementConvert.INSTANCE.convert(replacement));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
@Operation(summary = "获得替换车申请分页")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:vehicle-replacement:query')")
|
||||||
|
public CommonResult<PageResult<VehicleReplacementRespVO>> getReplacementPage(@Valid VehicleReplacementPageReqVO pageReqVO) {
|
||||||
|
PageResult<VehicleReplacementDO> pageResult = replacementService.getReplacementPage(pageReqVO);
|
||||||
|
return success(VehicleReplacementConvert.INSTANCE.convertPage(pageResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/submit")
|
||||||
|
@Operation(summary = "提交替换车审批")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:vehicle-replacement:update')")
|
||||||
|
public CommonResult<String> submitApproval(@RequestParam("id") Long id) {
|
||||||
|
return success(replacementService.submitApproval(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/withdraw")
|
||||||
|
@Operation(summary = "撤回替换车审批")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:vehicle-replacement:update')")
|
||||||
|
public CommonResult<Boolean> withdrawApproval(@RequestParam("id") Long id) {
|
||||||
|
replacementService.withdrawApproval(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/confirm-return")
|
||||||
|
@Operation(summary = "确认换回(临时替换)")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:vehicle-replacement:update')")
|
||||||
|
public CommonResult<Boolean> confirmReturn(@RequestParam("id") Long id) {
|
||||||
|
replacementService.confirmReturn(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.replacement.vo;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车申请分页查询 Request VO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Schema(description = "管理后台 - 替换车申请分页查询 Request VO")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class VehicleReplacementPageReqVO extends PageParam {
|
||||||
|
|
||||||
|
@Schema(description = "替换单编码", example = "TH-20260313-001")
|
||||||
|
private String replacementCode;
|
||||||
|
|
||||||
|
@Schema(description = "替换类型(1=临时 2=永久)", example = "1")
|
||||||
|
private Integer replacementType;
|
||||||
|
|
||||||
|
@Schema(description = "合同ID", example = "1")
|
||||||
|
private Long contractId;
|
||||||
|
|
||||||
|
@Schema(description = "客户名称(模糊搜索)", example = "上海某某科技")
|
||||||
|
private String customerName;
|
||||||
|
|
||||||
|
@Schema(description = "状态(0=草稿 1=审批中 2=审批通过 3=执行中 4=已完成 5=审批驳回 6=已撤回)", example = "0")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.replacement.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车申请 Response VO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Schema(description = "管理后台 - 替换车申请 Response VO")
|
||||||
|
@Data
|
||||||
|
public class VehicleReplacementRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键ID", example = "1")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "替换单编码", example = "TH-20260313-001")
|
||||||
|
private String replacementCode;
|
||||||
|
|
||||||
|
@Schema(description = "替换类型(1=临时 2=永久)", example = "1")
|
||||||
|
private Integer replacementType;
|
||||||
|
|
||||||
|
@Schema(description = "合同ID", example = "1")
|
||||||
|
private Long contractId;
|
||||||
|
|
||||||
|
@Schema(description = "合同编码", example = "HT-2026-0001")
|
||||||
|
private String contractCode;
|
||||||
|
|
||||||
|
@Schema(description = "客户ID", example = "1")
|
||||||
|
private Long customerId;
|
||||||
|
|
||||||
|
@Schema(description = "客户名称", example = "上海某某科技")
|
||||||
|
private String customerName;
|
||||||
|
|
||||||
|
@Schema(description = "来源交车单ID", example = "1")
|
||||||
|
private Long deliveryOrderId;
|
||||||
|
|
||||||
|
@Schema(description = "原车辆ID", example = "1")
|
||||||
|
private Long originalVehicleId;
|
||||||
|
|
||||||
|
@Schema(description = "原车牌号", example = "沪A12345")
|
||||||
|
private String originalPlateNo;
|
||||||
|
|
||||||
|
@Schema(description = "原车架号", example = "LVHRU1867N5012345")
|
||||||
|
private String originalVin;
|
||||||
|
|
||||||
|
@Schema(description = "新车辆ID", example = "2")
|
||||||
|
private Long newVehicleId;
|
||||||
|
|
||||||
|
@Schema(description = "新车牌号", example = "沪B67890")
|
||||||
|
private String newPlateNo;
|
||||||
|
|
||||||
|
@Schema(description = "新车架号", example = "LVHRU1867N5067890")
|
||||||
|
private String newVin;
|
||||||
|
|
||||||
|
@Schema(description = "替换原因", example = "车辆故障需维修")
|
||||||
|
private String replacementReason;
|
||||||
|
|
||||||
|
@Schema(description = "预计替换日期", example = "2026-03-15")
|
||||||
|
private LocalDate expectedDate;
|
||||||
|
|
||||||
|
@Schema(description = "实际替换日期", example = "2026-03-15")
|
||||||
|
private LocalDate actualDate;
|
||||||
|
|
||||||
|
@Schema(description = "临时替换预计归还日期", example = "2026-04-15")
|
||||||
|
private LocalDate returnDate;
|
||||||
|
|
||||||
|
@Schema(description = "实际归还日期", example = "2026-04-15")
|
||||||
|
private LocalDate actualReturnDate;
|
||||||
|
|
||||||
|
@Schema(description = "状态(0=草稿 1=审批中 2=审批通过 3=执行中 4=已完成 5=审批驳回 6=已撤回)", example = "0")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "审批状态", example = "0")
|
||||||
|
private Integer approvalStatus;
|
||||||
|
|
||||||
|
@Schema(description = "BPM流程实例ID", example = "123456")
|
||||||
|
private String bpmInstanceId;
|
||||||
|
|
||||||
|
@Schema(description = "备注", example = "紧急替换")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间", example = "2026-03-13 10:00:00")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "创建者", example = "admin")
|
||||||
|
private String creator;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.replacement.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车申请创建/更新 Request VO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Schema(description = "管理后台 - 替换车申请创建/更新 Request VO")
|
||||||
|
@Data
|
||||||
|
public class VehicleReplacementSaveReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "主键ID", example = "1")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "替换类型(1=临时 2=永久)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@NotNull(message = "替换类型不能为空")
|
||||||
|
private Integer replacementType;
|
||||||
|
|
||||||
|
@Schema(description = "合同ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@NotNull(message = "合同不能为空")
|
||||||
|
private Long contractId;
|
||||||
|
|
||||||
|
@Schema(description = "合同编码", example = "HT-2026-0001")
|
||||||
|
private String contractCode;
|
||||||
|
|
||||||
|
@Schema(description = "客户ID", example = "1")
|
||||||
|
private Long customerId;
|
||||||
|
|
||||||
|
@Schema(description = "客户名称", example = "上海某某科技")
|
||||||
|
private String customerName;
|
||||||
|
|
||||||
|
@Schema(description = "来源交车单ID", example = "1")
|
||||||
|
private Long deliveryOrderId;
|
||||||
|
|
||||||
|
@Schema(description = "原车辆ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@NotNull(message = "原车辆不能为空")
|
||||||
|
private Long originalVehicleId;
|
||||||
|
|
||||||
|
@Schema(description = "原车牌号", example = "沪A12345")
|
||||||
|
private String originalPlateNo;
|
||||||
|
|
||||||
|
@Schema(description = "原车架号", example = "LVHRU1867N5012345")
|
||||||
|
private String originalVin;
|
||||||
|
|
||||||
|
@Schema(description = "新车辆ID", example = "2")
|
||||||
|
private Long newVehicleId;
|
||||||
|
|
||||||
|
@Schema(description = "新车牌号", example = "沪B67890")
|
||||||
|
private String newPlateNo;
|
||||||
|
|
||||||
|
@Schema(description = "新车架号", example = "LVHRU1867N5067890")
|
||||||
|
private String newVin;
|
||||||
|
|
||||||
|
@Schema(description = "替换原因", example = "车辆故障需维修")
|
||||||
|
private String replacementReason;
|
||||||
|
|
||||||
|
@Schema(description = "预计替换日期", example = "2026-03-15")
|
||||||
|
private LocalDate expectedDate;
|
||||||
|
|
||||||
|
@Schema(description = "临时替换预计归还日期", example = "2026-04-15")
|
||||||
|
private LocalDate returnDate;
|
||||||
|
|
||||||
|
@Schema(description = "备注", example = "紧急替换")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.controller.admin.returnorder;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.returnorder.ReturnOrderDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.returnorder.ReturnOrderService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
@Tag(name = "管理后台 - 还车管理")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/asset/return-order")
|
||||||
|
@Validated
|
||||||
|
public class ReturnOrderController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ReturnOrderService returnOrderService;
|
||||||
|
|
||||||
|
@PostMapping("/create")
|
||||||
|
@Operation(summary = "创建还车单")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:return-order:create')")
|
||||||
|
public CommonResult<Long> createReturnOrder(@Valid @RequestBody ReturnOrderSaveReqVO createReqVO) {
|
||||||
|
return success(returnOrderService.createReturnOrder(createReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/update")
|
||||||
|
@Operation(summary = "更新还车单")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||||
|
public CommonResult<Boolean> updateReturnOrder(@Valid @RequestBody ReturnOrderSaveReqVO updateReqVO) {
|
||||||
|
returnOrderService.updateReturnOrder(updateReqVO);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/delete")
|
||||||
|
@Operation(summary = "删除还车单")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:return-order:delete')")
|
||||||
|
public CommonResult<Boolean> deleteReturnOrder(@RequestParam("id") Long id) {
|
||||||
|
returnOrderService.deleteReturnOrder(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get")
|
||||||
|
@Operation(summary = "获得还车单详情")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:return-order:query')")
|
||||||
|
public CommonResult<ReturnOrderRespVO> getReturnOrder(@RequestParam("id") Long id) {
|
||||||
|
return success(returnOrderService.getReturnOrderDetail(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
@Operation(summary = "获得还车单分页")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:return-order:query')")
|
||||||
|
public CommonResult<PageResult<ReturnOrderRespVO>> getReturnOrderPage(@Valid ReturnOrderPageReqVO pageReqVO) {
|
||||||
|
PageResult<ReturnOrderDO> pageResult = returnOrderService.getReturnOrderPage(pageReqVO);
|
||||||
|
return success(BeanUtils.toBean(pageResult, ReturnOrderRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/complete-inspection")
|
||||||
|
@Operation(summary = "完成验车")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||||
|
public CommonResult<Boolean> completeInspection(@RequestParam("id") Long id) {
|
||||||
|
returnOrderService.completeInspection(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/settle")
|
||||||
|
@Operation(summary = "结算还车单")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||||
|
public CommonResult<Boolean> settleReturnOrder(@RequestParam("id") Long id) {
|
||||||
|
returnOrderService.settleReturnOrder(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/create-from-delivery")
|
||||||
|
@Operation(summary = "从交车单创建还车单")
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:return-order:create')")
|
||||||
|
public CommonResult<Long> createFromDelivery(@RequestParam("deliveryOrderId") Long deliveryOrderId,
|
||||||
|
@RequestParam("vehicleIds") List<Long> vehicleIds) {
|
||||||
|
return success(returnOrderService.createFromDelivery(deliveryOrderId, vehicleIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/start-inspection")
|
||||||
|
@Operation(summary = "开始单车验车")
|
||||||
|
@Parameter(name = "returnOrderVehicleId", description = "还车车辆ID", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||||
|
public CommonResult<Long> startVehicleInspection(@RequestParam("returnOrderVehicleId") Long returnOrderVehicleId) {
|
||||||
|
return success(returnOrderService.startVehicleInspection(returnOrderVehicleId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/complete-vehicle-inspection")
|
||||||
|
@Operation(summary = "完成单车验车")
|
||||||
|
@Parameter(name = "returnOrderVehicleId", description = "还车车辆ID", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||||
|
public CommonResult<Boolean> completeVehicleInspection(@RequestParam("returnOrderVehicleId") Long returnOrderVehicleId) {
|
||||||
|
returnOrderService.completeVehicleInspection(returnOrderVehicleId);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/submit")
|
||||||
|
@Operation(summary = "提交审批")
|
||||||
|
@Parameter(name = "id", description = "还车单ID", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||||
|
public CommonResult<Boolean> submitApproval(@RequestParam("id") Long id) {
|
||||||
|
returnOrderService.submitApproval(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/withdraw")
|
||||||
|
@Operation(summary = "撤回审批")
|
||||||
|
@Parameter(name = "id", description = "还车单ID", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('asset:return-order:update')")
|
||||||
|
public CommonResult<Boolean> withdrawApproval(@RequestParam("id") Long id) {
|
||||||
|
returnOrderService.withdrawApproval(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.convert.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.*;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车模板/记录 Convert
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface InspectionConvert {
|
||||||
|
|
||||||
|
InspectionConvert INSTANCE = Mappers.getMapper(InspectionConvert.class);
|
||||||
|
|
||||||
|
InspectionTemplateDO convert(InspectionTemplateSaveReqVO bean);
|
||||||
|
|
||||||
|
InspectionTemplateRespVO convert(InspectionTemplateDO bean);
|
||||||
|
|
||||||
|
PageResult<InspectionTemplateRespVO> convertPage(PageResult<InspectionTemplateDO> page);
|
||||||
|
|
||||||
|
List<InspectionTemplateItemDO> convertItemList(List<InspectionTemplateItemVO> list);
|
||||||
|
|
||||||
|
InspectionTemplateItemDO convertItem(InspectionTemplateItemVO bean);
|
||||||
|
|
||||||
|
List<InspectionTemplateItemVO> convertItemVOList(List<InspectionTemplateItemDO> list);
|
||||||
|
|
||||||
|
InspectionTemplateItemVO convertItemVO(InspectionTemplateItemDO bean);
|
||||||
|
|
||||||
|
InspectionRecordDetailVO convertRecordDetail(InspectionRecordDO bean);
|
||||||
|
|
||||||
|
List<InspectionRecordDetailVO.InspectionRecordItemVO> convertRecordItemVOList(List<InspectionRecordItemDO> list);
|
||||||
|
|
||||||
|
InspectionRecordDetailVO.InspectionRecordItemVO convertRecordItemVO(InspectionRecordItemDO bean);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.convert.replacement;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.replacement.vo.VehicleReplacementRespVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.replacement.vo.VehicleReplacementSaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.replacement.VehicleReplacementDO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车申请 Convert
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface VehicleReplacementConvert {
|
||||||
|
|
||||||
|
VehicleReplacementConvert INSTANCE = Mappers.getMapper(VehicleReplacementConvert.class);
|
||||||
|
|
||||||
|
VehicleReplacementDO convert(VehicleReplacementSaveReqVO bean);
|
||||||
|
|
||||||
|
VehicleReplacementRespVO convert(VehicleReplacementDO bean);
|
||||||
|
|
||||||
|
PageResult<VehicleReplacementRespVO> convertPage(PageResult<VehicleReplacementDO> page);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.dataobject.delivery;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交车单 DO
|
||||||
|
*/
|
||||||
|
@TableName("asset_delivery_order")
|
||||||
|
@KeySequence("asset_delivery_order_seq")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class DeliveryOrderDO extends BaseDO {
|
||||||
|
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
private String orderCode;
|
||||||
|
private Long taskId;
|
||||||
|
private String taskCode;
|
||||||
|
private Long contractId;
|
||||||
|
private String contractCode;
|
||||||
|
private String projectName;
|
||||||
|
private Long customerId;
|
||||||
|
private String customerName;
|
||||||
|
private LocalDateTime deliveryDate;
|
||||||
|
private String deliveryPerson;
|
||||||
|
private String deliveryLocation;
|
||||||
|
private Long authorizedPersonId;
|
||||||
|
private String authorizedPersonName;
|
||||||
|
private String authorizedPersonPhone;
|
||||||
|
private String authorizedPersonIdCard;
|
||||||
|
private String esignFlowId;
|
||||||
|
private Integer esignStatus;
|
||||||
|
private String deliveryPhotos;
|
||||||
|
private String driverName;
|
||||||
|
private String driverIdCard;
|
||||||
|
private String driverPhone;
|
||||||
|
private String inspectionData;
|
||||||
|
private String costList;
|
||||||
|
/**
|
||||||
|
* 关联验车记录ID
|
||||||
|
*/
|
||||||
|
private Long inspectionRecordId;
|
||||||
|
/**
|
||||||
|
* 状态(0=待完成 1=已完成)
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.dataobject.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车记录 DO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@TableName("asset_inspection_record")
|
||||||
|
@KeySequence("asset_inspection_record_seq")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class InspectionRecordDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录编码
|
||||||
|
*/
|
||||||
|
private String recordCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板ID
|
||||||
|
*/
|
||||||
|
private Long templateId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 来源类型(1=备车 2=交车 3=还车)
|
||||||
|
*/
|
||||||
|
private Integer sourceType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 来源ID
|
||||||
|
*/
|
||||||
|
private Long sourceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车辆ID
|
||||||
|
*/
|
||||||
|
private Long vehicleId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查人
|
||||||
|
*/
|
||||||
|
private String inspectorName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime inspectionTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0=待检 1=检查中 2=已完成)
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总体结果(1=通过 2=不通过 3=不适用)
|
||||||
|
*/
|
||||||
|
private Integer overallResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 克隆来源记录ID
|
||||||
|
*/
|
||||||
|
private Long clonedFromId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.dataobject.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车记录检查项 DO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@TableName("asset_inspection_record_item")
|
||||||
|
@KeySequence("asset_inspection_record_item_seq")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class InspectionRecordItemDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录ID
|
||||||
|
*/
|
||||||
|
private Long recordId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查项编码
|
||||||
|
*/
|
||||||
|
private String itemCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类
|
||||||
|
*/
|
||||||
|
private String category;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查项名称
|
||||||
|
*/
|
||||||
|
private String itemName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输入类型
|
||||||
|
*/
|
||||||
|
private String inputType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查结果(1=通过 2=不通过 3=不适用)
|
||||||
|
*/
|
||||||
|
private Integer result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查值
|
||||||
|
*/
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片URL列表
|
||||||
|
*/
|
||||||
|
private String imageUrls;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.dataobject.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车模板 DO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@TableName("asset_inspection_template")
|
||||||
|
@KeySequence("asset_inspection_template_seq")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class InspectionTemplateDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板编码
|
||||||
|
*/
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务类型(1=备车 2=交车 3=还车)
|
||||||
|
*/
|
||||||
|
private Integer bizType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车辆类型
|
||||||
|
*/
|
||||||
|
private String vehicleType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0=禁用 1=启用)
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.dataobject.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车模板检查项 DO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@TableName("asset_inspection_template_item")
|
||||||
|
@KeySequence("asset_inspection_template_item_seq")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class InspectionTemplateItemDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板ID
|
||||||
|
*/
|
||||||
|
private Long templateId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类
|
||||||
|
*/
|
||||||
|
private String category;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查项名称
|
||||||
|
*/
|
||||||
|
private String itemName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查项编码
|
||||||
|
*/
|
||||||
|
private String itemCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输入类型
|
||||||
|
*/
|
||||||
|
private String inputType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序
|
||||||
|
*/
|
||||||
|
private Integer sort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否必填(0=否 1=是)
|
||||||
|
*/
|
||||||
|
private Integer required;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.dataobject.prepare;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备车记录 DO
|
||||||
|
*/
|
||||||
|
@TableName("asset_vehicle_prepare")
|
||||||
|
@KeySequence("asset_vehicle_prepare_seq")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class VehiclePrepareDO extends BaseDO {
|
||||||
|
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
private Long vehicleId;
|
||||||
|
private String plateNo;
|
||||||
|
private String vin;
|
||||||
|
private Long vehicleModelId;
|
||||||
|
private String brand;
|
||||||
|
private String model;
|
||||||
|
private String vehicleType;
|
||||||
|
private String parkingLot;
|
||||||
|
private Long contractId;
|
||||||
|
private String contractCode;
|
||||||
|
private String preparationType;
|
||||||
|
private Integer mileage;
|
||||||
|
private BigDecimal hydrogenRemaining;
|
||||||
|
private String hydrogenUnit;
|
||||||
|
private BigDecimal batteryRemaining;
|
||||||
|
private Boolean hasBodyAd;
|
||||||
|
private String bodyAdPhotos;
|
||||||
|
private String enlargedTextPhoto;
|
||||||
|
private Boolean hasTailLift;
|
||||||
|
private BigDecimal spareTireDepth;
|
||||||
|
private String spareTirePhoto;
|
||||||
|
private String trailerPlateNo;
|
||||||
|
private String defectPhotos;
|
||||||
|
/**
|
||||||
|
* 关联验车记录ID
|
||||||
|
*/
|
||||||
|
private Long inspectionRecordId;
|
||||||
|
private String checkList;
|
||||||
|
private String remark;
|
||||||
|
/**
|
||||||
|
* 状态(0=待提交 1=已完成)
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
private LocalDateTime completeTime;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.dataobject.replacement;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车申请 DO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@TableName("asset_vehicle_replacement")
|
||||||
|
@KeySequence("asset_vehicle_replacement_seq")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class VehicleReplacementDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换单编码
|
||||||
|
*/
|
||||||
|
private String replacementCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换类型(1=临时 2=永久)
|
||||||
|
*/
|
||||||
|
private Integer replacementType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合同ID
|
||||||
|
*/
|
||||||
|
private Long contractId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合同编码(冗余)
|
||||||
|
*/
|
||||||
|
private String contractCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户ID
|
||||||
|
*/
|
||||||
|
private Long customerId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户名称(冗余)
|
||||||
|
*/
|
||||||
|
private String customerName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 来源交车单ID
|
||||||
|
*/
|
||||||
|
private Long deliveryOrderId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原车辆ID
|
||||||
|
*/
|
||||||
|
private Long originalVehicleId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原车牌号(冗余)
|
||||||
|
*/
|
||||||
|
private String originalPlateNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原车架号(冗余)
|
||||||
|
*/
|
||||||
|
private String originalVin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新车辆ID
|
||||||
|
*/
|
||||||
|
private Long newVehicleId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新车牌号(冗余)
|
||||||
|
*/
|
||||||
|
private String newPlateNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新车架号(冗余)
|
||||||
|
*/
|
||||||
|
private String newVin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换原因
|
||||||
|
*/
|
||||||
|
private String replacementReason;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预计替换日期
|
||||||
|
*/
|
||||||
|
private LocalDate expectedDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际替换日期
|
||||||
|
*/
|
||||||
|
private LocalDate actualDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 临时替换预计归还日期
|
||||||
|
*/
|
||||||
|
private LocalDate returnDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际归还日期
|
||||||
|
*/
|
||||||
|
private LocalDate actualReturnDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0=草稿 1=审批中 2=审批通过 3=执行中 4=已完成 5=审批驳回 6=已撤回)
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批状态
|
||||||
|
*/
|
||||||
|
private Integer approvalStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BPM流程实例ID
|
||||||
|
*/
|
||||||
|
private String bpmInstanceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.dataobject.returnorder;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 还车单 DO
|
||||||
|
*/
|
||||||
|
@TableName("asset_return_order")
|
||||||
|
@KeySequence("asset_return_order_seq")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ReturnOrderDO extends BaseDO {
|
||||||
|
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
private String orderCode;
|
||||||
|
private Long contractId;
|
||||||
|
private String contractCode;
|
||||||
|
private String projectName;
|
||||||
|
private Long customerId;
|
||||||
|
private String customerName;
|
||||||
|
private LocalDateTime returnDate;
|
||||||
|
private String returnPerson;
|
||||||
|
private String returnLocation;
|
||||||
|
private String returnReason;
|
||||||
|
private String returnReasonDesc;
|
||||||
|
private BigDecimal totalRefundAmount;
|
||||||
|
private BigDecimal depositRefund;
|
||||||
|
private BigDecimal hydrogenRefund;
|
||||||
|
private BigDecimal otherCharges;
|
||||||
|
private String returnPhotos;
|
||||||
|
/**
|
||||||
|
* 状态(0=待验车 1=验车完成 2=已结算)
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
private Integer approvalStatus;
|
||||||
|
private String bpmInstanceId;
|
||||||
|
/**
|
||||||
|
* 来源:1=手动 2=替换车触发
|
||||||
|
*/
|
||||||
|
private Integer sourceType;
|
||||||
|
/**
|
||||||
|
* 来源业务ID
|
||||||
|
*/
|
||||||
|
private Long sourceId;
|
||||||
|
/**
|
||||||
|
* 关联交车单ID
|
||||||
|
*/
|
||||||
|
private Long deliveryOrderId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.dataobject.returnorder;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 还车车辆 DO
|
||||||
|
*/
|
||||||
|
@TableName("asset_return_order_vehicle")
|
||||||
|
@KeySequence("asset_return_order_vehicle_seq")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ReturnOrderVehicleDO extends BaseDO {
|
||||||
|
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
private Long returnOrderId;
|
||||||
|
private Long vehicleId;
|
||||||
|
private String plateNo;
|
||||||
|
private String vin;
|
||||||
|
private String brand;
|
||||||
|
private String model;
|
||||||
|
private Integer returnMileage;
|
||||||
|
private BigDecimal returnHydrogenLevel;
|
||||||
|
private BigDecimal deliveryHydrogenLevel;
|
||||||
|
private BigDecimal hydrogenDiff;
|
||||||
|
private BigDecimal hydrogenUnitPrice;
|
||||||
|
private BigDecimal hydrogenRefundAmount;
|
||||||
|
private String checkList;
|
||||||
|
private String defectPhotos;
|
||||||
|
private BigDecimal vehicleDamageFee;
|
||||||
|
private BigDecimal toolDamageFee;
|
||||||
|
private BigDecimal unpaidMaintenanceFee;
|
||||||
|
private BigDecimal unpaidRepairFee;
|
||||||
|
private BigDecimal violationFee;
|
||||||
|
private BigDecimal otherFee;
|
||||||
|
/**
|
||||||
|
* 关联验车记录ID
|
||||||
|
*/
|
||||||
|
private Long inspectionRecordId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.mysql.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionRecordItemDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车记录检查项 Mapper
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface InspectionRecordItemMapper extends BaseMapperX<InspectionRecordItemDO> {
|
||||||
|
|
||||||
|
default List<InspectionRecordItemDO> selectByRecordId(Long recordId) {
|
||||||
|
return selectList(new LambdaQueryWrapperX<InspectionRecordItemDO>()
|
||||||
|
.eq(InspectionRecordItemDO::getRecordId, recordId)
|
||||||
|
.orderByAsc(InspectionRecordItemDO::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
default int deleteByRecordId(Long recordId) {
|
||||||
|
return delete(new LambdaQueryWrapperX<InspectionRecordItemDO>()
|
||||||
|
.eq(InspectionRecordItemDO::getRecordId, recordId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.mysql.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionRecordDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车记录 Mapper
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface InspectionRecordMapper extends BaseMapperX<InspectionRecordDO> {
|
||||||
|
|
||||||
|
default InspectionRecordDO selectLatestByVehicleAndSourceType(Long vehicleId, Integer sourceType) {
|
||||||
|
return selectOne(new LambdaQueryWrapperX<InspectionRecordDO>()
|
||||||
|
.eq(InspectionRecordDO::getVehicleId, vehicleId)
|
||||||
|
.eq(InspectionRecordDO::getSourceType, sourceType)
|
||||||
|
.eq(InspectionRecordDO::getStatus, 2)
|
||||||
|
.orderByDesc(InspectionRecordDO::getId)
|
||||||
|
.last("LIMIT 1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.mysql.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionTemplateItemDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车模板检查项 Mapper
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface InspectionTemplateItemMapper extends BaseMapperX<InspectionTemplateItemDO> {
|
||||||
|
|
||||||
|
default List<InspectionTemplateItemDO> selectByTemplateId(Long templateId) {
|
||||||
|
return selectList(new LambdaQueryWrapperX<InspectionTemplateItemDO>()
|
||||||
|
.eq(InspectionTemplateItemDO::getTemplateId, templateId)
|
||||||
|
.orderByAsc(InspectionTemplateItemDO::getSort));
|
||||||
|
}
|
||||||
|
|
||||||
|
default int deleteByTemplateId(Long templateId) {
|
||||||
|
return delete(new LambdaQueryWrapperX<InspectionTemplateItemDO>()
|
||||||
|
.eq(InspectionTemplateItemDO::getTemplateId, templateId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.mysql.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionTemplatePageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionTemplateDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车模板 Mapper
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface InspectionTemplateMapper extends BaseMapperX<InspectionTemplateDO> {
|
||||||
|
|
||||||
|
default PageResult<InspectionTemplateDO> selectPage(InspectionTemplatePageReqVO reqVO) {
|
||||||
|
return selectPage(reqVO, new LambdaQueryWrapperX<InspectionTemplateDO>()
|
||||||
|
.likeIfPresent(InspectionTemplateDO::getCode, reqVO.getCode())
|
||||||
|
.likeIfPresent(InspectionTemplateDO::getName, reqVO.getName())
|
||||||
|
.eqIfPresent(InspectionTemplateDO::getBizType, reqVO.getBizType())
|
||||||
|
.eqIfPresent(InspectionTemplateDO::getStatus, reqVO.getStatus())
|
||||||
|
.orderByDesc(InspectionTemplateDO::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
default InspectionTemplateDO selectByBizTypeAndVehicleType(Integer bizType, String vehicleType) {
|
||||||
|
return selectOne(new LambdaQueryWrapperX<InspectionTemplateDO>()
|
||||||
|
.eq(InspectionTemplateDO::getBizType, bizType)
|
||||||
|
.eqIfPresent(InspectionTemplateDO::getVehicleType, vehicleType)
|
||||||
|
.eq(InspectionTemplateDO::getStatus, 1)
|
||||||
|
.last("LIMIT 1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
default InspectionTemplateDO selectDefaultByBizType(Integer bizType) {
|
||||||
|
return selectOne(new LambdaQueryWrapperX<InspectionTemplateDO>()
|
||||||
|
.eq(InspectionTemplateDO::getBizType, bizType)
|
||||||
|
.isNull(InspectionTemplateDO::getVehicleType)
|
||||||
|
.eq(InspectionTemplateDO::getStatus, 1)
|
||||||
|
.last("LIMIT 1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.dal.mysql.replacement;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.replacement.vo.VehicleReplacementPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.replacement.VehicleReplacementDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车申请 Mapper
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface VehicleReplacementMapper extends BaseMapperX<VehicleReplacementDO> {
|
||||||
|
|
||||||
|
default PageResult<VehicleReplacementDO> selectPage(VehicleReplacementPageReqVO reqVO) {
|
||||||
|
return selectPage(reqVO, new LambdaQueryWrapperX<VehicleReplacementDO>()
|
||||||
|
.likeIfPresent(VehicleReplacementDO::getReplacementCode, reqVO.getReplacementCode())
|
||||||
|
.eqIfPresent(VehicleReplacementDO::getReplacementType, reqVO.getReplacementType())
|
||||||
|
.eqIfPresent(VehicleReplacementDO::getContractId, reqVO.getContractId())
|
||||||
|
.likeIfPresent(VehicleReplacementDO::getCustomerName, reqVO.getCustomerName())
|
||||||
|
.eqIfPresent(VehicleReplacementDO::getStatus, reqVO.getStatus())
|
||||||
|
.orderByDesc(VehicleReplacementDO::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Select("SELECT replacement_code FROM asset_vehicle_replacement WHERE replacement_code LIKE CONCAT(#{prefix}, '%') AND deleted = 0 ORDER BY replacement_code DESC LIMIT 1")
|
||||||
|
String selectMaxReplacementCodeByPrefix(@Param("prefix") String prefix);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -23,4 +23,59 @@ public interface ErrorCodeConstants {
|
|||||||
// ========== 供应商管理 1-008-004-000 ==========
|
// ========== 供应商管理 1-008-004-000 ==========
|
||||||
ErrorCode SUPPLIER_NOT_EXISTS = new ErrorCode(1_008_004_000, "供应商不存在");
|
ErrorCode SUPPLIER_NOT_EXISTS = new ErrorCode(1_008_004_000, "供应商不存在");
|
||||||
|
|
||||||
|
// ========== 车辆租赁合同管理 1-008-005-000 ==========
|
||||||
|
ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_008_005_000, "合同不存在");
|
||||||
|
ErrorCode CONTRACT_CODE_DUPLICATE = new ErrorCode(1_008_005_001, "合同编码已存在");
|
||||||
|
ErrorCode CONTRACT_STATUS_NOT_ALLOW_UPDATE = new ErrorCode(1_008_005_002, "当前合同状态不允许修改");
|
||||||
|
ErrorCode CONTRACT_STATUS_NOT_ALLOW_DELETE = new ErrorCode(1_008_005_003, "当前合同状态不允许删除");
|
||||||
|
ErrorCode CONTRACT_STATUS_NOT_ALLOW_SUBMIT = new ErrorCode(1_008_005_004, "当前合同状态不允许提交审批");
|
||||||
|
ErrorCode CONTRACT_STATUS_NOT_ALLOW_WITHDRAW = new ErrorCode(1_008_005_005, "当前合同状态不允许撤回");
|
||||||
|
ErrorCode CONTRACT_STATUS_NOT_ALLOW_TERMINATE = new ErrorCode(1_008_005_006, "当前合同状态不允许终止");
|
||||||
|
ErrorCode CONTRACT_STATUS_NOT_ALLOW_RENEW = new ErrorCode(1_008_005_007, "当前合同状态不允许续签");
|
||||||
|
ErrorCode CONTRACT_END_DATE_BEFORE_START_DATE = new ErrorCode(1_008_005_008, "合同结束日期不能早于开始日期");
|
||||||
|
ErrorCode CONTRACT_VEHICLE_TIME_CONFLICT = new ErrorCode(1_008_005_009, "该车辆在此时间段内已有有效合同");
|
||||||
|
ErrorCode CONTRACT_STATUS_NOT_ALLOW_CONVERT = new ErrorCode(1_008_005_010, "当前合同状态不允许变更");
|
||||||
|
ErrorCode CONTRACT_STATUS_NOT_ALLOW_ADD_VEHICLE = new ErrorCode(1_008_005_011, "当前合同状态不允许新增车辆");
|
||||||
|
ErrorCode CONTRACT_TYPE_NOT_TRIAL = new ErrorCode(1_008_005_012, "只有试用合同才能转正式");
|
||||||
|
|
||||||
|
// ========== 车辆登记 1-008-006-000 ==========
|
||||||
|
ErrorCode VEHICLE_REGISTRATION_NOT_EXISTS = new ErrorCode(1_008_006_000, "车辆登记不存在");
|
||||||
|
|
||||||
|
// ========== 备车管理 1-008-007-000 ==========
|
||||||
|
ErrorCode VEHICLE_PREPARE_NOT_EXISTS = new ErrorCode(1_008_007_000, "备车记录不存在");
|
||||||
|
ErrorCode VEHICLE_PREPARE_ALREADY_COMPLETED = new ErrorCode(1_008_007_001, "备车记录已完成,不允许修改");
|
||||||
|
|
||||||
|
// ========== 交车任务管理 1-008-008-000 ==========
|
||||||
|
ErrorCode DELIVERY_TASK_NOT_EXISTS = new ErrorCode(1_008_008_000, "交车任务不存在");
|
||||||
|
ErrorCode DELIVERY_TASK_ALREADY_DELIVERED = new ErrorCode(1_008_008_001, "交车任务已完成交车");
|
||||||
|
ErrorCode DELIVERY_TASK_SUSPENDED = new ErrorCode(1_008_008_002, "交车任务已挂起");
|
||||||
|
|
||||||
|
// ========== 交车单管理 1-008-009-000 ==========
|
||||||
|
ErrorCode DELIVERY_ORDER_NOT_EXISTS = new ErrorCode(1_008_009_000, "交车单不存在");
|
||||||
|
ErrorCode DELIVERY_ORDER_ALREADY_COMPLETED = new ErrorCode(1_008_009_001, "交车单已完成");
|
||||||
|
|
||||||
|
// ========== 还车单管理 1-008-010-000 ==========
|
||||||
|
ErrorCode RETURN_ORDER_NOT_EXISTS = new ErrorCode(1_008_010_000, "还车单不存在");
|
||||||
|
ErrorCode RETURN_ORDER_ALREADY_SETTLED = new ErrorCode(1_008_010_001, "还车单已结算");
|
||||||
|
ErrorCode RETURN_ORDER_VEHICLE_NOT_EXISTS = new ErrorCode(1_008_010_002, "还车车辆不存在");
|
||||||
|
ErrorCode RETURN_ORDER_STATUS_NOT_ALLOW_SUBMIT = new ErrorCode(1_008_010_003, "当前状态不允许提交审批");
|
||||||
|
ErrorCode RETURN_ORDER_STATUS_NOT_ALLOW_WITHDRAW = new ErrorCode(1_008_010_004, "当前状态不允许撤回");
|
||||||
|
ErrorCode RETURN_ORDER_INSPECTION_ALREADY_STARTED = new ErrorCode(1_008_010_005, "该车辆验车已开始");
|
||||||
|
ErrorCode RETURN_ORDER_INSPECTION_NOT_STARTED = new ErrorCode(1_008_010_006, "该车辆验车未开始");
|
||||||
|
|
||||||
|
// ========== 验车模板管理 1-008-011-000 ==========
|
||||||
|
ErrorCode INSPECTION_TEMPLATE_NOT_EXISTS = new ErrorCode(1_008_011_000, "验车模板不存在");
|
||||||
|
ErrorCode INSPECTION_RECORD_NOT_EXISTS = new ErrorCode(1_008_011_001, "验车记录不存在");
|
||||||
|
ErrorCode INSPECTION_RECORD_ALREADY_COMPLETED = new ErrorCode(1_008_011_002, "验车记录已完成");
|
||||||
|
ErrorCode INSPECTION_RECORD_REQUIRED_ITEMS_INCOMPLETE = new ErrorCode(1_008_011_003, "必填检查项未全部完成");
|
||||||
|
ErrorCode INSPECTION_TEMPLATE_MATCH_FAILED = new ErrorCode(1_008_011_004, "未找到匹配的验车模板");
|
||||||
|
|
||||||
|
// ========== 替换车管理 1-008-012-000 ==========
|
||||||
|
ErrorCode VEHICLE_REPLACEMENT_NOT_EXISTS = new ErrorCode(1_008_012_000, "替换车申请不存在");
|
||||||
|
ErrorCode VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_UPDATE = new ErrorCode(1_008_012_001, "当前状态不允许修改");
|
||||||
|
ErrorCode VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_DELETE = new ErrorCode(1_008_012_002, "当前状态不允许删除");
|
||||||
|
ErrorCode VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_SUBMIT = new ErrorCode(1_008_012_003, "当前状态不允许提交审批");
|
||||||
|
ErrorCode VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_WITHDRAW = new ErrorCode(1_008_012_004, "当前状态不允许撤回");
|
||||||
|
ErrorCode VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_CONFIRM = new ErrorCode(1_008_012_005, "当前状态不允许确认换回");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,182 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.delivery;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.delivery.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.*;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionRecordDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.delivery.*;
|
||||||
|
import cn.iocoder.yudao.module.asset.enums.inspection.InspectionSourceTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.inspection.InspectionRecordService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
public class DeliveryOrderServiceImpl implements DeliveryOrderService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeliveryOrderMapper deliveryOrderMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeliveryOrderVehicleMapper deliveryOrderVehicleMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeliveryTaskMapper deliveryTaskMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeliveryTaskVehicleMapper deliveryTaskVehicleMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionRecordService inspectionRecordService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createDeliveryOrder(DeliveryOrderSaveReqVO createReqVO) {
|
||||||
|
// Get task info
|
||||||
|
DeliveryTaskDO task = deliveryTaskMapper.selectById(createReqVO.getTaskId());
|
||||||
|
if (task == null) {
|
||||||
|
throw exception(DELIVERY_TASK_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
if (task.getTaskStatus().equals(1)) {
|
||||||
|
throw exception(DELIVERY_TASK_SUSPENDED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate order code
|
||||||
|
String orderCode = task.getTaskCode() + "O0001";
|
||||||
|
|
||||||
|
DeliveryOrderDO order = BeanUtils.toBean(createReqVO, DeliveryOrderDO.class);
|
||||||
|
order.setOrderCode(orderCode);
|
||||||
|
order.setTaskCode(task.getTaskCode());
|
||||||
|
order.setContractId(task.getContractId());
|
||||||
|
order.setContractCode(task.getContractCode());
|
||||||
|
order.setProjectName(task.getProjectName());
|
||||||
|
order.setCustomerId(task.getCustomerId());
|
||||||
|
order.setCustomerName(task.getCustomerName());
|
||||||
|
order.setStatus(0); // pending
|
||||||
|
order.setEsignStatus(0);
|
||||||
|
deliveryOrderMapper.insert(order);
|
||||||
|
|
||||||
|
// Insert vehicles
|
||||||
|
if (createReqVO.getVehicles() != null) {
|
||||||
|
for (DeliveryOrderVehicleVO vehicleVO : createReqVO.getVehicles()) {
|
||||||
|
DeliveryOrderVehicleDO vehicle = BeanUtils.toBean(vehicleVO, DeliveryOrderVehicleDO.class);
|
||||||
|
vehicle.setOrderId(order.getId());
|
||||||
|
deliveryOrderVehicleMapper.insert(vehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从第一辆车的备车验车记录克隆交车验车记录
|
||||||
|
DeliveryOrderVehicleVO firstVehicle = createReqVO.getVehicles().get(0);
|
||||||
|
if (firstVehicle.getVehicleId() != null) {
|
||||||
|
InspectionRecordDO prepareRecord = inspectionRecordService.getLatestRecord(
|
||||||
|
firstVehicle.getVehicleId(), InspectionSourceTypeEnum.PREPARE.getType());
|
||||||
|
if (prepareRecord != null) {
|
||||||
|
Long inspectionRecordId = inspectionRecordService.cloneRecord(
|
||||||
|
prepareRecord.getId(), InspectionSourceTypeEnum.DELIVERY.getType(), order.getId());
|
||||||
|
deliveryOrderMapper.updateById(DeliveryOrderDO.builder()
|
||||||
|
.id(order.getId()).inspectionRecordId(inspectionRecordId).build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return order.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void updateDeliveryOrder(DeliveryOrderSaveReqVO updateReqVO) {
|
||||||
|
DeliveryOrderDO order = validateDeliveryOrderExists(updateReqVO.getId());
|
||||||
|
if (order.getStatus().equals(1)) {
|
||||||
|
throw exception(DELIVERY_ORDER_ALREADY_COMPLETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeliveryOrderDO updateObj = BeanUtils.toBean(updateReqVO, DeliveryOrderDO.class);
|
||||||
|
deliveryOrderMapper.updateById(updateObj);
|
||||||
|
|
||||||
|
// Update vehicles
|
||||||
|
if (updateReqVO.getVehicles() != null) {
|
||||||
|
deliveryOrderVehicleMapper.deleteByOrderId(updateReqVO.getId());
|
||||||
|
for (DeliveryOrderVehicleVO vehicleVO : updateReqVO.getVehicles()) {
|
||||||
|
DeliveryOrderVehicleDO vehicle = BeanUtils.toBean(vehicleVO, DeliveryOrderVehicleDO.class);
|
||||||
|
vehicle.setOrderId(updateReqVO.getId());
|
||||||
|
deliveryOrderVehicleMapper.insert(vehicle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void deleteDeliveryOrder(Long id) {
|
||||||
|
validateDeliveryOrderExists(id);
|
||||||
|
deliveryOrderMapper.deleteById(id);
|
||||||
|
deliveryOrderVehicleMapper.deleteByOrderId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeliveryOrderDO getDeliveryOrder(Long id) {
|
||||||
|
return deliveryOrderMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeliveryOrderRespVO getDeliveryOrderDetail(Long id) {
|
||||||
|
DeliveryOrderDO order = validateDeliveryOrderExists(id);
|
||||||
|
DeliveryOrderRespVO respVO = BeanUtils.toBean(order, DeliveryOrderRespVO.class);
|
||||||
|
List<DeliveryOrderVehicleDO> vehicles = deliveryOrderVehicleMapper.selectListByOrderId(id);
|
||||||
|
respVO.setVehicles(BeanUtils.toBean(vehicles, DeliveryOrderVehicleVO.class));
|
||||||
|
return respVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<DeliveryOrderDO> getDeliveryOrderPage(DeliveryOrderPageReqVO pageReqVO) {
|
||||||
|
return deliveryOrderMapper.selectPage(pageReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void completeDeliveryOrder(Long id) {
|
||||||
|
DeliveryOrderDO order = validateDeliveryOrderExists(id);
|
||||||
|
if (order.getStatus().equals(1)) {
|
||||||
|
throw exception(DELIVERY_ORDER_ALREADY_COMPLETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update order status
|
||||||
|
deliveryOrderMapper.updateById(DeliveryOrderDO.builder().id(id).status(1).build());
|
||||||
|
|
||||||
|
// Mark task vehicles as delivered
|
||||||
|
List<DeliveryOrderVehicleDO> orderVehicles = deliveryOrderVehicleMapper.selectListByOrderId(id);
|
||||||
|
for (DeliveryOrderVehicleDO ov : orderVehicles) {
|
||||||
|
deliveryTaskVehicleMapper.updateById(
|
||||||
|
DeliveryTaskVehicleDO.builder()
|
||||||
|
.id(ov.getTaskVehicleId())
|
||||||
|
.isDelivered(true)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if all task vehicles are delivered, update task delivery status
|
||||||
|
DeliveryTaskDO task = deliveryTaskMapper.selectById(order.getTaskId());
|
||||||
|
if (task != null) {
|
||||||
|
List<DeliveryTaskVehicleDO> taskVehicles = deliveryTaskVehicleMapper.selectListByTaskId(task.getId());
|
||||||
|
boolean allDelivered = taskVehicles.stream().allMatch(v -> Boolean.TRUE.equals(v.getIsDelivered()));
|
||||||
|
if (allDelivered) {
|
||||||
|
deliveryTaskMapper.updateById(DeliveryTaskDO.builder().id(task.getId()).deliveryStatus(1).build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeliveryOrderDO validateDeliveryOrderExists(Long id) {
|
||||||
|
DeliveryOrderDO order = deliveryOrderMapper.selectById(id);
|
||||||
|
if (order == null) {
|
||||||
|
throw exception(DELIVERY_ORDER_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.delivery.event;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交车完成事件
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class DeliveryCompletedEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交车单ID
|
||||||
|
*/
|
||||||
|
private final Long deliveryOrderId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车辆ID
|
||||||
|
*/
|
||||||
|
private final Long vehicleId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.event;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.asset.enums.replacement.ReplacementTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.replacement.event.ReplacementApprovedEvent;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.returnorder.ReturnOrderService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 还车单事件监听器
|
||||||
|
* 监听替换车审批通过事件,自动创建还车单
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class ReturnOrderEventListener {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ReturnOrderService returnOrderService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 永久替换审批通过时,自动创建还车单
|
||||||
|
* 使用 @EventListener 而非 @TransactionalEventListener,确保在同一事务中执行
|
||||||
|
*/
|
||||||
|
@EventListener
|
||||||
|
public void onReplacementApproved(ReplacementApprovedEvent event) {
|
||||||
|
if (event.getReplacementType().equals(ReplacementTypeEnum.PERMANENT.getType())) {
|
||||||
|
log.info("[onReplacementApproved] permanent replacement, creating return order: replacementId={}",
|
||||||
|
event.getReplacementId());
|
||||||
|
returnOrderService.createFromReplacement(
|
||||||
|
event.getReplacementId(),
|
||||||
|
event.getContractId(),
|
||||||
|
event.getOriginalVehicleId()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.event;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.asset.service.delivery.event.DeliveryCompletedEvent;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.replacement.event.ReplacementReturnConfirmedEvent;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.returnorder.event.ReturnApprovedEvent;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.event.TransactionalEventListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车辆状态事件监听器
|
||||||
|
* 负责在业务事件发生时更新车辆状态
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class VehicleStatusEventListener {
|
||||||
|
|
||||||
|
@TransactionalEventListener
|
||||||
|
public void onDeliveryCompleted(DeliveryCompletedEvent event) {
|
||||||
|
log.info("[onDeliveryCompleted] vehicleId={}", event.getVehicleId());
|
||||||
|
// TODO: update vehicle status to DELIVERED when vehicle status management is implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
@TransactionalEventListener
|
||||||
|
public void onReturnApproved(ReturnApprovedEvent event) {
|
||||||
|
log.info("[onReturnApproved] vehicleIds={}", event.getVehicleIds());
|
||||||
|
// TODO: update vehicle status to AVAILABLE when vehicle status management is implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
@TransactionalEventListener
|
||||||
|
public void onReplacementReturnConfirmed(ReplacementReturnConfirmedEvent event) {
|
||||||
|
log.info("[onReplacementReturnConfirmed] vehicleId={}", event.getOriginalVehicleId());
|
||||||
|
// TODO: update vehicle status to AVAILABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionRecordDetailVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionRecordItemUpdateReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionRecordDO;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车记录 Service 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface InspectionRecordService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建验车记录(根据模板生成检查项)
|
||||||
|
*/
|
||||||
|
Long createRecord(Long templateId, Integer sourceType, Long sourceId, Long vehicleId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 克隆验车记录(从已有记录克隆,保留结果数据)
|
||||||
|
*/
|
||||||
|
Long cloneRecord(Long sourceRecordId, Integer newSourceType, Long newSourceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新验车记录检查项
|
||||||
|
*/
|
||||||
|
void updateRecordItem(@Valid InspectionRecordItemUpdateReqVO updateReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完成验车记录
|
||||||
|
*/
|
||||||
|
void completeRecord(Long recordId, String inspectorName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取验车记录详情
|
||||||
|
*/
|
||||||
|
InspectionRecordDetailVO getRecordDetail(Long recordId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最新已完成的验车记录
|
||||||
|
*/
|
||||||
|
InspectionRecordDO getLatestRecord(Long vehicleId, Integer sourceType);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionRecordDetailVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionRecordItemUpdateReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.convert.inspection.InspectionConvert;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionRecordDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionRecordItemDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionTemplateItemDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.inspection.InspectionRecordItemMapper;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.inspection.InspectionRecordMapper;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.inspection.InspectionTemplateItemMapper;
|
||||||
|
import cn.iocoder.yudao.module.asset.enums.inspection.InspectionSourceTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.asset.enums.inspection.InspectionStatusEnum;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车记录 Service 实现类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
@Slf4j
|
||||||
|
public class InspectionRecordServiceImpl implements InspectionRecordService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionRecordMapper inspectionRecordMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionRecordItemMapper inspectionRecordItemMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionTemplateItemMapper inspectionTemplateItemMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createRecord(Long templateId, Integer sourceType, Long sourceId, Long vehicleId) {
|
||||||
|
// 查询模板检查项
|
||||||
|
List<InspectionTemplateItemDO> templateItems = inspectionTemplateItemMapper.selectByTemplateId(templateId);
|
||||||
|
|
||||||
|
// 生成记录编码
|
||||||
|
String recordCode = generateRecordCode(sourceType);
|
||||||
|
|
||||||
|
// 创建验车记录
|
||||||
|
InspectionRecordDO record = InspectionRecordDO.builder()
|
||||||
|
.recordCode(recordCode)
|
||||||
|
.templateId(templateId)
|
||||||
|
.sourceType(sourceType)
|
||||||
|
.sourceId(sourceId)
|
||||||
|
.vehicleId(vehicleId)
|
||||||
|
.status(InspectionStatusEnum.PENDING.getStatus())
|
||||||
|
.build();
|
||||||
|
inspectionRecordMapper.insert(record);
|
||||||
|
|
||||||
|
// 批量插入检查项(从模板复制)
|
||||||
|
if (!templateItems.isEmpty()) {
|
||||||
|
List<InspectionRecordItemDO> recordItems = new ArrayList<>(templateItems.size());
|
||||||
|
for (InspectionTemplateItemDO templateItem : templateItems) {
|
||||||
|
InspectionRecordItemDO recordItem = InspectionRecordItemDO.builder()
|
||||||
|
.recordId(record.getId())
|
||||||
|
.itemCode(templateItem.getItemCode())
|
||||||
|
.category(templateItem.getCategory())
|
||||||
|
.itemName(templateItem.getItemName())
|
||||||
|
.inputType(templateItem.getInputType())
|
||||||
|
.build();
|
||||||
|
recordItems.add(recordItem);
|
||||||
|
}
|
||||||
|
inspectionRecordItemMapper.insertBatch(recordItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
return record.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long cloneRecord(Long sourceRecordId, Integer newSourceType, Long newSourceId) {
|
||||||
|
// 查询源记录
|
||||||
|
InspectionRecordDO sourceRecord = inspectionRecordMapper.selectById(sourceRecordId);
|
||||||
|
if (sourceRecord == null) {
|
||||||
|
throw exception(INSPECTION_RECORD_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询源检查项
|
||||||
|
List<InspectionRecordItemDO> sourceItems = inspectionRecordItemMapper.selectByRecordId(sourceRecordId);
|
||||||
|
|
||||||
|
// 生成记录编码
|
||||||
|
String recordCode = generateRecordCode(newSourceType);
|
||||||
|
|
||||||
|
// 创建新记录
|
||||||
|
InspectionRecordDO newRecord = InspectionRecordDO.builder()
|
||||||
|
.recordCode(recordCode)
|
||||||
|
.templateId(sourceRecord.getTemplateId())
|
||||||
|
.sourceType(newSourceType)
|
||||||
|
.sourceId(newSourceId)
|
||||||
|
.vehicleId(sourceRecord.getVehicleId())
|
||||||
|
.status(InspectionStatusEnum.PENDING.getStatus())
|
||||||
|
.clonedFromId(sourceRecordId)
|
||||||
|
.build();
|
||||||
|
inspectionRecordMapper.insert(newRecord);
|
||||||
|
|
||||||
|
// 复制检查项(保留结果数据)
|
||||||
|
if (!sourceItems.isEmpty()) {
|
||||||
|
List<InspectionRecordItemDO> newItems = new ArrayList<>(sourceItems.size());
|
||||||
|
for (InspectionRecordItemDO sourceItem : sourceItems) {
|
||||||
|
InspectionRecordItemDO newItem = InspectionRecordItemDO.builder()
|
||||||
|
.recordId(newRecord.getId())
|
||||||
|
.itemCode(sourceItem.getItemCode())
|
||||||
|
.category(sourceItem.getCategory())
|
||||||
|
.itemName(sourceItem.getItemName())
|
||||||
|
.inputType(sourceItem.getInputType())
|
||||||
|
.result(sourceItem.getResult())
|
||||||
|
.value(sourceItem.getValue())
|
||||||
|
.remark(sourceItem.getRemark())
|
||||||
|
.imageUrls(sourceItem.getImageUrls())
|
||||||
|
.build();
|
||||||
|
newItems.add(newItem);
|
||||||
|
}
|
||||||
|
inspectionRecordItemMapper.insertBatch(newItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRecord.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateRecordItem(InspectionRecordItemUpdateReqVO updateReqVO) {
|
||||||
|
// 校验检查项存在
|
||||||
|
InspectionRecordItemDO item = inspectionRecordItemMapper.selectById(updateReqVO.getId());
|
||||||
|
if (item == null) {
|
||||||
|
throw exception(INSPECTION_RECORD_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新检查项
|
||||||
|
InspectionRecordItemDO updateObj = InspectionRecordItemDO.builder()
|
||||||
|
.id(updateReqVO.getId())
|
||||||
|
.result(updateReqVO.getResult())
|
||||||
|
.value(updateReqVO.getValue())
|
||||||
|
.remark(updateReqVO.getRemark())
|
||||||
|
.imageUrls(updateReqVO.getImageUrls())
|
||||||
|
.build();
|
||||||
|
inspectionRecordItemMapper.updateById(updateObj);
|
||||||
|
|
||||||
|
// 如果记录状态为待检,更新为检查中
|
||||||
|
InspectionRecordDO record = inspectionRecordMapper.selectById(item.getRecordId());
|
||||||
|
if (record != null && InspectionStatusEnum.PENDING.getStatus().equals(record.getStatus())) {
|
||||||
|
InspectionRecordDO updateRecord = InspectionRecordDO.builder()
|
||||||
|
.id(record.getId())
|
||||||
|
.status(InspectionStatusEnum.IN_PROGRESS.getStatus())
|
||||||
|
.build();
|
||||||
|
inspectionRecordMapper.updateById(updateRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void completeRecord(Long recordId, String inspectorName) {
|
||||||
|
// 校验记录存在
|
||||||
|
InspectionRecordDO record = inspectionRecordMapper.selectById(recordId);
|
||||||
|
if (record == null) {
|
||||||
|
throw exception(INSPECTION_RECORD_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验未完成
|
||||||
|
if (InspectionStatusEnum.COMPLETED.getStatus().equals(record.getStatus())) {
|
||||||
|
throw exception(INSPECTION_RECORD_ALREADY_COMPLETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验必填项是否全部完成
|
||||||
|
List<InspectionRecordItemDO> items = inspectionRecordItemMapper.selectByRecordId(recordId);
|
||||||
|
// 查询模板检查项获取必填信息
|
||||||
|
List<InspectionTemplateItemDO> templateItems = inspectionTemplateItemMapper.selectByTemplateId(record.getTemplateId());
|
||||||
|
for (InspectionTemplateItemDO templateItem : templateItems) {
|
||||||
|
if (Integer.valueOf(1).equals(templateItem.getRequired())) {
|
||||||
|
// 查找对应的记录检查项
|
||||||
|
boolean hasResult = items.stream()
|
||||||
|
.filter(item -> item.getItemCode().equals(templateItem.getItemCode()))
|
||||||
|
.anyMatch(item -> item.getResult() != null);
|
||||||
|
if (!hasResult) {
|
||||||
|
throw exception(INSPECTION_RECORD_REQUIRED_ITEMS_INCOMPLETE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算总体结果:如果有任一不通过则整体不通过,否则通过
|
||||||
|
Integer overallResult = 1; // 默认通过
|
||||||
|
for (InspectionRecordItemDO item : items) {
|
||||||
|
if (item.getResult() != null && item.getResult() == 2) {
|
||||||
|
overallResult = 2; // 不通过
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新记录状态
|
||||||
|
InspectionRecordDO updateRecord = InspectionRecordDO.builder()
|
||||||
|
.id(recordId)
|
||||||
|
.status(InspectionStatusEnum.COMPLETED.getStatus())
|
||||||
|
.inspectorName(inspectorName)
|
||||||
|
.inspectionTime(LocalDateTime.now())
|
||||||
|
.overallResult(overallResult)
|
||||||
|
.build();
|
||||||
|
inspectionRecordMapper.updateById(updateRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InspectionRecordDetailVO getRecordDetail(Long recordId) {
|
||||||
|
InspectionRecordDO record = inspectionRecordMapper.selectById(recordId);
|
||||||
|
if (record == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
InspectionRecordDetailVO detailVO = InspectionConvert.INSTANCE.convertRecordDetail(record);
|
||||||
|
|
||||||
|
// 查询检查项
|
||||||
|
List<InspectionRecordItemDO> items = inspectionRecordItemMapper.selectByRecordId(recordId);
|
||||||
|
detailVO.setItems(InspectionConvert.INSTANCE.convertRecordItemVOList(items));
|
||||||
|
|
||||||
|
return detailVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InspectionRecordDO getLatestRecord(Long vehicleId, Integer sourceType) {
|
||||||
|
return inspectionRecordMapper.selectLatestByVehicleAndSourceType(vehicleId, sourceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成记录编码
|
||||||
|
* 格式: {BC|JC|HC}-yyyyMMdd-{seq}
|
||||||
|
*/
|
||||||
|
private String generateRecordCode(Integer sourceType) {
|
||||||
|
String prefix;
|
||||||
|
InspectionSourceTypeEnum sourceTypeEnum = InspectionSourceTypeEnum.valueOf(sourceType);
|
||||||
|
if (sourceTypeEnum == null) {
|
||||||
|
prefix = "YC";
|
||||||
|
} else {
|
||||||
|
switch (sourceTypeEnum) {
|
||||||
|
case PREPARE:
|
||||||
|
prefix = "BC";
|
||||||
|
break;
|
||||||
|
case DELIVERY:
|
||||||
|
prefix = "JC";
|
||||||
|
break;
|
||||||
|
case RETURN:
|
||||||
|
prefix = "HC";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
prefix = "YC";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||||
|
int seq = ThreadLocalRandom.current().nextInt(100, 999);
|
||||||
|
return prefix + "-" + dateStr + "-" + String.format("%03d", seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionTemplatePageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionTemplateSaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionTemplateRespVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionTemplateDO;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车模板 Service 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface InspectionTemplateService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建验车模板
|
||||||
|
*/
|
||||||
|
Long createTemplate(@Valid InspectionTemplateSaveReqVO createReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新验车模板
|
||||||
|
*/
|
||||||
|
void updateTemplate(@Valid InspectionTemplateSaveReqVO updateReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除验车模板
|
||||||
|
*/
|
||||||
|
void deleteTemplate(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取验车模板详情(含检查项)
|
||||||
|
*/
|
||||||
|
InspectionTemplateRespVO getTemplate(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取验车模板分页
|
||||||
|
*/
|
||||||
|
PageResult<InspectionTemplateDO> getTemplatePage(InspectionTemplatePageReqVO pageReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 匹配验车模板
|
||||||
|
* 优先精确匹配 bizType + vehicleType,其次匹配 bizType + vehicleType IS NULL 的默认模板
|
||||||
|
*/
|
||||||
|
InspectionTemplateDO matchTemplate(Integer bizType, String vehicleType);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.inspection;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionTemplatePageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionTemplateSaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionTemplateRespVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.convert.inspection.InspectionConvert;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionTemplateDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionTemplateItemDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.inspection.InspectionTemplateItemMapper;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.inspection.InspectionTemplateMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验车模板 Service 实现类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
@Slf4j
|
||||||
|
public class InspectionTemplateServiceImpl implements InspectionTemplateService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionTemplateMapper inspectionTemplateMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionTemplateItemMapper inspectionTemplateItemMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createTemplate(InspectionTemplateSaveReqVO createReqVO) {
|
||||||
|
// 插入模板
|
||||||
|
InspectionTemplateDO template = InspectionConvert.INSTANCE.convert(createReqVO);
|
||||||
|
inspectionTemplateMapper.insert(template);
|
||||||
|
|
||||||
|
// 插入检查项
|
||||||
|
if (createReqVO.getItems() != null && !createReqVO.getItems().isEmpty()) {
|
||||||
|
List<InspectionTemplateItemDO> items = InspectionConvert.INSTANCE.convertItemList(createReqVO.getItems());
|
||||||
|
items.forEach(item -> item.setTemplateId(template.getId()));
|
||||||
|
inspectionTemplateItemMapper.insertBatch(items);
|
||||||
|
}
|
||||||
|
return template.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void updateTemplate(InspectionTemplateSaveReqVO updateReqVO) {
|
||||||
|
// 校验存在
|
||||||
|
validateTemplateExists(updateReqVO.getId());
|
||||||
|
|
||||||
|
// 更新模板
|
||||||
|
InspectionTemplateDO updateObj = InspectionConvert.INSTANCE.convert(updateReqVO);
|
||||||
|
inspectionTemplateMapper.updateById(updateObj);
|
||||||
|
|
||||||
|
// 删除旧检查项,插入新检查项
|
||||||
|
inspectionTemplateItemMapper.deleteByTemplateId(updateReqVO.getId());
|
||||||
|
if (updateReqVO.getItems() != null && !updateReqVO.getItems().isEmpty()) {
|
||||||
|
List<InspectionTemplateItemDO> items = InspectionConvert.INSTANCE.convertItemList(updateReqVO.getItems());
|
||||||
|
items.forEach(item -> item.setTemplateId(updateReqVO.getId()));
|
||||||
|
inspectionTemplateItemMapper.insertBatch(items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteTemplate(Long id) {
|
||||||
|
// 校验存在
|
||||||
|
validateTemplateExists(id);
|
||||||
|
// 删除模板
|
||||||
|
inspectionTemplateMapper.deleteById(id);
|
||||||
|
// 删除检查项
|
||||||
|
inspectionTemplateItemMapper.deleteByTemplateId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InspectionTemplateRespVO getTemplate(Long id) {
|
||||||
|
InspectionTemplateDO template = inspectionTemplateMapper.selectById(id);
|
||||||
|
if (template == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
InspectionTemplateRespVO respVO = InspectionConvert.INSTANCE.convert(template);
|
||||||
|
// 查询检查项
|
||||||
|
List<InspectionTemplateItemDO> items = inspectionTemplateItemMapper.selectByTemplateId(id);
|
||||||
|
respVO.setItems(InspectionConvert.INSTANCE.convertItemVOList(items));
|
||||||
|
return respVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<InspectionTemplateDO> getTemplatePage(InspectionTemplatePageReqVO pageReqVO) {
|
||||||
|
return inspectionTemplateMapper.selectPage(pageReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InspectionTemplateDO matchTemplate(Integer bizType, String vehicleType) {
|
||||||
|
// 优先精确匹配 bizType + vehicleType
|
||||||
|
if (vehicleType != null) {
|
||||||
|
InspectionTemplateDO template = inspectionTemplateMapper.selectByBizTypeAndVehicleType(bizType, vehicleType);
|
||||||
|
if (template != null) {
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 其次匹配默认模板(vehicleType IS NULL)
|
||||||
|
InspectionTemplateDO defaultTemplate = inspectionTemplateMapper.selectDefaultByBizType(bizType);
|
||||||
|
if (defaultTemplate != null) {
|
||||||
|
return defaultTemplate;
|
||||||
|
}
|
||||||
|
throw exception(INSPECTION_TEMPLATE_MATCH_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateTemplateExists(Long id) {
|
||||||
|
InspectionTemplateDO template = inspectionTemplateMapper.selectById(id);
|
||||||
|
if (template == null) {
|
||||||
|
throw exception(INSPECTION_TEMPLATE_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.prepare;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.prepare.vo.VehiclePreparePageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.prepare.vo.VehiclePrepareSaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionTemplateDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.prepare.VehiclePrepareDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.prepare.VehiclePrepareMapper;
|
||||||
|
import cn.iocoder.yudao.module.asset.enums.inspection.InspectionSourceTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.inspection.InspectionRecordService;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.inspection.InspectionTemplateService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
public class VehiclePrepareServiceImpl implements VehiclePrepareService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private VehiclePrepareMapper vehiclePrepareMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionTemplateService inspectionTemplateService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionRecordService inspectionRecordService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long createVehiclePrepare(VehiclePrepareSaveReqVO createReqVO) {
|
||||||
|
VehiclePrepareDO prepare = BeanUtils.toBean(createReqVO, VehiclePrepareDO.class);
|
||||||
|
vehiclePrepareMapper.insert(prepare);
|
||||||
|
|
||||||
|
// 自动匹配验车模板并创建验车记录
|
||||||
|
InspectionTemplateDO template = inspectionTemplateService.matchTemplate(
|
||||||
|
InspectionSourceTypeEnum.PREPARE.getType(), prepare.getVehicleType());
|
||||||
|
if (template != null) {
|
||||||
|
Long inspectionRecordId = inspectionRecordService.createRecord(
|
||||||
|
template.getId(), InspectionSourceTypeEnum.PREPARE.getType(),
|
||||||
|
prepare.getId(), prepare.getVehicleId());
|
||||||
|
// 回写验车记录ID
|
||||||
|
vehiclePrepareMapper.updateById(VehiclePrepareDO.builder()
|
||||||
|
.id(prepare.getId()).inspectionRecordId(inspectionRecordId).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
return prepare.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateVehiclePrepare(VehiclePrepareSaveReqVO updateReqVO) {
|
||||||
|
validateVehiclePrepareExists(updateReqVO.getId());
|
||||||
|
VehiclePrepareDO updateObj = BeanUtils.toBean(updateReqVO, VehiclePrepareDO.class);
|
||||||
|
vehiclePrepareMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteVehiclePrepare(Long id) {
|
||||||
|
validateVehiclePrepareExists(id);
|
||||||
|
vehiclePrepareMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VehiclePrepareDO getVehiclePrepare(Long id) {
|
||||||
|
return vehiclePrepareMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<VehiclePrepareDO> getVehiclePreparePage(VehiclePreparePageReqVO pageReqVO) {
|
||||||
|
return vehiclePrepareMapper.selectPage(pageReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void completeVehiclePrepare(Long id) {
|
||||||
|
VehiclePrepareDO prepare = validateVehiclePrepareExists(id);
|
||||||
|
if (prepare.getStatus().equals(1)) {
|
||||||
|
throw exception(VEHICLE_PREPARE_ALREADY_COMPLETED);
|
||||||
|
}
|
||||||
|
vehiclePrepareMapper.updateById(VehiclePrepareDO.builder()
|
||||||
|
.id(id).status(1).completeTime(LocalDateTime.now()).build());
|
||||||
|
|
||||||
|
// 同时完成关联的验车记录
|
||||||
|
if (prepare.getInspectionRecordId() != null) {
|
||||||
|
inspectionRecordService.completeRecord(prepare.getInspectionRecordId(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private VehiclePrepareDO validateVehiclePrepareExists(Long id) {
|
||||||
|
VehiclePrepareDO prepare = vehiclePrepareMapper.selectById(id);
|
||||||
|
if (prepare == null) {
|
||||||
|
throw exception(VEHICLE_PREPARE_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
return prepare;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.replacement;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.replacement.vo.VehicleReplacementPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.replacement.vo.VehicleReplacementSaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.replacement.VehicleReplacementDO;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车申请 Service 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface VehicleReplacementService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建替换车申请
|
||||||
|
*
|
||||||
|
* @param createReqVO 创建信息
|
||||||
|
* @return 编号
|
||||||
|
*/
|
||||||
|
Long createReplacement(@Valid VehicleReplacementSaveReqVO createReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新替换车申请
|
||||||
|
*
|
||||||
|
* @param updateReqVO 更新信息
|
||||||
|
*/
|
||||||
|
void updateReplacement(@Valid VehicleReplacementSaveReqVO updateReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除替换车申请
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
*/
|
||||||
|
void deleteReplacement(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得替换车申请
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
* @return 替换车申请
|
||||||
|
*/
|
||||||
|
VehicleReplacementDO getReplacement(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得替换车申请分页
|
||||||
|
*
|
||||||
|
* @param pageReqVO 分页查询
|
||||||
|
* @return 替换车申请分页
|
||||||
|
*/
|
||||||
|
PageResult<VehicleReplacementDO> getReplacementPage(VehicleReplacementPageReqVO pageReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交审批
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
* @return 流程实例ID
|
||||||
|
*/
|
||||||
|
String submitApproval(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤回审批
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
*/
|
||||||
|
void withdrawApproval(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新审批状态(BPM回调)
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
* @param bpmStatus BPM状态
|
||||||
|
*/
|
||||||
|
void updateApprovalStatus(Long id, Integer bpmStatus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认换回(临时替换)
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
*/
|
||||||
|
void confirmReturn(Long id);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,273 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.replacement;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.replacement.vo.VehicleReplacementPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.replacement.vo.VehicleReplacementSaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.convert.replacement.VehicleReplacementConvert;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.replacement.VehicleReplacementDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.replacement.VehicleReplacementMapper;
|
||||||
|
import cn.iocoder.yudao.module.asset.enums.replacement.ReplacementStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.asset.enums.replacement.ReplacementTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.replacement.event.ReplacementApprovedEvent;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.replacement.event.ReplacementReturnConfirmedEvent;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.replacement.listener.ReplacementBpmListener;
|
||||||
|
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
|
||||||
|
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
|
||||||
|
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车申请 Service 实现类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
@Slf4j
|
||||||
|
public class VehicleReplacementServiceImpl implements VehicleReplacementService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private VehicleReplacementMapper replacementMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BpmProcessInstanceApi bpmProcessInstanceApi;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ApplicationEventPublisher eventPublisher;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createReplacement(VehicleReplacementSaveReqVO createReqVO) {
|
||||||
|
// 转换并插入
|
||||||
|
VehicleReplacementDO replacement = VehicleReplacementConvert.INSTANCE.convert(createReqVO);
|
||||||
|
|
||||||
|
// 生成替换单编码
|
||||||
|
replacement.setReplacementCode(generateReplacementCode());
|
||||||
|
|
||||||
|
// 设置初始状态
|
||||||
|
replacement.setStatus(ReplacementStatusEnum.DRAFT.getStatus());
|
||||||
|
replacement.setApprovalStatus(0);
|
||||||
|
|
||||||
|
replacementMapper.insert(replacement);
|
||||||
|
return replacement.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void updateReplacement(VehicleReplacementSaveReqVO updateReqVO) {
|
||||||
|
// 校验存在
|
||||||
|
VehicleReplacementDO existing = validateReplacementExists(updateReqVO.getId());
|
||||||
|
|
||||||
|
// 校验状态:只有草稿、审批驳回状态才能修改
|
||||||
|
if (!ReplacementStatusEnum.DRAFT.getStatus().equals(existing.getStatus())
|
||||||
|
&& !ReplacementStatusEnum.REJECTED.getStatus().equals(existing.getStatus())) {
|
||||||
|
throw exception(VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_UPDATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换并更新
|
||||||
|
VehicleReplacementDO updateObj = VehicleReplacementConvert.INSTANCE.convert(updateReqVO);
|
||||||
|
replacementMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void deleteReplacement(Long id) {
|
||||||
|
// 校验存在
|
||||||
|
VehicleReplacementDO replacement = validateReplacementExists(id);
|
||||||
|
|
||||||
|
// 校验状态:只有草稿状态才能删除
|
||||||
|
if (!ReplacementStatusEnum.DRAFT.getStatus().equals(replacement.getStatus())) {
|
||||||
|
throw exception(VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_DELETE);
|
||||||
|
}
|
||||||
|
|
||||||
|
replacementMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VehicleReplacementDO getReplacement(Long id) {
|
||||||
|
return replacementMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<VehicleReplacementDO> getReplacementPage(VehicleReplacementPageReqVO pageReqVO) {
|
||||||
|
return replacementMapper.selectPage(pageReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public String submitApproval(Long id) {
|
||||||
|
// 校验存在
|
||||||
|
VehicleReplacementDO replacement = validateReplacementExists(id);
|
||||||
|
|
||||||
|
// 校验状态:只有草稿、审批驳回状态才能提交审批
|
||||||
|
if (!ReplacementStatusEnum.DRAFT.getStatus().equals(replacement.getStatus())
|
||||||
|
&& !ReplacementStatusEnum.REJECTED.getStatus().equals(replacement.getStatus())) {
|
||||||
|
throw exception(VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_SUBMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建流程变量
|
||||||
|
Map<String, Object> variables = new HashMap<>();
|
||||||
|
variables.put("replacementCode", replacement.getReplacementCode());
|
||||||
|
variables.put("replacementType", replacement.getReplacementType());
|
||||||
|
variables.put("contractCode", replacement.getContractCode());
|
||||||
|
variables.put("customerName", replacement.getCustomerName());
|
||||||
|
variables.put("originalPlateNo", replacement.getOriginalPlateNo());
|
||||||
|
variables.put("newPlateNo", replacement.getNewPlateNo());
|
||||||
|
|
||||||
|
// 创建流程实例
|
||||||
|
BpmProcessInstanceCreateReqDTO reqDTO = new BpmProcessInstanceCreateReqDTO();
|
||||||
|
reqDTO.setProcessDefinitionKey(ReplacementBpmListener.PROCESS_KEY);
|
||||||
|
reqDTO.setBusinessKey(String.valueOf(id));
|
||||||
|
reqDTO.setVariables(variables);
|
||||||
|
|
||||||
|
Long userId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
|
String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, reqDTO).getData();
|
||||||
|
|
||||||
|
// 更新状态
|
||||||
|
VehicleReplacementDO updateObj = new VehicleReplacementDO();
|
||||||
|
updateObj.setId(id);
|
||||||
|
updateObj.setStatus(ReplacementStatusEnum.APPROVING.getStatus());
|
||||||
|
updateObj.setBpmInstanceId(processInstanceId);
|
||||||
|
replacementMapper.updateById(updateObj);
|
||||||
|
|
||||||
|
return processInstanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void withdrawApproval(Long id) {
|
||||||
|
// 校验存在
|
||||||
|
VehicleReplacementDO replacement = validateReplacementExists(id);
|
||||||
|
|
||||||
|
// 校验状态:只有审批中状态才能撤回
|
||||||
|
if (!ReplacementStatusEnum.APPROVING.getStatus().equals(replacement.getStatus())) {
|
||||||
|
throw exception(VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_WITHDRAW);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新状态
|
||||||
|
VehicleReplacementDO updateObj = new VehicleReplacementDO();
|
||||||
|
updateObj.setId(id);
|
||||||
|
updateObj.setStatus(ReplacementStatusEnum.WITHDRAWN.getStatus());
|
||||||
|
replacementMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void updateApprovalStatus(Long id, Integer bpmStatus) {
|
||||||
|
// 校验存在
|
||||||
|
VehicleReplacementDO replacement = validateReplacementExists(id);
|
||||||
|
|
||||||
|
VehicleReplacementDO updateObj = new VehicleReplacementDO();
|
||||||
|
updateObj.setId(id);
|
||||||
|
|
||||||
|
if (BpmProcessInstanceStatusEnum.APPROVE.getStatus().equals(bpmStatus)) {
|
||||||
|
// 审批通过 → 直接进入执行中
|
||||||
|
updateObj.setStatus(ReplacementStatusEnum.EXECUTING.getStatus());
|
||||||
|
updateObj.setActualDate(LocalDate.now());
|
||||||
|
replacementMapper.updateById(updateObj);
|
||||||
|
|
||||||
|
// 发布审批通过事件
|
||||||
|
eventPublisher.publishEvent(new ReplacementApprovedEvent(
|
||||||
|
replacement.getId(),
|
||||||
|
replacement.getReplacementType(),
|
||||||
|
replacement.getContractId(),
|
||||||
|
replacement.getOriginalVehicleId()
|
||||||
|
));
|
||||||
|
|
||||||
|
// 永久替换审批通过后直接完成
|
||||||
|
if (ReplacementTypeEnum.PERMANENT.getType().equals(replacement.getReplacementType())) {
|
||||||
|
VehicleReplacementDO completeObj = new VehicleReplacementDO();
|
||||||
|
completeObj.setId(id);
|
||||||
|
completeObj.setStatus(ReplacementStatusEnum.COMPLETED.getStatus());
|
||||||
|
replacementMapper.updateById(completeObj);
|
||||||
|
}
|
||||||
|
} else if (BpmProcessInstanceStatusEnum.REJECT.getStatus().equals(bpmStatus)) {
|
||||||
|
updateObj.setStatus(ReplacementStatusEnum.REJECTED.getStatus());
|
||||||
|
replacementMapper.updateById(updateObj);
|
||||||
|
} else if (BpmProcessInstanceStatusEnum.CANCEL.getStatus().equals(bpmStatus)) {
|
||||||
|
updateObj.setStatus(ReplacementStatusEnum.WITHDRAWN.getStatus());
|
||||||
|
replacementMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void confirmReturn(Long id) {
|
||||||
|
// 校验存在
|
||||||
|
VehicleReplacementDO replacement = validateReplacementExists(id);
|
||||||
|
|
||||||
|
// 校验状态:只有执行中状态才能确认换回
|
||||||
|
if (!ReplacementStatusEnum.EXECUTING.getStatus().equals(replacement.getStatus())) {
|
||||||
|
throw exception(VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_CONFIRM);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验类型:只有临时替换才能确认换回
|
||||||
|
if (!ReplacementTypeEnum.TEMPORARY.getType().equals(replacement.getReplacementType())) {
|
||||||
|
throw exception(VEHICLE_REPLACEMENT_STATUS_NOT_ALLOW_CONFIRM);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新状态
|
||||||
|
VehicleReplacementDO updateObj = new VehicleReplacementDO();
|
||||||
|
updateObj.setId(id);
|
||||||
|
updateObj.setStatus(ReplacementStatusEnum.COMPLETED.getStatus());
|
||||||
|
updateObj.setActualReturnDate(LocalDate.now());
|
||||||
|
replacementMapper.updateById(updateObj);
|
||||||
|
|
||||||
|
// 发布换回确认事件
|
||||||
|
eventPublisher.publishEvent(new ReplacementReturnConfirmedEvent(
|
||||||
|
replacement.getId(),
|
||||||
|
replacement.getOriginalVehicleId()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 私有方法 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验替换车申请是否存在
|
||||||
|
*/
|
||||||
|
private VehicleReplacementDO validateReplacementExists(Long id) {
|
||||||
|
VehicleReplacementDO replacement = replacementMapper.selectById(id);
|
||||||
|
if (replacement == null) {
|
||||||
|
throw exception(VEHICLE_REPLACEMENT_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
return replacement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成替换单编码
|
||||||
|
*/
|
||||||
|
private String generateReplacementCode() {
|
||||||
|
// 格式:TH-yyyyMMdd-NNN
|
||||||
|
String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||||
|
String prefix = "TH-" + dateStr + "-";
|
||||||
|
|
||||||
|
String maxCode = replacementMapper.selectMaxReplacementCodeByPrefix(prefix);
|
||||||
|
|
||||||
|
int nextSeq = 1;
|
||||||
|
if (maxCode != null && maxCode.startsWith(prefix)) {
|
||||||
|
try {
|
||||||
|
String seqStr = maxCode.substring(prefix.length());
|
||||||
|
nextSeq = Integer.parseInt(seqStr) + 1;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("解析替换单编码失败: {}", maxCode, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefix + String.format("%03d", nextSeq);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.replacement.event;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车审批通过事件
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ReplacementApprovedEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车申请ID
|
||||||
|
*/
|
||||||
|
private final Long replacementId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换类型(1=临时 2=永久)
|
||||||
|
*/
|
||||||
|
private final Integer replacementType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合同ID
|
||||||
|
*/
|
||||||
|
private final Long contractId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原车辆ID
|
||||||
|
*/
|
||||||
|
private final Long originalVehicleId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.replacement.event;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车换回确认事件
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ReplacementReturnConfirmedEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车申请ID
|
||||||
|
*/
|
||||||
|
private final Long replacementId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原车辆ID
|
||||||
|
*/
|
||||||
|
private final Long originalVehicleId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.replacement.listener;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
|
||||||
|
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.replacement.VehicleReplacementService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换车审批状态监听器
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ReplacementBpmListener extends BpmProcessInstanceStatusEventListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程定义 Key
|
||||||
|
*/
|
||||||
|
public static final String PROCESS_KEY = "asset_vehicle_replacement";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private VehicleReplacementService replacementService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getProcessDefinitionKey() {
|
||||||
|
return PROCESS_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onEvent(BpmProcessInstanceStatusEvent event) {
|
||||||
|
replacementService.updateApprovalStatus(Long.parseLong(event.getBusinessKey()), event.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.returnorder;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo.ReturnOrderPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo.ReturnOrderRespVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo.ReturnOrderSaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.returnorder.ReturnOrderDO;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ReturnOrderService {
|
||||||
|
|
||||||
|
Long createReturnOrder(@Valid ReturnOrderSaveReqVO createReqVO);
|
||||||
|
|
||||||
|
void updateReturnOrder(@Valid ReturnOrderSaveReqVO updateReqVO);
|
||||||
|
|
||||||
|
void deleteReturnOrder(Long id);
|
||||||
|
|
||||||
|
ReturnOrderDO getReturnOrder(Long id);
|
||||||
|
|
||||||
|
ReturnOrderRespVO getReturnOrderDetail(Long id);
|
||||||
|
|
||||||
|
PageResult<ReturnOrderDO> getReturnOrderPage(ReturnOrderPageReqVO pageReqVO);
|
||||||
|
|
||||||
|
void completeInspection(Long id);
|
||||||
|
|
||||||
|
void settleReturnOrder(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从交车单创建还车单
|
||||||
|
*/
|
||||||
|
Long createFromDelivery(Long deliveryOrderId, List<Long> vehicleIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从替换车创建还车单(永久替换审批通过时)
|
||||||
|
*/
|
||||||
|
Long createFromReplacement(Long replacementId, Long contractId, Long vehicleId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始单车验车(创建或克隆验车记录)
|
||||||
|
*/
|
||||||
|
Long startVehicleInspection(Long returnOrderVehicleId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完成单车验车
|
||||||
|
*/
|
||||||
|
void completeVehicleInspection(Long returnOrderVehicleId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交审批
|
||||||
|
*/
|
||||||
|
void submitApproval(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤回审批
|
||||||
|
*/
|
||||||
|
void withdrawApproval(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新审批状态(BPM 回调)
|
||||||
|
*/
|
||||||
|
void updateApprovalStatus(Long id, Integer bpmStatus);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,449 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.returnorder;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
|
import cn.iocoder.yudao.module.asset.controller.admin.returnorder.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.contract.ContractDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryOrderDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.delivery.DeliveryOrderVehicleDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionRecordDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionTemplateDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.returnorder.ReturnOrderDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.dataobject.returnorder.ReturnOrderVehicleDO;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.contract.ContractMapper;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.delivery.DeliveryOrderMapper;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.inspection.InspectionRecordMapper;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.delivery.DeliveryOrderVehicleMapper;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.returnorder.ReturnOrderMapper;
|
||||||
|
import cn.iocoder.yudao.module.asset.dal.mysql.returnorder.ReturnOrderVehicleMapper;
|
||||||
|
import cn.iocoder.yudao.module.asset.enums.inspection.InspectionSourceTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.inspection.InspectionRecordService;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.inspection.InspectionTemplateService;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.returnorder.event.ReturnApprovedEvent;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.returnorder.listener.ReturnOrderBpmListener;
|
||||||
|
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
|
||||||
|
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
@Slf4j
|
||||||
|
public class ReturnOrderServiceImpl implements ReturnOrderService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ReturnOrderMapper returnOrderMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ReturnOrderVehicleMapper returnOrderVehicleMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeliveryOrderMapper deliveryOrderMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeliveryOrderVehicleMapper deliveryOrderVehicleMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ContractMapper contractMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionRecordMapper inspectionRecordMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionRecordService inspectionRecordService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionTemplateService inspectionTemplateService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BpmProcessInstanceApi bpmProcessInstanceApi;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ApplicationEventPublisher eventPublisher;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createReturnOrder(ReturnOrderSaveReqVO createReqVO) {
|
||||||
|
// Generate order code: HC + timestamp
|
||||||
|
String orderCode = "HC" + System.currentTimeMillis();
|
||||||
|
|
||||||
|
ReturnOrderDO order = BeanUtils.toBean(createReqVO, ReturnOrderDO.class);
|
||||||
|
order.setOrderCode(orderCode);
|
||||||
|
order.setSourceType(1); // 手动创建
|
||||||
|
order.setStatus(0); // pending inspection
|
||||||
|
order.setApprovalStatus(0); // draft
|
||||||
|
returnOrderMapper.insert(order);
|
||||||
|
|
||||||
|
// Insert vehicles
|
||||||
|
if (createReqVO.getVehicles() != null) {
|
||||||
|
for (ReturnOrderVehicleVO vehicleVO : createReqVO.getVehicles()) {
|
||||||
|
ReturnOrderVehicleDO vehicle = BeanUtils.toBean(vehicleVO, ReturnOrderVehicleDO.class);
|
||||||
|
vehicle.setReturnOrderId(order.getId());
|
||||||
|
returnOrderVehicleMapper.insert(vehicle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate total refund
|
||||||
|
calculateTotalRefund(order.getId());
|
||||||
|
|
||||||
|
return order.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void updateReturnOrder(ReturnOrderSaveReqVO updateReqVO) {
|
||||||
|
ReturnOrderDO order = validateReturnOrderExists(updateReqVO.getId());
|
||||||
|
if (order.getStatus().equals(2)) {
|
||||||
|
throw exception(RETURN_ORDER_ALREADY_SETTLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOrderDO updateObj = BeanUtils.toBean(updateReqVO, ReturnOrderDO.class);
|
||||||
|
returnOrderMapper.updateById(updateObj);
|
||||||
|
|
||||||
|
// Update vehicles
|
||||||
|
if (updateReqVO.getVehicles() != null) {
|
||||||
|
returnOrderVehicleMapper.deleteByReturnOrderId(updateReqVO.getId());
|
||||||
|
for (ReturnOrderVehicleVO vehicleVO : updateReqVO.getVehicles()) {
|
||||||
|
ReturnOrderVehicleDO vehicle = BeanUtils.toBean(vehicleVO, ReturnOrderVehicleDO.class);
|
||||||
|
vehicle.setReturnOrderId(updateReqVO.getId());
|
||||||
|
returnOrderVehicleMapper.insert(vehicle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateTotalRefund(updateReqVO.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void deleteReturnOrder(Long id) {
|
||||||
|
validateReturnOrderExists(id);
|
||||||
|
returnOrderMapper.deleteById(id);
|
||||||
|
returnOrderVehicleMapper.deleteByReturnOrderId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReturnOrderDO getReturnOrder(Long id) {
|
||||||
|
return returnOrderMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReturnOrderRespVO getReturnOrderDetail(Long id) {
|
||||||
|
ReturnOrderDO order = validateReturnOrderExists(id);
|
||||||
|
ReturnOrderRespVO respVO = BeanUtils.toBean(order, ReturnOrderRespVO.class);
|
||||||
|
List<ReturnOrderVehicleDO> vehicles = returnOrderVehicleMapper.selectListByReturnOrderId(id);
|
||||||
|
respVO.setVehicles(BeanUtils.toBean(vehicles, ReturnOrderVehicleVO.class));
|
||||||
|
return respVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<ReturnOrderDO> getReturnOrderPage(ReturnOrderPageReqVO pageReqVO) {
|
||||||
|
return returnOrderMapper.selectPage(pageReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void completeInspection(Long id) {
|
||||||
|
ReturnOrderDO order = validateReturnOrderExists(id);
|
||||||
|
if (order.getStatus().equals(2)) {
|
||||||
|
throw exception(RETURN_ORDER_ALREADY_SETTLED);
|
||||||
|
}
|
||||||
|
returnOrderMapper.updateById(ReturnOrderDO.builder().id(id).status(1).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void settleReturnOrder(Long id) {
|
||||||
|
ReturnOrderDO order = validateReturnOrderExists(id);
|
||||||
|
if (order.getStatus().equals(2)) {
|
||||||
|
throw exception(RETURN_ORDER_ALREADY_SETTLED);
|
||||||
|
}
|
||||||
|
returnOrderMapper.updateById(ReturnOrderDO.builder().id(id).status(2).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createFromDelivery(Long deliveryOrderId, List<Long> vehicleIds) {
|
||||||
|
// 查询交车单信息
|
||||||
|
DeliveryOrderDO deliveryOrder = deliveryOrderMapper.selectById(deliveryOrderId);
|
||||||
|
if (deliveryOrder == null) {
|
||||||
|
throw exception(DELIVERY_ORDER_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建还车单
|
||||||
|
ReturnOrderDO order = new ReturnOrderDO();
|
||||||
|
order.setOrderCode("HC" + System.currentTimeMillis());
|
||||||
|
order.setSourceType(1); // 手动(从交车单创建)
|
||||||
|
order.setDeliveryOrderId(deliveryOrderId);
|
||||||
|
order.setContractId(deliveryOrder.getContractId());
|
||||||
|
order.setContractCode(deliveryOrder.getContractCode());
|
||||||
|
order.setProjectName(deliveryOrder.getProjectName());
|
||||||
|
order.setCustomerId(deliveryOrder.getCustomerId());
|
||||||
|
order.setCustomerName(deliveryOrder.getCustomerName());
|
||||||
|
order.setStatus(0); // 待验车
|
||||||
|
order.setApprovalStatus(0); // 草稿
|
||||||
|
returnOrderMapper.insert(order);
|
||||||
|
|
||||||
|
// 查询交车单车辆,筛选指定的 vehicleIds
|
||||||
|
List<DeliveryOrderVehicleDO> deliveryVehicles = deliveryOrderVehicleMapper.selectListByOrderId(deliveryOrderId);
|
||||||
|
for (DeliveryOrderVehicleDO dv : deliveryVehicles) {
|
||||||
|
if (vehicleIds.contains(dv.getVehicleId())) {
|
||||||
|
ReturnOrderVehicleDO vehicle = new ReturnOrderVehicleDO();
|
||||||
|
vehicle.setReturnOrderId(order.getId());
|
||||||
|
vehicle.setVehicleId(dv.getVehicleId());
|
||||||
|
vehicle.setPlateNo(dv.getPlateNo());
|
||||||
|
vehicle.setVin(dv.getVin());
|
||||||
|
vehicle.setBrand(dv.getBrand());
|
||||||
|
vehicle.setModel(dv.getModel());
|
||||||
|
returnOrderVehicleMapper.insert(vehicle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return order.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long createFromReplacement(Long replacementId, Long contractId, Long vehicleId) {
|
||||||
|
// 查询合同信息
|
||||||
|
ContractDO contract = contractMapper.selectById(contractId);
|
||||||
|
if (contract == null) {
|
||||||
|
throw exception(CONTRACT_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建还车单
|
||||||
|
ReturnOrderDO order = new ReturnOrderDO();
|
||||||
|
order.setOrderCode("HC" + System.currentTimeMillis());
|
||||||
|
order.setSourceType(2); // 替换车触发
|
||||||
|
order.setSourceId(replacementId);
|
||||||
|
order.setContractId(contractId);
|
||||||
|
order.setContractCode(contract.getContractCode());
|
||||||
|
order.setProjectName(contract.getProjectName());
|
||||||
|
order.setCustomerId(contract.getCustomerId());
|
||||||
|
order.setCustomerName(contract.getCustomerName());
|
||||||
|
order.setStatus(0); // 待验车
|
||||||
|
order.setApprovalStatus(0); // 草稿
|
||||||
|
returnOrderMapper.insert(order);
|
||||||
|
|
||||||
|
// 创建还车车辆(原车辆)
|
||||||
|
// TODO: 查询车辆信息获取 plateNo/vin/brand/model,暂时只设置 vehicleId
|
||||||
|
ReturnOrderVehicleDO vehicle = new ReturnOrderVehicleDO();
|
||||||
|
vehicle.setReturnOrderId(order.getId());
|
||||||
|
vehicle.setVehicleId(vehicleId);
|
||||||
|
returnOrderVehicleMapper.insert(vehicle);
|
||||||
|
|
||||||
|
return order.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long startVehicleInspection(Long returnOrderVehicleId) {
|
||||||
|
// 查找还车车辆
|
||||||
|
ReturnOrderVehicleDO vehicle = returnOrderVehicleMapper.selectById(returnOrderVehicleId);
|
||||||
|
if (vehicle == null) {
|
||||||
|
throw exception(RETURN_ORDER_VEHICLE_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
if (vehicle.getInspectionRecordId() != null) {
|
||||||
|
throw exception(RETURN_ORDER_INSPECTION_ALREADY_STARTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
Long inspectionRecordId;
|
||||||
|
|
||||||
|
// 尝试查找最新的交车验车记录进行克隆
|
||||||
|
InspectionRecordDO latestRecord = inspectionRecordService.getLatestRecord(
|
||||||
|
vehicle.getVehicleId(), InspectionSourceTypeEnum.DELIVERY.getType());
|
||||||
|
|
||||||
|
if (latestRecord != null) {
|
||||||
|
// 克隆交车验车记录
|
||||||
|
inspectionRecordId = inspectionRecordService.cloneRecord(
|
||||||
|
latestRecord.getId(),
|
||||||
|
InspectionSourceTypeEnum.RETURN.getType(),
|
||||||
|
returnOrderVehicleId);
|
||||||
|
} else {
|
||||||
|
// 没有交车记录,尝试匹配模板创建新记录
|
||||||
|
InspectionTemplateDO template = inspectionTemplateService.matchTemplate(
|
||||||
|
InspectionSourceTypeEnum.RETURN.getType(), null);
|
||||||
|
if (template == null) {
|
||||||
|
throw exception(INSPECTION_TEMPLATE_MATCH_FAILED);
|
||||||
|
}
|
||||||
|
inspectionRecordId = inspectionRecordService.createRecord(
|
||||||
|
template.getId(),
|
||||||
|
InspectionSourceTypeEnum.RETURN.getType(),
|
||||||
|
returnOrderVehicleId,
|
||||||
|
vehicle.getVehicleId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新还车车辆的验车记录ID
|
||||||
|
ReturnOrderVehicleDO updateObj = new ReturnOrderVehicleDO();
|
||||||
|
updateObj.setId(returnOrderVehicleId);
|
||||||
|
updateObj.setInspectionRecordId(inspectionRecordId);
|
||||||
|
returnOrderVehicleMapper.updateById(updateObj);
|
||||||
|
|
||||||
|
return inspectionRecordId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void completeVehicleInspection(Long returnOrderVehicleId) {
|
||||||
|
// 查找还车车辆
|
||||||
|
ReturnOrderVehicleDO vehicle = returnOrderVehicleMapper.selectById(returnOrderVehicleId);
|
||||||
|
if (vehicle == null) {
|
||||||
|
throw exception(RETURN_ORDER_VEHICLE_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
if (vehicle.getInspectionRecordId() == null) {
|
||||||
|
throw exception(RETURN_ORDER_INSPECTION_NOT_STARTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 完成验车记录
|
||||||
|
Long userId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
|
String inspectorName = userId != null ? String.valueOf(userId) : "system";
|
||||||
|
inspectionRecordService.completeRecord(vehicle.getInspectionRecordId(), inspectorName);
|
||||||
|
|
||||||
|
// 检查该还车单的所有车辆是否都完成了验车
|
||||||
|
List<ReturnOrderVehicleDO> allVehicles = returnOrderVehicleMapper.selectListByReturnOrderId(vehicle.getReturnOrderId());
|
||||||
|
boolean allCompleted = allVehicles.stream().allMatch(v -> {
|
||||||
|
if (v.getInspectionRecordId() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 当前正在完成的车辆视为已完成
|
||||||
|
if (v.getId().equals(returnOrderVehicleId)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 检查验车记录状态(2=已完成)
|
||||||
|
InspectionRecordDO record = inspectionRecordMapper.selectById(v.getInspectionRecordId());
|
||||||
|
return record != null && Integer.valueOf(2).equals(record.getStatus());
|
||||||
|
});
|
||||||
|
|
||||||
|
if (allCompleted) {
|
||||||
|
// 所有车辆验车完成,更新还车单状态
|
||||||
|
returnOrderMapper.updateById(ReturnOrderDO.builder()
|
||||||
|
.id(vehicle.getReturnOrderId())
|
||||||
|
.status(1) // 验车完成
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void submitApproval(Long id) {
|
||||||
|
ReturnOrderDO order = validateReturnOrderExists(id);
|
||||||
|
|
||||||
|
// 校验状态:验车完成才能提交审批
|
||||||
|
if (!Integer.valueOf(1).equals(order.getStatus())) {
|
||||||
|
throw exception(RETURN_ORDER_STATUS_NOT_ALLOW_SUBMIT);
|
||||||
|
}
|
||||||
|
// 校验审批状态:草稿、已驳回、已撤回才能提交
|
||||||
|
if (order.getApprovalStatus() != null && order.getApprovalStatus() == 1) {
|
||||||
|
throw exception(RETURN_ORDER_STATUS_NOT_ALLOW_SUBMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建流程变量
|
||||||
|
Map<String, Object> variables = new HashMap<>();
|
||||||
|
variables.put("orderCode", order.getOrderCode());
|
||||||
|
variables.put("contractCode", order.getContractCode());
|
||||||
|
variables.put("customerName", order.getCustomerName());
|
||||||
|
|
||||||
|
// 创建流程实例
|
||||||
|
BpmProcessInstanceCreateReqDTO reqDTO = new BpmProcessInstanceCreateReqDTO();
|
||||||
|
reqDTO.setProcessDefinitionKey(ReturnOrderBpmListener.PROCESS_KEY);
|
||||||
|
reqDTO.setBusinessKey(String.valueOf(id));
|
||||||
|
reqDTO.setVariables(variables);
|
||||||
|
|
||||||
|
Long userId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
|
String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, reqDTO).getData();
|
||||||
|
|
||||||
|
// 更新审批状态
|
||||||
|
ReturnOrderDO updateObj = new ReturnOrderDO();
|
||||||
|
updateObj.setId(id);
|
||||||
|
updateObj.setApprovalStatus(1); // 审批中
|
||||||
|
updateObj.setBpmInstanceId(processInstanceId);
|
||||||
|
returnOrderMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void withdrawApproval(Long id) {
|
||||||
|
ReturnOrderDO order = validateReturnOrderExists(id);
|
||||||
|
|
||||||
|
// 校验审批状态:只有审批中才能撤回
|
||||||
|
if (!Integer.valueOf(1).equals(order.getApprovalStatus())) {
|
||||||
|
throw exception(RETURN_ORDER_STATUS_NOT_ALLOW_WITHDRAW);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新审批状态
|
||||||
|
ReturnOrderDO updateObj = new ReturnOrderDO();
|
||||||
|
updateObj.setId(id);
|
||||||
|
updateObj.setApprovalStatus(4); // 已撤回
|
||||||
|
returnOrderMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void updateApprovalStatus(Long id, Integer bpmStatus) {
|
||||||
|
ReturnOrderDO order = validateReturnOrderExists(id);
|
||||||
|
|
||||||
|
ReturnOrderDO updateObj = new ReturnOrderDO();
|
||||||
|
updateObj.setId(id);
|
||||||
|
|
||||||
|
if (BpmProcessInstanceStatusEnum.APPROVE.getStatus().equals(bpmStatus)) {
|
||||||
|
updateObj.setApprovalStatus(2); // 审批通过
|
||||||
|
returnOrderMapper.updateById(updateObj);
|
||||||
|
|
||||||
|
// 发布审批通过事件
|
||||||
|
List<ReturnOrderVehicleDO> vehicles = returnOrderVehicleMapper.selectListByReturnOrderId(id);
|
||||||
|
List<Long> vehicleIds = vehicles.stream()
|
||||||
|
.map(ReturnOrderVehicleDO::getVehicleId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
eventPublisher.publishEvent(new ReturnApprovedEvent(id, vehicleIds));
|
||||||
|
} else if (BpmProcessInstanceStatusEnum.REJECT.getStatus().equals(bpmStatus)) {
|
||||||
|
updateObj.setApprovalStatus(3); // 审批拒绝
|
||||||
|
returnOrderMapper.updateById(updateObj);
|
||||||
|
} else if (BpmProcessInstanceStatusEnum.CANCEL.getStatus().equals(bpmStatus)) {
|
||||||
|
updateObj.setApprovalStatus(4); // 已撤回
|
||||||
|
returnOrderMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 私有方法 ====================
|
||||||
|
|
||||||
|
private ReturnOrderDO validateReturnOrderExists(Long id) {
|
||||||
|
ReturnOrderDO order = returnOrderMapper.selectById(id);
|
||||||
|
if (order == null) {
|
||||||
|
throw exception(RETURN_ORDER_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateTotalRefund(Long orderId) {
|
||||||
|
ReturnOrderDO order = returnOrderMapper.selectById(orderId);
|
||||||
|
if (order == null) return;
|
||||||
|
|
||||||
|
List<ReturnOrderVehicleDO> vehicles = returnOrderVehicleMapper.selectListByReturnOrderId(orderId);
|
||||||
|
BigDecimal totalHydrogenRefund = vehicles.stream()
|
||||||
|
.map(v -> v.getHydrogenRefundAmount() != null ? v.getHydrogenRefundAmount() : BigDecimal.ZERO)
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
|
||||||
|
BigDecimal depositRefund = order.getDepositRefund() != null ? order.getDepositRefund() : BigDecimal.ZERO;
|
||||||
|
BigDecimal otherCharges = order.getOtherCharges() != null ? order.getOtherCharges() : BigDecimal.ZERO;
|
||||||
|
BigDecimal totalRefund = depositRefund.add(totalHydrogenRefund).subtract(otherCharges);
|
||||||
|
|
||||||
|
returnOrderMapper.updateById(ReturnOrderDO.builder()
|
||||||
|
.id(orderId)
|
||||||
|
.hydrogenRefund(totalHydrogenRefund)
|
||||||
|
.totalRefundAmount(totalRefund)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.returnorder.event;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 还车单审批通过事件
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ReturnApprovedEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 还车单ID
|
||||||
|
*/
|
||||||
|
private final Long returnOrderId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 还车单中的所有车辆ID
|
||||||
|
*/
|
||||||
|
private final List<Long> vehicleIds;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package cn.iocoder.yudao.module.asset.service.returnorder.listener;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
|
||||||
|
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener;
|
||||||
|
import cn.iocoder.yudao.module.asset.service.returnorder.ReturnOrderService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 还车单审批状态监听器
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ReturnOrderBpmListener extends BpmProcessInstanceStatusEventListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程定义 Key
|
||||||
|
*/
|
||||||
|
public static final String PROCESS_KEY = "asset_return_order";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ReturnOrderService returnOrderService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getProcessDefinitionKey() {
|
||||||
|
return PROCESS_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onEvent(BpmProcessInstanceStatusEvent event) {
|
||||||
|
returnOrderService.updateApprovalStatus(Long.parseLong(event.getBusinessKey()), event.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:flowable="http://flowable.org/bpmn"
|
||||||
|
typeLanguage="http://www.w3.org/2001/XMLSchema"
|
||||||
|
expressionLanguage="http://www.w3.org/1999/XPath"
|
||||||
|
targetNamespace="http://www.flowable.org/processdef">
|
||||||
|
|
||||||
|
<process id="asset_return_order" name="还车单审批" isExecutable="true">
|
||||||
|
|
||||||
|
<startEvent id="startEvent" name="开始"/>
|
||||||
|
|
||||||
|
<sequenceFlow sourceRef="startEvent" targetRef="deptManagerApproval"/>
|
||||||
|
|
||||||
|
<!-- 部门主管审批 -->
|
||||||
|
<userTask id="deptManagerApproval" name="部门主管审批" flowable:candidateGroups="dept_manager">
|
||||||
|
<extensionElements>
|
||||||
|
<flowable:formProperty id="approved" name="是否同意" type="boolean" required="true"/>
|
||||||
|
<flowable:formProperty id="comment" name="审批意见" type="string"/>
|
||||||
|
</extensionElements>
|
||||||
|
</userTask>
|
||||||
|
|
||||||
|
<sequenceFlow sourceRef="deptManagerApproval" targetRef="gateway1"/>
|
||||||
|
|
||||||
|
<!-- 网关:判断部门主管是否同意 -->
|
||||||
|
<exclusiveGateway id="gateway1"/>
|
||||||
|
|
||||||
|
<sequenceFlow sourceRef="gateway1" targetRef="endEventApprove">
|
||||||
|
<conditionExpression xsi:type="tFormalExpression">${approved == true}</conditionExpression>
|
||||||
|
</sequenceFlow>
|
||||||
|
|
||||||
|
<sequenceFlow sourceRef="gateway1" targetRef="endEventReject">
|
||||||
|
<conditionExpression xsi:type="tFormalExpression">${approved == false}</conditionExpression>
|
||||||
|
</sequenceFlow>
|
||||||
|
|
||||||
|
<!-- 审批通过结束 -->
|
||||||
|
<endEvent id="endEventApprove" name="审批通过"/>
|
||||||
|
|
||||||
|
<!-- 审批拒绝结束 -->
|
||||||
|
<endEvent id="endEventReject" name="审批拒绝"/>
|
||||||
|
|
||||||
|
</process>
|
||||||
|
|
||||||
|
</definitions>
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:flowable="http://flowable.org/bpmn"
|
||||||
|
typeLanguage="http://www.w3.org/2001/XMLSchema"
|
||||||
|
expressionLanguage="http://www.w3.org/1999/XPath"
|
||||||
|
targetNamespace="http://www.flowable.org/processdef">
|
||||||
|
|
||||||
|
<process id="asset_vehicle_replacement" name="替换车审批" isExecutable="true">
|
||||||
|
|
||||||
|
<startEvent id="startEvent" name="开始"/>
|
||||||
|
|
||||||
|
<sequenceFlow sourceRef="startEvent" targetRef="deptManagerApproval"/>
|
||||||
|
|
||||||
|
<!-- 部门主管审批 -->
|
||||||
|
<userTask id="deptManagerApproval" name="部门主管审批" flowable:candidateGroups="dept_manager">
|
||||||
|
<extensionElements>
|
||||||
|
<flowable:formProperty id="approved" name="是否同意" type="boolean" required="true"/>
|
||||||
|
<flowable:formProperty id="comment" name="审批意见" type="string"/>
|
||||||
|
</extensionElements>
|
||||||
|
</userTask>
|
||||||
|
|
||||||
|
<sequenceFlow sourceRef="deptManagerApproval" targetRef="gateway1"/>
|
||||||
|
|
||||||
|
<!-- 网关:判断部门主管是否同意 -->
|
||||||
|
<exclusiveGateway id="gateway1"/>
|
||||||
|
|
||||||
|
<!-- 同意且为永久替换 → 总经理审批 -->
|
||||||
|
<sequenceFlow sourceRef="gateway1" targetRef="gmApproval">
|
||||||
|
<conditionExpression xsi:type="tFormalExpression">${approved == true && replacementType == 2}</conditionExpression>
|
||||||
|
</sequenceFlow>
|
||||||
|
|
||||||
|
<!-- 同意且为临时替换 → 直接通过 -->
|
||||||
|
<sequenceFlow sourceRef="gateway1" targetRef="endEventApprove">
|
||||||
|
<conditionExpression xsi:type="tFormalExpression">${approved == true && replacementType == 1}</conditionExpression>
|
||||||
|
</sequenceFlow>
|
||||||
|
|
||||||
|
<!-- 不同意 → 拒绝 -->
|
||||||
|
<sequenceFlow sourceRef="gateway1" targetRef="endEventReject">
|
||||||
|
<conditionExpression xsi:type="tFormalExpression">${approved == false}</conditionExpression>
|
||||||
|
</sequenceFlow>
|
||||||
|
|
||||||
|
<!-- 总经理审批 -->
|
||||||
|
<userTask id="gmApproval" name="总经理审批" flowable:candidateGroups="general_manager">
|
||||||
|
<extensionElements>
|
||||||
|
<flowable:formProperty id="approved" name="是否同意" type="boolean" required="true"/>
|
||||||
|
<flowable:formProperty id="comment" name="审批意见" type="string"/>
|
||||||
|
</extensionElements>
|
||||||
|
</userTask>
|
||||||
|
|
||||||
|
<sequenceFlow sourceRef="gmApproval" targetRef="gateway2"/>
|
||||||
|
|
||||||
|
<!-- 网关:判断总经理是否同意 -->
|
||||||
|
<exclusiveGateway id="gateway2"/>
|
||||||
|
|
||||||
|
<sequenceFlow sourceRef="gateway2" targetRef="endEventApprove">
|
||||||
|
<conditionExpression xsi:type="tFormalExpression">${approved == true}</conditionExpression>
|
||||||
|
</sequenceFlow>
|
||||||
|
|
||||||
|
<sequenceFlow sourceRef="gateway2" targetRef="endEventReject">
|
||||||
|
<conditionExpression xsi:type="tFormalExpression">${approved == false}</conditionExpression>
|
||||||
|
</sequenceFlow>
|
||||||
|
|
||||||
|
<!-- 审批通过结束 -->
|
||||||
|
<endEvent id="endEventApprove" name="审批通过"/>
|
||||||
|
|
||||||
|
<!-- 审批拒绝结束 -->
|
||||||
|
<endEvent id="endEventReject" name="审批拒绝"/>
|
||||||
|
|
||||||
|
</process>
|
||||||
|
|
||||||
|
</definitions>
|
||||||
Reference in New Issue
Block a user