feat: 实现 OCR 模块和车辆上牌管理功能
- 新增 yudao-module-ocr 模块 - OCR API 模块:定义 Feign 接口和 DTO - OCR Server 模块:实现行驶证识别功能 - 集成百度 OCR SDK - 支持多厂商扩展(百度/腾讯/阿里云) - 新增车辆上牌管理功能 - 数据库表:asset_vehicle_registration - 完整的 CRUD 接口 - 行驶证识别接口(集成 OCR) - 车辆匹配功能(根据 VIN) - 确认上牌功能(更新车辆信息) - 技术实现 - 遵循 BPM/System 模块的 RPC API 模式 - 使用 Feign 实现服务间调用 - Base64 编码传输图片数据 - 统一返回格式 CommonResult<T> - 文档 - OCR 模块使用文档 - OCR 部署指南 - 车辆上牌管理总结 - API 集成规划和总结
This commit is contained in:
211
yudao-module-asset/VEHICLE_REGISTRATION_SUMMARY.md
Normal file
211
yudao-module-asset/VEHICLE_REGISTRATION_SUMMARY.md
Normal file
@@ -0,0 +1,211 @@
|
||||
# 车辆上牌管理功能实施总结
|
||||
|
||||
## 实施完成情况
|
||||
|
||||
### ✅ Phase 2 已完成
|
||||
|
||||
#### 2.1 数据库设计
|
||||
- ✅ 创建 `asset_vehicle_registration` 表
|
||||
- ✅ 添加菜单和权限 SQL
|
||||
- ✅ 文件位置:`yudao-module-asset/sql/mysql/vehicle_registration.sql`
|
||||
|
||||
#### 2.2 后端实现
|
||||
|
||||
**DO 层**
|
||||
- ✅ `VehicleRegistrationDO.java` - 车辆上牌记录实体
|
||||
|
||||
**Mapper 层**
|
||||
- ✅ `VehicleRegistrationMapper.java` - 数据访问层
|
||||
|
||||
**VO 层**
|
||||
- ✅ `VehicleRegistrationBaseVO.java` - 基础 VO
|
||||
- ✅ `VehicleRegistrationSaveReqVO.java` - 创建/更新请求 VO
|
||||
- ✅ `VehicleRegistrationPageReqVO.java` - 分页查询请求 VO
|
||||
- ✅ `VehicleRegistrationRespVO.java` - 响应 VO
|
||||
- ✅ `VehicleLicenseRecognizeRespVO.java` - 识别响应 VO
|
||||
|
||||
**Convert 层**
|
||||
- ✅ `VehicleRegistrationConvert.java` - 对象转换器
|
||||
|
||||
**Service 层**
|
||||
- ✅ `VehicleRegistrationService.java` - 服务接口
|
||||
- ✅ `VehicleRegistrationServiceImpl.java` - 服务实现
|
||||
- 识别行驶证(待集成 OCR)
|
||||
- 创建上牌记录
|
||||
- 更新上牌记录
|
||||
- 删除上牌记录
|
||||
- 查询上牌记录
|
||||
- 确认上牌(更新车辆信息)
|
||||
|
||||
**Controller 层**
|
||||
- ✅ `VehicleRegistrationController.java` - REST API
|
||||
- `POST /asset/vehicle-registration/recognize-license` - 识别行驶证
|
||||
- `POST /asset/vehicle-registration/create` - 创建记录
|
||||
- `PUT /asset/vehicle-registration/update` - 更新记录
|
||||
- `DELETE /asset/vehicle-registration/delete` - 删除记录
|
||||
- `GET /asset/vehicle-registration/get` - 获取单条
|
||||
- `GET /asset/vehicle-registration/page` - 分页查询
|
||||
- `POST /asset/vehicle-registration/confirm` - 确认上牌
|
||||
|
||||
#### 2.3 依赖配置
|
||||
- ✅ 在 `asset-server/pom.xml` 中添加 OCR 模块依赖
|
||||
|
||||
#### 2.4 编译验证
|
||||
- ✅ Maven 编译成功
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
yudao-module-asset/
|
||||
├── sql/mysql/
|
||||
│ └── vehicle_registration.sql # 数据库脚本
|
||||
└── yudao-module-asset-server/
|
||||
└── src/main/java/cn/iocoder/yudao/module/asset/
|
||||
├── controller/admin/vehicleregistration/
|
||||
│ ├── VehicleRegistrationController.java # REST API
|
||||
│ └── vo/
|
||||
│ ├── VehicleRegistrationBaseVO.java
|
||||
│ ├── VehicleRegistrationSaveReqVO.java
|
||||
│ ├── VehicleRegistrationPageReqVO.java
|
||||
│ ├── VehicleRegistrationRespVO.java
|
||||
│ └── VehicleLicenseRecognizeRespVO.java
|
||||
├── service/vehicleregistration/
|
||||
│ ├── VehicleRegistrationService.java # 服务接口
|
||||
│ └── VehicleRegistrationServiceImpl.java # 服务实现
|
||||
├── convert/vehicleregistration/
|
||||
│ └── VehicleRegistrationConvert.java # 对象转换
|
||||
├── dal/
|
||||
│ ├── dataobject/vehicleregistration/
|
||||
│ │ └── VehicleRegistrationDO.java # 实体类
|
||||
│ └── mysql/vehicleregistration/
|
||||
│ └── VehicleRegistrationMapper.java # Mapper
|
||||
└── pom.xml # 添加 OCR 依赖
|
||||
```
|
||||
|
||||
## 核心功能
|
||||
|
||||
### 1. 行驶证识别
|
||||
- 接口:`POST /asset/vehicle-registration/recognize-license`
|
||||
- 功能:上传行驶证照片,OCR 识别车辆信息
|
||||
- 状态:**待集成 OCR 服务**(需要通过 Feign 或 HTTP 调用 OCR 模块)
|
||||
|
||||
### 2. 上牌记录管理
|
||||
- 创建上牌记录
|
||||
- 更新上牌记录
|
||||
- 删除上牌记录
|
||||
- 分页查询上牌记录
|
||||
|
||||
### 3. 确认上牌
|
||||
- 接口:`POST /asset/vehicle-registration/confirm`
|
||||
- 功能:确认上牌记录后,自动更新车辆基础信息表
|
||||
- 更新字段:
|
||||
- 车牌号 (plateNo)
|
||||
- VIN (vin)
|
||||
- 发动机号 (engineNo)
|
||||
- 注册日期 (registerDate)
|
||||
- 强制报废期 (scrapDate)
|
||||
- 检验有效期 (inspectExpire)
|
||||
- 车型ID (vehicleModelId)
|
||||
|
||||
## 技术亮点
|
||||
|
||||
1. **分离设计**:车辆信息拆分为多个表(base/location/business/status),上牌管理只更新基础信息表
|
||||
2. **状态管理**:上牌记录有三种状态(待确认/已确认/已作废)
|
||||
3. **事务保证**:确认上牌时,同时更新上牌记录和车辆信息,保证数据一致性
|
||||
4. **权限控制**:所有接口都有权限验证
|
||||
|
||||
## 待完成工作
|
||||
|
||||
### 🔲 Phase 2.5: OCR 服务集成
|
||||
|
||||
**方案 A:Feign 调用(推荐)**
|
||||
1. 创建 Feign 客户端
|
||||
```java
|
||||
@FeignClient(name = "ocr-server", contextId = "ocrApi")
|
||||
public interface OcrApi {
|
||||
@PostMapping("/admin-api/ocr/vehicle-license")
|
||||
CommonResult<VehicleLicenseRespVO> recognizeVehicleLicense(
|
||||
@RequestParam("file") MultipartFile file);
|
||||
}
|
||||
```
|
||||
|
||||
2. 在 VehicleRegistrationServiceImpl 中注入并调用
|
||||
```java
|
||||
@Resource
|
||||
private OcrApi ocrApi;
|
||||
|
||||
public VehicleLicenseRecognizeRespVO recognizeVehicleLicense(byte[] imageData) {
|
||||
// 调用 OCR 服务
|
||||
CommonResult<VehicleLicenseRespVO> result = ocrApi.recognizeVehicleLicense(...);
|
||||
// 处理结果
|
||||
}
|
||||
```
|
||||
|
||||
**方案 B:HTTP 调用**
|
||||
使用 RestTemplate 或 WebClient 调用 OCR 服务
|
||||
|
||||
### 🔲 Phase 2.6: 测试
|
||||
1. 单元测试
|
||||
2. 集成测试
|
||||
3. 端到端测试
|
||||
|
||||
### 🔲 Phase 2.7: 部署
|
||||
1. 执行数据库脚本
|
||||
2. 配置权限
|
||||
3. 启动服务
|
||||
4. 验证功能
|
||||
|
||||
## API 接口列表
|
||||
|
||||
| 接口 | 方法 | 路径 | 权限 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| 识别行驶证 | POST | /asset/vehicle-registration/recognize-license | asset:vehicle-registration:recognize | 上传照片识别 |
|
||||
| 创建记录 | POST | /asset/vehicle-registration/create | asset:vehicle-registration:create | 创建上牌记录 |
|
||||
| 更新记录 | PUT | /asset/vehicle-registration/update | asset:vehicle-registration:update | 更新上牌记录 |
|
||||
| 删除记录 | DELETE | /asset/vehicle-registration/delete | asset:vehicle-registration:delete | 删除上牌记录 |
|
||||
| 获取单条 | GET | /asset/vehicle-registration/get | asset:vehicle-registration:query | 根据ID查询 |
|
||||
| 分页查询 | GET | /asset/vehicle-registration/page | asset:vehicle-registration:query | 分页查询 |
|
||||
| 确认上牌 | POST | /asset/vehicle-registration/confirm | asset:vehicle-registration:update | 确认并更新车辆 |
|
||||
|
||||
## 数据库表结构
|
||||
|
||||
### asset_vehicle_registration
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | BIGINT | 主键ID |
|
||||
| vehicle_id | BIGINT | 车辆ID |
|
||||
| vin | VARCHAR(50) | 车辆识别代号 |
|
||||
| plate_no | VARCHAR(20) | 车牌号 |
|
||||
| plate_date | DATE | 上牌日期 |
|
||||
| operator | VARCHAR(50) | 操作员 |
|
||||
| recognized_brand | VARCHAR(100) | OCR识别的品牌型号 |
|
||||
| vehicle_model_id | BIGINT | 匹配的车型ID |
|
||||
| photo_url | VARCHAR(500) | 行驶证照片URL |
|
||||
| ocr_provider | VARCHAR(50) | OCR厂商 |
|
||||
| status | TINYINT | 状态(0-待确认 1-已确认 2-已作废) |
|
||||
| ... | ... | 其他字段 |
|
||||
|
||||
## 下一步建议
|
||||
|
||||
1. **优先级 1:集成 OCR 服务**
|
||||
- 实现 Feign 客户端
|
||||
- 完成识别功能
|
||||
- 测试端到端流程
|
||||
|
||||
2. **优先级 2:完善业务逻辑**
|
||||
- 添加车型匹配算法
|
||||
- 实现照片上传到文件服务
|
||||
- 添加识别结果缓存
|
||||
|
||||
3. **优先级 3:前端对接**
|
||||
- 提供 API 文档
|
||||
- 协助前端集成
|
||||
- 联调测试
|
||||
|
||||
---
|
||||
|
||||
**实施日期**:2026-03-12
|
||||
**实施人员**:AI Assistant
|
||||
**版本**:v1.0.0
|
||||
**状态**:Phase 2 完成,待集成 OCR 服务
|
||||
81
yudao-module-asset/sql/mysql/vehicle_registration.sql
Normal file
81
yudao-module-asset/sql/mysql/vehicle_registration.sql
Normal file
@@ -0,0 +1,81 @@
|
||||
-- 车辆上牌记录表
|
||||
CREATE TABLE IF NOT EXISTS `asset_vehicle_registration` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`vehicle_id` BIGINT NOT NULL COMMENT '车辆ID',
|
||||
`vin` VARCHAR(50) NOT NULL COMMENT '车辆识别代号(VIN)',
|
||||
`plate_no` VARCHAR(20) NOT NULL COMMENT '车牌号',
|
||||
`plate_date` DATE NOT NULL COMMENT '上牌日期',
|
||||
`operator` VARCHAR(50) COMMENT '操作员',
|
||||
|
||||
-- OCR 识别信息
|
||||
`recognized_brand` VARCHAR(100) COMMENT 'OCR识别的品牌型号',
|
||||
`recognized_model` VARCHAR(100) COMMENT 'OCR识别的车型',
|
||||
`vehicle_type` VARCHAR(50) COMMENT '车辆类型',
|
||||
`owner` VARCHAR(100) COMMENT '所有人',
|
||||
`use_character` VARCHAR(50) COMMENT '使用性质',
|
||||
`engine_no` VARCHAR(50) COMMENT '发动机号码',
|
||||
`register_date` DATE COMMENT '注册日期',
|
||||
`issue_date` DATE COMMENT '发证日期',
|
||||
`inspection_record` VARCHAR(50) COMMENT '检验记录',
|
||||
`scrap_date` DATE COMMENT '强制报废期止',
|
||||
`curb_weight` VARCHAR(20) COMMENT '整备质量(kg)',
|
||||
`total_mass` VARCHAR(20) COMMENT '总质量(kg)',
|
||||
`approved_passenger_capacity` VARCHAR(20) COMMENT '核定载人数',
|
||||
|
||||
-- 匹配信息
|
||||
`vehicle_model_id` BIGINT COMMENT '匹配的车型ID',
|
||||
`match_confidence` DECIMAL(5,2) COMMENT '匹配置信度(0-100)',
|
||||
`match_method` VARCHAR(20) COMMENT '匹配方式(exact/fuzzy/manual)',
|
||||
|
||||
-- 照片信息
|
||||
`photo_url` VARCHAR(500) COMMENT '行驶证照片URL',
|
||||
`photo_size` INT COMMENT '照片大小(字节)',
|
||||
|
||||
-- OCR 信息
|
||||
`ocr_provider` VARCHAR(50) COMMENT 'OCR厂商',
|
||||
`ocr_cost_time` INT COMMENT 'OCR识别耗时(毫秒)',
|
||||
`ocr_raw_result` TEXT COMMENT 'OCR原始结果(JSON)',
|
||||
|
||||
-- 状态信息
|
||||
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '状态(0-待确认 1-已确认 2-已作废)',
|
||||
`remark` VARCHAR(500) COMMENT '备注',
|
||||
|
||||
-- 审计字段
|
||||
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_vehicle_plate` (`vehicle_id`, `plate_no`, `deleted`),
|
||||
INDEX `idx_vin` (`vin`),
|
||||
INDEX `idx_plate_no` (`plate_no`),
|
||||
INDEX `idx_plate_date` (`plate_date`),
|
||||
INDEX `idx_status` (`status`),
|
||||
INDEX `idx_create_time` (`create_time`),
|
||||
INDEX `idx_tenant_id` (`tenant_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='车辆上牌记录表';
|
||||
|
||||
-- 菜单 SQL
|
||||
INSERT INTO system_menu(
|
||||
name, permission, type, sort, parent_id,
|
||||
path, icon, component, status, component_name
|
||||
)
|
||||
VALUES (
|
||||
'上牌管理', '', 2, 3, (SELECT id FROM system_menu WHERE name = '车辆管理' LIMIT 1),
|
||||
'registration', 'form', 'asset/vehicle/registration/index', 0, 'VehicleRegistration'
|
||||
);
|
||||
|
||||
-- 获取刚插入的菜单ID
|
||||
SET @menuId = LAST_INSERT_ID();
|
||||
|
||||
-- 上牌管理按钮权限
|
||||
INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
|
||||
VALUES
|
||||
('上牌记录查询', 'asset:vehicle-registration:query', 3, 1, @menuId, '', '', '', 0),
|
||||
('上牌记录创建', 'asset:vehicle-registration:create', 3, 2, @menuId, '', '', '', 0),
|
||||
('上牌记录更新', 'asset:vehicle-registration:update', 3, 3, @menuId, '', '', '', 0),
|
||||
('上牌记录删除', 'asset:vehicle-registration:delete', 3, 4, @menuId, '', '', '', 0),
|
||||
('行驶证识别', 'asset:vehicle-registration:recognize', 3, 5, @menuId, '', '', '', 0);
|
||||
@@ -50,6 +50,13 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- OCR 模块 API -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-module-ocr-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Cloud 基础 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
package cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo.VehicleLicenseRecognizeRespVO;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo.VehicleRegistrationPageReqVO;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo.VehicleRegistrationRespVO;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo.VehicleRegistrationSaveReqVO;
|
||||
import cn.iocoder.yudao.module.asset.convert.vehicleregistration.VehicleRegistrationConvert;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.vehicleregistration.VehicleRegistrationDO;
|
||||
import cn.iocoder.yudao.module.asset.service.vehicleregistration.VehicleRegistrationService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import java.io.IOException;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* 车辆上牌记录 Controller
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Tag(name = "管理后台 - 车辆上牌记录")
|
||||
@RestController
|
||||
@RequestMapping("/asset/vehicle-registration")
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class VehicleRegistrationController {
|
||||
|
||||
@Resource
|
||||
private VehicleRegistrationService vehicleRegistrationService;
|
||||
|
||||
@PostMapping("/recognize-license")
|
||||
@Operation(summary = "识别行驶证")
|
||||
@PreAuthorize("@ss.hasPermission('asset:vehicle-registration:recognize')")
|
||||
public CommonResult<VehicleLicenseRecognizeRespVO> recognizeVehicleLicense(
|
||||
@Parameter(description = "行驶证图片文件", required = true)
|
||||
@RequestParam("file") MultipartFile file) throws IOException {
|
||||
|
||||
log.info("[recognizeVehicleLicense][开始识别行驶证,文件名:{},大小:{}]",
|
||||
file.getOriginalFilename(), file.getSize());
|
||||
|
||||
// 读取图片数据
|
||||
byte[] imageData = file.getBytes();
|
||||
|
||||
// 调用识别服务
|
||||
VehicleLicenseRecognizeRespVO result = vehicleRegistrationService.recognizeVehicleLicense(imageData);
|
||||
|
||||
return success(result);
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建车辆上牌记录")
|
||||
@PreAuthorize("@ss.hasPermission('asset:vehicle-registration:create')")
|
||||
public CommonResult<Long> createVehicleRegistration(@Valid @RequestBody VehicleRegistrationSaveReqVO createReqVO) {
|
||||
return success(vehicleRegistrationService.createVehicleRegistration(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新车辆上牌记录")
|
||||
@PreAuthorize("@ss.hasPermission('asset:vehicle-registration:update')")
|
||||
public CommonResult<Boolean> updateVehicleRegistration(@Valid @RequestBody VehicleRegistrationSaveReqVO updateReqVO) {
|
||||
vehicleRegistrationService.updateVehicleRegistration(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除车辆上牌记录")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('asset:vehicle-registration:delete')")
|
||||
public CommonResult<Boolean> deleteVehicleRegistration(@RequestParam("id") Long id) {
|
||||
vehicleRegistrationService.deleteVehicleRegistration(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得车辆上牌记录")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||
@PreAuthorize("@ss.hasPermission('asset:vehicle-registration:query')")
|
||||
public CommonResult<VehicleRegistrationRespVO> getVehicleRegistration(@RequestParam("id") Long id) {
|
||||
VehicleRegistrationDO registration = vehicleRegistrationService.getVehicleRegistration(id);
|
||||
return success(VehicleRegistrationConvert.INSTANCE.convert(registration));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得车辆上牌记录分页")
|
||||
@PreAuthorize("@ss.hasPermission('asset:vehicle-registration:query')")
|
||||
public CommonResult<PageResult<VehicleRegistrationRespVO>> getVehicleRegistrationPage(@Valid VehicleRegistrationPageReqVO pageReqVO) {
|
||||
PageResult<VehicleRegistrationDO> pageResult = vehicleRegistrationService.getVehicleRegistrationPage(pageReqVO);
|
||||
return success(VehicleRegistrationConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@PostMapping("/confirm")
|
||||
@Operation(summary = "确认上牌记录(更新车辆信息)")
|
||||
@Parameter(name = "id", description = "上牌记录ID", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('asset:vehicle-registration:update')")
|
||||
public CommonResult<Boolean> confirmRegistration(@RequestParam("id") Long id) {
|
||||
vehicleRegistrationService.confirmRegistration(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 行驶证识别 Response VO
|
||||
*/
|
||||
@Schema(description = "管理后台 - 行驶证识别 Response VO")
|
||||
@Data
|
||||
public class VehicleLicenseRecognizeRespVO {
|
||||
|
||||
@Schema(description = "车辆识别代号(VIN)", example = "LB9A32A22R0LS1439")
|
||||
private String vin;
|
||||
|
||||
@Schema(description = "号牌号码", example = "粤AGR5547")
|
||||
private String plateNo;
|
||||
|
||||
@Schema(description = "品牌型号", example = "帕力安牌XDQ5041XLCFCEV")
|
||||
private String brand;
|
||||
|
||||
@Schema(description = "车辆类型", example = "轻型厢式货车")
|
||||
private String vehicleType;
|
||||
|
||||
@Schema(description = "所有人", example = "广州开发区交投氯能运营管理有限公司")
|
||||
private String owner;
|
||||
|
||||
@Schema(description = "使用性质", example = "货运")
|
||||
private String useCharacter;
|
||||
|
||||
@Schema(description = "发动机号码", example = "268E7AEL153")
|
||||
private String engineNo;
|
||||
|
||||
@Schema(description = "注册日期", example = "2025-02-19")
|
||||
private LocalDate registerDate;
|
||||
|
||||
@Schema(description = "发证日期", example = "2025-10-21")
|
||||
private LocalDate issueDate;
|
||||
|
||||
@Schema(description = "检验记录", example = "2026-06")
|
||||
private String inspectionRecord;
|
||||
|
||||
@Schema(description = "强制报废期止", example = "2035-12-31")
|
||||
private LocalDate scrapDate;
|
||||
|
||||
@Schema(description = "整备质量(kg)", example = "1500")
|
||||
private String curbWeight;
|
||||
|
||||
@Schema(description = "总质量(kg)", example = "1875")
|
||||
private String totalMass;
|
||||
|
||||
@Schema(description = "核定载人数", example = "5")
|
||||
private String approvedPassengerCapacity;
|
||||
|
||||
// ==================== 扩展信息 ====================
|
||||
|
||||
@Schema(description = "车辆ID(如果找到匹配车辆)", example = "1")
|
||||
private Long vehicleId;
|
||||
|
||||
@Schema(description = "匹配的车型ID", example = "1")
|
||||
private Long vehicleModelId;
|
||||
|
||||
@Schema(description = "匹配置信度(0-100)", example = "95.5")
|
||||
private BigDecimal matchConfidence;
|
||||
|
||||
@Schema(description = "匹配方式(exact/fuzzy/none)", example = "exact")
|
||||
private String matchMethod;
|
||||
|
||||
@Schema(description = "OCR厂商", example = "baidu")
|
||||
private String ocrProvider;
|
||||
|
||||
@Schema(description = "OCR识别耗时(毫秒)", example = "988")
|
||||
private Integer ocrCostTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
/**
|
||||
* 车辆上牌记录 Base VO
|
||||
*/
|
||||
@Data
|
||||
public class VehicleRegistrationBaseVO {
|
||||
|
||||
@Schema(description = "车辆ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long vehicleId;
|
||||
|
||||
@Schema(description = "车辆识别代号(VIN)", requiredMode = Schema.RequiredMode.REQUIRED, example = "LB9A32A22R0LS1439")
|
||||
private String vin;
|
||||
|
||||
@Schema(description = "车牌号", requiredMode = Schema.RequiredMode.REQUIRED, example = "粤AGR5547")
|
||||
private String plateNo;
|
||||
|
||||
@Schema(description = "上牌日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2025-02-19")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate plateDate;
|
||||
|
||||
@Schema(description = "操作员", example = "张三")
|
||||
private String operator;
|
||||
|
||||
@Schema(description = "OCR识别的品牌型号", example = "帕力安牌XDQ5041XLCFCEV")
|
||||
private String recognizedBrand;
|
||||
|
||||
@Schema(description = "OCR识别的车型", example = "轻型厢式货车")
|
||||
private String recognizedModel;
|
||||
|
||||
@Schema(description = "车辆类型", example = "轻型厢式货车")
|
||||
private String vehicleType;
|
||||
|
||||
@Schema(description = "所有人", example = "广州开发区交投氯能运营管理有限公司")
|
||||
private String owner;
|
||||
|
||||
@Schema(description = "使用性质", example = "货运")
|
||||
private String useCharacter;
|
||||
|
||||
@Schema(description = "发动机号码", example = "268E7AEL153")
|
||||
private String engineNo;
|
||||
|
||||
@Schema(description = "注册日期", example = "2025-02-19")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate registerDate;
|
||||
|
||||
@Schema(description = "发证日期", example = "2025-10-21")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate issueDate;
|
||||
|
||||
@Schema(description = "检验记录", example = "2026-06")
|
||||
private String inspectionRecord;
|
||||
|
||||
@Schema(description = "强制报废期止", example = "2035-12-31")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate scrapDate;
|
||||
|
||||
@Schema(description = "整备质量(kg)", example = "1500")
|
||||
private String curbWeight;
|
||||
|
||||
@Schema(description = "总质量(kg)", example = "1875")
|
||||
private String totalMass;
|
||||
|
||||
@Schema(description = "核定载人数", example = "5")
|
||||
private String approvedPassengerCapacity;
|
||||
|
||||
@Schema(description = "匹配的车型ID", example = "1")
|
||||
private Long vehicleModelId;
|
||||
|
||||
@Schema(description = "行驶证照片URL", example = "https://example.com/photo.jpg")
|
||||
private String photoUrl;
|
||||
|
||||
@Schema(description = "照片大小(字节)", example = "890000")
|
||||
private Integer photoSize;
|
||||
|
||||
@Schema(description = "OCR厂商", example = "baidu")
|
||||
private String ocrProvider;
|
||||
|
||||
@Schema(description = "状态(0-待确认 1-已确认 2-已作废)", example = "0")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "备注", example = "备注信息")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.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;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
/**
|
||||
* 车辆上牌记录分页查询 Request VO
|
||||
*/
|
||||
@Schema(description = "管理后台 - 车辆上牌记录分页查询 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class VehicleRegistrationPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "车辆ID", example = "1")
|
||||
private Long vehicleId;
|
||||
|
||||
@Schema(description = "车辆识别代号(VIN)", example = "LB9A32A22R0LS1439")
|
||||
private String vin;
|
||||
|
||||
@Schema(description = "车牌号", example = "粤AGR5547")
|
||||
private String plateNo;
|
||||
|
||||
@Schema(description = "上牌日期开始", example = "2025-01-01")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate plateDateStart;
|
||||
|
||||
@Schema(description = "上牌日期结束", example = "2025-12-31")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate plateDateEnd;
|
||||
|
||||
@Schema(description = "操作员", example = "张三")
|
||||
private String operator;
|
||||
|
||||
@Schema(description = "状态(0-待确认 1-已确认 2-已作废)", example = "0")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间开始", example = "2025-01-01 00:00:00")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime createTimeStart;
|
||||
|
||||
@Schema(description = "创建时间结束", example = "2025-12-31 23:59:59")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime createTimeEnd;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 车辆上牌记录 Response VO
|
||||
*/
|
||||
@Schema(description = "管理后台 - 车辆上牌记录 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class VehicleRegistrationRespVO extends VehicleRegistrationBaseVO {
|
||||
|
||||
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "匹配置信度(0-100)", example = "95.5")
|
||||
private BigDecimal matchConfidence;
|
||||
|
||||
@Schema(description = "匹配方式(exact/fuzzy/manual)", example = "exact")
|
||||
private String matchMethod;
|
||||
|
||||
@Schema(description = "OCR识别耗时(毫秒)", example = "988")
|
||||
private Integer ocrCostTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 车辆上牌记录创建/更新 Request VO
|
||||
*/
|
||||
@Schema(description = "管理后台 - 车辆上牌记录创建/更新 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class VehicleRegistrationSaveReqVO extends VehicleRegistrationBaseVO {
|
||||
|
||||
@Schema(description = "主键ID(更新时必填)", example = "1")
|
||||
private Long id;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package cn.iocoder.yudao.module.asset.convert.vehicleregistration;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo.VehicleRegistrationRespVO;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo.VehicleRegistrationSaveReqVO;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.vehicleregistration.VehicleRegistrationDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 车辆上牌记录 Convert
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Mapper
|
||||
public interface VehicleRegistrationConvert {
|
||||
|
||||
VehicleRegistrationConvert INSTANCE = Mappers.getMapper(VehicleRegistrationConvert.class);
|
||||
|
||||
VehicleRegistrationDO convert(VehicleRegistrationSaveReqVO bean);
|
||||
|
||||
VehicleRegistrationRespVO convert(VehicleRegistrationDO bean);
|
||||
|
||||
List<VehicleRegistrationRespVO> convertList(List<VehicleRegistrationDO> list);
|
||||
|
||||
PageResult<VehicleRegistrationRespVO> convertPage(PageResult<VehicleRegistrationDO> page);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package cn.iocoder.yudao.module.asset.dal.dataobject.vehicleregistration;
|
||||
|
||||
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.LocalDate;
|
||||
|
||||
/**
|
||||
* 车辆上牌记录 DO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName("asset_vehicle_registration")
|
||||
@KeySequence("asset_vehicle_registration_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class VehicleRegistrationDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 车辆ID
|
||||
*/
|
||||
private Long vehicleId;
|
||||
|
||||
/**
|
||||
* 车辆识别代号(VIN)
|
||||
*/
|
||||
private String vin;
|
||||
|
||||
/**
|
||||
* 车牌号
|
||||
*/
|
||||
private String plateNo;
|
||||
|
||||
/**
|
||||
* 上牌日期
|
||||
*/
|
||||
private LocalDate plateDate;
|
||||
|
||||
/**
|
||||
* 操作员
|
||||
*/
|
||||
private String operator;
|
||||
|
||||
// ==================== OCR 识别信息 ====================
|
||||
|
||||
/**
|
||||
* OCR识别的品牌型号
|
||||
*/
|
||||
private String recognizedBrand;
|
||||
|
||||
/**
|
||||
* OCR识别的车型
|
||||
*/
|
||||
private String recognizedModel;
|
||||
|
||||
/**
|
||||
* 车辆类型
|
||||
*/
|
||||
private String vehicleType;
|
||||
|
||||
/**
|
||||
* 所有人
|
||||
*/
|
||||
private String owner;
|
||||
|
||||
/**
|
||||
* 使用性质
|
||||
*/
|
||||
private String useCharacter;
|
||||
|
||||
/**
|
||||
* 发动机号码
|
||||
*/
|
||||
private String engineNo;
|
||||
|
||||
/**
|
||||
* 注册日期
|
||||
*/
|
||||
private LocalDate registerDate;
|
||||
|
||||
/**
|
||||
* 发证日期
|
||||
*/
|
||||
private LocalDate issueDate;
|
||||
|
||||
/**
|
||||
* 检验记录
|
||||
*/
|
||||
private String inspectionRecord;
|
||||
|
||||
/**
|
||||
* 强制报废期止
|
||||
*/
|
||||
private LocalDate scrapDate;
|
||||
|
||||
/**
|
||||
* 整备质量(kg)
|
||||
*/
|
||||
private String curbWeight;
|
||||
|
||||
/**
|
||||
* 总质量(kg)
|
||||
*/
|
||||
private String totalMass;
|
||||
|
||||
/**
|
||||
* 核定载人数
|
||||
*/
|
||||
private String approvedPassengerCapacity;
|
||||
|
||||
// ==================== 匹配信息 ====================
|
||||
|
||||
/**
|
||||
* 匹配的车型ID
|
||||
*/
|
||||
private Long vehicleModelId;
|
||||
|
||||
/**
|
||||
* 匹配置信度(0-100)
|
||||
*/
|
||||
private BigDecimal matchConfidence;
|
||||
|
||||
/**
|
||||
* 匹配方式(exact/fuzzy/manual)
|
||||
*/
|
||||
private String matchMethod;
|
||||
|
||||
// ==================== 照片信息 ====================
|
||||
|
||||
/**
|
||||
* 行驶证照片URL
|
||||
*/
|
||||
private String photoUrl;
|
||||
|
||||
/**
|
||||
* 照片大小(字节)
|
||||
*/
|
||||
private Integer photoSize;
|
||||
|
||||
// ==================== OCR 信息 ====================
|
||||
|
||||
/**
|
||||
* OCR厂商
|
||||
*/
|
||||
private String ocrProvider;
|
||||
|
||||
/**
|
||||
* OCR识别耗时(毫秒)
|
||||
*/
|
||||
private Integer ocrCostTime;
|
||||
|
||||
/**
|
||||
* OCR原始结果(JSON)
|
||||
*/
|
||||
private String ocrRawResult;
|
||||
|
||||
// ==================== 状态信息 ====================
|
||||
|
||||
/**
|
||||
* 状态(0-待确认 1-已确认 2-已作废)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package cn.iocoder.yudao.module.asset.dal.mysql.vehicleregistration;
|
||||
|
||||
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.vehicleregistration.vo.VehicleRegistrationPageReqVO;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.vehicleregistration.VehicleRegistrationDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 车辆上牌记录 Mapper
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Mapper
|
||||
public interface VehicleRegistrationMapper extends BaseMapperX<VehicleRegistrationDO> {
|
||||
|
||||
default PageResult<VehicleRegistrationDO> selectPage(VehicleRegistrationPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<VehicleRegistrationDO>()
|
||||
.eqIfPresent(VehicleRegistrationDO::getVehicleId, reqVO.getVehicleId())
|
||||
.likeIfPresent(VehicleRegistrationDO::getVin, reqVO.getVin())
|
||||
.likeIfPresent(VehicleRegistrationDO::getPlateNo, reqVO.getPlateNo())
|
||||
.betweenIfPresent(VehicleRegistrationDO::getPlateDate, reqVO.getPlateDateStart(), reqVO.getPlateDateEnd())
|
||||
.likeIfPresent(VehicleRegistrationDO::getOperator, reqVO.getOperator())
|
||||
.eqIfPresent(VehicleRegistrationDO::getStatus, reqVO.getStatus())
|
||||
.betweenIfPresent(VehicleRegistrationDO::getCreateTime, reqVO.getCreateTimeStart(), reqVO.getCreateTimeEnd())
|
||||
.orderByDesc(VehicleRegistrationDO::getId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package cn.iocoder.yudao.module.asset.service.vehicleregistration;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo.VehicleLicenseRecognizeRespVO;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo.VehicleRegistrationPageReqVO;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo.VehicleRegistrationSaveReqVO;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.vehicleregistration.VehicleRegistrationDO;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
/**
|
||||
* 车辆上牌记录 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface VehicleRegistrationService {
|
||||
|
||||
/**
|
||||
* 识别行驶证
|
||||
*
|
||||
* @param imageData 图片数据
|
||||
* @return 识别结果
|
||||
*/
|
||||
VehicleLicenseRecognizeRespVO recognizeVehicleLicense(byte[] imageData);
|
||||
|
||||
/**
|
||||
* 创建车辆上牌记录
|
||||
*
|
||||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
*/
|
||||
Long createVehicleRegistration(@Valid VehicleRegistrationSaveReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 更新车辆上牌记录
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updateVehicleRegistration(@Valid VehicleRegistrationSaveReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 删除车辆上牌记录
|
||||
*
|
||||
* @param id 编号
|
||||
*/
|
||||
void deleteVehicleRegistration(Long id);
|
||||
|
||||
/**
|
||||
* 获得车辆上牌记录
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 车辆上牌记录
|
||||
*/
|
||||
VehicleRegistrationDO getVehicleRegistration(Long id);
|
||||
|
||||
/**
|
||||
* 获得车辆上牌记录分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 车辆上牌记录分页
|
||||
*/
|
||||
PageResult<VehicleRegistrationDO> getVehicleRegistrationPage(VehicleRegistrationPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 确认上牌记录(更新车辆信息)
|
||||
*
|
||||
* @param id 上牌记录ID
|
||||
*/
|
||||
void confirmRegistration(Long id);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package cn.iocoder.yudao.module.asset.service.vehicleregistration;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
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.vehicleregistration.vo.VehicleLicenseRecognizeRespVO;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo.VehicleRegistrationPageReqVO;
|
||||
import cn.iocoder.yudao.module.asset.controller.admin.vehicleregistration.vo.VehicleRegistrationSaveReqVO;
|
||||
import cn.iocoder.yudao.module.asset.convert.vehicleregistration.VehicleRegistrationConvert;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.vehicle.VehicleBaseDO;
|
||||
import cn.iocoder.yudao.module.asset.dal.dataobject.vehicleregistration.VehicleRegistrationDO;
|
||||
import cn.iocoder.yudao.module.asset.dal.mysql.vehicle.VehicleBaseMapper;
|
||||
import cn.iocoder.yudao.module.asset.dal.mysql.vehicleregistration.VehicleRegistrationMapper;
|
||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.ocr.api.OcrApi;
|
||||
import cn.iocoder.yudao.module.ocr.api.dto.VehicleLicenseRespDTO;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
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.math.BigDecimal;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
|
||||
/**
|
||||
* 车辆上牌记录 Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class VehicleRegistrationServiceImpl implements VehicleRegistrationService {
|
||||
|
||||
@Resource
|
||||
private VehicleRegistrationMapper vehicleRegistrationMapper;
|
||||
|
||||
@Resource
|
||||
private VehicleBaseMapper vehicleBaseMapper;
|
||||
|
||||
@Resource
|
||||
private OcrApi ocrApi;
|
||||
|
||||
@Override
|
||||
public VehicleLicenseRecognizeRespVO recognizeVehicleLicense(byte[] imageData) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
// Base64 编码图片数据
|
||||
String imageDataBase64 = Base64.encode(imageData);
|
||||
|
||||
// 调用 OCR API 识别
|
||||
CommonResult<VehicleLicenseRespDTO> ocrResult = ocrApi.recognizeVehicleLicense(imageDataBase64, null);
|
||||
|
||||
long costTime = System.currentTimeMillis() - startTime;
|
||||
|
||||
// 检查调用结果
|
||||
if (ocrResult == null || !ocrResult.isSuccess() || ocrResult.getData() == null) {
|
||||
log.error("[recognizeVehicleLicense][OCR识别失败,结果:{}]", ocrResult);
|
||||
throw exception(new ErrorCode(500, "OCR识别失败"));
|
||||
}
|
||||
|
||||
VehicleLicenseRespDTO ocrData = ocrResult.getData();
|
||||
log.info("[recognizeVehicleLicense][OCR识别完成,耗时:{}ms,VIN:{},车牌号:{}]",
|
||||
costTime, ocrData.getVin(), ocrData.getPlateNo());
|
||||
|
||||
// 转换为响应 VO
|
||||
VehicleLicenseRecognizeRespVO respVO = new VehicleLicenseRecognizeRespVO();
|
||||
BeanUtil.copyProperties(ocrData, respVO);
|
||||
respVO.setOcrProvider("baidu");
|
||||
respVO.setOcrCostTime((int) costTime);
|
||||
|
||||
// 根据 VIN 查找车辆
|
||||
if (StrUtil.isNotBlank(ocrData.getVin())) {
|
||||
VehicleBaseDO vehicle = vehicleBaseMapper.selectOne(new LambdaQueryWrapper<VehicleBaseDO>()
|
||||
.eq(VehicleBaseDO::getVin, ocrData.getVin())
|
||||
.last("LIMIT 1"));
|
||||
|
||||
if (vehicle != null) {
|
||||
respVO.setVehicleId(vehicle.getId());
|
||||
respVO.setVehicleModelId(vehicle.getVehicleModelId());
|
||||
respVO.setMatchMethod("exact");
|
||||
respVO.setMatchConfidence(new BigDecimal("100.00"));
|
||||
log.info("[recognizeVehicleLicense][找到匹配车辆,车辆ID:{}]", vehicle.getId());
|
||||
} else {
|
||||
respVO.setMatchMethod("none");
|
||||
respVO.setMatchConfidence(BigDecimal.ZERO);
|
||||
log.warn("[recognizeVehicleLicense][未找到匹配车辆,VIN:{}]", ocrData.getVin());
|
||||
}
|
||||
}
|
||||
|
||||
return respVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createVehicleRegistration(VehicleRegistrationSaveReqVO createReqVO) {
|
||||
// 验证车辆是否存在
|
||||
VehicleBaseDO vehicle = validateVehicleExists(createReqVO.getVehicleId());
|
||||
|
||||
// 插入
|
||||
VehicleRegistrationDO registration = VehicleRegistrationConvert.INSTANCE.convert(createReqVO);
|
||||
registration.setStatus(0); // 待确认
|
||||
vehicleRegistrationMapper.insert(registration);
|
||||
|
||||
log.info("[createVehicleRegistration][创建上牌记录成功,ID:{},车辆ID:{},车牌号:{}]",
|
||||
registration.getId(), registration.getVehicleId(), registration.getPlateNo());
|
||||
|
||||
return registration.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateVehicleRegistration(VehicleRegistrationSaveReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
validateVehicleRegistrationExists(updateReqVO.getId());
|
||||
|
||||
// 验证车辆是否存在
|
||||
if (updateReqVO.getVehicleId() != null) {
|
||||
validateVehicleExists(updateReqVO.getVehicleId());
|
||||
}
|
||||
|
||||
// 更新
|
||||
VehicleRegistrationDO updateObj = VehicleRegistrationConvert.INSTANCE.convert(updateReqVO);
|
||||
vehicleRegistrationMapper.updateById(updateObj);
|
||||
|
||||
log.info("[updateVehicleRegistration][更新上牌记录成功,ID:{}]", updateReqVO.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteVehicleRegistration(Long id) {
|
||||
// 校验存在
|
||||
validateVehicleRegistrationExists(id);
|
||||
|
||||
// 删除
|
||||
vehicleRegistrationMapper.deleteById(id);
|
||||
|
||||
log.info("[deleteVehicleRegistration][删除上牌记录成功,ID:{}]", id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VehicleRegistrationDO getVehicleRegistration(Long id) {
|
||||
return vehicleRegistrationMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<VehicleRegistrationDO> getVehicleRegistrationPage(VehicleRegistrationPageReqVO pageReqVO) {
|
||||
return vehicleRegistrationMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void confirmRegistration(Long id) {
|
||||
// 获取上牌记录
|
||||
VehicleRegistrationDO registration = validateVehicleRegistrationExists(id);
|
||||
|
||||
// 验证状态
|
||||
if (registration.getStatus() != 0) {
|
||||
throw exception(new ErrorCode(400, "上牌记录已确认或已作废"));
|
||||
}
|
||||
|
||||
// 更新车辆信息
|
||||
VehicleBaseDO vehicle = validateVehicleExists(registration.getVehicleId());
|
||||
VehicleBaseDO updateVehicle = new VehicleBaseDO();
|
||||
updateVehicle.setId(vehicle.getId());
|
||||
updateVehicle.setPlateNo(registration.getPlateNo());
|
||||
updateVehicle.setVin(registration.getVin());
|
||||
updateVehicle.setEngineNo(registration.getEngineNo());
|
||||
updateVehicle.setRegisterDate(registration.getRegisterDate());
|
||||
updateVehicle.setScrapDate(registration.getScrapDate());
|
||||
if (StrUtil.isNotBlank(registration.getInspectionRecord())) {
|
||||
updateVehicle.setInspectExpire(registration.getInspectionRecord());
|
||||
}
|
||||
if (registration.getVehicleModelId() != null) {
|
||||
updateVehicle.setVehicleModelId(registration.getVehicleModelId());
|
||||
}
|
||||
|
||||
vehicleBaseMapper.updateById(updateVehicle);
|
||||
|
||||
// 更新上牌记录状态为已确认
|
||||
VehicleRegistrationDO updateRegistration = new VehicleRegistrationDO();
|
||||
updateRegistration.setId(id);
|
||||
updateRegistration.setStatus(1);
|
||||
vehicleRegistrationMapper.updateById(updateRegistration);
|
||||
|
||||
log.info("[confirmRegistration][确认上牌记录成功,ID:{},车辆ID:{}]", id, vehicle.getId());
|
||||
}
|
||||
|
||||
// ==================== 私有方法 ====================
|
||||
|
||||
private VehicleRegistrationDO validateVehicleRegistrationExists(Long id) {
|
||||
VehicleRegistrationDO registration = vehicleRegistrationMapper.selectById(id);
|
||||
if (registration == null) {
|
||||
throw exception(new ErrorCode(400, "上牌记录不存在"));
|
||||
}
|
||||
return registration;
|
||||
}
|
||||
|
||||
private VehicleBaseDO validateVehicleExists(Long vehicleId) {
|
||||
VehicleBaseDO vehicle = vehicleBaseMapper.selectById(vehicleId);
|
||||
if (vehicle == null) {
|
||||
throw exception(new ErrorCode(400, "车辆不存在,请先录入车辆信息"));
|
||||
}
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user