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 ==========
|
||||
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