Compare commits
59 Commits
19fcac1b98
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d3130c4fe | |||
| 96d7f8d803 | |||
| 0adba6f5cb | |||
| 668ae04530 | |||
| 116dca0543 | |||
| c54de034d2 | |||
| efab0eeb18 | |||
| b1913abab5 | |||
| f21c57943c | |||
| c737dd5571 | |||
| 7a40f887a2 | |||
| 5133b20cca | |||
| 15f20d9e28 | |||
| bcc39277b0 | |||
| 98a83bc79c | |||
| 5b87e2f7ca | |||
| e76b3a35aa | |||
| 977bd0a2bb | |||
| 38b393cafa | |||
| 041bdf1a32 | |||
| d9ce694835 | |||
| c29596337f | |||
| 71558b072d | |||
| afaa25489d | |||
| 9ada784a17 | |||
| eab8a4693d | |||
| 7f79698681 | |||
| 0ebdcdb6bf | |||
| 5b3c300c75 | |||
| 7254f7c35f | |||
| d48ecdd89c | |||
| 6d288e7d3e | |||
| e1ce6413ba | |||
| 52dbbe5cc3 | |||
| d5f5ef3f37 | |||
| 627f155564 | |||
| 4a77f3e431 | |||
| 0cc73dc267 | |||
| 0784898e48 | |||
| 3557a1a935 | |||
| 9346f2d04d | |||
| b0f0121243 | |||
| 1faf21460e | |||
| be53d4b47b | |||
| e8f15ae740 | |||
| a8cd9183c8 | |||
| 2661e36c36 | |||
| 4e1d73d3cb | |||
| cea67f5e43 | |||
| 436f1ab5a3 | |||
| 6a446ed607 | |||
| 691fa4a94d | |||
| 175f1a310a | |||
| e4b4b89354 | |||
| faecd5586b | |||
| 159d2d97df | |||
| b5c16ad096 | |||
| 799d919575 | |||
| b8970a2c88 |
@@ -5,13 +5,15 @@ FROM bellsoft/liberica-openjdk-rocky:17.0.16-cds
|
||||
|
||||
LABEL maintainer="shihongwei"
|
||||
|
||||
RUN dnf install -y ffmpeg && dnf clean all
|
||||
|
||||
RUN mkdir -p /hot-platform/server/logs \
|
||||
/hot-platform/server/temp \
|
||||
/hot-platform/skywalking/agent
|
||||
|
||||
WORKDIR /hot-platform/server
|
||||
|
||||
ENV SERVER_PORT=19090 SNAIL_PORT=28080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" TZ=Asia/Shanghai
|
||||
ENV SERVER_PORT=19090 SNAIL_PORT=28080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" TZ=Asia/Shanghai VIDEO_UPLOAD_FFMPEG_COMMAND=ffmpeg
|
||||
|
||||
EXPOSE ${SERVER_PORT}
|
||||
# 暴露 snail job 客户端端口 用于定时任务调度中心通信
|
||||
|
||||
103
docs/HiddenDangerInspectionRejectResubmit.md
Normal file
103
docs/HiddenDangerInspectionRejectResubmit.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# 隐患排查审核不通过重提方案
|
||||
|
||||
## 目标
|
||||
|
||||
- 支持企业审核不通过后,驾驶员再次编辑并重新提交。
|
||||
- 每次审核不通过时,保存当次提交快照、驳回原因、照片、签名等信息。
|
||||
- 详情接口可返回多次审核不通过历史,便于企业端查看。
|
||||
|
||||
## 后端改动
|
||||
|
||||
### 主表 `hot_hidden_danger_inspection`
|
||||
|
||||
新增字段:
|
||||
|
||||
- `submit_version`:提交版本号
|
||||
- `audit_result`:审核结果,`PASS` / `REJECT`
|
||||
- `reject_count`:驳回次数
|
||||
- `last_reject_reason`:最近一次驳回原因
|
||||
- `last_reject_time`:最近一次驳回时间
|
||||
- `last_reject_by_id`:最近一次驳回人ID
|
||||
- `last_reject_by_name`:最近一次驳回人姓名
|
||||
|
||||
### 新表 `hot_hidden_danger_inspection_audit_history`
|
||||
|
||||
用于保存每次审核不通过时的完整快照:
|
||||
|
||||
- 主单ID、计划ID、项目信息
|
||||
- 提交版本号、审核轮次
|
||||
- 驳回原因、审核人、审核时间、审核签名
|
||||
- 当次排查内容、隐患描述、附件、排查人签名、排查人、排查时间
|
||||
- `submit_snapshot_json` 作为完整快照冗余
|
||||
|
||||
## 业务逻辑
|
||||
|
||||
### 驾驶员提交
|
||||
|
||||
- 首次提交时,沿用原有 `updateByBo` 提交流程。
|
||||
- 驳回后再次编辑提交时,只要主单已经被回调置为:
|
||||
- `status = 1`
|
||||
- `flow_status = REJECTED`
|
||||
- `instance_id = null`
|
||||
- 再次保存后会重新启动 `HIDDEN_DANGER_CHECK` 流程。
|
||||
- 每次重提时:
|
||||
- `submit_version + 1`
|
||||
- 清空上一轮审核结论、审核签名、评估人等中间字段
|
||||
- 状态回到 `status = 2`
|
||||
|
||||
### 企业审核
|
||||
|
||||
审核新增两种结果:
|
||||
|
||||
- `PASS`:审核通过
|
||||
- `REJECT`:审核不通过
|
||||
|
||||
处理规则:
|
||||
|
||||
- `PASS + auditHasDanger = 0`
|
||||
- 流程通过
|
||||
- 主单最终状态在回调中置为 `3`
|
||||
- `PASS + auditHasDanger = 1`
|
||||
- 流程通过
|
||||
- 主单在回调中置为 `6`
|
||||
- 自动创建隐患治理流程
|
||||
- `REJECT`
|
||||
- 先写入驳回历史表
|
||||
- 主单记录最近一次驳回信息
|
||||
- 流程按驳回处理
|
||||
- 回调把主单恢复为可再次编辑状态
|
||||
|
||||
### 流程回调
|
||||
|
||||
`HiddenDangerCheckCallback` 调整为:
|
||||
|
||||
- 成功:
|
||||
- `flow_status = APPROVED`
|
||||
- 无隐患:`status = 3`
|
||||
- 有隐患:`status = 6`
|
||||
- 仅在成功且存在隐患时创建治理流程
|
||||
- 驳回:
|
||||
- `flow_status = REJECTED`
|
||||
- `status = 1`
|
||||
- `instance_id = null`
|
||||
- 允许驾驶员再次提交
|
||||
|
||||
## 详情接口
|
||||
|
||||
`queryById` 返回主单详情时,额外附带:
|
||||
|
||||
- `rejectHistoryList`
|
||||
|
||||
该字段按驳回轮次倒序返回,可直接给前端做历史展开。
|
||||
|
||||
## SQL 文件
|
||||
|
||||
SQL 已写入:
|
||||
|
||||
- `sql/update_hidden_danger_inspection_reject_history.sql`
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 当前版本只改后端,未改前端和移动端展示。
|
||||
- 前端后续只要在详情页读取 `rejectHistoryList` 即可展示多次驳回历史。
|
||||
- 审核接口调用时建议明确传 `auditResult`,不要再仅依赖 `auditHasDanger` 推断审核结果。
|
||||
@@ -111,3 +111,200 @@ ADD COLUMN reject_reason varchar(500) NULL COMMENT '审核不通过原因';
|
||||
|
||||
- 详情接口、列表接口、导出接口会返回 `rejectReason` 字段。
|
||||
- 审核驳回通知优先展示 `rejectReason`,没有时才回退展示 `auditResult`。
|
||||
|
||||
## 6. 三检历史记录接口
|
||||
|
||||
### 6.1 新增字段
|
||||
|
||||
- `inspectNo`:三检记录编号,规则为 `SJ + 三检创建日期(yyyyMMdd) + 车牌号后3位 + 4位随机数`
|
||||
- `inspectLocation`:检查地点,出车前、行车中、收车后三个阶段都支持保存
|
||||
|
||||
### 6.2 历史列表接口
|
||||
|
||||
- 路径:`GET /securityManagement/vehicleThreeInspect/history/list`
|
||||
- 说明:按 `inspectId` 聚合查询一轮三检历史记录,支持分页
|
||||
|
||||
返回核心字段:
|
||||
|
||||
- `inspectId`:三检流程ID
|
||||
- `inspectNo`:三检记录编号
|
||||
- `plateNumber`:车牌号
|
||||
- `inspectorName`:检查人
|
||||
- `startTime`:检查开始时间(出车提交时间)
|
||||
- `endTime`:检查结束时间(收车提交时间)
|
||||
- `auditorName`:审核人
|
||||
- `outInspectLocation`:出车前检查地点
|
||||
- `drivingInspectLocation`:行车中检查地点
|
||||
- `backInspectLocation`:收车后检查地点
|
||||
- `outCheck` / `drivingCheck` / `backCheck`:三个阶段详情
|
||||
|
||||
### 6.3 历史详情接口
|
||||
|
||||
- 路径:`GET /securityManagement/vehicleThreeInspect/history/{inspectId}`
|
||||
- 说明:返回指定 `inspectId` 下三个阶段的车辆三检详情
|
||||
|
||||
### 6.4 数据库脚本
|
||||
|
||||
新增脚本:
|
||||
|
||||
- `sql/alter_hot_vehicle_three_inspect_history_fields_20260601.sql`
|
||||
|
||||
脚本内容包含:
|
||||
|
||||
- 为 `hot_vehicle_three_inspect` 增加 `inspect_no`、`inspect_location` 字段
|
||||
- 对历史数据回填 `inspect_no`
|
||||
|
||||
## 7. 多车辆批量审核接口
|
||||
|
||||
### 7.1 可批量审核列表接口
|
||||
|
||||
- 路径:`GET /securityManagement/vehicleThreeInspect/multiVehicleBatchAudit/list`
|
||||
- 说明:分页查询当前登录人员可进行多车辆批量审核的车辆三检列表
|
||||
|
||||
### 7.2 查询参数
|
||||
|
||||
- `pageNum`:页码
|
||||
- `pageSize`:每页条数,前端默认 `20`
|
||||
- `plateNumber`:车牌号,支持筛选
|
||||
- `companyId`:企业ID,可选;不传时后端默认取当前登录企业
|
||||
|
||||
请求示例:
|
||||
|
||||
```http
|
||||
GET /securityManagement/vehicleThreeInspect/multiVehicleBatchAudit/list?pageNum=1&pageSize=20&plateNumber=川A
|
||||
```
|
||||
|
||||
### 7.3 列表筛选规则
|
||||
|
||||
后端只会返回同时满足以下条件的三检流程:
|
||||
|
||||
1. 当前三检流程已经存在`收车后检查`记录。
|
||||
2. 当前三检流程下存在`审核人是当前登录账号`的未审核记录。
|
||||
3. 数据属于当前登录企业。
|
||||
|
||||
不满足上述条件的数据不会出现在列表中。
|
||||
|
||||
### 7.4 返回字段
|
||||
|
||||
后端返回类型为 `HotVehicleThreeInspectSummaryVo`,前端当前主要使用以下字段:
|
||||
|
||||
- `inspectId`:三检流程ID
|
||||
- `vehicleId`:车辆ID
|
||||
- `plateNumber`:车牌号
|
||||
- `inspectorName`:检查人姓名
|
||||
- `auditorName`:审核人姓名
|
||||
- `startTime`:开始时间
|
||||
- `endTime`:结束时间
|
||||
- `outCheck` / `drivingCheck` / `backCheck`:三个阶段详情,查看详情时可直接复用
|
||||
|
||||
返回示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"rows": [
|
||||
{
|
||||
"inspectId": 1001,
|
||||
"vehicleId": 501,
|
||||
"plateNumber": "川A12345",
|
||||
"inspectorName": "张三",
|
||||
"auditorName": "李四",
|
||||
"startTime": "2026-06-17 08:00:00",
|
||||
"endTime": "2026-06-17 18:00:00"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
## 8. 多车辆批量审核提交接口
|
||||
|
||||
### 8.1 接口信息
|
||||
|
||||
- 路径:`POST /securityManagement/vehicleThreeInspect/multiVehicleBatchAudit`
|
||||
- 说明:对多辆车的车辆三检进行批量审核
|
||||
- 处理方式:新接口只负责组装批量审核数据,底层仍复用原有 `batchAudit` 和 `doAudit` 逻辑
|
||||
|
||||
### 8.2 请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"inspectIds": [1001, 1002, 1003],
|
||||
"hasHiddenDanger": 1,
|
||||
"evaluatorId": 2001,
|
||||
"auditTime": "2026-06-17 18:30:00",
|
||||
"auditResult": "存在隐患,需整改",
|
||||
"rejectReason": "轮胎磨损严重",
|
||||
"auditorSignImgUrl": "https://example.com/sign.png"
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 请求字段说明
|
||||
|
||||
- `inspectIds`:三检流程ID集合,必填
|
||||
- `hasHiddenDanger`:是否存在隐患,必填;`0=否`、`1=是`
|
||||
- `evaluatorId`:评估人ID;当 `hasHiddenDanger = 1` 时必填
|
||||
- `auditTime`:审核时间;不传时后端默认取当前时间
|
||||
- `auditResult`:审核结论;不传时后端自动生成
|
||||
- `rejectReason`:审核不通过原因;有隐患时建议传入
|
||||
- `auditorSignImgUrl`:审核人员签名图片地址,必填
|
||||
|
||||
### 8.4 自动生成规则
|
||||
|
||||
- 当 `auditTime` 为空时,后端自动使用当前时间。
|
||||
- 当 `auditResult` 为空时:
|
||||
- `hasHiddenDanger = 0`:自动生成 `通过`
|
||||
- `hasHiddenDanger = 1` 且传了 `rejectReason`:自动生成 `不通过:{rejectReason}`
|
||||
- `hasHiddenDanger = 1` 且未传 `rejectReason`:自动生成 `不通过`
|
||||
|
||||
### 8.5 批量审核校验规则
|
||||
|
||||
后端会对每个 `inspectId` 依次校验:
|
||||
|
||||
1. 三检流程必须存在。
|
||||
2. 当前流程必须已完成收车检查,否则报错:`{车牌号}尚未完成收车检查,不可批量审核`
|
||||
3. 当前流程中必须存在`审核人是当前登录人`的未审核数据,否则报错:`{车牌号}没有当前账号可审核的未审核数据`
|
||||
4. 只有当前登录企业下的数据才会参与组装。
|
||||
5. 组装后的明细仍会走原有单条审核校验,包括:
|
||||
- 流程任务ID不能为空
|
||||
- 三检记录ID不能为空
|
||||
- 审核时间不能早于检查时间
|
||||
- 审核签名校验
|
||||
- 流程审批人校验
|
||||
|
||||
### 8.6 实际审核范围
|
||||
|
||||
每个 `inspectId` 并不是只审核一条数据,而是会自动筛出该三检流程下所有满足以下条件的阶段记录一起审核:
|
||||
|
||||
- 审核人等于当前登录账号
|
||||
- 当前记录尚未审核完成
|
||||
- 当前记录存在流程任务 `taskId`
|
||||
|
||||
因此一次多车辆批量审核,最终可能会展开成多条实际审核明细。
|
||||
|
||||
### 8.7 有隐患时的处理
|
||||
|
||||
- 当 `hasHiddenDanger = 1` 时,审核流程按不通过处理。
|
||||
- 流程结束后,会按每一条三检明细分别创建隐患治理数据。
|
||||
- 如果本次批量审核展开后共有 N 条三检明细,则会生成 N 条隐患治理数据,不会合并成 1 条。
|
||||
|
||||
### 8.8 返回结果
|
||||
|
||||
成功返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
失败时返回业务异常,例如:
|
||||
|
||||
- `三检流程ID不能为空`
|
||||
- `存在隐患时评估人不能为空`
|
||||
- `未查询到可批量审核的车辆三检数据`
|
||||
- `{车牌号}尚未完成收车检查,不可批量审核`
|
||||
- `{车牌号}没有当前账号可审核的未审核数据`
|
||||
|
||||
421
docs/图片水印后缀异常兜底与补救方案.md
Normal file
421
docs/图片水印后缀异常兜底与补救方案.md
Normal file
@@ -0,0 +1,421 @@
|
||||
# 图片水印后缀异常兜底与补救方案
|
||||
|
||||
## 1. 背景
|
||||
|
||||
现有图片取证水印流程位于 [PhotoEvidenceServiceImpl.java:L51-L149](file:///g:/code/shw/hot/wucaixing-full/wucaixing-backend/src/main/java/com/hotwj/platform/common/photoEvidence/service/impl/PhotoEvidenceServiceImpl.java#L51-L149)。
|
||||
|
||||
当前已确认的问题链路如下:
|
||||
|
||||
- 前端上传 OSS 时,部分原始图片没有正确的文件后缀名。
|
||||
- 原始 `sys_oss.file_suffix` 被写成了 `2`、`3`、`.2`、`.3` 这一类异常值。
|
||||
- 后端在生成水印图时,直接使用原始 `file_suffix` 作为 `ImageIO.write` 的输出格式。
|
||||
- 生成的临时文件可能为空文件,最终上传到 OSS 后变成 `0B`。
|
||||
- 新生成的 `sys_oss` 记录中,`ext1.fileSize=0`、`contentType=null`,页面预览和下载均异常。
|
||||
|
||||
示例数据可见 [data.json:L1-L35](file:///g:/code/shw/hot/wucaixing-full/data.json#L1-L35):
|
||||
|
||||
- 原图记录 `file_suffix=3`,但 `ext1.contentType=image/jpeg`
|
||||
- 水印图记录 `file_suffix=.3`,`ext1.fileSize=0`,`contentType=null`
|
||||
|
||||
当前风险点位于 [PhotoEvidenceServiceImpl.java:L137-L149](file:///g:/code/shw/hot/wucaixing-full/wucaixing-backend/src/main/java/com/hotwj/platform/common/photoEvidence/service/impl/PhotoEvidenceServiceImpl.java#L137-L149)
|
||||
,源码中也已经有 `TODO` 提示需要判断 `mime`。
|
||||
|
||||
## 2. 根因分析
|
||||
|
||||
本问题的根因不是“没有后缀名”本身,而是“后端把不可信的后缀名继续当成图片编码格式使用”。
|
||||
|
||||
具体来说:
|
||||
|
||||
- 原始图片是否可读,真正应该依据的是二进制内容和 MIME,不应该只依赖文件名后缀。
|
||||
- 水印图不是前端上传文件,而是后端重新生成的系统产物,其输出格式应由后端统一决定。
|
||||
- 只要继续信任 `sys_oss.file_suffix`,就会持续受到历史脏数据和前端上传异常的影响。
|
||||
|
||||
因此,兜底思路必须从“猜正确后缀”改成“后端固定输出规范”。
|
||||
|
||||
## 3. 线上兜底方案
|
||||
|
||||
### 3.1 目标
|
||||
|
||||
阻断新增坏数据,确保后续所有水印图都能稳定生成、上传、展示和下载。
|
||||
|
||||
### 3.2 方案原则
|
||||
|
||||
- 原图校验看内容,不看后缀。
|
||||
- 水印图输出格式由后端统一指定,不继承原图后缀。
|
||||
- 上传时必须带明确的 `contentType`。
|
||||
- 入库前必须校验结果文件非空。
|
||||
|
||||
### 3.3 推荐方案
|
||||
|
||||
建议将“图片取证水印图”统一输出为 `jpg/jpeg`。
|
||||
|
||||
原因:
|
||||
|
||||
-
|
||||
当前水印结果图在 [PhotoEvidenceServiceImpl.java:L261-L283](file:///g:/code/shw/hot/wucaixing-full/wucaixing-backend/src/main/java/com/hotwj/platform/common/photoEvidence/service/impl/PhotoEvidenceServiceImpl.java#L261-L283)
|
||||
中已经固定为 `BufferedImage.TYPE_INT_RGB`,天然适合输出为 `JPEG`。
|
||||
- 业务场景是现场拍照取证,统一输出 `jpg` 与实际使用习惯一致。
|
||||
- 可以彻底摆脱 `2`、`3`、`.2`、`.3` 这一类脏后缀的影响。
|
||||
- 后续历史修复和排障标准会非常统一。
|
||||
|
||||
### 3.4 兜底规则
|
||||
|
||||
建议按以下规则处理:
|
||||
|
||||
1. 下载原始 OSS 文件后,先尝试按图片内容解析。
|
||||
2. 只要原图字节能正常解析成图片,就允许继续加水印。
|
||||
3. 水印结果图统一编码为 `jpeg`。
|
||||
4. 临时文件统一使用 `.jpg` 后缀。
|
||||
5. 上传 OSS 时统一使用 `contentType=image/jpeg`。
|
||||
6. 上传前必须校验:
|
||||
- `ImageIO.write` 返回成功
|
||||
- 临时文件存在
|
||||
- 临时文件大小大于 `0`
|
||||
7. 任一校验失败,直接报错,不创建 `HotPhotoEvidence` 记录,不创建新的水印 `sys_oss` 记录。
|
||||
|
||||
### 3.5 兜底后的收益
|
||||
|
||||
- 前端即使继续上传无后缀文件,后端仍可稳定产出标准水印图。
|
||||
- 生成的水印图始终具备标准后缀和标准 `contentType`。
|
||||
- 不再出现 `.2`、`.3` 这类系统生成的异常文件。
|
||||
- 新增数据和历史补救数据将收敛到同一规范。
|
||||
|
||||
## 4. 历史补救总原则
|
||||
|
||||
### 4.1 必须满足的约束
|
||||
|
||||
本次历史补救必须满足以下硬约束:
|
||||
|
||||
- 必须替换原有坏掉的 `sys_oss` 记录内容。
|
||||
- 必须保持原 `oss_id` 不变。
|
||||
- 不能只改 `HotPhotoEvidence` 表中的 `watermarked_oss_id` 指向。
|
||||
- 不能新增一条新的 `sys_oss` 记录再让业务表改引用。
|
||||
|
||||
原因:
|
||||
|
||||
- 这个 `oss_id` 不仅存在于 `HotPhotoEvidence`,还可能被其他业务表、日志记录、导出记录、接口缓存、前端页面配置等位置复用。
|
||||
- 如果改成新 `oss_id`,补救范围会迅速扩散到未知引用方,风险不可控。
|
||||
- 保持原 `oss_id` 不变,才能把历史补救范围收敛在“文件对象替换 + 原记录修补”这一层。
|
||||
|
||||
### 4.2 正确的补救思路
|
||||
|
||||
正确思路不是“替换原始图的 `sys_oss` 记录”,而是:
|
||||
|
||||
- 以 `HotPhotoEvidence` 为主表定位坏掉的水印记录。
|
||||
- 通过 `original_oss_id` 找回原始图片。
|
||||
- 重新生成一张标准的水印图。
|
||||
- 上传到 OSS 获得新的对象文件。
|
||||
- 然后覆盖原 `watermarked_oss_id` 对应的 `sys_oss` 记录内容。
|
||||
- `oss_id` 保持不变,只更新该记录指向的对象信息和元数据。
|
||||
|
||||
换句话说:
|
||||
|
||||
- 替换的是“坏水印图对应的 `sys_oss` 内容”
|
||||
- 保留的是“该 `sys_oss` 的主键 `oss_id`”
|
||||
|
||||
## 5. 历史补救识别范围
|
||||
|
||||
建议先做数据筛查,再执行修补。
|
||||
|
||||
### 5.1 强特征
|
||||
|
||||
以下记录可直接视为高风险坏数据:
|
||||
|
||||
- `sys_oss.ext1.fileSize = 0`
|
||||
- `sys_oss.file_suffix` 为纯数字,如 `2`、`3`
|
||||
- `sys_oss.file_suffix` 为 `.数字`,如 `.2`、`.3`
|
||||
- `sys_oss.original_name` 像 `photo_evidence_xxx.2`、`photo_evidence_xxx.3`
|
||||
- `sys_oss.ext1.contentType is null`
|
||||
|
||||
### 5.2 建议以 `HotPhotoEvidence` 为主表驱动
|
||||
|
||||
原因:
|
||||
|
||||
- 该表已经保留了 `originalOssId`、`watermarkedOssId`
|
||||
- 已经保留了 `captureTimeClient`、`captureTimeServer`
|
||||
- 已经保留了 `latitude`、`longitude`
|
||||
- 已经保留了 `addressTextServer`、`addressTextClient`、`addressSource`
|
||||
|
||||
这些字段足够支撑“按历史状态重建水印图”,不需要重新依赖前端数据。
|
||||
|
||||
## 6. 历史补救执行方案
|
||||
|
||||
### 6.1 核心目标
|
||||
|
||||
在不改变 `watermarked_oss_id` 和 `oss_id` 的前提下,修复坏掉的水印图对象和其 `sys_oss` 元数据。
|
||||
|
||||
### 6.2 推荐执行步骤
|
||||
|
||||
1. 根据 `HotPhotoEvidence.watermarked_oss_id` 关联 `sys_oss`,筛出疑似坏水印记录。
|
||||
2. 按记录读取 `original_oss_id` 对应的原始图。
|
||||
3. 使用历史记录中的 `captureTimeClient` 作为水印时间。
|
||||
4. 水印地址按以下优先级确定:
|
||||
- 若 `addressSource=SERVER`,取 `addressTextServer`
|
||||
- 否则取 `addressTextClient`
|
||||
5. 不重新调用逆地理接口,不重算地址。
|
||||
6. 按统一规范重新生成 `jpg` 水印图。
|
||||
7. 先上传到 OSS 新对象路径,确认对象可访问且大小正常。
|
||||
8. 用新对象信息覆盖旧的 `sys_oss` 记录:
|
||||
- `file_name`
|
||||
- `url`
|
||||
- `file_suffix`
|
||||
- `original_name`
|
||||
- `ext1.fileSize`
|
||||
- `ext1.contentType`
|
||||
- 如有必要同步更新时间和更新人
|
||||
9. `oss_id` 保持不变。
|
||||
10. 数据更新成功后,再删除旧的坏对象文件,或先保留待统一清理。
|
||||
|
||||
### 6.3 必须覆盖的字段
|
||||
|
||||
覆盖原 `sys_oss` 记录时,建议至少同步修正以下内容:
|
||||
|
||||
- `file_name`:替换为新上传对象键
|
||||
- `url`:替换为新对象地址
|
||||
- `file_suffix`:统一改为 `.jpg`
|
||||
- `original_name`:统一规范化,例如 `photo_evidence_{ossId}.jpg`
|
||||
- `ext1.fileSize`:更新为真实大小
|
||||
- `ext1.contentType`:更新为 `image/jpeg`
|
||||
|
||||
如有以下字段被业务使用,也建议同步补齐:
|
||||
|
||||
- `ext1.source`
|
||||
- `ext1.remark`
|
||||
- `update_time`
|
||||
- `update_by`
|
||||
|
||||
### 6.4 为什么不要重新生成新的 `sys_oss` 记录
|
||||
|
||||
- 会引入新的 `oss_id`
|
||||
- 会导致其他业务表引用失效
|
||||
- 会让修复脚本必须跨全库改引用
|
||||
- 很难保证没有漏网表
|
||||
- 回滚和审计也会变复杂
|
||||
|
||||
因此,历史补救必须采用“新对象文件 + 原记录覆盖”的模式。
|
||||
|
||||
## 7. 前端可视化补救方案
|
||||
|
||||
为了让补救方案易于操作,建议将历史补救放到后台管理界面,而不是只做一次性脚本。
|
||||
|
||||
### 7.1 推荐入口
|
||||
|
||||
建议新增后台管理页面,例如:
|
||||
|
||||
- 菜单名称:`水印图片修复`
|
||||
- 所属模块:`系统管理` 或 `附件管理`
|
||||
- 页面定位:面向运维、实施、研发,不对普通业务用户开放
|
||||
|
||||
前端落点建议明确放到维护模块中,参考现有维护页 [index.vue](file:///g:/code/shw/hot/wucaixing-full/wucaixing-frontend/src/views/system/maintenance/index.vue)
|
||||
的维护项列表能力。
|
||||
|
||||
建议方案:
|
||||
|
||||
- 在前端维护模块 `wucaixing-frontend/src/views/system/maintenance/index.vue` 中新增一个维护项,例如 `图片水印修复`
|
||||
- 点击维护项后进入专门的修复弹窗或修复页面
|
||||
- 该页面承载异常筛选、预览比对、勾选记录、单条修复、批量修复、任务进度和结果查看
|
||||
|
||||
这样可以与现有 `媒体资源元数据修复` 的运维入口保持一致,便于统一权限、统一操作习惯、统一审计。
|
||||
|
||||
### 7.2 列表页建议字段
|
||||
|
||||
列表页建议展示以下信息,方便快速识别和人工核验:
|
||||
|
||||
- `evidenceId`
|
||||
- `watermarkedOssId`
|
||||
- `originalOssId`
|
||||
- 原始图片缩略图
|
||||
- 当前水印图缩略图
|
||||
- `sys_oss.file_suffix`
|
||||
- `ext1.fileSize`
|
||||
- `contentType`
|
||||
- `captureTimeClient`
|
||||
- `addressSource`
|
||||
- 地址文本
|
||||
- 公司 / 业务类型 / 业务 ID
|
||||
- 创建时间
|
||||
- 修复状态
|
||||
- 修复结果说明
|
||||
|
||||
### 7.3 列表页筛选条件
|
||||
|
||||
建议支持以下筛选项:
|
||||
|
||||
- 仅看异常记录
|
||||
- 按 `watermarkedOssId`
|
||||
- 按 `originalOssId`
|
||||
- 按公司
|
||||
- 按业务类型
|
||||
- 按时间范围
|
||||
- 按 `fileSize=0`
|
||||
- 按 `contentType为空`
|
||||
- 按 `file_suffix` 异常
|
||||
- 按修复状态
|
||||
|
||||
### 7.4 页面操作按钮
|
||||
|
||||
建议至少提供以下操作:
|
||||
|
||||
- `预览原图`
|
||||
- `预览当前水印图`
|
||||
- `生成修复预览`
|
||||
- `勾选当前记录`
|
||||
- `批量勾选筛选结果`
|
||||
- `清空勾选`
|
||||
- `执行单条修复`
|
||||
- `批量修复已勾选记录`
|
||||
- `导出异常清单`
|
||||
- `查看修复日志`
|
||||
|
||||
补充要求:
|
||||
|
||||
- 不允许用户在未查看修复前后效果的情况下直接发起批量修复
|
||||
- 批量修复应以“用户已勾选且已完成预览确认的记录”为执行范围,而不是直接对整个筛选结果无差别执行
|
||||
|
||||
### 7.5 单条修复建议流程
|
||||
|
||||
单条修复推荐流程如下:
|
||||
|
||||
1. 用户点开一条异常记录。
|
||||
2. 页面展示:
|
||||
- 原图预览
|
||||
- 当前坏水印图预览
|
||||
- 拟修复后的新水印预览
|
||||
- 修复前后元数据对比
|
||||
3. 用户点击 `确认修复`。
|
||||
4. 后端执行:
|
||||
- 读取原图
|
||||
- 按历史时间与地址重新加水印
|
||||
- 上传新 OSS 对象
|
||||
- 覆盖原 `sys_oss` 记录
|
||||
- 记录操作日志
|
||||
5. 页面回显修复结果。
|
||||
|
||||
这个流程适合先做试点修复和人工验证。
|
||||
|
||||
### 7.6 批量修复建议流程
|
||||
|
||||
批量修复推荐流程如下:
|
||||
|
||||
1. 用户先通过筛选条件锁定异常数据范围。
|
||||
2. 页面展示总数、可修复数、疑似失败风险数,并支持逐条勾选待修复记录。
|
||||
3. 用户先对准备修复的记录执行预览,页面必须展示:
|
||||
- 原图
|
||||
- 当前坏水印图
|
||||
- 拟修复后的新水印图
|
||||
- 修复前后元数据差异
|
||||
4. 用户确认预览效果无误后,勾选本次真正要修复的记录。
|
||||
5. 用户点击 `批量修复已勾选记录` 前,系统弹出二次确认,并明确显示本次修复条数。
|
||||
6. 后端采用任务方式异步执行,页面可轮询查看进度。
|
||||
7. 每条记录输出修复结果:
|
||||
- 成功
|
||||
- 原图不存在
|
||||
- 原图无法解析
|
||||
- 新水印生成失败
|
||||
- OSS 上传失败
|
||||
- 原 `sys_oss` 覆盖失败
|
||||
8. 任务完成后支持导出结果明细。
|
||||
|
||||
这里的关键要求是:
|
||||
|
||||
- 批量修复之前必须先有“预览确认”步骤
|
||||
- 批量修复的对象必须是“用户主动勾选的记录”
|
||||
- 不能仅凭筛选条件直接全量执行修复任务
|
||||
|
||||
### 7.7 为什么前端界面比一次性脚本更适合
|
||||
|
||||
- 更适合先小批量验证,再逐步扩大范围
|
||||
- 操作人员无需直接跑脚本和改 SQL
|
||||
- 每条记录可预览、可追踪、可重试
|
||||
- 更方便做权限控制和操作审计
|
||||
- 后续若再出现新脏数据,也可以复用同一页面处理
|
||||
|
||||
## 8. 后端接口建议
|
||||
|
||||
为支撑前端可视化操作,建议至少提供以下几类接口:
|
||||
|
||||
### 8.1 异常列表接口
|
||||
|
||||
用途:
|
||||
|
||||
- 按筛选条件查询疑似异常水印记录
|
||||
- 返回分页列表和异常原因标签
|
||||
|
||||
### 8.2 预览接口
|
||||
|
||||
用途:
|
||||
|
||||
- 根据 `evidenceId` 或 `watermarkedOssId` 生成“拟修复水印图”的临时预览
|
||||
- 不落库,不覆盖 `sys_oss`
|
||||
|
||||
### 8.3 单条修复接口
|
||||
|
||||
用途:
|
||||
|
||||
- 对单条异常记录执行正式修复
|
||||
- 修复成功后覆盖原 `sys_oss`
|
||||
|
||||
### 8.4 批量修复任务接口
|
||||
|
||||
用途:
|
||||
|
||||
- 创建批量修复任务
|
||||
- 入参必须是前端勾选确认后的记录 ID 列表,而不是只有筛选条件
|
||||
- 后台异步执行
|
||||
- 支持查询进度、成功数、失败数、失败原因
|
||||
|
||||
### 8.5 操作日志接口
|
||||
|
||||
用途:
|
||||
|
||||
- 记录谁在什么时间修复了哪条记录
|
||||
- 保留修复前后对象信息,便于追溯
|
||||
|
||||
## 9. 操作审计与回滚建议
|
||||
|
||||
### 9.1 建议记录的审计信息
|
||||
|
||||
每次修复建议记录:
|
||||
|
||||
- 操作人
|
||||
- 操作时间
|
||||
- `evidenceId`
|
||||
- `watermarkedOssId`
|
||||
- 旧 `file_name`
|
||||
- 新 `file_name`
|
||||
- 旧 `url`
|
||||
- 新 `url`
|
||||
- 旧 `ext1`
|
||||
- 新 `ext1`
|
||||
- 修复结果
|
||||
- 错误信息
|
||||
|
||||
### 9.2 回滚方式
|
||||
|
||||
由于要求保持原 `oss_id` 不变,回滚方案建议也按“对象替换”处理:
|
||||
|
||||
1. 修复前先记录旧对象信息。
|
||||
2. 如修复后发现异常,可重新把旧对象重新上传或恢复。
|
||||
3. 再次覆盖同一个 `sys_oss` 记录,使其回到修复前状态。
|
||||
|
||||
也就是说,回滚不是改回旧 `oss_id`,而是把同一个 `oss_id` 再次指回旧对象。
|
||||
|
||||
## 10. 推荐实施顺序
|
||||
|
||||
建议按以下顺序落地:
|
||||
|
||||
1. 先完成线上兜底,阻断新增坏数据。
|
||||
2. 再开发后台可视化补救页面和补救接口。
|
||||
3. 先选少量样本做单条修复验证。
|
||||
4. 确认预览、下载、页面展示全部正常后,再进行批量修复。
|
||||
5. 批量修复完成后,统一清理被替换掉的坏 OSS 对象。
|
||||
|
||||
## 11. 最终结论
|
||||
|
||||
本问题的正确处理方式是:
|
||||
|
||||
- 线上新增场景:后端不再信任原始上传后缀,水印图统一输出为 `jpg/jpeg`。
|
||||
- 历史补救场景:以 `HotPhotoEvidence` 为主表重建水印图,但不能改 `oss_id`,必须覆盖原坏水印图对应的 `sys_oss` 记录。
|
||||
- 落地形式:优先做成后台管理可视化能力,支持异常筛选、预览、单条修复、批量修复、日志追踪。
|
||||
|
||||
该方案既能快速止血,也能在不扩散引用风险的前提下,稳妥完成历史数据修复。
|
||||
63
docs/待办移动到历史表.md
Normal file
63
docs/待办移动到历史表.md
Normal file
@@ -0,0 +1,63 @@
|
||||
```sql
|
||||
|
||||
-- 传入你的 taskId
|
||||
set @taskId = 'f5e730e3bfaf57ce00af7c0f7228958a';
|
||||
|
||||
start transaction;
|
||||
|
||||
-- 1. 归档到历史表
|
||||
insert into sys_flow_task_his (his_id,
|
||||
task_id,
|
||||
instance_id,
|
||||
node_code,
|
||||
node_name,
|
||||
approver_id,
|
||||
status,
|
||||
comment,
|
||||
audit_time,
|
||||
company_id,
|
||||
is_read,
|
||||
create_by,
|
||||
create_time,
|
||||
update_by,
|
||||
update_time)
|
||||
select replace(uuid(), '-', '') as his_id,
|
||||
t.task_id,
|
||||
t.instance_id,
|
||||
t.node_code,
|
||||
t.node_name,
|
||||
t.approver_id,
|
||||
case
|
||||
when i.status = 1 then 1
|
||||
when i.status in (2, 9) then 2
|
||||
else 2
|
||||
end as status,
|
||||
'手工归档待办' as comment,
|
||||
coalesce(i.finish_time, t.update_time, now()) as audit_time,
|
||||
t.company_id,
|
||||
t.is_read,
|
||||
t.create_by,
|
||||
t.create_time,
|
||||
t.update_by,
|
||||
t.update_time
|
||||
from sys_flow_task t
|
||||
left join sys_flow_instance i
|
||||
on i.instance_id = t.instance_id
|
||||
where t.task_id = @taskId
|
||||
and not exists (select 1
|
||||
from sys_flow_task_his th
|
||||
where th.task_id = t.task_id
|
||||
and th.instance_id = t.instance_id);
|
||||
|
||||
-- 2. 删除当前待办
|
||||
delete
|
||||
from sys_flow_task
|
||||
where task_id = @taskId
|
||||
and exists (select 1
|
||||
from sys_flow_task_his th
|
||||
where th.task_id = @taskId
|
||||
and th.instance_id = sys_flow_task.instance_id);
|
||||
|
||||
commit;
|
||||
|
||||
```
|
||||
@@ -0,0 +1,14 @@
|
||||
ALTER TABLE hot_vehicle_three_inspect
|
||||
ADD COLUMN inspect_no varchar(32) NULL COMMENT '三检记录编号',
|
||||
ADD COLUMN inspect_location varchar(255) NULL COMMENT '检查地点';
|
||||
|
||||
UPDATE hot_vehicle_three_inspect t
|
||||
LEFT JOIN hot_vehicle v ON v.id = t.vehicle_id
|
||||
SET t.inspect_no = CONCAT(
|
||||
'SJ',
|
||||
DATE_FORMAT(COALESCE(t.inspect_time, t.create_time), '%Y%m%d'),
|
||||
RIGHT(COALESCE(v.plate_number, '000'), 3),
|
||||
LPAD(MOD(COALESCE(t.inspect_id, t.id), 10000), 4, '0')
|
||||
)
|
||||
WHERE (t.inspect_no IS NULL OR t.inspect_no = '')
|
||||
AND t.is_deleted = 0;
|
||||
138
sql/migrate_hidden_danger_inspection_old_data_to_reject.sql
Normal file
138
sql/migrate_hidden_danger_inspection_old_data_to_reject.sql
Normal file
@@ -0,0 +1,138 @@
|
||||
-- 存量隐患排查数据迁移为“审核不通过”状态,并补写驳回历史
|
||||
-- 使用前请先确认:
|
||||
-- 1. 已执行 update_hidden_danger_inspection_reject_history.sql
|
||||
-- 2. 首次执行前建议备份 hot_hidden_danger_inspection 与 hot_hidden_danger_inspection_audit_history
|
||||
-- 3. 本脚本默认将所有未删除的老数据统一初始化为第 1 次驳回
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
-- 1. 将主表老数据统一调整为驳回状态
|
||||
UPDATE `hot_hidden_danger_inspection`
|
||||
SET `submit_version` = IFNULL(NULLIF(`submit_version`, 0), 1),
|
||||
`audit_result` = 'REJECT',
|
||||
`reject_count` = CASE
|
||||
WHEN `reject_count` IS NULL OR `reject_count` = 0 THEN 1
|
||||
ELSE `reject_count`
|
||||
END,
|
||||
`last_reject_reason` = CASE
|
||||
WHEN `last_reject_reason` IS NULL OR `last_reject_reason` = '' THEN '历史数据初始化为审核不通过,请驾驶员重新编辑后提交'
|
||||
ELSE `last_reject_reason`
|
||||
END,
|
||||
`last_reject_time` = COALESCE(`last_reject_time`, `audit_date`, `update_time`, `create_time`, NOW()),
|
||||
`last_reject_by_id` = COALESCE(`last_reject_by_id`, `approver_id`),
|
||||
`last_reject_by_name` = COALESCE(NULLIF(`last_reject_by_name`, ''), `approver_name`),
|
||||
`flow_status` = 'REJECTED',
|
||||
`instance_id` = NULL,
|
||||
`status` = 10
|
||||
WHERE `is_deleted` = 0;
|
||||
|
||||
-- 2. 将老数据写入驳回历史表
|
||||
-- 说明:
|
||||
-- - 每条主单补 1 条“第 1 次驳回”历史
|
||||
-- - 已存在 inspection_id + audit_round=1 的记录时不会重复插入
|
||||
SET @history_max_id := (SELECT IFNULL(MAX(`id`), 0) FROM `hot_hidden_danger_inspection_audit_history`);
|
||||
|
||||
INSERT INTO `hot_hidden_danger_inspection_audit_history` (
|
||||
`id`,
|
||||
`inspection_id`,
|
||||
`company_id`,
|
||||
`plan_id`,
|
||||
`project_name`,
|
||||
`project_id`,
|
||||
`project_type`,
|
||||
`submit_version`,
|
||||
`audit_round`,
|
||||
`audit_result`,
|
||||
`reject_reason`,
|
||||
`audit_date`,
|
||||
`approver_id`,
|
||||
`approver_name`,
|
||||
`approver_sign_img_url`,
|
||||
`audit_has_danger`,
|
||||
`submit_snapshot_json`,
|
||||
`check_content_json`,
|
||||
`danger_desc`,
|
||||
`attachment_url`,
|
||||
`sign_img_url`,
|
||||
`checker_id`,
|
||||
`checker_name`,
|
||||
`check_date`,
|
||||
`create_dept`,
|
||||
`create_by`,
|
||||
`create_by_name`,
|
||||
`create_time`,
|
||||
`update_by`,
|
||||
`update_by_name`,
|
||||
`update_time`,
|
||||
`is_deleted`,
|
||||
`remark`
|
||||
)
|
||||
SELECT
|
||||
(@history_max_id := @history_max_id + 1) AS `id`,
|
||||
i.`id` AS `inspection_id`,
|
||||
i.`company_id`,
|
||||
i.`plan_id`,
|
||||
i.`project_name`,
|
||||
i.`project_id`,
|
||||
i.`project_type`,
|
||||
IFNULL(NULLIF(i.`submit_version`, 0), 1) AS `submit_version`,
|
||||
1 AS `audit_round`,
|
||||
'REJECT' AS `audit_result`,
|
||||
COALESCE(NULLIF(i.`last_reject_reason`, ''), '历史数据初始化为审核不通过,请驾驶员重新编辑后提交') AS `reject_reason`,
|
||||
COALESCE(i.`last_reject_time`, i.`audit_date`, i.`update_time`, i.`create_time`, NOW()) AS `audit_date`,
|
||||
COALESCE(i.`last_reject_by_id`, i.`approver_id`) AS `approver_id`,
|
||||
COALESCE(NULLIF(i.`last_reject_by_name`, ''), i.`approver_name`) AS `approver_name`,
|
||||
i.`approver_sign_img_url`,
|
||||
i.`audit_has_danger`,
|
||||
JSON_OBJECT(
|
||||
'inspectionId', i.`id`,
|
||||
'companyId', i.`company_id`,
|
||||
'planId', i.`plan_id`,
|
||||
'projectName', i.`project_name`,
|
||||
'projectId', i.`project_id`,
|
||||
'projectType', i.`project_type`,
|
||||
'submitVersion', IFNULL(NULLIF(i.`submit_version`, 0), 1),
|
||||
'checkContentJson', i.`check_content_json`,
|
||||
'dangerDesc', i.`danger_desc`,
|
||||
'attachmentUrl', i.`attachment_url`,
|
||||
'signImgUrl', i.`sign_img_url`,
|
||||
'checkerId', i.`checker_id`,
|
||||
'checkerName', i.`checker_name`,
|
||||
'checkDate', i.`check_date`
|
||||
) AS `submit_snapshot_json`,
|
||||
i.`check_content_json`,
|
||||
i.`danger_desc`,
|
||||
i.`attachment_url`,
|
||||
i.`sign_img_url`,
|
||||
i.`checker_id`,
|
||||
i.`checker_name`,
|
||||
i.`check_date`,
|
||||
i.`create_dept`,
|
||||
COALESCE(i.`update_by`, i.`create_by`) AS `create_by`,
|
||||
NULL AS `create_by_name`,
|
||||
COALESCE(i.`update_time`, i.`create_time`, NOW()) AS `create_time`,
|
||||
i.`update_by`,
|
||||
NULL AS `update_by_name`,
|
||||
i.`update_time`,
|
||||
0 AS `is_deleted`,
|
||||
'历史数据初始化补录' AS `remark`
|
||||
FROM `hot_hidden_danger_inspection` i
|
||||
WHERE i.`is_deleted` = 0
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM `hot_hidden_danger_inspection_audit_history` h
|
||||
WHERE h.`inspection_id` = i.`id`
|
||||
AND h.`audit_round` = 1
|
||||
AND h.`is_deleted` = 0
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- 校验SQL
|
||||
-- SELECT COUNT(*) FROM hot_hidden_danger_inspection WHERE is_deleted = 0 AND audit_result = 'REJECT' AND status = 10;
|
||||
-- SELECT COUNT(*) FROM hot_hidden_danger_inspection_audit_history WHERE is_deleted = 0;
|
||||
|
||||
|
||||
|
||||
update hot_hidden_danger_inspection set status = 1
|
||||
update hot_hidden_danger_inspection set status = 10 where approver_id is not null
|
||||
49
sql/update_hidden_danger_inspection_reject_history.sql
Normal file
49
sql/update_hidden_danger_inspection_reject_history.sql
Normal file
@@ -0,0 +1,49 @@
|
||||
ALTER TABLE `hot_hidden_danger_inspection`
|
||||
ADD COLUMN `submit_version` bigint NULL DEFAULT 0 COMMENT '提交版本号' AFTER `flow_status`,
|
||||
ADD COLUMN `audit_result` varchar(16) NULL COMMENT '审核结果(PASS=通过 REJECT=驳回)' AFTER `submit_version`,
|
||||
ADD COLUMN `reject_count` bigint NULL DEFAULT 0 COMMENT '驳回次数' AFTER `audit_result`,
|
||||
ADD COLUMN `last_reject_reason` varchar(500) NULL COMMENT '最近一次驳回原因' AFTER `reject_count`,
|
||||
ADD COLUMN `last_reject_time` datetime NULL COMMENT '最近一次驳回时间' AFTER `last_reject_reason`,
|
||||
ADD COLUMN `last_reject_by_id` bigint NULL COMMENT '最近一次驳回人ID' AFTER `last_reject_time`,
|
||||
ADD COLUMN `last_reject_by_name` varchar(64) NULL COMMENT '最近一次驳回人姓名' AFTER `last_reject_by_id`;
|
||||
|
||||
CREATE TABLE `hot_hidden_danger_inspection_audit_history` (
|
||||
`id` bigint NOT NULL COMMENT '主键',
|
||||
`inspection_id` bigint NOT NULL COMMENT '隐患排查主单ID',
|
||||
`company_id` bigint DEFAULT NULL COMMENT '公司ID',
|
||||
`plan_id` bigint DEFAULT NULL COMMENT '计划ID',
|
||||
`project_name` varchar(255) DEFAULT NULL COMMENT '排查项目',
|
||||
`project_id` varchar(64) DEFAULT NULL COMMENT '排查项目ID',
|
||||
`project_type` bigint DEFAULT NULL COMMENT '排查类型(1=公司 2=车辆 3=人员)',
|
||||
`submit_version` bigint DEFAULT NULL COMMENT '提交版本号',
|
||||
`audit_round` bigint DEFAULT NULL COMMENT '审核轮次',
|
||||
`audit_result` varchar(16) DEFAULT NULL COMMENT '审核结果(REJECT)',
|
||||
`reject_reason` varchar(500) DEFAULT NULL COMMENT '驳回原因',
|
||||
`audit_date` datetime DEFAULT NULL COMMENT '审核日期',
|
||||
`approver_id` bigint DEFAULT NULL COMMENT '审核人ID',
|
||||
`approver_name` varchar(64) DEFAULT NULL COMMENT '审核人姓名',
|
||||
`approver_sign_img_url` varchar(500) DEFAULT NULL COMMENT '审核人签名图片',
|
||||
`audit_has_danger` bigint DEFAULT NULL COMMENT '审核时是否存在隐患',
|
||||
`submit_snapshot_json` longtext COMMENT '当次提交快照JSON',
|
||||
`check_content_json` longtext COMMENT '排查内容JSON',
|
||||
`danger_desc` varchar(500) DEFAULT NULL COMMENT '隐患描述',
|
||||
`attachment_url` varchar(2000) DEFAULT NULL COMMENT '附件URL',
|
||||
`sign_img_url` varchar(500) DEFAULT NULL COMMENT '排查人签名图片',
|
||||
`checker_id` varchar(64) DEFAULT NULL COMMENT '排查人ID',
|
||||
`checker_name` varchar(64) DEFAULT NULL COMMENT '排查人姓名',
|
||||
`check_date` datetime DEFAULT NULL COMMENT '排查日期',
|
||||
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
|
||||
`create_by` bigint DEFAULT NULL COMMENT '创建者',
|
||||
`create_by_name` varchar(64) DEFAULT NULL COMMENT '创建者名称',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint DEFAULT NULL COMMENT '更新者',
|
||||
`update_by_name` varchar(64) DEFAULT NULL COMMENT '更新者名称',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`is_deleted` bigint DEFAULT 0 COMMENT '0=正常,1=已删除',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_hdiah_inspection_id` (`inspection_id`),
|
||||
KEY `idx_hdiah_company_id` (`company_id`),
|
||||
KEY `idx_hdiah_audit_round` (`audit_round`),
|
||||
KEY `idx_hdiah_is_deleted` (`is_deleted`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='隐患排查审核驳回历史表';
|
||||
@@ -61,7 +61,7 @@ public final class DriverLoginContextHelper {
|
||||
lqw.eq(HotDriver::getId, userId);
|
||||
lqw.eq(HotDriver::getStatus, 1L);
|
||||
lqw.eq(HotDriver::getAuditStatus, 1);
|
||||
lqw.orderByDesc(HotDriver::getCreateTime);
|
||||
lqw.orderByDesc(HotDriver::getCreateTime, HotDriver::getId);
|
||||
lqw.last("limit 1");
|
||||
HotDriverMapper hotDriverMapper = SpringUtils.getBean(HotDriverMapper.class);
|
||||
HotDriver driver = hotDriverMapper.selectOne(lqw);
|
||||
|
||||
@@ -2,9 +2,22 @@ package com.hotwj.platform.common.photoEvidence.mapper;
|
||||
|
||||
import com.hotwj.platform.common.photoEvidence.domain.HotPhotoEvidence;
|
||||
import com.hotwj.platform.common.photoEvidence.domain.vo.PhotoEvidenceVo;
|
||||
import com.hotwj.platform.system.maintenance.domain.bo.PhotoEvidenceRepairQueryBo;
|
||||
import com.hotwj.platform.system.maintenance.domain.vo.PhotoEvidenceRepairCandidateVo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface HotPhotoEvidenceMapper extends BaseMapperPlus<HotPhotoEvidence, PhotoEvidenceVo> {
|
||||
|
||||
long countRepairCandidates(@Param("query") PhotoEvidenceRepairQueryBo query);
|
||||
|
||||
List<PhotoEvidenceRepairCandidateVo> selectRepairCandidates(@Param("query") PhotoEvidenceRepairQueryBo query,
|
||||
@Param("offset") long offset,
|
||||
@Param("pageSize") long pageSize);
|
||||
|
||||
PhotoEvidenceRepairCandidateVo selectRepairCandidateByEvidenceId(@Param("evidenceId") Long evidenceId);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.hotwj.platform.common.photoEvidence.domain.bo.PhotoEvidenceCreateBo;
|
||||
import com.hotwj.platform.common.photoEvidence.domain.vo.PhotoEvidenceVo;
|
||||
import com.hotwj.platform.common.photoEvidence.mapper.HotPhotoEvidenceMapper;
|
||||
import com.hotwj.platform.common.photoEvidence.service.IPhotoEvidenceService;
|
||||
import com.hotwj.platform.common.photoEvidence.support.PhotoEvidenceWatermarkSupport;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.enums.FormatsType;
|
||||
@@ -22,16 +23,12 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -43,6 +40,9 @@ public class PhotoEvidenceServiceImpl implements IPhotoEvidenceService {
|
||||
@Resource
|
||||
private ISysOssService ossService;
|
||||
|
||||
@Resource
|
||||
private PhotoEvidenceWatermarkSupport watermarkSupport;
|
||||
|
||||
@Value("${map.gd.key:}")
|
||||
private String gdKey;
|
||||
|
||||
@@ -129,30 +129,19 @@ public class PhotoEvidenceServiceImpl implements IPhotoEvidenceService {
|
||||
Date captureTimeClient,
|
||||
String address) {
|
||||
byte[] originalBytes = downloadOssFile(originalOss);
|
||||
BufferedImage originalImage = readImage(originalBytes);
|
||||
BufferedImage watermarked = addWatermark(originalImage, captureTimeClient, address);
|
||||
|
||||
File tempFile = null;
|
||||
PhotoEvidenceWatermarkSupport.RenderedWatermark renderedWatermark = null;
|
||||
try {
|
||||
String suffix = originalOss.getFileSuffix();
|
||||
if (StringUtils.isBlank(suffix)) {
|
||||
suffix = "jpg";
|
||||
}
|
||||
if (suffix.startsWith(".")) {
|
||||
suffix = suffix.substring(1);
|
||||
}
|
||||
tempFile = File.createTempFile("photo_evidence_", "." + suffix);
|
||||
try (OutputStream os = new FileOutputStream(tempFile)) {
|
||||
ImageIO.write(watermarked, suffix, os);
|
||||
}
|
||||
return ossService.upload(tempFile).getOssId();
|
||||
} catch (IOException e) {
|
||||
throw new ServiceException("水印图片生成失败");
|
||||
renderedWatermark = watermarkSupport.renderToTempFile(originalBytes, captureTimeClient, address);
|
||||
OssClient storage = OssFactory.instance();
|
||||
String objectKey = storage.getPath("photo-evidence", PhotoEvidenceWatermarkSupport.OUTPUT_SUFFIX);
|
||||
return ossService.upload(
|
||||
renderedWatermark.getFile(),
|
||||
objectKey,
|
||||
PhotoEvidenceWatermarkSupport.OUTPUT_CONTENT_TYPE
|
||||
).getOssId();
|
||||
} finally {
|
||||
if (tempFile != null && tempFile.exists()) {
|
||||
if (!tempFile.delete()) {
|
||||
log.warn("临时文件删除失败: {}", tempFile.getAbsolutePath());
|
||||
}
|
||||
if (renderedWatermark != null) {
|
||||
watermarkSupport.deleteQuietly(renderedWatermark.getFile());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,124 +156,6 @@ public class PhotoEvidenceServiceImpl implements IPhotoEvidenceService {
|
||||
}
|
||||
}
|
||||
|
||||
private BufferedImage readImage(byte[] bytes) {
|
||||
try (InputStream is = new ByteArrayInputStream(bytes)) {
|
||||
BufferedImage image = ImageIO.read(is);
|
||||
if (image == null) {
|
||||
String hex = "";
|
||||
if (bytes.length >= 4) {
|
||||
hex = String.format("%02X%02X%02X%02X", bytes[0], bytes[1], bytes[2], bytes[3]);
|
||||
}
|
||||
log.error("ImageIO.read returned null. Header: {}", hex);
|
||||
throw new ServiceException("原始图片格式不支持 (Header: " + hex + ")");
|
||||
}
|
||||
return image;
|
||||
} catch (IOException e) {
|
||||
log.error("图片解析失败", e);
|
||||
throw new ServiceException("原始图片解析失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private BufferedImage addWatermark(BufferedImage original,
|
||||
Date captureTimeClient,
|
||||
String address) {
|
||||
int width = original.getWidth();
|
||||
int height = original.getHeight();
|
||||
|
||||
// 强制最小画布宽度,防止文字区域过窄
|
||||
int minWidth = 600;
|
||||
if (width < minWidth) {
|
||||
int newWidth = minWidth;
|
||||
int newHeight = (int) Math.round((double) height * newWidth / width);
|
||||
BufferedImage resized = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D gResize = resized.createGraphics();
|
||||
gResize.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
gResize.drawImage(original, 0, 0, newWidth, newHeight, null);
|
||||
gResize.dispose();
|
||||
original = resized;
|
||||
width = newWidth;
|
||||
height = newHeight;
|
||||
}
|
||||
|
||||
// 字体大小随宽度自适应(设置最小值)
|
||||
int fontSize = Math.max(20, width / 30);
|
||||
int padding = Math.max(fontSize, 16);
|
||||
|
||||
String timeText = DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, captureTimeClient);
|
||||
String addressText = "地址:" + (address != null ? address : "");
|
||||
|
||||
// 构建字体并测量
|
||||
Font font;
|
||||
try (InputStream is = getClass().getResourceAsStream("/fonts/simsun.ttc")) {
|
||||
if (is == null) {
|
||||
font = new Font("SansSerif", Font.PLAIN, fontSize);
|
||||
} else {
|
||||
font = Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(Font.PLAIN, fontSize);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to load simsun font, fallback to SansSerif", e);
|
||||
font = new Font("SansSerif", Font.PLAIN, fontSize);
|
||||
}
|
||||
|
||||
// 使用临时图形上下文计算文字宽度与行高
|
||||
BufferedImage tmp = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D gMeasure = tmp.createGraphics();
|
||||
gMeasure.setFont(font);
|
||||
FontMetrics fm = gMeasure.getFontMetrics();
|
||||
int contentWidth = Math.max(1, width - padding * 2);
|
||||
|
||||
// 构造文本行:第一行时间,后续为地址按宽度换行
|
||||
List<String> lines = new ArrayList<>();
|
||||
lines.add(timeText);
|
||||
if (fm.stringWidth(addressText) <= contentWidth) {
|
||||
lines.add(addressText);
|
||||
} else {
|
||||
StringBuilder current = new StringBuilder();
|
||||
for (char c : addressText.toCharArray()) {
|
||||
if (fm.stringWidth(current.toString() + c) > contentWidth) {
|
||||
lines.add(current.toString());
|
||||
current = new StringBuilder();
|
||||
}
|
||||
current.append(c);
|
||||
}
|
||||
if (current.length() > 0) {
|
||||
lines.add(current.toString());
|
||||
}
|
||||
}
|
||||
int lineHeight = fm.getHeight() + fontSize / 4;
|
||||
gMeasure.dispose();
|
||||
|
||||
// 计算白条高度,确保所有行完整显示
|
||||
int barHeight = Math.max(lineHeight + padding * 2, lines.size() * lineHeight + padding * 2);
|
||||
|
||||
// 输出结果图
|
||||
BufferedImage result = new BufferedImage(width, height + barHeight, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g = result.createGraphics();
|
||||
try {
|
||||
// 绘制原图
|
||||
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g.drawImage(original, 0, 0, null);
|
||||
|
||||
// 绘制底部白条
|
||||
g.setColor(Color.WHITE);
|
||||
g.fillRect(0, height, width, barHeight);
|
||||
|
||||
// 绘制文本
|
||||
g.setFont(font);
|
||||
g.setColor(new Color(51, 51, 51));
|
||||
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
|
||||
int y = height + padding + fm.getAscent();
|
||||
for (String line : lines) {
|
||||
g.drawString(line, padding, y);
|
||||
y += lineHeight;
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private String reverseGeocode(Double latitude, Double longitude) {
|
||||
if (latitude == null || longitude == null) {
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
package com.hotwj.platform.common.photoEvidence.support;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.enums.FormatsType;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.DateUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 照片取证水印图统一生成组件。
|
||||
* 无论原图文件名或后缀是否异常,系统产出的水印图都固定为 jpg/jpeg。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class PhotoEvidenceWatermarkSupport {
|
||||
|
||||
public static final String OUTPUT_FORMAT = "jpeg";
|
||||
public static final String OUTPUT_SUFFIX = ".jpg";
|
||||
public static final String OUTPUT_CONTENT_TYPE = "image/jpeg";
|
||||
|
||||
public RenderedWatermark renderToTempFile(byte[] originalBytes, Date captureTimeClient, String address) {
|
||||
BufferedImage watermarked = renderImage(originalBytes, captureTimeClient, address);
|
||||
File tempFile = null;
|
||||
try {
|
||||
tempFile = File.createTempFile("photo_evidence_", OUTPUT_SUFFIX);
|
||||
boolean writeSuccess;
|
||||
try (OutputStream os = new FileOutputStream(tempFile)) {
|
||||
writeSuccess = ImageIO.write(watermarked, OUTPUT_FORMAT, os);
|
||||
}
|
||||
validateWriteResult(writeSuccess, tempFile);
|
||||
return new RenderedWatermark(tempFile, tempFile.length());
|
||||
} catch (IOException ex) {
|
||||
deleteQuietly(tempFile);
|
||||
throw new ServiceException("水印图片生成失败: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] renderToBytes(byte[] originalBytes, Date captureTimeClient, String address) {
|
||||
BufferedImage watermarked = renderImage(originalBytes, captureTimeClient, address);
|
||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
boolean writeSuccess = ImageIO.write(watermarked, OUTPUT_FORMAT, outputStream);
|
||||
if (!writeSuccess || outputStream.size() <= 0) {
|
||||
throw new ServiceException("水印图片生成失败");
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
} catch (IOException ex) {
|
||||
throw new ServiceException("水印图片生成失败: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public String buildStandardOriginalName(Long ossId) {
|
||||
if (ossId == null) {
|
||||
return "photo_evidence" + OUTPUT_SUFFIX;
|
||||
}
|
||||
return "photo_evidence_" + ossId + OUTPUT_SUFFIX;
|
||||
}
|
||||
|
||||
private BufferedImage renderImage(byte[] originalBytes, Date captureTimeClient, String address) {
|
||||
BufferedImage originalImage = readImage(originalBytes);
|
||||
return addWatermark(originalImage, captureTimeClient, address);
|
||||
}
|
||||
|
||||
private void validateWriteResult(boolean writeSuccess, File tempFile) {
|
||||
if (!writeSuccess) {
|
||||
throw new ServiceException("水印图片生成失败: 未找到可用的 JPEG 编码器");
|
||||
}
|
||||
if (tempFile == null || !tempFile.exists()) {
|
||||
throw new ServiceException("水印图片生成失败: 临时文件不存在");
|
||||
}
|
||||
if (tempFile.length() <= 0) {
|
||||
throw new ServiceException("水印图片生成失败: 临时文件为空");
|
||||
}
|
||||
}
|
||||
|
||||
private BufferedImage readImage(byte[] bytes) {
|
||||
try (InputStream is = new ByteArrayInputStream(bytes)) {
|
||||
BufferedImage image = ImageIO.read(is);
|
||||
if (image == null) {
|
||||
String hex = "";
|
||||
if (bytes.length >= 4) {
|
||||
hex = String.format("%02X%02X%02X%02X", bytes[0], bytes[1], bytes[2], bytes[3]);
|
||||
}
|
||||
log.error("ImageIO.read returned null. Header: {}", hex);
|
||||
throw new ServiceException("原始图片格式不支持 (Header: " + hex + ")");
|
||||
}
|
||||
return image;
|
||||
} catch (IOException e) {
|
||||
log.error("图片解析失败", e);
|
||||
throw new ServiceException("原始图片解析失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private BufferedImage addWatermark(BufferedImage original, Date captureTimeClient, String address) {
|
||||
int width = original.getWidth();
|
||||
int height = original.getHeight();
|
||||
|
||||
int minWidth = 600;
|
||||
if (width < minWidth) {
|
||||
int newWidth = minWidth;
|
||||
int newHeight = (int) Math.round((double) height * newWidth / width);
|
||||
BufferedImage resized = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D gResize = resized.createGraphics();
|
||||
gResize.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
gResize.drawImage(original, 0, 0, newWidth, newHeight, null);
|
||||
gResize.dispose();
|
||||
original = resized;
|
||||
width = newWidth;
|
||||
height = newHeight;
|
||||
}
|
||||
|
||||
int fontSize = Math.max(20, width / 30);
|
||||
int padding = Math.max(fontSize, 16);
|
||||
|
||||
String timeText = DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, captureTimeClient);
|
||||
String addressText = "地址:" + (address != null ? address : "");
|
||||
|
||||
Font font;
|
||||
try (InputStream is = getClass().getResourceAsStream("/fonts/simsun.ttc")) {
|
||||
if (is == null) {
|
||||
font = new Font("SansSerif", Font.PLAIN, fontSize);
|
||||
} else {
|
||||
font = Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(Font.PLAIN, fontSize);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to load simsun font, fallback to SansSerif", e);
|
||||
font = new Font("SansSerif", Font.PLAIN, fontSize);
|
||||
}
|
||||
|
||||
BufferedImage tmp = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D gMeasure = tmp.createGraphics();
|
||||
gMeasure.setFont(font);
|
||||
FontMetrics fm = gMeasure.getFontMetrics();
|
||||
int contentWidth = Math.max(1, width - padding * 2);
|
||||
|
||||
List<String> lines = new ArrayList<>();
|
||||
lines.add(timeText);
|
||||
if (fm.stringWidth(addressText) <= contentWidth) {
|
||||
lines.add(addressText);
|
||||
} else {
|
||||
StringBuilder current = new StringBuilder();
|
||||
for (char c : addressText.toCharArray()) {
|
||||
if (fm.stringWidth(current.toString() + c) > contentWidth) {
|
||||
lines.add(current.toString());
|
||||
current = new StringBuilder();
|
||||
}
|
||||
current.append(c);
|
||||
}
|
||||
if (current.length() > 0) {
|
||||
lines.add(current.toString());
|
||||
}
|
||||
}
|
||||
int lineHeight = fm.getHeight() + fontSize / 4;
|
||||
gMeasure.dispose();
|
||||
|
||||
int barHeight = Math.max(lineHeight + padding * 2, lines.size() * lineHeight + padding * 2);
|
||||
|
||||
BufferedImage result = new BufferedImage(width, height + barHeight, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g = result.createGraphics();
|
||||
try {
|
||||
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g.drawImage(original, 0, 0, null);
|
||||
|
||||
g.setColor(Color.WHITE);
|
||||
g.fillRect(0, height, width, barHeight);
|
||||
|
||||
g.setFont(font);
|
||||
g.setColor(new Color(51, 51, 51));
|
||||
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
|
||||
int y = height + padding + fm.getAscent();
|
||||
for (String line : lines) {
|
||||
g.drawString(line, padding, y);
|
||||
y += lineHeight;
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteQuietly(File file) {
|
||||
if (file == null || !file.exists()) {
|
||||
return;
|
||||
}
|
||||
if (!file.delete()) {
|
||||
log.warn("临时文件删除失败: {}", file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class RenderedWatermark {
|
||||
private final File file;
|
||||
private final long fileSize;
|
||||
|
||||
public RenderedWatermark(File file, long fileSize) {
|
||||
this.file = file;
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,4 +119,9 @@ public class ExamPaperQuestionDetailVo implements Serializable {
|
||||
* 题库题目逻辑删除标记(hot_question_bank.is_deleted)
|
||||
*/
|
||||
private Long questionIsDeleted;
|
||||
|
||||
/**
|
||||
* 题目解析
|
||||
*/
|
||||
private String caseDesc;
|
||||
}
|
||||
|
||||
@@ -84,6 +84,10 @@ public class HotExamPaperQuestionServiceImpl implements IHotExamPaperQuestionSer
|
||||
lqw.eq(bo.getQuestionId() != null, HotExamPaperQuestion::getQuestionId, bo.getQuestionId());
|
||||
lqw.eq(bo.getSortOrder() != null, HotExamPaperQuestion::getSortOrder, bo.getSortOrder());
|
||||
lqw.eq(bo.getScore() != null, HotExamPaperQuestion::getScore, bo.getScore());
|
||||
// 修复试卷试题顺序问题
|
||||
lqw.orderByAsc(HotExamPaperQuestion::getQuestionType)
|
||||
.orderByAsc(HotExamPaperQuestion::getSortOrder)
|
||||
.orderByAsc(HotExamPaperQuestion::getId);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,12 +40,15 @@ public class HiddenDangerCheckCallback implements IFlowCallback {
|
||||
HotHiddenDangerInspection inspection = inspectMapper.selectById(id);
|
||||
if (inspection != null) {
|
||||
if (success) {
|
||||
inspection.setStatus(3L);
|
||||
inspection.setFlowStatus("APPROVED");
|
||||
inspection.setStatus(inspection.getAuditHasDanger() != null && inspection.getAuditHasDanger() == 1L ? 6L : 3L);
|
||||
} else {
|
||||
inspection.setStatus(6L);
|
||||
inspection.setFlowStatus("REJECTED");
|
||||
inspection.setStatus(10L);
|
||||
inspection.setInstanceId(null);
|
||||
log.info("隐患排查流程被驳回或非正常结束: {}", businessId);
|
||||
}
|
||||
if (inspection.getAuditHasDanger() != null && inspection.getAuditHasDanger() == 1L) {
|
||||
if (success && inspection.getAuditHasDanger() != null && inspection.getAuditHasDanger() == 1L) {
|
||||
createHiddenDangerFlow(inspection);
|
||||
}
|
||||
inspectMapper.updateById(inspection);
|
||||
|
||||
@@ -37,25 +37,53 @@ public class HiddenDangerCheckStrategy implements IFlowStrategy {
|
||||
|
||||
@Override
|
||||
public FlowNextDto next(SysFlowInstance instance, String currentNodeCode) {
|
||||
// 简单流程:只有一级审批,审批通过即结束
|
||||
if ("NODE_CHECK_EDIT".equals(currentNodeCode)) {
|
||||
return buildAuditNode(instance.getBusinessId());
|
||||
}
|
||||
// 审核通过即结束
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowNextDto reject(SysFlowInstance instance, String currentNodeCode) {
|
||||
if (!"NODE_CHECK_AUDIT".equals(currentNodeCode)) {
|
||||
return null;
|
||||
}
|
||||
InspectionNodeMeta meta = getInspectionNodeMeta(instance.getBusinessId());
|
||||
String editApproverId = meta.inspection != null && meta.inspection.getCheckerId() != null
|
||||
? meta.inspection.getCheckerId() : instance.getInitiatorId();
|
||||
return buildEditNode(instance.getBusinessId(), editApproverId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowNextDto getInitialNode(String businessId) {
|
||||
return getNextNode(businessId);
|
||||
return buildAuditNode(businessId);
|
||||
}
|
||||
|
||||
private FlowNextDto getNextNode(String id) {
|
||||
private FlowNextDto buildAuditNode(String id) {
|
||||
InspectionNodeMeta meta = getInspectionNodeMeta(id);
|
||||
String approverId = meta.inspection != null && meta.inspection.getApproverId() != null
|
||||
? String.valueOf(meta.inspection.getApproverId()) : null;
|
||||
String nodeName = String.format("(%s)(%s)审核", meta.planName, meta.inspectItemName);
|
||||
return new FlowNextDto("NODE_CHECK_AUDIT", nodeName, approverId);
|
||||
}
|
||||
|
||||
private FlowNextDto buildEditNode(String id, String approverId) {
|
||||
InspectionNodeMeta meta = getInspectionNodeMeta(id);
|
||||
String nodeName = String.format("(%s)(%s)处理", meta.planName, meta.inspectItemName);
|
||||
return new FlowNextDto("NODE_CHECK_EDIT", nodeName, approverId);
|
||||
}
|
||||
|
||||
private InspectionNodeMeta getInspectionNodeMeta(String id) {
|
||||
// 待办名称规则:(排查计划名称)(排查项名称)审核
|
||||
|
||||
String inspectItemName = "未知排查项";
|
||||
String planName = "未知计划";
|
||||
HotHiddenDangerInspection inspection = null;
|
||||
|
||||
try {
|
||||
if (id != null) {
|
||||
HotHiddenDangerInspection inspection = inspectMapper.selectById(id);
|
||||
inspection = inspectMapper.selectById(id);
|
||||
if (inspection != null) {
|
||||
// 处理排查项名称
|
||||
if (inspection.getProjectName() != null) {
|
||||
@@ -80,8 +108,9 @@ public class HiddenDangerCheckStrategy implements IFlowStrategy {
|
||||
} catch (Exception e) {
|
||||
// 忽略异常,使用默认值
|
||||
}
|
||||
return new InspectionNodeMeta(inspection, inspectItemName, planName);
|
||||
}
|
||||
|
||||
String nodeName = String.format("(%s)(%s)审核", planName, inspectItemName);
|
||||
return new FlowNextDto("NODE_CHECK_AUDIT", nodeName, null);
|
||||
private record InspectionNodeMeta(HotHiddenDangerInspection inspection, String inspectItemName, String planName) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class HotQuestionBankImportVo implements Serializable {
|
||||
@ExcelDictFormat(readConverterExp = "1=普通,2=困难,3=极难")
|
||||
private Long difficulty;
|
||||
|
||||
@ExcelProperty(value = "案例描述", index = 11)
|
||||
@ExcelProperty(value = "解析", index = 11)
|
||||
private String caseDesc;
|
||||
|
||||
@ExcelProperty(value = "题型分类", index = 12, converter = ExcelDictConvert.class)
|
||||
|
||||
@@ -73,7 +73,7 @@ public class HotRiskLevelConfigServiceImpl implements IHotRiskLevelConfigService
|
||||
private LambdaQueryWrapper<HotRiskLevelConfig> buildQueryWrapper(HotRiskLevelConfigBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotRiskLevelConfig> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(HotRiskLevelConfig::getLevelValue);
|
||||
lqw.orderByDesc(HotRiskLevelConfig::getLevelValue, HotRiskLevelConfig::getId);
|
||||
lqw.eq(bo.getLevelValue() != null, HotRiskLevelConfig::getLevelValue, bo.getLevelValue());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getLevelName()), HotRiskLevelConfig::getLevelName, bo.getLevelName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDescription()), HotRiskLevelConfig::getDescription, bo.getDescription());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.hotwj.platform.config.vehicleThreeInspect.callback;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.HotVehicleThreeInspect;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.mapper.HotVehicleThreeInspectMapper;
|
||||
import com.hotwj.platform.flow.callback.IFlowCallback;
|
||||
@@ -10,8 +11,8 @@ import com.hotwj.platform.securityManagement.hiddenDanger.domain.HotHiddenDanger
|
||||
import com.hotwj.platform.securityManagement.hiddenDanger.domain.bo.HotHiddenDangerBo;
|
||||
import com.hotwj.platform.securityManagement.hiddenDanger.mapper.HotHiddenDangerMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -48,7 +49,7 @@ public class VehicleThreeInspectCallback implements IFlowCallback {
|
||||
|
||||
@Override
|
||||
public void onProcessEnd(String instanceId, String businessId, String flowCode, boolean success) {
|
||||
log.info("车辆三检流程结束回调: businessId={}, success={}", businessId, success);
|
||||
log.info("车辆三检流程结束回调: instanceId={}, businessId={}, flowCode={}, success={}", instanceId, businessId, flowCode, success);
|
||||
Long id = Long.parseLong(businessId);
|
||||
// 去掉try catch,防止事务无法正常回滚
|
||||
HotVehicleThreeInspect inspect = inspectMapper.selectById(id);
|
||||
@@ -74,45 +75,70 @@ public class VehicleThreeInspectCallback implements IFlowCallback {
|
||||
* 创建隐患治理流程
|
||||
*/
|
||||
private void createHiddenDangerFlow(HotVehicleThreeInspect inspect) {
|
||||
if (inspect.getHasHiddenDanger() != null && inspect.getHasHiddenDanger() == 1L) {
|
||||
log.info("车辆三检存在隐患,自动创建隐患治理流程,业务ID: {}", inspect.getId());
|
||||
|
||||
HotHiddenDangerBo hiddenDangerBo = new HotHiddenDangerBo();
|
||||
hiddenDangerBo.setCompanyId(inspect.getCompanyId());
|
||||
hiddenDangerBo.setCheckTime(new Date());
|
||||
hiddenDangerBo.setCheckerId(String.valueOf(inspect.getAuditorId()));
|
||||
hiddenDangerBo.setCheckerName(inspect.getAuditorName());
|
||||
hiddenDangerBo.setDescription(inspect.getAuditResult());
|
||||
hiddenDangerBo.setEvidenceUrls(inspect.getAttachImgUrl());
|
||||
hiddenDangerBo.setDangerNo("YH-" + System.currentTimeMillis() / 1000);
|
||||
hiddenDangerBo.setSourceName("车辆");
|
||||
hiddenDangerBo.setSourceId(String.valueOf(inspect.getId()));
|
||||
hiddenDangerBo.setSourceType(2L);
|
||||
hiddenDangerBo.setDataSource(2L);
|
||||
hiddenDangerBo.setDangerName("车辆三检治理");
|
||||
hiddenDangerBo.setStatus(0L);
|
||||
|
||||
HotHiddenDanger danger = MapstructUtils.convert(hiddenDangerBo, HotHiddenDanger.class);
|
||||
hiddenDangerMapper.insert(danger);
|
||||
|
||||
// 启动隐患治理流程
|
||||
// 发起人为审核人(发现隐患的人)
|
||||
String initiator = String.valueOf(inspect.getAuditorId());
|
||||
// 默认整改人也先设置为审核人,或者留空等待指派
|
||||
String rectifierId = String.valueOf(inspect.getEvaluatorId());
|
||||
|
||||
String instanceId = flowService.startFlow(
|
||||
"HIDDEN_DANGER_GOVERNANCE",
|
||||
String.valueOf(danger.getId()),
|
||||
inspect.getCompanyId(),
|
||||
initiator,
|
||||
rectifierId
|
||||
);
|
||||
danger.setInstanceId(instanceId);
|
||||
danger.setEvaluatorId(inspect.getEvaluatorId());
|
||||
danger.setFlowStatus("SUBMITTED");
|
||||
hiddenDangerMapper.updateById(danger);
|
||||
if (!Long.valueOf(1L).equals(inspect.getHasHiddenDanger())) {
|
||||
log.info("车辆三检未标记隐患,跳过隐患治理创建: recordId={}, inspectId={}", inspect.getId(), inspect.getInspectId());
|
||||
return;
|
||||
}
|
||||
String sourceId = String.valueOf(inspect.getInspectId() != null ? inspect.getInspectId() : inspect.getId());
|
||||
log.info("车辆三检存在隐患,准备创建隐患治理流程: recordId={}, inspectId={}, sourceId={}, auditorId={}, evaluatorId={}",
|
||||
inspect.getId(), inspect.getInspectId(), sourceId, inspect.getAuditorId(), inspect.getEvaluatorId());
|
||||
|
||||
HotHiddenDanger existingDanger = hiddenDangerMapper.selectOne(
|
||||
Wrappers.<HotHiddenDanger>lambdaQuery()
|
||||
.eq(HotHiddenDanger::getSourceType, 2L)
|
||||
.eq(HotHiddenDanger::getDataSource, 2L)
|
||||
.eq(HotHiddenDanger::getSourceId, sourceId)
|
||||
.eq(HotHiddenDanger::getIsDeleted, 0L)
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
if (existingDanger != null) {
|
||||
log.warn("车辆三检隐患治理已存在,跳过重复创建: recordId={}, inspectId={}, sourceId={}, existingDangerId={}, existingInstanceId={}",
|
||||
inspect.getId(), inspect.getInspectId(), sourceId, existingDanger.getId(), existingDanger.getInstanceId());
|
||||
return;
|
||||
}
|
||||
|
||||
HotHiddenDangerBo hiddenDangerBo = new HotHiddenDangerBo();
|
||||
hiddenDangerBo.setCompanyId(inspect.getCompanyId());
|
||||
hiddenDangerBo.setCheckTime(new Date());
|
||||
hiddenDangerBo.setCheckerId(String.valueOf(inspect.getAuditorId()));
|
||||
hiddenDangerBo.setCheckerName(inspect.getAuditorName());
|
||||
hiddenDangerBo.setDescription(StringUtils.defaultIfBlank(
|
||||
StringUtils.trimToNull(inspect.getRejectReason()),
|
||||
resolveReadableAuditResult(inspect.getAuditResult())
|
||||
));
|
||||
hiddenDangerBo.setEvidenceUrls(inspect.getAttachImgUrl());
|
||||
hiddenDangerBo.setDangerNo("YH-" + System.currentTimeMillis() / 1000);
|
||||
hiddenDangerBo.setSourceName("车辆");
|
||||
hiddenDangerBo.setSourceId(sourceId);
|
||||
hiddenDangerBo.setSourceType(2L);
|
||||
hiddenDangerBo.setDataSource(2L);
|
||||
hiddenDangerBo.setDangerName("车辆三检治理");
|
||||
hiddenDangerBo.setStatus(0L);
|
||||
|
||||
HotHiddenDanger danger = MapstructUtils.convert(hiddenDangerBo, HotHiddenDanger.class);
|
||||
hiddenDangerMapper.insert(danger);
|
||||
log.info("车辆三检隐患治理数据已创建: recordId={}, inspectId={}, sourceId={}, dangerId={}",
|
||||
inspect.getId(), inspect.getInspectId(), sourceId, danger.getId());
|
||||
|
||||
// 启动隐患治理流程
|
||||
// 发起人为审核人(发现隐患的人)
|
||||
String initiator = String.valueOf(inspect.getAuditorId());
|
||||
// 默认整改人也先设置为审核人,或者留空等待指派
|
||||
String rectifierId = String.valueOf(inspect.getEvaluatorId());
|
||||
|
||||
String instanceId = flowService.startFlow(
|
||||
"HIDDEN_DANGER_GOVERNANCE",
|
||||
String.valueOf(danger.getId()),
|
||||
inspect.getCompanyId(),
|
||||
initiator,
|
||||
rectifierId
|
||||
);
|
||||
danger.setInstanceId(instanceId);
|
||||
danger.setEvaluatorId(inspect.getEvaluatorId());
|
||||
danger.setFlowStatus("SUBMITTED");
|
||||
hiddenDangerMapper.updateById(danger);
|
||||
log.info("车辆三检隐患治理流程已启动: recordId={}, inspectId={}, sourceId={}, dangerId={}, hiddenDangerInstanceId={}",
|
||||
inspect.getId(), inspect.getInspectId(), sourceId, danger.getId(), instanceId);
|
||||
}
|
||||
|
||||
private void sendDriverAuditNotification(HotVehicleThreeInspect inspect, boolean success) {
|
||||
@@ -139,13 +165,27 @@ public class VehicleThreeInspectCallback implements IFlowCallback {
|
||||
if (StringUtils.isNotBlank(rejectReason)) {
|
||||
return "您的车辆三检【" + phaseName + "】未通过,不通过原因:" + rejectReason;
|
||||
}
|
||||
String auditResult = StringUtils.trimToEmpty(inspect.getAuditResult());
|
||||
String auditResult = StringUtils.trimToEmpty(resolveReadableAuditResult(inspect.getAuditResult()));
|
||||
if (StringUtils.isNotBlank(auditResult)) {
|
||||
return "您的车辆三检【" + phaseName + "】未通过,审核意见:" + auditResult;
|
||||
}
|
||||
return "您的车辆三检【" + phaseName + "】未通过,请及时查看审核意见。";
|
||||
}
|
||||
|
||||
private String resolveReadableAuditResult(String auditResult) {
|
||||
String value = StringUtils.trimToNull(auditResult);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if ("1".equals(value)) {
|
||||
return "通过";
|
||||
}
|
||||
if ("2".equals(value)) {
|
||||
return "不通过";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private String getPhaseName(Long phase) {
|
||||
if (phase == null) {
|
||||
return "未知阶段";
|
||||
|
||||
@@ -2,6 +2,12 @@ package com.hotwj.platform.config.vehicleThreeInspect.controller;
|
||||
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectBatchAuditBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectMultiVehicleBatchAuditBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectProcessVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectVehicleQueryBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectReceivedVehicleVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectSummaryVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectUnreceivedVehicleVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.service.IHotVehicleThreeInspectPrintService;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.service.IHotVehicleThreeInspectService;
|
||||
@@ -10,6 +16,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -54,6 +61,15 @@ public class HotVehicleThreeInspectController extends BaseController {
|
||||
return hotVehicleThreeInspectService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询车辆三检流程列表
|
||||
*/
|
||||
@GetMapping("/listProcess")
|
||||
@Operation(summary = "分页查询车辆三检流程列表")
|
||||
public TableDataInfo<HotVehicleThreeInspectProcessVo> listProcess(HotVehicleThreeInspectBo bo, PageQuery pageQuery) {
|
||||
return hotVehicleThreeInspectService.queryProcessPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询可进行三检的车辆列表
|
||||
*/
|
||||
@@ -63,6 +79,34 @@ public class HotVehicleThreeInspectController extends BaseController {
|
||||
return R.ok(hotVehicleThreeInspectService.queryAvailableVehicles(companyId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有三检未收车的车辆列表
|
||||
*/
|
||||
@GetMapping("/unreceivedVehicles")
|
||||
@Operation(summary = "查询所有三检还未收车的车辆列表")
|
||||
public R<List<HotVehicleThreeInspectUnreceivedVehicleVo>> queryUnreceivedVehicles(HotVehicleThreeInspectVehicleQueryBo bo) {
|
||||
return R.ok(hotVehicleThreeInspectService.queryUnreceivedVehicles(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有三检已收车的车辆列表
|
||||
*/
|
||||
@GetMapping("/receivedVehicles")
|
||||
@Operation(summary = "查询所有三检已收车的车辆列表")
|
||||
public R<List<HotVehicleThreeInspectReceivedVehicleVo>> queryReceivedVehicles(HotVehicleThreeInspectVehicleQueryBo bo) {
|
||||
return R.ok(hotVehicleThreeInspectService.queryReceivedVehicles(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验当前驾驶员是否可选择指定车辆
|
||||
*/
|
||||
@GetMapping("/checkSelectableVehicle")
|
||||
@Operation(summary = "校验当前驾驶员是否可选择指定车辆")
|
||||
public R<Boolean> checkSelectableVehicle(@RequestParam @NotBlank(message = "驾驶员ID不能为空") String driverId,
|
||||
@RequestParam @NotBlank(message = "车辆ID不能为空") String vehicleId) {
|
||||
return R.ok(hotVehicleThreeInspectService.checkSelectableVehicle(driverId, vehicleId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出车辆三检列表
|
||||
*/
|
||||
@@ -171,4 +215,54 @@ public class HotVehicleThreeInspectController extends BaseController {
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(hotVehicleThreeInspectService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询车辆三检聚合列表
|
||||
*/
|
||||
@GetMapping("/listSummary")
|
||||
@Operation(summary = "分页查询车辆三检聚合列表")
|
||||
public TableDataInfo<HotVehicleThreeInspectSummaryVo> listSummary(HotVehicleThreeInspectBo bo, PageQuery pageQuery) {
|
||||
return hotVehicleThreeInspectService.querySummaryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前人员可进行多车辆批量审核的车辆三检列表
|
||||
*/
|
||||
@GetMapping("/multiVehicleBatchAudit/list")
|
||||
@Operation(summary = "分页查询当前人员可进行多车辆批量审核的车辆三检列表")
|
||||
public TableDataInfo<HotVehicleThreeInspectSummaryVo> listMultiVehicleBatchAudit(HotVehicleThreeInspectVehicleQueryBo bo, PageQuery pageQuery) {
|
||||
return hotVehicleThreeInspectService.queryBatchAuditVehiclePageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 多车辆批量审核车辆三检
|
||||
*/
|
||||
@Log(title = "车辆三检多车辆批量审核", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/multiVehicleBatchAudit")
|
||||
@Operation(summary = "多车辆批量审核车辆三检")
|
||||
public R<Void> multiVehicleBatchAudit(@Validated @RequestBody HotVehicleThreeInspectMultiVehicleBatchAuditBo bo) {
|
||||
hotVehicleThreeInspectService.multiVehicleBatchAudit(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询车辆三检历史记录列表
|
||||
*/
|
||||
@GetMapping("/history/list")
|
||||
@Operation(summary = "分页查询车辆三检历史记录列表")
|
||||
public TableDataInfo<HotVehicleThreeInspectSummaryVo> listHistory(HotVehicleThreeInspectBo bo, PageQuery pageQuery) {
|
||||
return hotVehicleThreeInspectService.queryHistoryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询车辆三检历史记录详情
|
||||
*/
|
||||
@GetMapping("/history/{inspectId}")
|
||||
@Operation(summary = "查询车辆三检历史记录详情")
|
||||
public R<HotVehicleThreeInspectSummaryVo> getHistoryDetail(@NotNull(message = "三检流程ID不能为空")
|
||||
@Parameter(name = "inspectId", description = "三检流程ID", required = true, example = "1")
|
||||
@PathVariable Long inspectId) {
|
||||
return R.ok(hotVehicleThreeInspectService.queryHistoryDetail(inspectId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,11 +60,21 @@ public class HotVehicleThreeInspect extends BaseEntity {
|
||||
*/
|
||||
private Long inspectId;
|
||||
|
||||
/**
|
||||
* 三检记录编号
|
||||
*/
|
||||
private String inspectNo;
|
||||
|
||||
/**
|
||||
* 检查时间
|
||||
*/
|
||||
private Date inspectTime;
|
||||
|
||||
/**
|
||||
* 检查地点
|
||||
*/
|
||||
private String inspectLocation;
|
||||
|
||||
/**
|
||||
* 审核人ID
|
||||
*/
|
||||
|
||||
@@ -63,12 +63,32 @@ public class HotVehicleThreeInspectBo extends BaseEntity {
|
||||
*/
|
||||
private Long inspectId;
|
||||
|
||||
/**
|
||||
* 三检记录编号
|
||||
*/
|
||||
private String inspectNo;
|
||||
|
||||
/**
|
||||
* 检查时间
|
||||
*/
|
||||
@NotNull(message = "检查时间不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Date inspectTime;
|
||||
|
||||
/**
|
||||
* 检查地点
|
||||
*/
|
||||
private String inspectLocation;
|
||||
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
private Double latitude;
|
||||
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
private Double longitude;
|
||||
|
||||
/**
|
||||
* 审核人ID
|
||||
*/
|
||||
@@ -89,7 +109,6 @@ public class HotVehicleThreeInspectBo extends BaseEntity {
|
||||
/**
|
||||
* 检查附件图片url
|
||||
*/
|
||||
@NotBlank(message = "检查附件图片url不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String attachImgUrl;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.hotwj.platform.config.vehicleThreeInspect.domain.bo;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 车辆三检多车辆批量审核业务对象
|
||||
*
|
||||
* @author shihongwei
|
||||
* @date 2026-06-17
|
||||
*/
|
||||
@Data
|
||||
public class HotVehicleThreeInspectMultiVehicleBatchAuditBo {
|
||||
|
||||
/**
|
||||
* 三检流程ID集合
|
||||
*/
|
||||
@NotEmpty(message = "三检流程ID不能为空")
|
||||
private List<Long> inspectIds;
|
||||
|
||||
/**
|
||||
* 是否存在隐患 0=否, 1=是
|
||||
*/
|
||||
@NotNull(message = "是否存在隐患不能为空")
|
||||
private Long hasHiddenDanger;
|
||||
|
||||
/**
|
||||
* 评估人ID
|
||||
*/
|
||||
private Long evaluatorId;
|
||||
|
||||
/**
|
||||
* 审核时间
|
||||
*/
|
||||
private Date auditTime;
|
||||
|
||||
/**
|
||||
* 审核结论
|
||||
*/
|
||||
private String auditResult;
|
||||
|
||||
/**
|
||||
* 审核不通过原因
|
||||
*/
|
||||
private String rejectReason;
|
||||
|
||||
/**
|
||||
* 审核人员签名图片url
|
||||
*/
|
||||
@NotBlank(message = "审核人员签名不能为空")
|
||||
private String auditorSignImgUrl;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.hotwj.platform.config.vehicleThreeInspect.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 车辆三检车辆列表查询对象
|
||||
*
|
||||
* @author shihongwei
|
||||
* @date 2026-05-27
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class HotVehicleThreeInspectVehicleQueryBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 企业ID
|
||||
*/
|
||||
private Long companyId;
|
||||
|
||||
/**
|
||||
* 车牌号
|
||||
*/
|
||||
private String plateNumber;
|
||||
}
|
||||
@@ -13,50 +13,48 @@ public class HotVehicleThreeInspectPrintVo {
|
||||
*/
|
||||
private Long inspectId;
|
||||
|
||||
/**
|
||||
* 三检记录编号
|
||||
*/
|
||||
private String inspectNo;
|
||||
|
||||
/**
|
||||
* 车牌号
|
||||
*/
|
||||
private String plateNumber;
|
||||
|
||||
// --- 出车前 Phase 1 ---
|
||||
/**
|
||||
* 出车前-检查时间
|
||||
* 检查人
|
||||
*/
|
||||
private String startPhaseTime;
|
||||
/**
|
||||
* 出车前-状态
|
||||
*/
|
||||
private String startPhaseStatus;
|
||||
/**
|
||||
* 出车前-隐患
|
||||
*/
|
||||
private String startPhaseHiddenDanger;
|
||||
private String inspectorName;
|
||||
|
||||
// --- 行车中 Phase 2 ---
|
||||
/**
|
||||
* 行车中-检查时间
|
||||
* 审核人
|
||||
*/
|
||||
private String runningPhaseTime;
|
||||
/**
|
||||
* 行车中-状态
|
||||
*/
|
||||
private String runningPhaseStatus;
|
||||
/**
|
||||
* 行车中-隐患
|
||||
*/
|
||||
private String runningPhaseHiddenDanger;
|
||||
private String auditorName;
|
||||
|
||||
// --- 收车后 Phase 3 ---
|
||||
/**
|
||||
* 收车后-检查时间
|
||||
* 检查开始时间
|
||||
*/
|
||||
private String endPhaseTime;
|
||||
private String startTime;
|
||||
|
||||
/**
|
||||
* 收车后-状态
|
||||
* 检查结束时间
|
||||
*/
|
||||
private String endPhaseStatus;
|
||||
private String endTime;
|
||||
|
||||
/**
|
||||
* 收车后-隐患
|
||||
* 出车前检查地点
|
||||
*/
|
||||
private String endPhaseHiddenDanger;
|
||||
private String outInspectLocation;
|
||||
|
||||
/**
|
||||
* 行车中检查地点
|
||||
*/
|
||||
private String drivingInspectLocation;
|
||||
|
||||
/**
|
||||
* 收车后检查地点
|
||||
*/
|
||||
private String backInspectLocation;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.hotwj.platform.config.vehicleThreeInspect.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 车辆三检流程列表视图对象
|
||||
*
|
||||
* @author shihongwei
|
||||
* @date 2025-12-29
|
||||
*/
|
||||
@Data
|
||||
public class HotVehicleThreeInspectProcessVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 三检流程ID
|
||||
*/
|
||||
private Long inspectId;
|
||||
|
||||
/**
|
||||
* 公司ID
|
||||
*/
|
||||
private Long companyId;
|
||||
|
||||
/**
|
||||
* 车辆ID
|
||||
*/
|
||||
private Long vehicleId;
|
||||
|
||||
/**
|
||||
* 车牌号
|
||||
*/
|
||||
private String plateNumber;
|
||||
|
||||
/**
|
||||
* 检查者姓名
|
||||
*/
|
||||
private String driverName;
|
||||
|
||||
/**
|
||||
* 流程开始时间
|
||||
*/
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 流程结束时间
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 流程时间展示
|
||||
*/
|
||||
private String inspectTime;
|
||||
|
||||
/**
|
||||
* 完成状态
|
||||
*/
|
||||
private String completeStatus;
|
||||
|
||||
/**
|
||||
* 是否已完成
|
||||
*/
|
||||
private Boolean completed;
|
||||
|
||||
/**
|
||||
* 审核完成状态
|
||||
*/
|
||||
private String auditCompleteStatus;
|
||||
|
||||
/**
|
||||
* 是否完成审核
|
||||
*/
|
||||
private Boolean auditCompleted;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.hotwj.platform.config.vehicleThreeInspect.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 车辆三检已收车车辆列表视图对象
|
||||
*
|
||||
* @author shihongwei
|
||||
* @date 2026-05-27
|
||||
*/
|
||||
@Data
|
||||
public class HotVehicleThreeInspectReceivedVehicleVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 车辆ID
|
||||
*/
|
||||
private String vehicleId;
|
||||
|
||||
/**
|
||||
* 车牌号
|
||||
*/
|
||||
private String plateNumber;
|
||||
|
||||
/**
|
||||
* 车辆类型
|
||||
*/
|
||||
private String vehicleType;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.hotwj.platform.config.vehicleThreeInspect.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 车辆三检聚合列表视图对象
|
||||
*
|
||||
* @author shihongwei
|
||||
* @date 2026-06-01
|
||||
*/
|
||||
@Data
|
||||
public class HotVehicleThreeInspectSummaryVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 三检流程ID
|
||||
*/
|
||||
private Long inspectId;
|
||||
|
||||
/**
|
||||
* 三检记录编号
|
||||
*/
|
||||
private String inspectNo;
|
||||
|
||||
/**
|
||||
* 公司ID
|
||||
*/
|
||||
private Long companyId;
|
||||
|
||||
/**
|
||||
* 车辆ID
|
||||
*/
|
||||
private Long vehicleId;
|
||||
|
||||
/**
|
||||
* 车牌号
|
||||
*/
|
||||
private String plateNumber;
|
||||
|
||||
/**
|
||||
* 驾驶员ID
|
||||
*/
|
||||
private String driverId;
|
||||
|
||||
/**
|
||||
* 驾驶员姓名
|
||||
*/
|
||||
private String driverName;
|
||||
|
||||
/**
|
||||
* 检查人
|
||||
*/
|
||||
private String inspectorName;
|
||||
|
||||
/**
|
||||
* 审核人
|
||||
*/
|
||||
private String auditorName;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 检查时间展示
|
||||
*/
|
||||
private String inspectTime;
|
||||
|
||||
/**
|
||||
* 完成状态
|
||||
*/
|
||||
private String completeStatus;
|
||||
|
||||
/**
|
||||
* 是否已完成
|
||||
*/
|
||||
private Boolean completed;
|
||||
|
||||
/**
|
||||
* 审核完成状态
|
||||
*/
|
||||
private String auditCompleteStatus;
|
||||
|
||||
/**
|
||||
* 是否完成审核
|
||||
*/
|
||||
private Boolean auditCompleted;
|
||||
|
||||
/**
|
||||
* 出车前检查地点
|
||||
*/
|
||||
private String outInspectLocation;
|
||||
|
||||
/**
|
||||
* 行车中检查地点
|
||||
*/
|
||||
private String drivingInspectLocation;
|
||||
|
||||
/**
|
||||
* 收车后检查地点
|
||||
*/
|
||||
private String backInspectLocation;
|
||||
|
||||
/**
|
||||
* 出车检查
|
||||
*/
|
||||
private HotVehicleThreeInspectVo outCheck;
|
||||
|
||||
/**
|
||||
* 行车检查
|
||||
*/
|
||||
private HotVehicleThreeInspectVo drivingCheck;
|
||||
|
||||
/**
|
||||
* 收车检查
|
||||
*/
|
||||
private HotVehicleThreeInspectVo backCheck;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.hotwj.platform.config.vehicleThreeInspect.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 车辆三检未收车车辆列表视图对象
|
||||
*
|
||||
* @author shihongwei
|
||||
* @date 2026-05-27
|
||||
*/
|
||||
@Data
|
||||
public class HotVehicleThreeInspectUnreceivedVehicleVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 车辆ID
|
||||
*/
|
||||
private String vehicleId;
|
||||
|
||||
/**
|
||||
* 车牌号
|
||||
*/
|
||||
private String plateNumber;
|
||||
|
||||
/**
|
||||
* 审核人
|
||||
*/
|
||||
private String auditorName;
|
||||
|
||||
/**
|
||||
* 车辆类型
|
||||
*/
|
||||
private String vehicleType;
|
||||
}
|
||||
@@ -66,12 +66,24 @@ public class HotVehicleThreeInspectVo implements Serializable {
|
||||
*/
|
||||
private Long inspectId;
|
||||
|
||||
/**
|
||||
* 三检记录编号
|
||||
*/
|
||||
@ExcelProperty(value = "三检记录编号")
|
||||
private String inspectNo;
|
||||
|
||||
/**
|
||||
* 检查时间
|
||||
*/
|
||||
@ExcelProperty(value = "检查时间")
|
||||
private Date inspectTime;
|
||||
|
||||
/**
|
||||
* 检查地点
|
||||
*/
|
||||
@ExcelProperty(value = "检查地点")
|
||||
private String inspectLocation;
|
||||
|
||||
/**
|
||||
* 审核人ID
|
||||
*/
|
||||
|
||||
@@ -2,8 +2,14 @@ package com.hotwj.platform.config.vehicleThreeInspect.mapper;
|
||||
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.HotVehicleThreeInspect;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectVehicleQueryBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectProcessVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectPrintVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectReceivedVehicleVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectSummaryVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectUnreceivedVehicleVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectVo;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
@@ -27,4 +33,74 @@ public interface HotVehicleThreeInspectMapper extends BaseMapperPlus<HotVehicleT
|
||||
*/
|
||||
List<HotVehicleThreeInspectPrintVo> selectPrintList(@Param("bo") HotVehicleThreeInspectBo bo);
|
||||
|
||||
/**
|
||||
* 分页查询车辆三检流程列表
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @return 流程分页列表
|
||||
*/
|
||||
Page<HotVehicleThreeInspectProcessVo> queryProcessPageList(
|
||||
Page<HotVehicleThreeInspectProcessVo> page,
|
||||
@Param("bo") HotVehicleThreeInspectBo bo
|
||||
);
|
||||
|
||||
/**
|
||||
* 分页查询车辆三检聚合列表
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @return 聚合分页列表
|
||||
*/
|
||||
Page<HotVehicleThreeInspectSummaryVo> querySummaryPageList(
|
||||
Page<HotVehicleThreeInspectSummaryVo> page,
|
||||
@Param("bo") HotVehicleThreeInspectBo bo
|
||||
);
|
||||
|
||||
/**
|
||||
* 分页查询当前人员可进行多车辆批量审核的车辆三检聚合列表
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @param auditorId 当前审核人ID
|
||||
* @return 聚合分页列表
|
||||
*/
|
||||
Page<HotVehicleThreeInspectSummaryVo> queryBatchAuditVehiclePageList(
|
||||
Page<HotVehicleThreeInspectSummaryVo> page,
|
||||
@Param("bo") HotVehicleThreeInspectVehicleQueryBo bo,
|
||||
@Param("auditorId") Long auditorId
|
||||
);
|
||||
|
||||
/**
|
||||
* 按流程ID查询车辆三检聚合详情
|
||||
*
|
||||
* @param inspectId 流程ID
|
||||
* @return 聚合详情
|
||||
*/
|
||||
HotVehicleThreeInspectSummaryVo querySummaryByInspectId(@Param("inspectId") Long inspectId);
|
||||
|
||||
/**
|
||||
* 按流程ID集合查询三检明细
|
||||
*
|
||||
* @param inspectIds 流程ID集合
|
||||
* @return 三检明细列表
|
||||
*/
|
||||
List<HotVehicleThreeInspectVo> querySummaryDetailList(@Param("inspectIds") List<Long> inspectIds);
|
||||
|
||||
/**
|
||||
* 查询所有三检未收车的车辆列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 未收车车辆列表
|
||||
*/
|
||||
List<HotVehicleThreeInspectUnreceivedVehicleVo> queryUnreceivedVehicles(@Param("bo") HotVehicleThreeInspectVehicleQueryBo bo);
|
||||
|
||||
/**
|
||||
* 查询所有三检已收车的车辆列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 已收车车辆列表
|
||||
*/
|
||||
List<HotVehicleThreeInspectReceivedVehicleVo> queryReceivedVehicles(@Param("bo") HotVehicleThreeInspectVehicleQueryBo bo);
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,12 @@ package com.hotwj.platform.config.vehicleThreeInspect.service;
|
||||
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectBatchAuditBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectMultiVehicleBatchAuditBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectVehicleQueryBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectProcessVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectReceivedVehicleVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectSummaryVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectUnreceivedVehicleVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectVo;
|
||||
import com.hotwj.platform.resourceManagement.vehicleManagement.domain.vo.HotVehicleVo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
@@ -26,6 +32,22 @@ public interface IHotVehicleThreeInspectService {
|
||||
*/
|
||||
List<HotVehicleVo> queryAvailableVehicles(Long companyId);
|
||||
|
||||
/**
|
||||
* 查询所有三检未收车的车辆列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 未收车车辆列表
|
||||
*/
|
||||
List<HotVehicleThreeInspectUnreceivedVehicleVo> queryUnreceivedVehicles(HotVehicleThreeInspectVehicleQueryBo bo);
|
||||
|
||||
/**
|
||||
* 查询所有三检已收车的车辆列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 已收车车辆列表
|
||||
*/
|
||||
List<HotVehicleThreeInspectReceivedVehicleVo> queryReceivedVehicles(HotVehicleThreeInspectVehicleQueryBo bo);
|
||||
|
||||
/**
|
||||
* 查询车辆三检
|
||||
*
|
||||
@@ -43,6 +65,50 @@ public interface IHotVehicleThreeInspectService {
|
||||
*/
|
||||
TableDataInfo<HotVehicleThreeInspectVo> queryPageList(HotVehicleThreeInspectBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 分页查询车辆三检流程列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 车辆三检流程分页列表
|
||||
*/
|
||||
TableDataInfo<HotVehicleThreeInspectProcessVo> queryProcessPageList(HotVehicleThreeInspectBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 分页查询车辆三检聚合列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 车辆三检聚合分页列表
|
||||
*/
|
||||
TableDataInfo<HotVehicleThreeInspectSummaryVo> querySummaryPageList(HotVehicleThreeInspectBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 分页查询当前人员可进行多车辆批量审核的三检流程列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 聚合分页列表
|
||||
*/
|
||||
TableDataInfo<HotVehicleThreeInspectSummaryVo> queryBatchAuditVehiclePageList(HotVehicleThreeInspectVehicleQueryBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询车辆三检历史记录分页列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 历史记录分页列表
|
||||
*/
|
||||
TableDataInfo<HotVehicleThreeInspectSummaryVo> queryHistoryPageList(HotVehicleThreeInspectBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 按三检流程ID查询历史详情
|
||||
*
|
||||
* @param inspectId 三检流程ID
|
||||
* @return 历史详情
|
||||
*/
|
||||
HotVehicleThreeInspectSummaryVo queryHistoryDetail(Long inspectId);
|
||||
|
||||
/**
|
||||
* 查询符合条件的车辆三检列表
|
||||
*
|
||||
@@ -76,6 +142,25 @@ public interface IHotVehicleThreeInspectService {
|
||||
*/
|
||||
void validateNoUnfinishedProcess(String vehicleId, String actionMessage);
|
||||
|
||||
/**
|
||||
* 校验车辆当前不存在影响默认车辆切换的未完成三检流程。
|
||||
* 切换默认车辆时仅要求最新一条三检记录已到收车检查阶段,不区分审核结果。
|
||||
*
|
||||
* @param vehicleId 车辆ID
|
||||
* @param actionMessage 失败提示文案
|
||||
*/
|
||||
void validateNoUnfinishedSwitchVehicleProcess(String vehicleId, String actionMessage);
|
||||
|
||||
/**
|
||||
* 校验当前驾驶员是否可选择指定车辆。
|
||||
* 若车辆未出车则直接返回true;若车辆已出车,且当次三检流程未完成,且记录驾驶员不是当前驾驶员,则抛出异常。
|
||||
*
|
||||
* @param driverId 当前驾驶员ID
|
||||
* @param vehicleId 车辆ID
|
||||
* @return 是否可选择
|
||||
*/
|
||||
boolean checkSelectableVehicle(String driverId, String vehicleId);
|
||||
|
||||
/**
|
||||
* 修改车辆三检
|
||||
*
|
||||
@@ -106,4 +191,11 @@ public interface IHotVehicleThreeInspectService {
|
||||
* @param bo 批量审核业务对象
|
||||
*/
|
||||
void batchAudit(HotVehicleThreeInspectBatchAuditBo bo);
|
||||
|
||||
/**
|
||||
* 多车辆批量审核车辆三检
|
||||
*
|
||||
* @param bo 多车辆批量审核业务对象
|
||||
*/
|
||||
void multiVehicleBatchAudit(HotVehicleThreeInspectMultiVehicleBatchAuditBo bo);
|
||||
}
|
||||
|
||||
@@ -1,37 +1,52 @@
|
||||
package com.hotwj.platform.config.vehicleThreeInspect.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.hotwj.platform.common.helper.DriverLoginContextHelper;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.HotVehicleThreeInspect;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectBatchAuditBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.HotVehicleThreeInspectVo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectMultiVehicleBatchAuditBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.bo.HotVehicleThreeInspectVehicleQueryBo;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.domain.vo.*;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.mapper.HotVehicleThreeInspectMapper;
|
||||
import com.hotwj.platform.config.vehicleThreeInspect.service.IHotVehicleThreeInspectService;
|
||||
import com.hotwj.platform.config.vehicleThreeInspectConfig.domain.HotVehicleThreeInspectConfig;
|
||||
import com.hotwj.platform.config.vehicleThreeInspectConfig.mapper.HotVehicleThreeInspectConfigMapper;
|
||||
import com.hotwj.platform.flow.service.ISysFlowService;
|
||||
import com.hotwj.platform.integration.ocr.SignatureVerifyService;
|
||||
import com.hotwj.platform.noticeManagerment.systemNotification.domain.bo.HotSystemNotificationGroupBo;
|
||||
import com.hotwj.platform.noticeManagerment.systemNotification.service.IHotSystemNotificationService;
|
||||
import com.hotwj.platform.resourceManagement.vehicleManagement.domain.HotVehicle;
|
||||
import com.hotwj.platform.resourceManagement.vehicleManagement.domain.vo.HotVehicleVo;
|
||||
import com.hotwj.platform.resourceManagement.vehicleManagement.mapper.HotVehicleMapper;
|
||||
import com.hotwj.platform.securityManagement.hiddenDanger.mapper.HotHiddenDangerMapper;
|
||||
import com.hotwj.platform.securityManagement.vehicleInoutCheck.domain.HotVehicleInoutCheck;
|
||||
import com.hotwj.platform.securityManagement.vehicleInoutCheck.mapper.HotVehicleInoutCheckMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.domain.model.LoginUser;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* 车辆三检Service业务层处理
|
||||
@@ -47,9 +62,14 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
private final HotVehicleThreeInspectMapper baseMapper;
|
||||
private final HotVehicleMapper hotVehicleMapper;
|
||||
private final HotHiddenDangerMapper hotHiddenDangerMapper;
|
||||
private final HotVehicleInoutCheckMapper hotVehicleInoutCheckMapper;
|
||||
private final ISysFlowService flowService;
|
||||
private final IHotSystemNotificationService notificationService;
|
||||
private final SignatureVerifyService signatureVerifyService;
|
||||
private final HotVehicleThreeInspectConfigMapper hotVehicleThreeInspectConfigMapper;
|
||||
|
||||
@Value("${map.gd.key:}")
|
||||
private String gdKey;
|
||||
|
||||
/**
|
||||
* 查询可进行三检的车辆列表(无历史记录或上一轮已完结)
|
||||
@@ -62,19 +82,23 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
return hotVehicleMapper.selectAvailableForThreeInspect(companyId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HotVehicleThreeInspectUnreceivedVehicleVo> queryUnreceivedVehicles(HotVehicleThreeInspectVehicleQueryBo bo) {
|
||||
return baseMapper.queryUnreceivedVehicles(bo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HotVehicleThreeInspectReceivedVehicleVo> queryReceivedVehicles(HotVehicleThreeInspectVehicleQueryBo bo) {
|
||||
return baseMapper.queryReceivedVehicles(bo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnfinishedProcess(String vehicleId) {
|
||||
Long parsedVehicleId = parseVehicleId(vehicleId);
|
||||
if (parsedVehicleId == null) {
|
||||
return false;
|
||||
}
|
||||
HotVehicleThreeInspect latestInspect = baseMapper.selectOne(
|
||||
Wrappers.<HotVehicleThreeInspect>lambdaQuery()
|
||||
.eq(HotVehicleThreeInspect::getVehicleId, parsedVehicleId)
|
||||
.eq(HotVehicleThreeInspect::getIsDeleted, 0L)
|
||||
.orderByDesc(HotVehicleThreeInspect::getCreateTime)
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
HotVehicleThreeInspect latestInspect = selectLatestInspect(parsedVehicleId);
|
||||
if (latestInspect == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -91,6 +115,42 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateNoUnfinishedSwitchVehicleProcess(String vehicleId, String actionMessage) {
|
||||
Long parsedVehicleId = parseVehicleId(vehicleId);
|
||||
if (parsedVehicleId == null) {
|
||||
return;
|
||||
}
|
||||
HotVehicleThreeInspect latestInspect = selectLatestInspect(parsedVehicleId);
|
||||
if (latestInspect == null) {
|
||||
return;
|
||||
}
|
||||
if (!Long.valueOf(3L).equals(latestInspect.getInspectPhase())) {
|
||||
throw new ServiceException(actionMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkSelectableVehicle(String driverId, String vehicleId) {
|
||||
String trimmedDriverId = StringUtils.trimToNull(driverId);
|
||||
String trimmedVehicleId = StringUtils.trimToNull(vehicleId);
|
||||
if (StringUtils.isBlank(trimmedDriverId)) {
|
||||
throw new ServiceException("驾驶员ID不能为空");
|
||||
}
|
||||
Long parsedVehicleId = parseVehicleId(trimmedVehicleId);
|
||||
if (parsedVehicleId == null) {
|
||||
return true;
|
||||
}
|
||||
HotVehicleThreeInspect latestInspect = selectLatestInspect(parsedVehicleId);
|
||||
if (latestInspect == null || Objects.equals(latestInspect.getInspectPhase(), 3L)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.equals(trimmedDriverId, StringUtils.trimToEmpty(latestInspect.getDriverId()))) {
|
||||
return true;
|
||||
}
|
||||
throw new ServiceException(buildVehicleOccupiedMessage(parsedVehicleId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询车辆三检
|
||||
*
|
||||
@@ -129,6 +189,67 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询车辆三检流程列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 车辆三检流程分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<HotVehicleThreeInspectProcessVo> queryProcessPageList(HotVehicleThreeInspectBo bo, PageQuery pageQuery) {
|
||||
Page<HotVehicleThreeInspectProcessVo> result = baseMapper.queryProcessPageList(pageQuery.build(), bo);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询车辆三检聚合列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 车辆三检聚合分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<HotVehicleThreeInspectSummaryVo> querySummaryPageList(HotVehicleThreeInspectBo bo, PageQuery pageQuery) {
|
||||
Page<HotVehicleThreeInspectSummaryVo> result = baseMapper.querySummaryPageList(pageQuery.build(), bo);
|
||||
enrichSummaryList(result.getRecords());
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<HotVehicleThreeInspectSummaryVo> queryBatchAuditVehiclePageList(HotVehicleThreeInspectVehicleQueryBo bo, PageQuery pageQuery) {
|
||||
Long currentAuditorId = resolveCurrentAuditorId();
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
if (bo == null) {
|
||||
bo = new HotVehicleThreeInspectVehicleQueryBo();
|
||||
}
|
||||
if (bo.getCompanyId() == null && loginUser != null) {
|
||||
bo.setCompanyId(loginUser.getCompanyId());
|
||||
}
|
||||
Page<HotVehicleThreeInspectSummaryVo> result = baseMapper.queryBatchAuditVehiclePageList(pageQuery.build(), bo, currentAuditorId);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<HotVehicleThreeInspectSummaryVo> queryHistoryPageList(HotVehicleThreeInspectBo bo, PageQuery pageQuery) {
|
||||
return querySummaryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HotVehicleThreeInspectSummaryVo queryHistoryDetail(Long inspectId) {
|
||||
HotVehicleThreeInspectSummaryVo summary = baseMapper.querySummaryByInspectId(inspectId);
|
||||
if (summary == null) {
|
||||
throw new ServiceException("车辆三检历史记录不存在");
|
||||
}
|
||||
List<HotVehicleThreeInspectVo> detailList = baseMapper.querySummaryDetailList(Collections.singletonList(inspectId));
|
||||
fillTaskId(detailList);
|
||||
for (HotVehicleThreeInspectVo detail : detailList) {
|
||||
attachPhaseDetail(summary, detail);
|
||||
}
|
||||
refreshSummary(summary);
|
||||
return summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询符合条件的车辆三检列表
|
||||
*
|
||||
@@ -141,10 +262,56 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private void attachPhaseDetail(HotVehicleThreeInspectSummaryVo summary, HotVehicleThreeInspectVo detail) {
|
||||
if (summary == null || detail == null || detail.getInspectPhase() == null) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isBlank(summary.getInspectNo()) && StringUtils.isNotBlank(detail.getInspectNo())) {
|
||||
summary.setInspectNo(detail.getInspectNo());
|
||||
}
|
||||
if (StringUtils.isBlank(summary.getInspectorName()) && StringUtils.isNotBlank(detail.getDriverName())) {
|
||||
summary.setInspectorName(detail.getDriverName());
|
||||
}
|
||||
if (StringUtils.isBlank(summary.getAuditorName()) && StringUtils.isNotBlank(detail.getAuditorName())) {
|
||||
summary.setAuditorName(detail.getAuditorName());
|
||||
}
|
||||
Long inspectPhase = detail.getInspectPhase();
|
||||
if (Objects.equals(inspectPhase, 1L)) {
|
||||
if (summary.getOutCheck() == null) {
|
||||
summary.setOutCheck(detail);
|
||||
summary.setOutInspectLocation(detail.getInspectLocation());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (Objects.equals(inspectPhase, 2L)) {
|
||||
if (summary.getDrivingCheck() == null) {
|
||||
summary.setDrivingCheck(detail);
|
||||
summary.setDrivingInspectLocation(detail.getInspectLocation());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (Objects.equals(inspectPhase, 3L) && summary.getBackCheck() == null) {
|
||||
summary.setBackCheck(detail);
|
||||
summary.setBackInspectLocation(detail.getInspectLocation());
|
||||
}
|
||||
}
|
||||
|
||||
private void fillTaskId(List<HotVehicleThreeInspectVo> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
String businessUserId = LoginHelper.getBusinessUserId();
|
||||
for (HotVehicleThreeInspectVo vo : list) {
|
||||
if (StringUtils.isNotBlank(vo.getInstanceId())) {
|
||||
vo.setTaskId(flowService.getTaskId(vo.getInstanceId(), businessUserId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<HotVehicleThreeInspect> buildQueryWrapper(HotVehicleThreeInspectBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotVehicleThreeInspect> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(HotVehicleThreeInspect::getCreateTime);
|
||||
lqw.orderByDesc(HotVehicleThreeInspect::getCreateTime, HotVehicleThreeInspect::getId);
|
||||
Object beginTime = params == null ? null : params.get("beginTime");
|
||||
Object endTime = params == null ? null : params.get("endTime");
|
||||
if (beginTime != null && endTime != null) {
|
||||
@@ -177,6 +344,8 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
lqw.eq(bo.getInspectPhase() != null, HotVehicleThreeInspect::getInspectPhase, bo.getInspectPhase());
|
||||
lqw.eq(bo.getInspectTime() != null, HotVehicleThreeInspect::getInspectTime, bo.getInspectTime());
|
||||
lqw.eq(bo.getInspectId() != null, HotVehicleThreeInspect::getInspectId, bo.getInspectId());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getInspectNo()), HotVehicleThreeInspect::getInspectNo, bo.getInspectNo());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getInspectLocation()), HotVehicleThreeInspect::getInspectLocation, bo.getInspectLocation());
|
||||
lqw.eq(bo.getAuditorId() != null, HotVehicleThreeInspect::getAuditorId, bo.getAuditorId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getAuditorName()), HotVehicleThreeInspect::getAuditorName, bo.getAuditorName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getInspectResultJson()), HotVehicleThreeInspect::getInspectResultJson, bo.getInspectResultJson());
|
||||
@@ -194,6 +363,9 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(HotVehicleThreeInspectBo bo) {
|
||||
normalizeInspectLocation(bo);
|
||||
prepareInspectIdentity(bo);
|
||||
validateAttachImgUrlRequiredWhenAbnormal(bo);
|
||||
HotVehicleThreeInspect add = MapstructUtils.convert(bo, HotVehicleThreeInspect.class);
|
||||
validEntityBeforeSave(add);
|
||||
|
||||
@@ -203,18 +375,12 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
|
||||
// 校验该车辆三检流程逻辑
|
||||
if (add.getVehicleId() != null) {
|
||||
// 获取该车辆最近的一条三检记录
|
||||
List<HotVehicleThreeInspect> list = baseMapper.selectList(
|
||||
Wrappers.<HotVehicleThreeInspect>lambdaQuery()
|
||||
.eq(HotVehicleThreeInspect::getVehicleId, add.getVehicleId())
|
||||
.orderByDesc(HotVehicleThreeInspect::getCreateTime)
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
|
||||
Long currentPhase = add.getInspectPhase();
|
||||
// 获取该车辆最近的一条三检记录
|
||||
HotVehicleThreeInspect last = selectLatestInspect(add.getVehicleId());
|
||||
validateOutboundVehicleDriver(add, last);
|
||||
|
||||
if (list != null && !list.isEmpty()) {
|
||||
HotVehicleThreeInspect last = list.get(0);
|
||||
if (last != null) {
|
||||
Long lastPhase = last.getInspectPhase();
|
||||
// 1. 如果上一条是收车检查(第3阶段),则本次必须是新一轮的出车检查(第1阶段)
|
||||
if (lastPhase == 3) {
|
||||
@@ -263,6 +429,7 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
patchNewRoundInspectIdentity(add, bo);
|
||||
bo.setId(add.getId());
|
||||
|
||||
// 开启车辆三检的流程
|
||||
@@ -296,6 +463,45 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
return flag;
|
||||
}
|
||||
|
||||
private void validateOutboundVehicleDriver(HotVehicleThreeInspect currentInspect, HotVehicleThreeInspect latestInspect) {
|
||||
if (currentInspect == null || !Objects.equals(currentInspect.getInspectPhase(), 1L) || latestInspect == null) {
|
||||
return;
|
||||
}
|
||||
if (Objects.equals(latestInspect.getInspectPhase(), 3L)) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.equals(StringUtils.trimToEmpty(currentInspect.getDriverId()),
|
||||
StringUtils.trimToEmpty(latestInspect.getDriverId()))) {
|
||||
return;
|
||||
}
|
||||
throw new ServiceException(buildVehicleOccupiedMessage(currentInspect.getVehicleId()));
|
||||
}
|
||||
|
||||
private String buildVehicleOccupiedMessage(Long vehicleId) {
|
||||
if (vehicleId == null) {
|
||||
return "该车辆已出任务,请重新选择其他车辆";
|
||||
}
|
||||
HotVehicle vehicle = hotVehicleMapper.selectById(String.valueOf(vehicleId));
|
||||
String plateNumber = vehicle == null ? null : StringUtils.trimToNull(vehicle.getPlateNumber());
|
||||
if (plateNumber == null) {
|
||||
return "该车辆已出任务,请重新选择其他车辆";
|
||||
}
|
||||
return "'" + plateNumber + "'车辆已出任务,请重新选择其他车辆";
|
||||
}
|
||||
|
||||
private boolean isVehicleOutbound(Long vehicleId) {
|
||||
if (vehicleId == null) {
|
||||
return false;
|
||||
}
|
||||
return hotVehicleInoutCheckMapper.selectCount(
|
||||
Wrappers.<HotVehicleInoutCheck>lambdaQuery()
|
||||
.eq(HotVehicleInoutCheck::getVehicleId, vehicleId)
|
||||
.eq(HotVehicleInoutCheck::getIsDeleted, 0L)
|
||||
.isNotNull(HotVehicleInoutCheck::getDepartureTime)
|
||||
.isNull(HotVehicleInoutCheck::getReturnTime)
|
||||
) > 0;
|
||||
}
|
||||
|
||||
private void validateInspectorSignatureByPhase(HotVehicleThreeInspectBo bo) {
|
||||
Long inspectPhase = bo.getInspectPhase();
|
||||
if (inspectPhase == null) {
|
||||
@@ -365,12 +571,86 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean updateByBo(HotVehicleThreeInspectBo bo) {
|
||||
normalizeInspectLocation(bo);
|
||||
validateAttachImgUrlRequiredWhenAbnormal(bo);
|
||||
HotVehicleThreeInspect update = MapstructUtils.convert(bo, HotVehicleThreeInspect.class);
|
||||
validEntityBeforeSave(update);
|
||||
boolean flag = baseMapper.updateById(update) > 0;
|
||||
return flag;
|
||||
}
|
||||
|
||||
private void validateAttachImgUrlRequiredWhenAbnormal(HotVehicleThreeInspectBo bo) {
|
||||
if (!hasAbnormalInspectItem(bo)) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isBlank(bo.getAttachImgUrl())) {
|
||||
throw new ServiceException("检查项存在异常时,检查附件不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasAbnormalInspectItem(HotVehicleThreeInspectBo bo) {
|
||||
if (bo == null || StringUtils.isBlank(bo.getInspectResultJson())) {
|
||||
return false;
|
||||
}
|
||||
Map<String, Object> inspectResultMap;
|
||||
try {
|
||||
inspectResultMap = JsonUtils.parseObject(bo.getInspectResultJson(), new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
} catch (RuntimeException e) {
|
||||
throw new ServiceException("检查项目结果JSON格式错误");
|
||||
}
|
||||
if (inspectResultMap == null || inspectResultMap.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<Long, String> abnormalTextMap = queryAbnormalTextMap(bo, inspectResultMap);
|
||||
for (Map.Entry<String, Object> entry : inspectResultMap.entrySet()) {
|
||||
String resultText = StringUtils.trimToNull(Objects.toString(entry.getValue(), null));
|
||||
if (resultText == null) {
|
||||
continue;
|
||||
}
|
||||
Long configId = parseConfigId(entry.getKey());
|
||||
String abnormalText = configId == null ? "异常" : abnormalTextMap.getOrDefault(configId, "异常");
|
||||
if (StringUtils.equals(resultText, abnormalText)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Map<Long, String> queryAbnormalTextMap(HotVehicleThreeInspectBo bo, Map<String, Object> inspectResultMap) {
|
||||
List<Long> configIds = inspectResultMap.keySet().stream()
|
||||
.map(this::parseConfigId)
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
if (configIds.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
List<HotVehicleThreeInspectConfig> configList = hotVehicleThreeInspectConfigMapper.selectList(
|
||||
Wrappers.<HotVehicleThreeInspectConfig>lambdaQuery()
|
||||
.in(HotVehicleThreeInspectConfig::getId, configIds)
|
||||
.eq(bo.getCompanyId() != null, HotVehicleThreeInspectConfig::getCompanyId, bo.getCompanyId())
|
||||
.eq(bo.getInspectPhase() != null, HotVehicleThreeInspectConfig::getInspectType, bo.getInspectPhase())
|
||||
);
|
||||
if (configList == null || configList.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<Long, String> abnormalTextMap = new HashMap<>(configList.size());
|
||||
for (HotVehicleThreeInspectConfig config : configList) {
|
||||
String abnormalText = StringUtils.trimToNull(config.getAbnormalText());
|
||||
abnormalTextMap.put(config.getId(), abnormalText == null ? "异常" : abnormalText);
|
||||
}
|
||||
return abnormalTextMap;
|
||||
}
|
||||
|
||||
private Long parseConfigId(String configIdText) {
|
||||
String value = StringUtils.trimToNull(configIdText);
|
||||
if (value == null || !value.matches("\\d+")) {
|
||||
return null;
|
||||
}
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
@@ -418,6 +698,7 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchAudit(HotVehicleThreeInspectBatchAuditBo bo) {
|
||||
validateBatchAuditAuditor(bo);
|
||||
for (HotVehicleThreeInspectBo item : bo.getAuditItems()) {
|
||||
if (item == null) {
|
||||
continue;
|
||||
@@ -426,6 +707,41 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void multiVehicleBatchAudit(HotVehicleThreeInspectMultiVehicleBatchAuditBo bo) {
|
||||
validateMultiVehicleBatchAuditRequest(bo);
|
||||
HotVehicleThreeInspectBatchAuditBo batchAuditBo = new HotVehicleThreeInspectBatchAuditBo();
|
||||
batchAuditBo.setAuditItems(buildMultiVehicleBatchAuditItems(bo));
|
||||
batchAudit(batchAuditBo);
|
||||
}
|
||||
|
||||
private void validateBatchAuditAuditor(HotVehicleThreeInspectBatchAuditBo bo) {
|
||||
Long expectedAuditorId = null;
|
||||
String expectedAuditorName = null;
|
||||
for (HotVehicleThreeInspectBo item : bo.getAuditItems()) {
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
if (item.getAuditorId() == null) {
|
||||
throw new ServiceException("批量审核时审核人不能为空");
|
||||
}
|
||||
String currentAuditorName = StringUtils.trimToNull(item.getAuditorName());
|
||||
if (StringUtils.isBlank(currentAuditorName)) {
|
||||
throw new ServiceException("批量审核时审核人姓名不能为空");
|
||||
}
|
||||
if (expectedAuditorId == null) {
|
||||
expectedAuditorId = item.getAuditorId();
|
||||
expectedAuditorName = currentAuditorName;
|
||||
continue;
|
||||
}
|
||||
if (!Objects.equals(expectedAuditorId, item.getAuditorId())
|
||||
|| !StringUtils.equals(expectedAuditorName, currentAuditorName)) {
|
||||
throw new ServiceException("批量审核时审核人必须是同一个人");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doAudit(HotVehicleThreeInspectBo bo) {
|
||||
// 1. 校验参数
|
||||
if (bo.getTaskId() == null) {
|
||||
@@ -472,9 +788,9 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
return;
|
||||
}
|
||||
bo.setRejectReason(StringUtils.trimToNull(bo.getRejectReason()));
|
||||
if (StringUtils.isBlank(bo.getRejectReason())) {
|
||||
throw new ServiceException("审核不通过时,不通过原因不能为空");
|
||||
}
|
||||
// if (StringUtils.isBlank(bo.getRejectReason())) {
|
||||
// throw new ServiceException("审核不通过时,不通过原因不能为空");
|
||||
// }
|
||||
}
|
||||
|
||||
private void validateAuditTimeNotBeforeInspectTime(HotVehicleThreeInspectBo bo, HotVehicleThreeInspect current) {
|
||||
@@ -511,4 +827,415 @@ public class HotVehicleThreeInspectServiceImpl implements IHotVehicleThreeInspec
|
||||
}
|
||||
return Long.valueOf(vehicleId);
|
||||
}
|
||||
|
||||
private HotVehicleThreeInspect selectLatestInspect(Long vehicleId) {
|
||||
return baseMapper.selectOne(
|
||||
Wrappers.<HotVehicleThreeInspect>lambdaQuery()
|
||||
.eq(HotVehicleThreeInspect::getVehicleId, vehicleId)
|
||||
.eq(HotVehicleThreeInspect::getIsDeleted, 0L)
|
||||
.orderByDesc(HotVehicleThreeInspect::getCreateTime, HotVehicleThreeInspect::getId)
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
}
|
||||
|
||||
private void enrichSummaryList(List<HotVehicleThreeInspectSummaryVo> summaryList) {
|
||||
if (summaryList == null || summaryList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<Long> inspectIds = summaryList.stream()
|
||||
.map(HotVehicleThreeInspectSummaryVo::getInspectId)
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
if (inspectIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<HotVehicleThreeInspectVo> detailList = baseMapper.querySummaryDetailList(inspectIds);
|
||||
fillTaskId(detailList);
|
||||
|
||||
Map<Long, HotVehicleThreeInspectSummaryVo> summaryMap = new HashMap<>(summaryList.size());
|
||||
for (HotVehicleThreeInspectSummaryVo summary : summaryList) {
|
||||
summaryMap.put(summary.getInspectId(), summary);
|
||||
}
|
||||
|
||||
for (HotVehicleThreeInspectVo detail : detailList) {
|
||||
HotVehicleThreeInspectSummaryVo summary = summaryMap.get(detail.getInspectId());
|
||||
if (summary == null) {
|
||||
continue;
|
||||
}
|
||||
attachPhaseDetail(summary, detail);
|
||||
}
|
||||
|
||||
for (HotVehicleThreeInspectSummaryVo summary : summaryList) {
|
||||
refreshSummary(summary);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMultiVehicleBatchAuditRequest(HotVehicleThreeInspectMultiVehicleBatchAuditBo bo) {
|
||||
if (bo == null || bo.getInspectIds() == null || bo.getInspectIds().isEmpty()) {
|
||||
throw new ServiceException("三检流程ID不能为空");
|
||||
}
|
||||
if (Objects.equals(bo.getHasHiddenDanger(), 1L) && bo.getEvaluatorId() == null) {
|
||||
throw new ServiceException("存在隐患时评估人不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
private List<HotVehicleThreeInspectBo> buildMultiVehicleBatchAuditItems(HotVehicleThreeInspectMultiVehicleBatchAuditBo bo) {
|
||||
Long currentAuditorId = resolveCurrentAuditorId();
|
||||
Long currentCompanyId = resolveCurrentCompanyId();
|
||||
LinkedHashSet<Long> inspectIdSet = new LinkedHashSet<>();
|
||||
for (Long inspectId : bo.getInspectIds()) {
|
||||
if (inspectId != null) {
|
||||
inspectIdSet.add(inspectId);
|
||||
}
|
||||
}
|
||||
if (inspectIdSet.isEmpty()) {
|
||||
throw new ServiceException("三检流程ID不能为空");
|
||||
}
|
||||
log.info("车辆三检批量审核开始: inspectIds={}, currentAuditorId={}, currentCompanyId={}, hasHiddenDanger={}, evaluatorId={}",
|
||||
inspectIdSet, currentAuditorId, currentCompanyId, bo.getHasHiddenDanger(), bo.getEvaluatorId());
|
||||
|
||||
List<HotVehicleThreeInspectVo> detailList = baseMapper.querySummaryDetailList(new ArrayList<>(inspectIdSet));
|
||||
if (detailList == null || detailList.isEmpty()) {
|
||||
throw new ServiceException("未查询到可批量审核的车辆三检数据");
|
||||
}
|
||||
fillTaskId(detailList);
|
||||
log.info("车辆三检批量审核明细加载完成: detailCount={}, inspectCount={}", detailList.size(), inspectIdSet.size());
|
||||
|
||||
Map<Long, List<HotVehicleThreeInspectVo>> detailMap = new LinkedHashMap<>();
|
||||
for (HotVehicleThreeInspectVo detail : detailList) {
|
||||
if (detail == null || detail.getInspectId() == null) {
|
||||
continue;
|
||||
}
|
||||
detailMap.computeIfAbsent(detail.getInspectId(), key -> new ArrayList<>()).add(detail);
|
||||
}
|
||||
|
||||
Date auditTime = resolveBatchAuditTime(bo);
|
||||
String auditResult = buildBatchAuditResult(bo);
|
||||
List<HotVehicleThreeInspectBo> auditItems = new ArrayList<>();
|
||||
for (Long inspectId : inspectIdSet) {
|
||||
List<HotVehicleThreeInspectVo> currentDetails = detailMap.get(inspectId);
|
||||
if (currentDetails == null || currentDetails.isEmpty()) {
|
||||
throw new ServiceException("三检流程不存在,inspectId=" + inspectId);
|
||||
}
|
||||
appendPendingAuditItems(bo, currentDetails, currentAuditorId, currentCompanyId, auditTime, auditResult, auditItems);
|
||||
}
|
||||
if (auditItems.isEmpty()) {
|
||||
throw new ServiceException("没有符合批量审核条件的数据");
|
||||
}
|
||||
log.info("车辆三检批量审核审核项构建完成: inspectCount={}, auditItemCount={}, auditItemRecordIds={}",
|
||||
inspectIdSet.size(),
|
||||
auditItems.size(),
|
||||
auditItems.stream().map(HotVehicleThreeInspectBo::getId).filter(Objects::nonNull).toList());
|
||||
return auditItems;
|
||||
}
|
||||
|
||||
private void appendPendingAuditItems(HotVehicleThreeInspectMultiVehicleBatchAuditBo bo,
|
||||
List<HotVehicleThreeInspectVo> currentDetails,
|
||||
Long currentAuditorId,
|
||||
Long currentCompanyId,
|
||||
Date auditTime,
|
||||
String auditResult,
|
||||
List<HotVehicleThreeInspectBo> auditItems) {
|
||||
boolean hasBackCheck = false;
|
||||
String plateNumber = null;
|
||||
Long inspectId = null;
|
||||
for (HotVehicleThreeInspectVo detail : currentDetails) {
|
||||
if (detail == null) {
|
||||
continue;
|
||||
}
|
||||
if (inspectId == null) {
|
||||
inspectId = detail.getInspectId();
|
||||
}
|
||||
if (Objects.equals(detail.getInspectPhase(), 3L)) {
|
||||
hasBackCheck = true;
|
||||
}
|
||||
if (StringUtils.isBlank(plateNumber)) {
|
||||
plateNumber = resolvePlateNumber(detail.getVehicleId());
|
||||
}
|
||||
}
|
||||
if (!hasBackCheck) {
|
||||
throw new ServiceException(buildBatchAuditVehicleMessage(plateNumber, "尚未完成收车检查,不可批量审核"));
|
||||
}
|
||||
|
||||
List<HotVehicleThreeInspectVo> candidateDetails = new ArrayList<>();
|
||||
int skippedByCompany = 0;
|
||||
int skippedByAuditor = 0;
|
||||
int skippedByStatus = 0;
|
||||
int skippedByTask = 0;
|
||||
for (HotVehicleThreeInspectVo detail : currentDetails) {
|
||||
if (detail == null) {
|
||||
continue;
|
||||
}
|
||||
if (currentCompanyId != null && !Objects.equals(currentCompanyId, detail.getCompanyId())) {
|
||||
skippedByCompany++;
|
||||
continue;
|
||||
}
|
||||
if (!Objects.equals(currentAuditorId, detail.getAuditorId())) {
|
||||
skippedByAuditor++;
|
||||
continue;
|
||||
}
|
||||
if (!isPendingAuditRecord(detail)) {
|
||||
skippedByStatus++;
|
||||
continue;
|
||||
}
|
||||
if (StringUtils.isBlank(detail.getTaskId())) {
|
||||
skippedByTask++;
|
||||
continue;
|
||||
}
|
||||
candidateDetails.add(detail);
|
||||
}
|
||||
|
||||
log.info("车辆三检批量审核候选明细筛选: inspectId={}, plateNumber={}, totalDetails={}, candidateCount={}, skippedByCompany={}, skippedByAuditor={}, skippedByStatus={}, skippedByTask={}, candidateRecordIds={}",
|
||||
inspectId,
|
||||
plateNumber,
|
||||
currentDetails.size(),
|
||||
candidateDetails.size(),
|
||||
skippedByCompany,
|
||||
skippedByAuditor,
|
||||
skippedByStatus,
|
||||
skippedByTask,
|
||||
candidateDetails.stream().map(HotVehicleThreeInspectVo::getId).filter(Objects::nonNull).toList());
|
||||
|
||||
if (candidateDetails.isEmpty()) {
|
||||
throw new ServiceException(buildBatchAuditVehicleMessage(plateNumber, "没有当前账号可审核的未审核数据"));
|
||||
}
|
||||
for (HotVehicleThreeInspectVo detail : candidateDetails) {
|
||||
HotVehicleThreeInspectBo item = new HotVehicleThreeInspectBo();
|
||||
item.setId(detail.getId());
|
||||
item.setTaskId(detail.getTaskId());
|
||||
item.setAuditTime(auditTime);
|
||||
item.setHasHiddenDanger(bo.getHasHiddenDanger());
|
||||
item.setAuditResult(auditResult);
|
||||
item.setRejectReason(bo.getRejectReason());
|
||||
item.setAuditorSignImgUrl(bo.getAuditorSignImgUrl());
|
||||
item.setAuditorId(detail.getAuditorId());
|
||||
item.setAuditorName(detail.getAuditorName());
|
||||
item.setEvaluatorId(bo.getEvaluatorId());
|
||||
auditItems.add(item);
|
||||
}
|
||||
|
||||
log.info("车辆三检批量审核候选明细全部入队: inspectId={}, plateNumber={}, queuedCount={}, queuedRecordIds={}",
|
||||
inspectId,
|
||||
plateNumber,
|
||||
candidateDetails.size(),
|
||||
candidateDetails.stream().map(HotVehicleThreeInspectVo::getId).filter(Objects::nonNull).toList());
|
||||
}
|
||||
|
||||
private boolean isPendingAuditRecord(HotVehicleThreeInspectVo detail) {
|
||||
if (detail == null) {
|
||||
return false;
|
||||
}
|
||||
return !"APPROVED".equals(detail.getFlowStatus()) && !"REJECTED".equals(detail.getFlowStatus());
|
||||
}
|
||||
|
||||
private Date resolveBatchAuditTime(HotVehicleThreeInspectMultiVehicleBatchAuditBo bo) {
|
||||
return bo.getAuditTime() != null ? bo.getAuditTime() : new Date();
|
||||
}
|
||||
|
||||
private String buildBatchAuditResult(HotVehicleThreeInspectMultiVehicleBatchAuditBo bo) {
|
||||
String auditResult = StringUtils.trimToNull(bo.getAuditResult());
|
||||
if (auditResult != null) {
|
||||
return auditResult;
|
||||
}
|
||||
if (Objects.equals(bo.getHasHiddenDanger(), 1L)) {
|
||||
String rejectReason = StringUtils.trimToNull(bo.getRejectReason());
|
||||
return rejectReason != null ? "不通过:" + rejectReason : "不通过";
|
||||
}
|
||||
return "通过";
|
||||
}
|
||||
|
||||
private String buildBatchAuditVehicleMessage(String plateNumber, String suffix) {
|
||||
String vehicleName = StringUtils.defaultIfBlank(StringUtils.trimToNull(plateNumber), "当前车辆");
|
||||
return vehicleName + suffix;
|
||||
}
|
||||
|
||||
private Long resolveCurrentAuditorId() {
|
||||
String businessUserId = LoginHelper.getBusinessUserId();
|
||||
if (StringUtils.isBlank(businessUserId)) {
|
||||
throw new ServiceException("当前登录人员不存在");
|
||||
}
|
||||
try {
|
||||
return Long.valueOf(businessUserId);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ServiceException("当前登录人员信息异常");
|
||||
}
|
||||
}
|
||||
|
||||
private Long resolveCurrentCompanyId() {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
return loginUser != null ? loginUser.getCompanyId() : null;
|
||||
}
|
||||
|
||||
private void refreshSummary(HotVehicleThreeInspectSummaryVo summary) {
|
||||
if (summary == null) {
|
||||
return;
|
||||
}
|
||||
if (summary.getOutCheck() != null) {
|
||||
summary.setStartTime(summary.getOutCheck().getInspectTime());
|
||||
if (StringUtils.isBlank(summary.getInspectNo())) {
|
||||
summary.setInspectNo(summary.getOutCheck().getInspectNo());
|
||||
}
|
||||
}
|
||||
if (summary.getBackCheck() != null) {
|
||||
summary.setEndTime(summary.getBackCheck().getInspectTime());
|
||||
}
|
||||
if (StringUtils.isBlank(summary.getInspectorName())) {
|
||||
summary.setInspectorName(summary.getDriverName());
|
||||
}
|
||||
summary.setInspectTime(buildInspectTimeRange(summary.getStartTime(), summary.getEndTime()));
|
||||
}
|
||||
|
||||
private String buildInspectTimeRange(Date startTime, Date endTime) {
|
||||
if (startTime == null && endTime == null) {
|
||||
return null;
|
||||
}
|
||||
if (startTime == null) {
|
||||
return DateUtil.formatDateTime(endTime);
|
||||
}
|
||||
if (endTime == null || Objects.equals(startTime, endTime)) {
|
||||
return DateUtil.formatDateTime(startTime);
|
||||
}
|
||||
return DateUtil.formatDateTime(startTime) + " ~ " + DateUtil.formatDateTime(endTime);
|
||||
}
|
||||
|
||||
private void normalizeInspectLocation(HotVehicleThreeInspectBo bo) {
|
||||
if (bo == null) {
|
||||
return;
|
||||
}
|
||||
String inspectLocation = StringUtils.trimToNull(bo.getInspectLocation());
|
||||
String reverseAddress = reverseGeocode(bo.getLatitude(), bo.getLongitude());
|
||||
bo.setInspectLocation(StringUtils.defaultIfBlank(reverseAddress, inspectLocation));
|
||||
}
|
||||
|
||||
private void prepareInspectIdentity(HotVehicleThreeInspectBo bo) {
|
||||
if (bo == null || bo.getVehicleId() == null || bo.getInspectPhase() == null) {
|
||||
return;
|
||||
}
|
||||
HotVehicleThreeInspect latestInspect = selectLatestInspect(bo.getVehicleId());
|
||||
if (Objects.equals(bo.getInspectPhase(), 1L)) {
|
||||
if (StringUtils.isBlank(bo.getInspectNo())) {
|
||||
bo.setInspectNo(generateInspectNo(bo.getInspectTime(), bo.getVehicleId()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (latestInspect == null) {
|
||||
return;
|
||||
}
|
||||
if (bo.getInspectId() == null) {
|
||||
bo.setInspectId(latestInspect.getInspectId() != null ? latestInspect.getInspectId() : latestInspect.getId());
|
||||
}
|
||||
if (StringUtils.isBlank(bo.getInspectNo())) {
|
||||
bo.setInspectNo(latestInspect.getInspectNo());
|
||||
}
|
||||
}
|
||||
|
||||
private void patchNewRoundInspectIdentity(HotVehicleThreeInspect add, HotVehicleThreeInspectBo bo) {
|
||||
if (add == null || !Objects.equals(add.getInspectPhase(), 1L)) {
|
||||
return;
|
||||
}
|
||||
boolean changed = false;
|
||||
if (add.getInspectId() == null) {
|
||||
add.setInspectId(add.getId());
|
||||
changed = true;
|
||||
}
|
||||
if (StringUtils.isBlank(add.getInspectNo())) {
|
||||
add.setInspectNo(generateInspectNo(add.getInspectTime(), add.getVehicleId()));
|
||||
changed = true;
|
||||
}
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
baseMapper.updateById(add);
|
||||
bo.setInspectId(add.getInspectId());
|
||||
bo.setInspectNo(add.getInspectNo());
|
||||
}
|
||||
|
||||
private String generateInspectNo(Date inspectTime, Long vehicleId) {
|
||||
Date recordDate = inspectTime == null ? new Date() : inspectTime;
|
||||
String dateText = DateUtil.format(recordDate, "yyyyMMdd");
|
||||
String plateSuffix = resolvePlateSuffix(vehicleId);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
String candidate = "SJ" + dateText + plateSuffix + randomFourDigits();
|
||||
Long count = baseMapper.selectCount(
|
||||
Wrappers.<HotVehicleThreeInspect>lambdaQuery()
|
||||
.eq(HotVehicleThreeInspect::getInspectNo, candidate)
|
||||
);
|
||||
if (count == null || count == 0L) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return "SJ" + dateText + plateSuffix + String.format("%04d", System.currentTimeMillis() % 10000);
|
||||
}
|
||||
|
||||
private String resolvePlateSuffix(Long vehicleId) {
|
||||
if (vehicleId == null) {
|
||||
return "000";
|
||||
}
|
||||
HotVehicle vehicle = hotVehicleMapper.selectById(String.valueOf(vehicleId));
|
||||
String plateNumber = vehicle == null ? null : StringUtils.trimToNull(vehicle.getPlateNumber());
|
||||
if (plateNumber == null) {
|
||||
return "000";
|
||||
}
|
||||
String normalized = plateNumber.replace(" ", "");
|
||||
if (normalized.length() <= 3) {
|
||||
return normalized;
|
||||
}
|
||||
return normalized.substring(normalized.length() - 3);
|
||||
}
|
||||
|
||||
private String resolvePlateNumber(Long vehicleId) {
|
||||
if (vehicleId == null) {
|
||||
return null;
|
||||
}
|
||||
HotVehicle vehicle = hotVehicleMapper.selectById(String.valueOf(vehicleId));
|
||||
return vehicle == null ? null : StringUtils.trimToNull(vehicle.getPlateNumber());
|
||||
}
|
||||
|
||||
private String randomFourDigits() {
|
||||
return String.format("%04d", ThreadLocalRandom.current().nextInt(1000, 10000));
|
||||
}
|
||||
|
||||
private String reverseGeocode(Double latitude, Double longitude) {
|
||||
if (latitude == null || longitude == null) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.isBlank(gdKey)) {
|
||||
return null;
|
||||
}
|
||||
String location = longitude + "," + latitude;
|
||||
String url = "https://restapi.amap.com/v3/geocode/regeo?output=JSON&location="
|
||||
+ location + "&key=" + gdKey + "&radius=1000&extensions=base";
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
URL u = new URL(url);
|
||||
connection = (HttpURLConnection) u.openConnection();
|
||||
connection.setConnectTimeout(3000);
|
||||
connection.setReadTimeout(3000);
|
||||
connection.setRequestMethod("GET");
|
||||
int code = connection.getResponseCode();
|
||||
if (code != HttpURLConnection.HTTP_OK) {
|
||||
return null;
|
||||
}
|
||||
try (InputStream is = connection.getInputStream()) {
|
||||
String body = new String(is.readAllBytes(), StandardCharsets.UTF_8);
|
||||
JsonNode root = JsonUtils.getObjectMapper().readTree(body);
|
||||
if (root == null) {
|
||||
return null;
|
||||
}
|
||||
if (!"1".equals(root.path("status").asText())) {
|
||||
return null;
|
||||
}
|
||||
String formatted = root.path("regeocode").path("formatted_address").asText();
|
||||
return StringUtils.trimToNull(formatted);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("车辆三检逆地理解析失败: {},{}", latitude, longitude);
|
||||
return null;
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public class HotVehicleThreeInspectItemServiceImpl implements IHotVehicleThreeIn
|
||||
private LambdaQueryWrapper<HotVehicleThreeInspectItem> buildQueryWrapper(HotVehicleThreeInspectItemBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotVehicleThreeInspectItem> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByAsc(HotVehicleThreeInspectItem::getSortNo);
|
||||
lqw.orderByAsc(HotVehicleThreeInspectItem::getSortNo, HotVehicleThreeInspectItem::getId);
|
||||
lqw.eq(bo.getCompanyId() != null, HotVehicleThreeInspectItem::getCompanyId, bo.getCompanyId());
|
||||
lqw.eq(bo.getInspectId() != null, HotVehicleThreeInspectItem::getInspectId, bo.getInspectId());
|
||||
lqw.eq(bo.getInspectType() != null, HotVehicleThreeInspectItem::getInspectType, bo.getInspectType());
|
||||
|
||||
@@ -270,7 +270,7 @@ public class HotDriverServiceImpl implements IHotDriverService {
|
||||
private LambdaQueryWrapper<HotDriver> buildQueryWrapper(HotDriverBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotDriver> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(HotDriver::getCreateTime);
|
||||
lqw.orderByDesc(HotDriver::getCreateTime, HotDriver::getId);
|
||||
lqw.in(CollUtil.isNotEmpty(bo.getIds()), HotDriver::getId, bo.getIds());
|
||||
lqw.eq(bo.getCompanyId() != null, HotDriver::getCompanyId, bo.getCompanyId());
|
||||
lqw.eq(bo.getEntryDate() != null, HotDriver::getEntryDate, bo.getEntryDate());
|
||||
@@ -990,22 +990,14 @@ public class HotDriverServiceImpl implements IHotDriverService {
|
||||
throw new ServiceException("目标车辆ID不能为空");
|
||||
}
|
||||
|
||||
List<String> boundVehicleIds = getBoundVehicleIds(driver);
|
||||
if (CollUtil.isEmpty(boundVehicleIds)) {
|
||||
throw new ServiceException("当前驾驶员未绑定车辆,不能切换");
|
||||
}
|
||||
if (!boundVehicleIds.contains(targetVehicleId)) {
|
||||
throw new ServiceException("驾驶员只能切换属于自己的车辆");
|
||||
}
|
||||
if (StringUtils.equals(driver.getVehicleId(), targetVehicleId)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.isBlank(driver.getVehicleId())) {
|
||||
throw new ServiceException("当前默认车辆不存在,不能切换");
|
||||
if (StringUtils.isNotBlank(driver.getVehicleId())) {
|
||||
hotVehicleThreeInspectService.validateNoUnfinishedSwitchVehicleProcess(driver.getVehicleId(),
|
||||
"请先完成'" + StringUtils.defaultIfBlank(driver.getPlateNumber(), "当前车辆") + "'的车辆三检");
|
||||
}
|
||||
|
||||
hotVehicleThreeInspectService.validateNoUnfinishedProcess(driver.getVehicleId(), "当前车辆三检流程未完成,不可切换车辆");
|
||||
|
||||
HotVehicle targetVehicle = vehicleMapper.selectOne(Wrappers.<HotVehicle>lambdaQuery()
|
||||
.eq(HotVehicle::getId, targetVehicleId)
|
||||
.eq(HotVehicle::getCompanyId, driver.getCompanyId())
|
||||
@@ -1014,9 +1006,6 @@ public class HotDriverServiceImpl implements IHotDriverService {
|
||||
if (targetVehicle == null) {
|
||||
throw new ServiceException("目标车辆不存在");
|
||||
}
|
||||
if (!splitCsv(targetVehicle.getCurrentDriver()).contains(driver.getId())) {
|
||||
throw new ServiceException("驾驶员只能切换属于自己的车辆");
|
||||
}
|
||||
|
||||
return baseMapper.update(null, new LambdaUpdateWrapper<HotDriver>()
|
||||
.set(HotDriver::getVehicleId, targetVehicle.getId())
|
||||
|
||||
@@ -76,7 +76,7 @@ public class HotDriverAnnualAssessmentServiceImpl implements IHotDriverAnnualAss
|
||||
private LambdaQueryWrapper<HotDriverAnnualAssessment> buildQueryWrapper(HotDriverAnnualAssessmentBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotDriverAnnualAssessment> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(HotDriverAnnualAssessment::getAssessmentTime);
|
||||
lqw.orderByDesc(HotDriverAnnualAssessment::getAssessmentTime, HotDriverAnnualAssessment::getId);
|
||||
lqw.eq(bo.getCompanyId() != null, HotDriverAnnualAssessment::getCompanyId, bo.getCompanyId());
|
||||
lqw.eq(bo.getDriverId() != null, HotDriverAnnualAssessment::getDriverId, bo.getDriverId());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getAssessmentContent()), HotDriverAnnualAssessment::getAssessmentContent, bo.getAssessmentContent());
|
||||
|
||||
@@ -74,7 +74,7 @@ public class HotDriverHealthReportServiceImpl implements IHotDriverHealthReportS
|
||||
private LambdaQueryWrapper<HotDriverHealthReport> buildQueryWrapper(HotDriverHealthReportBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotDriverHealthReport> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(HotDriverHealthReport::getReportDate);
|
||||
lqw.orderByDesc(HotDriverHealthReport::getReportDate, HotDriverHealthReport::getId);
|
||||
lqw.eq(bo.getCompanyId() != null, HotDriverHealthReport::getCompanyId, bo.getCompanyId());
|
||||
lqw.eq(bo.getDriverId() != null, HotDriverHealthReport::getDriverId, bo.getDriverId());
|
||||
lqw.eq(bo.getReportDate() != null, HotDriverHealthReport::getReportDate, bo.getReportDate());
|
||||
|
||||
@@ -137,6 +137,15 @@ public interface ISysFlowService {
|
||||
*/
|
||||
String getTaskIdByBusinessId(String flowCode, String businessId, String userId);
|
||||
|
||||
/**
|
||||
* 根据业务ID获取当前活动任务ID(不限定处理人)
|
||||
*
|
||||
* @param flowCode 流程编码
|
||||
* @param businessId 业务ID
|
||||
* @return 当前活动任务ID
|
||||
*/
|
||||
String getCurrentTaskIdByBusinessId(String flowCode, String businessId);
|
||||
|
||||
/**
|
||||
* 根据任务ID获取任务详情
|
||||
*
|
||||
|
||||
@@ -249,7 +249,7 @@ public class SysFlowServiceImpl implements ISysFlowService {
|
||||
if (StrUtil.isNotBlank(isRead)) {
|
||||
lqw.eq(SysFlowTask::getIsRead, Integer.valueOf(isRead));
|
||||
}
|
||||
lqw.orderByDesc(SysFlowTask::getCreateTime);
|
||||
lqw.orderByDesc(SysFlowTask::getCreateTime, SysFlowTask::getTaskId);
|
||||
List<SysFlowTask> records = taskMapper.selectList(lqw);
|
||||
fillFlowInfo(records);
|
||||
filterInvalidTrainingStudyTodos(records);
|
||||
@@ -264,7 +264,7 @@ public class SysFlowServiceImpl implements ISysFlowService {
|
||||
if (loginUser != null && cn.hutool.core.util.StrUtil.isNotBlank(loginUser.getBusinessUserId())) {
|
||||
lqw.ne(SysFlowTask::getApproverId, loginUser.getBusinessUserId());
|
||||
}
|
||||
lqw.orderByDesc(SysFlowTask::getCreateTime);
|
||||
lqw.orderByDesc(SysFlowTask::getCreateTime, SysFlowTask::getTaskId);
|
||||
List<SysFlowTask> records = taskMapper.selectList(lqw);
|
||||
fillFlowInfo(records);
|
||||
filterInvalidTrainingStudyTodos(records);
|
||||
@@ -634,7 +634,7 @@ public class SysFlowServiceImpl implements ISysFlowService {
|
||||
public List<SysFlowTaskHis> getHistory(String instanceId) {
|
||||
LambdaQueryWrapper<SysFlowTaskHis> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(SysFlowTaskHis::getInstanceId, instanceId);
|
||||
lqw.orderByAsc(SysFlowTaskHis::getAuditTime);
|
||||
lqw.orderByAsc(SysFlowTaskHis::getAuditTime, SysFlowTaskHis::getHisId);
|
||||
return taskHisMapper.selectList(lqw);
|
||||
}
|
||||
|
||||
@@ -737,6 +737,32 @@ public class SysFlowServiceImpl implements ISysFlowService {
|
||||
return task != null ? task.getTaskId() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentTaskIdByBusinessId(String flowCode, String businessId) {
|
||||
List<SysFlowInstance> instances = instanceMapper.selectList(
|
||||
Wrappers.<SysFlowInstance>lambdaQuery()
|
||||
.eq(SysFlowInstance::getFlowCode, flowCode)
|
||||
.eq(SysFlowInstance::getBusinessId, businessId)
|
||||
.eq(SysFlowInstance::getStatus, STATUS_RUNNING)
|
||||
);
|
||||
|
||||
if (instances.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> instanceIds = instances.stream()
|
||||
.map(SysFlowInstance::getInstanceId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
SysFlowTask task = taskMapper.selectOne(
|
||||
Wrappers.<SysFlowTask>lambdaQuery()
|
||||
.in(SysFlowTask::getInstanceId, instanceIds)
|
||||
.orderByDesc(SysFlowTask::getCreateTime, SysFlowTask::getTaskId)
|
||||
.last("limit 1")
|
||||
);
|
||||
return task != null ? task.getTaskId() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPendingTask(String flowCode, String businessId, String userId) {
|
||||
// 1. 查找相关的运行中流程实例
|
||||
|
||||
@@ -91,7 +91,7 @@ public class HotCompanyNoticeServiceImpl implements IHotCompanyNoticeService {
|
||||
lqw.eq(HotCompanyNotice::getIsPublished, 1L);
|
||||
lqw.apply("NOT EXISTS (SELECT 1 FROM hot_company_notice_read r WHERE r.notice_id = hot_company_notice.id AND r.reader_id = {0} AND r.is_deleted = 0)", readerId);
|
||||
lqw.orderByDesc(HotCompanyNotice::getIsTop);
|
||||
lqw.orderByDesc(HotCompanyNotice::getCreateTime);
|
||||
lqw.orderByDesc(HotCompanyNotice::getCreateTime, HotCompanyNotice::getId);
|
||||
lqw.orderByDesc(HotCompanyNotice::getId);
|
||||
lqw.last("limit 1");
|
||||
HotCompanyNotice notice = baseMapper.selectOne(lqw);
|
||||
@@ -104,7 +104,7 @@ public class HotCompanyNoticeServiceImpl implements IHotCompanyNoticeService {
|
||||
private LambdaQueryWrapper<HotCompanyNotice> buildQueryWrapper(HotCompanyNoticeBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotCompanyNotice> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(HotCompanyNotice::getCreateTime);
|
||||
lqw.orderByDesc(HotCompanyNotice::getCreateTime, HotCompanyNotice::getId);
|
||||
Object beginTime = params.get("beginTime");
|
||||
Object endTime = params.get("endTime");
|
||||
if (beginTime != null && endTime != null) {
|
||||
@@ -140,7 +140,7 @@ public class HotCompanyNoticeServiceImpl implements IHotCompanyNoticeService {
|
||||
HotCompanyNotice maxSortNotice = baseMapper.selectOne(new LambdaQueryWrapper<HotCompanyNotice>()
|
||||
.select(HotCompanyNotice::getSortNo)
|
||||
.eq(HotCompanyNotice::getCompanyId, bo.getCompanyId())
|
||||
.orderByDesc(HotCompanyNotice::getSortNo)
|
||||
.orderByDesc(HotCompanyNotice::getSortNo, HotCompanyNotice::getId)
|
||||
.last("limit 1"));
|
||||
long maxSort = (maxSortNotice != null && maxSortNotice.getSortNo() != null) ? maxSortNotice.getSortNo() : 0L;
|
||||
add.setSortNo(maxSort + 1);
|
||||
|
||||
@@ -121,7 +121,7 @@ public class HotFileTypeConfigServiceImpl implements IHotFileTypeConfigService {
|
||||
private LambdaQueryWrapper<HotFileTypeConfig> buildQueryWrapper(HotFileTypeConfigBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotFileTypeConfig> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByAsc(HotFileTypeConfig::getSortOrder).orderByDesc(BaseEntity::getCreateTime);
|
||||
lqw.orderByAsc(HotFileTypeConfig::getSortOrder).orderByDesc(BaseEntity::getCreateTime).orderByDesc(HotFileTypeConfig::getId);
|
||||
lqw.eq(bo.getCompanyId() != null, HotFileTypeConfig::getCompanyId, bo.getCompanyId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getName()), HotFileTypeConfig::getName, bo.getName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getValue()), HotFileTypeConfig::getValue, bo.getValue());
|
||||
|
||||
@@ -96,7 +96,7 @@ public class HotLawRegulationServiceImpl implements IHotLawRegulationService {
|
||||
HotLawRegulation maxEntity = baseMapper.selectOne(Wrappers.<HotLawRegulation>lambdaQuery()
|
||||
.select(HotLawRegulation::getSortno)
|
||||
.eq(add.getCompanyId() != null, HotLawRegulation::getCompanyId, add.getCompanyId())
|
||||
.orderByDesc(HotLawRegulation::getSortno)
|
||||
.orderByDesc(HotLawRegulation::getSortno, HotLawRegulation::getId)
|
||||
.last("LIMIT 1"));
|
||||
Long maxSort = (maxEntity != null && maxEntity.getSortno() != null) ? maxEntity.getSortno() : 0L;
|
||||
add.setSortno(maxSort + 1);
|
||||
|
||||
@@ -359,7 +359,7 @@ public class HotNoticeReplyServiceImpl implements IHotNoticeReplyService {
|
||||
.eq(HotCompanySafetyManager::getIsDeleted, 0L)
|
||||
.eq(HotCompanySafetyManager::getIsResigned, 0L)
|
||||
.eq(HotCompanySafetyManager::getStatus, 1L)
|
||||
.orderByDesc(HotCompanySafetyManager::getCreateTime)
|
||||
.orderByDesc(HotCompanySafetyManager::getCreateTime, HotCompanySafetyManager::getId)
|
||||
);
|
||||
if (heads != null && !heads.isEmpty()) {
|
||||
return String.valueOf(heads.get(0).getId());
|
||||
@@ -370,7 +370,7 @@ public class HotNoticeReplyServiceImpl implements IHotNoticeReplyService {
|
||||
.eq(HotCompanySafetyManager::getIsDeleted, 0L)
|
||||
.eq(HotCompanySafetyManager::getIsResigned, 0L)
|
||||
.eq(HotCompanySafetyManager::getStatus, 1L)
|
||||
.orderByDesc(HotCompanySafetyManager::getCreateTime)
|
||||
.orderByDesc(HotCompanySafetyManager::getCreateTime, HotCompanySafetyManager::getId)
|
||||
);
|
||||
if (managers == null || managers.isEmpty()) {
|
||||
return null;
|
||||
|
||||
@@ -305,7 +305,7 @@ public class HotNotificationIssueController extends BaseController {
|
||||
.eq(HotCompanySafetyManager::getIsDeleted, 0L)
|
||||
.eq(HotCompanySafetyManager::getIsResigned, 0L)
|
||||
.eq(HotCompanySafetyManager::getStatus, 1L)
|
||||
.orderByDesc(HotCompanySafetyManager::getCreateTime)
|
||||
.orderByDesc(HotCompanySafetyManager::getCreateTime, HotCompanySafetyManager::getId)
|
||||
);
|
||||
if (heads != null && !heads.isEmpty()) {
|
||||
return String.valueOf(heads.get(0).getId());
|
||||
@@ -316,7 +316,7 @@ public class HotNotificationIssueController extends BaseController {
|
||||
.eq(HotCompanySafetyManager::getIsDeleted, 0L)
|
||||
.eq(HotCompanySafetyManager::getIsResigned, 0L)
|
||||
.eq(HotCompanySafetyManager::getStatus, 1L)
|
||||
.orderByDesc(HotCompanySafetyManager::getCreateTime)
|
||||
.orderByDesc(HotCompanySafetyManager::getCreateTime, HotCompanySafetyManager::getId)
|
||||
);
|
||||
if (managers == null || managers.isEmpty()) {
|
||||
return null;
|
||||
|
||||
@@ -127,7 +127,7 @@ public class HotSystemNotificationServiceImpl implements IHotSystemNotificationS
|
||||
private LambdaQueryWrapper<HotSystemNotification> buildQueryWrapper(HotSystemNotificationBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotSystemNotification> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(HotSystemNotification::getSendTime);
|
||||
lqw.orderByDesc(HotSystemNotification::getSendTime, HotSystemNotification::getId);
|
||||
Object beginTime = params == null ? null : params.get("beginTime");
|
||||
Object endTime = params == null ? null : params.get("endTime");
|
||||
if (beginTime != null && endTime != null) {
|
||||
|
||||
@@ -325,13 +325,13 @@ public class PayRechargeOpenServiceImpl implements PayRechargeOpenService {
|
||||
.in(PayOrder::getStatus, PayOrderStatusEnum.WAITING.getStatus(), PayOrderStatusEnum.PAYING.getStatus())
|
||||
.gt(PayOrder::getExpireTime, now)
|
||||
.ge(PayOrder::getCreateTime, DateUtil.offsetMinute(now, -ORDER_EXPIRE_MINUTES))
|
||||
.orderByAsc(PayOrder::getCreateTime)
|
||||
.orderByAsc(PayOrder::getCreateTime, PayOrder::getId)
|
||||
.last("limit " + COMPENSATE_BATCH_SIZE));
|
||||
List<PayOrder> expiredOrders = payOrderMapper.selectList(Wrappers.<PayOrder>lambdaQuery()
|
||||
.in(PayOrder::getStatus, PayOrderStatusEnum.WAITING.getStatus(), PayOrderStatusEnum.PAYING.getStatus())
|
||||
.isNotNull(PayOrder::getExpireTime)
|
||||
.le(PayOrder::getExpireTime, now)
|
||||
.orderByAsc(PayOrder::getExpireTime)
|
||||
.orderByAsc(PayOrder::getExpireTime, PayOrder::getId)
|
||||
.last("limit " + COMPENSATE_BATCH_SIZE));
|
||||
|
||||
int queried = 0;
|
||||
|
||||
@@ -109,7 +109,7 @@ public class HotPolicyRevisionServiceImpl implements IHotPolicyRevisionService {
|
||||
private LambdaQueryWrapper<HotPolicyRevision> buildQueryWrapper(HotPolicyRevisionBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotPolicyRevision> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(HotPolicyRevision::getCreatedTime);
|
||||
lqw.orderByDesc(HotPolicyRevision::getCreatedTime, HotPolicyRevision::getId);
|
||||
lqw.eq(bo.getCompanyId() != null, HotPolicyRevision::getCompanyId, bo.getCompanyId());
|
||||
lqw.eq(bo.getPolicyId() != null, HotPolicyRevision::getPolicyId, bo.getPolicyId());
|
||||
lqw.eq(bo.getVersionNo() != null, HotPolicyRevision::getVersionNo, bo.getVersionNo());
|
||||
@@ -185,7 +185,7 @@ public class HotPolicyRevisionServiceImpl implements IHotPolicyRevisionService {
|
||||
public Long nextVersionNo(Long policyId) {
|
||||
LambdaQueryWrapper<HotPolicyRevision> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(HotPolicyRevision::getPolicyId, policyId);
|
||||
lqw.orderByDesc(HotPolicyRevision::getVersionNo);
|
||||
lqw.orderByDesc(HotPolicyRevision::getVersionNo, HotPolicyRevision::getId);
|
||||
lqw.last("limit 1");
|
||||
HotPolicyRevision last = baseMapper.selectOne(lqw);
|
||||
Long lastNo = last != null ? last.getVersionNo() : 0L;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.hotwj.platform.reportStatistics.controller;
|
||||
|
||||
import com.hotwj.platform.reportStatistics.domain.bo.SysReportTemplateBo;
|
||||
import com.hotwj.platform.reportStatistics.domain.bo.SysReportTemplateSyncBo;
|
||||
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateVo;
|
||||
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateSyncCompareVo;
|
||||
import com.hotwj.platform.reportStatistics.service.ISysReportTemplateService;
|
||||
import com.hotwj.platform.reportStatistics.service.ReportRenderService;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@@ -97,6 +99,26 @@ public class SysReportTemplateController extends BaseController {
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询模板同步差异
|
||||
*/
|
||||
//@SaCheckPermission("report:template:sync")
|
||||
@GetMapping("/sync/diff")
|
||||
public R<List<SysReportTemplateSyncCompareVo>> syncDiff() {
|
||||
return R.ok(sysReportTemplateService.querySyncDiffList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 按选中项同步模板
|
||||
*/
|
||||
//@SaCheckPermission("report:template:sync")
|
||||
@Log(title = "按项同步模版", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/sync/selective")
|
||||
public R<Void> selectiveSync(@Validated @RequestBody SysReportTemplateSyncBo bo) {
|
||||
sysReportTemplateService.syncTemplatesFromClasspath(bo.getTemplateCodes());
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除报表模板
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.hotwj.platform.reportStatistics.domain.bo;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 报表模板按项同步请求
|
||||
*/
|
||||
@Data
|
||||
public class SysReportTemplateSyncBo {
|
||||
|
||||
/**
|
||||
* 需要同步的模板编码集合
|
||||
*/
|
||||
@NotEmpty(message = "请选择需要同步的模板")
|
||||
private List<String> templateCodes;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.hotwj.platform.reportStatistics.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 报表模板同步差异视图对象
|
||||
*/
|
||||
@Data
|
||||
public class SysReportTemplateSyncCompareVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String templateCode;
|
||||
|
||||
private Long dbId;
|
||||
|
||||
private String localTemplateName;
|
||||
|
||||
private String dbTemplateName;
|
||||
|
||||
private String localContent;
|
||||
|
||||
private String dbContent;
|
||||
|
||||
private String localMockData;
|
||||
|
||||
private String dbMockData;
|
||||
|
||||
private String localRemark;
|
||||
|
||||
private String dbRemark;
|
||||
|
||||
private Boolean existsInLocal;
|
||||
|
||||
private Boolean existsInDb;
|
||||
|
||||
private Boolean syncable;
|
||||
|
||||
private List<String> diffTypes;
|
||||
}
|
||||
@@ -42,7 +42,7 @@ public class TrainingPlanMonthlyStatProvider implements IReportDataProvider {
|
||||
private final IHotTrainingCourseConfigService hotTrainingCourseConfigService;
|
||||
private final IHotCourseResourceService hotCourseResourceService;
|
||||
private final HotMediaResourceMapper hotMediaResourceMapper;
|
||||
|
||||
|
||||
@Override
|
||||
public String getTemplateCode() {
|
||||
return "templates/securityManage/onlineEducationMonthlyStatistics.html.vm";
|
||||
@@ -78,12 +78,12 @@ public class TrainingPlanMonthlyStatProvider implements IReportDataProvider {
|
||||
ctx.put("trainingCourses", buildTrainingCourses(trainingId));
|
||||
ctx.put("trainingContent", buildTrainingContent(trainingId));
|
||||
|
||||
ctx.put("completedCount", training.getCompleteCount() == null ? 0L : training.getCompleteCount());
|
||||
List<OnlineTrainingMonthlyRowVo> voRows = ledgerReportMapper.selectOnlineTrainingMonthlyRows(companyId, trainingId, normalizedUserIds);
|
||||
if (voRows == null || voRows.isEmpty()) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx.put("completedCount", countCompleted(voRows));
|
||||
ctx.put("rows", buildRows(voRows, progressMap));
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.hotwj.platform.reportStatistics.service;
|
||||
|
||||
import com.hotwj.platform.reportStatistics.domain.bo.SysReportTemplateBo;
|
||||
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateVo;
|
||||
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateSyncCompareVo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
@@ -56,6 +57,16 @@ public interface ISysReportTemplateService {
|
||||
*/
|
||||
void syncTemplatesFromClasspath();
|
||||
|
||||
/**
|
||||
* 查询本地模板与数据库模板的差异
|
||||
*/
|
||||
List<SysReportTemplateSyncCompareVo> querySyncDiffList();
|
||||
|
||||
/**
|
||||
* 按模板编码同步本地模板到数据库
|
||||
*/
|
||||
void syncTemplatesFromClasspath(Collection<String> templateCodes);
|
||||
|
||||
/**
|
||||
* 根据模板编码查找对应的 Provider
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.hotwj.platform.reportStatistics.domain.SysReportTemplate;
|
||||
import com.hotwj.platform.reportStatistics.domain.bo.SysReportTemplateBo;
|
||||
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateSyncCompareVo;
|
||||
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateVo;
|
||||
import com.hotwj.platform.reportStatistics.mapper.SysReportTemplateMapper;
|
||||
import com.hotwj.platform.reportStatistics.service.IReportDataProvider;
|
||||
@@ -16,6 +17,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
@@ -27,9 +29,15 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 报表模板Service业务层处理
|
||||
@@ -42,6 +50,9 @@ import java.util.Map;
|
||||
@Service
|
||||
public class SysReportTemplateServiceImpl implements ISysReportTemplateService {
|
||||
|
||||
private static final String CLASSPATH_SCAN_REMARK = "Synced from classpath scan";
|
||||
private static final String PROVIDER_REMARK_PREFIX = "Synced from Provider: ";
|
||||
|
||||
private final SysReportTemplateMapper baseMapper;
|
||||
private final List<IReportDataProvider> reportDataProviders;
|
||||
|
||||
@@ -153,114 +164,257 @@ public class SysReportTemplateServiceImpl implements ISysReportTemplateService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void syncTemplatesFromClasspath() {
|
||||
// 1. Sync from Providers (Source of truth for Title and MockData)
|
||||
syncTemplatesFromClasspath(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysReportTemplateSyncCompareVo> querySyncDiffList() {
|
||||
LinkedHashMap<String, LocalTemplateSnapshot> localTemplates = loadLocalTemplateSnapshots();
|
||||
Map<String, SysReportTemplateVo> dbTemplates = queryExistingTemplates(null);
|
||||
|
||||
Set<String> allCodes = new LinkedHashSet<>();
|
||||
allCodes.addAll(localTemplates.keySet());
|
||||
allCodes.addAll(dbTemplates.keySet());
|
||||
|
||||
return allCodes.stream()
|
||||
.map(code -> buildCompareVo(code, localTemplates.get(code), dbTemplates.get(code)))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void syncTemplatesFromClasspath(Collection<String> templateCodes) {
|
||||
LinkedHashMap<String, LocalTemplateSnapshot> localTemplates = loadLocalTemplateSnapshots();
|
||||
Set<String> targetCodes = normalizeTemplateCodes(templateCodes);
|
||||
if (targetCodes != null && targetCodes.isEmpty()) {
|
||||
throw new ServiceException("请选择需要同步的模板");
|
||||
}
|
||||
|
||||
if (targetCodes != null) {
|
||||
List<String> missingCodes = targetCodes.stream()
|
||||
.filter(code -> !localTemplates.containsKey(code))
|
||||
.collect(Collectors.toList());
|
||||
if (!missingCodes.isEmpty()) {
|
||||
throw new ServiceException("以下模板在本地不存在,无法同步: " + String.join(", ", missingCodes));
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, SysReportTemplateVo> dbTemplates = queryExistingTemplates(targetCodes);
|
||||
|
||||
for (LocalTemplateSnapshot snapshot : localTemplates.values()) {
|
||||
if (targetCodes != null && !targetCodes.contains(snapshot.getTemplateCode())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SysReportTemplateVo existing = dbTemplates.get(snapshot.getTemplateCode());
|
||||
if (existing == null) {
|
||||
SysReportTemplate insert = new SysReportTemplate();
|
||||
insert.setTemplateCode(snapshot.getTemplateCode());
|
||||
insert.setTemplateName(snapshot.getTemplateName());
|
||||
insert.setContent(snapshot.getContent());
|
||||
insert.setMockData(snapshot.getMockData());
|
||||
insert.setVersion(1);
|
||||
insert.setRemark(snapshot.getRemark());
|
||||
baseMapper.insert(insert);
|
||||
log.info("Inserted template from local source: {}", snapshot.getTemplateCode());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hasDiff(snapshot, existing)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SysReportTemplate update = new SysReportTemplate();
|
||||
update.setId(existing.getId());
|
||||
update.setTemplateCode(snapshot.getTemplateCode());
|
||||
update.setTemplateName(snapshot.getTemplateName());
|
||||
update.setContent(snapshot.getContent());
|
||||
update.setMockData(snapshot.getMockData());
|
||||
update.setRemark(snapshot.getRemark());
|
||||
update.setVersion(existing.getVersion() == null ? 1 : existing.getVersion() + 1);
|
||||
baseMapper.updateById(update);
|
||||
log.info("Updated template from local source: {}", snapshot.getTemplateCode());
|
||||
}
|
||||
}
|
||||
|
||||
private SysReportTemplateSyncCompareVo buildCompareVo(String code, LocalTemplateSnapshot local, SysReportTemplateVo db) {
|
||||
List<String> diffTypes = buildDiffTypes(local, db);
|
||||
if (diffTypes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SysReportTemplateSyncCompareVo vo = new SysReportTemplateSyncCompareVo();
|
||||
vo.setTemplateCode(code);
|
||||
vo.setDbId(db == null ? null : db.getId());
|
||||
vo.setLocalTemplateName(local == null ? "" : local.getTemplateName());
|
||||
vo.setDbTemplateName(db == null ? "" : db.getTemplateName());
|
||||
vo.setLocalContent(local == null ? "" : local.getContent());
|
||||
vo.setDbContent(db == null ? "" : normalizeText(db.getContent()));
|
||||
vo.setLocalMockData(toJsonText(local == null ? null : local.getMockData()));
|
||||
vo.setDbMockData(toJsonText(db == null ? null : db.getMockData()));
|
||||
vo.setLocalRemark(local == null ? "" : local.getRemark());
|
||||
vo.setDbRemark(db == null ? "" : normalizeText(db.getRemark()));
|
||||
vo.setExistsInLocal(local != null);
|
||||
vo.setExistsInDb(db != null);
|
||||
vo.setSyncable(local != null);
|
||||
vo.setDiffTypes(diffTypes);
|
||||
return vo;
|
||||
}
|
||||
|
||||
private boolean hasDiff(LocalTemplateSnapshot local, SysReportTemplateVo db) {
|
||||
return !buildDiffTypes(local, db).isEmpty();
|
||||
}
|
||||
|
||||
private List<String> buildDiffTypes(LocalTemplateSnapshot local, SysReportTemplateVo db) {
|
||||
List<String> diffTypes = new ArrayList<>();
|
||||
if (local == null && db != null) {
|
||||
diffTypes.add("仅数据库");
|
||||
return diffTypes;
|
||||
}
|
||||
if (local != null && db == null) {
|
||||
diffTypes.add("仅本地");
|
||||
return diffTypes;
|
||||
}
|
||||
if (local == null) {
|
||||
return diffTypes;
|
||||
}
|
||||
|
||||
if (!Objects.equals(normalizeText(local.getTemplateName()), normalizeText(db.getTemplateName()))) {
|
||||
diffTypes.add("名称");
|
||||
}
|
||||
if (!Objects.equals(normalizeText(local.getContent()), normalizeText(db.getContent()))) {
|
||||
diffTypes.add("内容");
|
||||
}
|
||||
if (!Objects.equals(toJsonText(local.getMockData()), toJsonText(db.getMockData()))) {
|
||||
diffTypes.add("模拟数据");
|
||||
}
|
||||
if (!Objects.equals(normalizeText(local.getRemark()), normalizeText(db.getRemark()))) {
|
||||
diffTypes.add("备注");
|
||||
}
|
||||
return diffTypes;
|
||||
}
|
||||
|
||||
private Map<String, SysReportTemplateVo> queryExistingTemplates(Set<String> templateCodes) {
|
||||
LambdaQueryWrapper<SysReportTemplate> queryWrapper = Wrappers.lambdaQuery();
|
||||
if (templateCodes != null && !templateCodes.isEmpty()) {
|
||||
queryWrapper.in(SysReportTemplate::getTemplateCode, templateCodes);
|
||||
}
|
||||
return baseMapper.selectVoList(queryWrapper).stream()
|
||||
.collect(Collectors.toMap(SysReportTemplateVo::getTemplateCode, item -> item, (left, right) -> left, LinkedHashMap::new));
|
||||
}
|
||||
|
||||
private LinkedHashMap<String, LocalTemplateSnapshot> loadLocalTemplateSnapshots() {
|
||||
LinkedHashMap<String, LocalTemplateSnapshot> templateMap = new LinkedHashMap<>();
|
||||
|
||||
if (reportDataProviders != null) {
|
||||
for (IReportDataProvider provider : reportDataProviders) {
|
||||
try {
|
||||
String code = provider.getTemplateCode();
|
||||
if (StringUtils.isBlank(code)) continue;
|
||||
|
||||
SysReportTemplateVo existing = queryByCode(code);
|
||||
|
||||
// Read content
|
||||
String content = null;
|
||||
try {
|
||||
ClassPathResource resource = new ClassPathResource(code);
|
||||
if (resource.exists()) {
|
||||
content = IoUtil.read(resource.getInputStream(), StandardCharsets.UTF_8);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Template file not found for provider: {}", provider.getClass().getSimpleName());
|
||||
if (StringUtils.isBlank(code)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (existing == null) {
|
||||
if (StringUtils.isBlank(content)) {
|
||||
log.warn("Skipping provider {} because template file {} not found", provider.getClass().getSimpleName(), code);
|
||||
continue;
|
||||
}
|
||||
SysReportTemplate template = new SysReportTemplate();
|
||||
template.setTemplateCode(code);
|
||||
template.setTemplateName(provider.getReportTitle());
|
||||
template.setContent(content);
|
||||
template.setMockData(provider.getMockData());
|
||||
template.setVersion(1);
|
||||
template.setRemark("Synced from Provider: " + provider.getClass().getSimpleName());
|
||||
baseMapper.insert(template);
|
||||
log.info("Inserted template from provider: {}", code);
|
||||
} else {
|
||||
// Update metadata
|
||||
SysReportTemplate update = new SysReportTemplate();
|
||||
update.setId(existing.getId());
|
||||
boolean changed = false;
|
||||
|
||||
// Sync Title
|
||||
String title = provider.getReportTitle();
|
||||
if (StringUtils.isNotBlank(title) && !title.equals(existing.getTemplateName())) {
|
||||
update.setTemplateName(title);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// Sync MockData if provided
|
||||
Map<String, Object> mockData = provider.getMockData();
|
||||
if (mockData != null && !mockData.isEmpty()) {
|
||||
update.setMockData(mockData);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// Optional: Sync content if it was empty in DB (unlikely)
|
||||
if (StringUtils.isBlank(existing.getContent()) && StringUtils.isNotBlank(content)) {
|
||||
update.setContent(content);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
baseMapper.updateById(update);
|
||||
log.info("Updated template metadata from provider: {}", code);
|
||||
}
|
||||
String content = readTemplateContent(code);
|
||||
if (StringUtils.isBlank(content)) {
|
||||
log.warn("Skipping provider {} because template file {} not found", provider.getClass().getSimpleName(), code);
|
||||
continue;
|
||||
}
|
||||
|
||||
LocalTemplateSnapshot snapshot = new LocalTemplateSnapshot();
|
||||
snapshot.setTemplateCode(code);
|
||||
snapshot.setTemplateName(provider.getReportTitle());
|
||||
snapshot.setContent(content);
|
||||
snapshot.setMockData(provider.getMockData());
|
||||
snapshot.setRemark(PROVIDER_REMARK_PREFIX + provider.getClass().getSimpleName());
|
||||
templateMap.put(code, snapshot);
|
||||
} catch (Exception e) {
|
||||
log.error("Error syncing provider template: " + provider.getClass().getSimpleName(), e);
|
||||
log.error("Error loading provider template: {}", provider.getClass().getSimpleName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Scan remaining files (for layouts and fragments)
|
||||
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||
try {
|
||||
// Find all .vm files in templates directory
|
||||
Resource[] resources = resolver.getResources("classpath*:templates/**/*.vm");
|
||||
for (Resource resource : resources) {
|
||||
try {
|
||||
String path = resource.getURL().getPath();
|
||||
// Normalize path separators
|
||||
path = path.replace("\\", "/");
|
||||
|
||||
int index = path.lastIndexOf("templates/");
|
||||
if (index > -1) {
|
||||
String code = path.substring(index); // Include "templates/" in the code
|
||||
|
||||
// Check if exists
|
||||
SysReportTemplateVo exist = queryByCode(code);
|
||||
if (exist == null) {
|
||||
String content = IoUtil.read(resource.getInputStream(), StandardCharsets.UTF_8);
|
||||
SysReportTemplate template = new SysReportTemplate();
|
||||
template.setTemplateCode(code);
|
||||
// Use filename as name
|
||||
template.setTemplateName(FileUtil.mainName(resource.getFilename()));
|
||||
template.setContent(content);
|
||||
template.setVersion(1);
|
||||
template.setRemark("Synced from classpath scan");
|
||||
baseMapper.insert(template);
|
||||
log.info("Synced template from scan: {}", code);
|
||||
}
|
||||
String code = extractTemplateCode(resource);
|
||||
if (StringUtils.isBlank(code) || templateMap.containsKey(code)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LocalTemplateSnapshot snapshot = new LocalTemplateSnapshot();
|
||||
snapshot.setTemplateCode(code);
|
||||
snapshot.setTemplateName(FileUtil.mainName(resource.getFilename()));
|
||||
snapshot.setContent(IoUtil.read(resource.getInputStream(), StandardCharsets.UTF_8));
|
||||
snapshot.setRemark(CLASSPATH_SCAN_REMARK);
|
||||
templateMap.put(code, snapshot);
|
||||
} catch (Exception e) {
|
||||
log.error("Error processing resource: " + resource, e);
|
||||
log.error("Error processing resource: {}", resource, e);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Failed to sync templates", e);
|
||||
throw new ServiceException("同步模版失败");
|
||||
log.error("Failed to load local templates", e);
|
||||
throw new ServiceException("读取本地模板失败");
|
||||
}
|
||||
|
||||
return templateMap;
|
||||
}
|
||||
|
||||
private String extractTemplateCode(Resource resource) throws IOException {
|
||||
String path = resource.getURL().getPath().replace("\\", "/");
|
||||
int index = path.lastIndexOf("templates/");
|
||||
if (index < 0) {
|
||||
return null;
|
||||
}
|
||||
return path.substring(index);
|
||||
}
|
||||
|
||||
private String readTemplateContent(String code) {
|
||||
try {
|
||||
ClassPathResource resource = new ClassPathResource(code);
|
||||
if (!resource.exists()) {
|
||||
return null;
|
||||
}
|
||||
return IoUtil.read(resource.getInputStream(), StandardCharsets.UTF_8);
|
||||
} catch (Exception e) {
|
||||
log.warn("Template file not found: {}", code, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> normalizeTemplateCodes(Collection<String> templateCodes) {
|
||||
if (templateCodes == null) {
|
||||
return null;
|
||||
}
|
||||
return templateCodes.stream()
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
}
|
||||
|
||||
private String normalizeText(String value) {
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
|
||||
private String toJsonText(Object value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return JsonUtils.toJsonString(value);
|
||||
}
|
||||
|
||||
@lombok.Data
|
||||
private static class LocalTemplateSnapshot {
|
||||
|
||||
private String templateCode;
|
||||
|
||||
private String templateName;
|
||||
|
||||
private String content;
|
||||
|
||||
private Object mockData;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ public class ReportVerifyTicketService {
|
||||
}
|
||||
|
||||
String style = "<style id=\"verify-seal-style\">"
|
||||
+ ".verify-seal{position:fixed;top:16px;right:16px;width:120px;opacity:.95;z-index:9999;pointer-events:none;}"
|
||||
+ ".verify-seal{position:absolute;top:16px;right:16px;width:120px;opacity:.95;z-index:9999;pointer-events:none;}"
|
||||
+ "@media(max-width:480px){.verify-seal{top:10px;right:10px;width:90px;}}"
|
||||
+ "</style>";
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ public class SysCompanyRoleServiceImpl implements ISysCompanyRoleService {
|
||||
|
||||
private LambdaQueryWrapper<SysCompanyRole> buildQueryWrapper(SysCompanyRoleBo bo) {
|
||||
LambdaQueryWrapper<SysCompanyRole> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByAsc(SysCompanyRole::getCompanyId).orderByAsc(SysCompanyRole::getRoleSort);
|
||||
lqw.orderByAsc(SysCompanyRole::getCompanyId).orderByAsc(SysCompanyRole::getRoleSort).orderByAsc(SysCompanyRole::getId);
|
||||
lqw.eq(bo.getCompanyId() != null, SysCompanyRole::getCompanyId, bo.getCompanyId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getRoleName()), SysCompanyRole::getRoleName, bo.getRoleName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getRoleKey()), SysCompanyRole::getRoleKey, bo.getRoleKey());
|
||||
@@ -171,15 +171,29 @@ public class SysCompanyRoleServiceImpl implements ISysCompanyRoleService {
|
||||
|
||||
@Override
|
||||
public Set<String> selectRoleKeys(Long userId, Long companyId) {
|
||||
// Query HotCompanySafetyManager to get role ID
|
||||
HotCompanySafetyManager manager = safetyManagerMapper.selectOne(Wrappers.<HotCompanySafetyManager>lambdaQuery()
|
||||
.select(HotCompanySafetyManager::getPermissionRoleId)
|
||||
// hot_company_safety_manager 可能存在重复有效数据,按最近一条记录兜底,避免登录鉴权直接失败
|
||||
List<HotCompanySafetyManager> managers = safetyManagerMapper.selectList(Wrappers.<HotCompanySafetyManager>lambdaQuery()
|
||||
.select(HotCompanySafetyManager::getId, HotCompanySafetyManager::getPermissionRoleId,
|
||||
HotCompanySafetyManager::getUpdateTime, HotCompanySafetyManager::getCreateTime)
|
||||
.eq(HotCompanySafetyManager::getUserId, userId)
|
||||
.eq(HotCompanySafetyManager::getCompanyId, companyId)
|
||||
.eq(HotCompanySafetyManager::getIsDeleted, 0)
|
||||
.eq(HotCompanySafetyManager::getStatus, 1)
|
||||
.and(w -> w.eq(HotCompanySafetyManager::getIsResigned, 0).or().isNull(HotCompanySafetyManager::getIsResigned))
|
||||
);
|
||||
.orderByDesc(HotCompanySafetyManager::getUpdateTime)
|
||||
.orderByDesc(HotCompanySafetyManager::getCreateTime)
|
||||
.orderByDesc(HotCompanySafetyManager::getId));
|
||||
|
||||
if (managers == null || managers.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
if (managers.size() > 1) {
|
||||
log.warn("查询企业角色标识命中多条安全管理人员记录,按最新一条兜底返回 userId={}, companyId={}, count={}",
|
||||
userId, companyId, managers.size());
|
||||
}
|
||||
|
||||
HotCompanySafetyManager manager = managers.get(0);
|
||||
|
||||
if (manager == null || manager.getPermissionRoleId() == null) {
|
||||
return Collections.emptySet();
|
||||
|
||||
@@ -163,7 +163,7 @@ public class SysCompanyServiceImpl implements ISysCompanyService {
|
||||
private LambdaQueryWrapper<SysCompany> buildQueryWrapper(SysCompanyBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<SysCompany> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(SysCompany::getCreateTime);
|
||||
lqw.orderByDesc(SysCompany::getCreateTime, SysCompany::getId);
|
||||
lqw.like(StringUtils.isNotBlank(bo.getCompanyName()), SysCompany::getCompanyName, bo.getCompanyName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getCompanyShortName()), SysCompany::getCompanyShortName, bo.getCompanyShortName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getCompanyType()), SysCompany::getCompanyType, bo.getCompanyType());
|
||||
@@ -378,42 +378,63 @@ public class SysCompanyServiceImpl implements ISysCompanyService {
|
||||
// 确保有企业管理员角色
|
||||
Long roleId = createEnterpriseAdminRole(companyId, userId, responsibleName);
|
||||
|
||||
// 查找是否已存在该人员记录
|
||||
LambdaQueryWrapper<HotCompanySafetyManager> smWrapper = new LambdaQueryWrapper<>();
|
||||
smWrapper.eq(HotCompanySafetyManager::getCompanyId, companyId)
|
||||
.eq(HotCompanySafetyManager::getPhone, responsibleMobile);
|
||||
HotCompanySafetyManager safetyManager = hotCompanySafetyManagerMapper.selectOne(smWrapper);
|
||||
HotCompanySafetyManager safetyManager = resolveResponsibleSafetyManager(companyId, userId, responsibleMobile);
|
||||
|
||||
if (safetyManager == null) {
|
||||
safetyManager = new HotCompanySafetyManager();
|
||||
safetyManager.setCompanyId(companyId);
|
||||
safetyManager.setName(responsibleName);
|
||||
safetyManager.setPhone(responsibleMobile);
|
||||
safetyManager.setUserId(userId);
|
||||
// 设置为企业负责人
|
||||
safetyManager.setCompanyHead(1L);
|
||||
// 企业负责人权限变更
|
||||
safetyManager.setPermissionType("company_admin");
|
||||
safetyManager.setPermissionRoleId(roleId);
|
||||
|
||||
safetyManager.setIsResigned(0L);
|
||||
safetyManager.setStatus(1L);
|
||||
fillResponsibleSafetyManager(safetyManager, companyId, responsibleName, responsibleMobile, userId, roleId);
|
||||
hotCompanySafetyManagerMapper.insert(safetyManager);
|
||||
log.info("[企业负责人] 创建安全管理人员记录 companyId={}, userId={}, managerId={}", companyId, userId, safetyManager.getId());
|
||||
} else {
|
||||
// 更新现有记录
|
||||
safetyManager.setName(responsibleName);
|
||||
safetyManager.setUserId(userId);
|
||||
safetyManager.setCompanyHead(1L);
|
||||
safetyManager.setPermissionType("company_admin");
|
||||
safetyManager.setPermissionRoleId(roleId);
|
||||
safetyManager.setIsResigned(0L);
|
||||
safetyManager.setStatus(1L);
|
||||
fillResponsibleSafetyManager(safetyManager, companyId, responsibleName, responsibleMobile, userId, roleId);
|
||||
hotCompanySafetyManagerMapper.updateById(safetyManager);
|
||||
log.info("[企业负责人] 更新安全管理人员记录 companyId={}, userId={}, managerId={}", companyId, userId, safetyManager.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private HotCompanySafetyManager resolveResponsibleSafetyManager(Long companyId, Long userId, String responsibleMobile) {
|
||||
List<HotCompanySafetyManager> matches = hotCompanySafetyManagerMapper.selectList(Wrappers.<HotCompanySafetyManager>lambdaQuery()
|
||||
.eq(HotCompanySafetyManager::getCompanyId, companyId)
|
||||
.eq(HotCompanySafetyManager::getUserId, userId)
|
||||
.eq(HotCompanySafetyManager::getIsDeleted, 0L)
|
||||
.orderByDesc(HotCompanySafetyManager::getCompanyHead)
|
||||
.orderByDesc(HotCompanySafetyManager::getUpdateTime)
|
||||
.orderByDesc(HotCompanySafetyManager::getCreateTime)
|
||||
.orderByDesc(HotCompanySafetyManager::getId));
|
||||
if (CollUtil.isEmpty(matches) && StringUtils.isNotBlank(responsibleMobile)) {
|
||||
matches = hotCompanySafetyManagerMapper.selectList(Wrappers.<HotCompanySafetyManager>lambdaQuery()
|
||||
.eq(HotCompanySafetyManager::getCompanyId, companyId)
|
||||
.eq(HotCompanySafetyManager::getPhone, responsibleMobile)
|
||||
.eq(HotCompanySafetyManager::getIsDeleted, 0L)
|
||||
.orderByDesc(HotCompanySafetyManager::getCompanyHead)
|
||||
.orderByDesc(HotCompanySafetyManager::getUpdateTime)
|
||||
.orderByDesc(HotCompanySafetyManager::getCreateTime)
|
||||
.orderByDesc(HotCompanySafetyManager::getId));
|
||||
}
|
||||
if (CollUtil.isEmpty(matches)) {
|
||||
return null;
|
||||
}
|
||||
if (matches.size() > 1) {
|
||||
log.warn("[企业负责人] 命中多条安全管理人员记录,按最新一条更新 companyId={}, userId={}, phone={}, count={}",
|
||||
companyId, userId, responsibleMobile, matches.size());
|
||||
}
|
||||
return matches.get(0);
|
||||
}
|
||||
|
||||
private void fillResponsibleSafetyManager(HotCompanySafetyManager safetyManager, Long companyId, String responsibleName,
|
||||
String responsibleMobile, Long userId, Long roleId) {
|
||||
safetyManager.setCompanyId(companyId);
|
||||
safetyManager.setName(responsibleName);
|
||||
safetyManager.setPhone(responsibleMobile);
|
||||
safetyManager.setUserId(userId);
|
||||
safetyManager.setCompanyHead(1L);
|
||||
safetyManager.setPermissionType("company_admin");
|
||||
safetyManager.setPermissionRoleId(roleId);
|
||||
safetyManager.setIsDeleted(0L);
|
||||
safetyManager.setIsResigned(0L);
|
||||
safetyManager.setStatus(1L);
|
||||
}
|
||||
|
||||
public Long createEnterpriseAdminRole(Long companyId, Long userId, String username) {
|
||||
// 1. Check/Create SysCompanyRole
|
||||
LambdaQueryWrapper<SysCompanyRole> roleWrapper = new LambdaQueryWrapper<>();
|
||||
@@ -486,23 +507,7 @@ public class SysCompanyServiceImpl implements ISysCompanyService {
|
||||
// 1. 处理旧负责人:移除相关权限,标记离职(仅当负责人手机号变更时)
|
||||
String oldMobile = oldCompany.getResponsibleMobile();
|
||||
if (StrUtil.isNotBlank(oldMobile) && !StrUtil.equals(oldMobile, bo.getResponsibleMobile())) {
|
||||
SysUser oldUser = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, oldMobile));
|
||||
if (oldUser != null) {
|
||||
Long oldUserId = oldUser.getUserId();
|
||||
// 移除该用户在当前企业的角色关联
|
||||
sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
|
||||
.eq(SysUserRole::getUserId, oldUserId)
|
||||
.eq(SysUserRole::getLoginPort, ENTERPRISE_PORT)
|
||||
.eq(SysUserRole::getCompanyId, bo.getId()));
|
||||
|
||||
// 移除该用户与企业的关联关系
|
||||
sysUserLoginPortMapper.delete(new LambdaQueryWrapper<SysUserLoginPort>()
|
||||
.eq(SysUserLoginPort::getUserId, oldUserId)
|
||||
.eq(SysUserLoginPort::getLoginPort, ENTERPRISE_PORT)
|
||||
.eq(SysUserLoginPort::getCompanyId, bo.getId()));
|
||||
|
||||
hotCompanySafetyManagerMapper.deleteCompanyHeadByPhone(bo.getId(), oldMobile);
|
||||
}
|
||||
cleanupOldResponsibleData(bo.getId(), oldMobile);
|
||||
}
|
||||
|
||||
// 2. 添加新负责人:创建用户(如果不存在)、赋予权限、添加安全管理人员记录
|
||||
@@ -512,6 +517,39 @@ public class SysCompanyServiceImpl implements ISysCompanyService {
|
||||
return flag;
|
||||
}
|
||||
|
||||
private void cleanupOldResponsibleData(Long companyId, String oldMobile) {
|
||||
if (companyId == null || StrUtil.isBlank(oldMobile)) {
|
||||
return;
|
||||
}
|
||||
SysUser oldUser = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, oldMobile));
|
||||
Long oldUserId = oldUser != null ? oldUser.getUserId() : null;
|
||||
if (oldUserId != null) {
|
||||
sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
|
||||
.eq(SysUserRole::getUserId, oldUserId)
|
||||
.eq(SysUserRole::getLoginPort, ENTERPRISE_PORT)
|
||||
.eq(SysUserRole::getCompanyId, companyId));
|
||||
sysUserLoginPortMapper.delete(new LambdaQueryWrapper<SysUserLoginPort>()
|
||||
.eq(SysUserLoginPort::getUserId, oldUserId)
|
||||
.eq(SysUserLoginPort::getLoginPort, ENTERPRISE_PORT)
|
||||
.eq(SysUserLoginPort::getCompanyId, companyId));
|
||||
}
|
||||
LambdaQueryWrapper<HotCompanySafetyManager> wrapper = Wrappers.<HotCompanySafetyManager>lambdaQuery()
|
||||
.eq(HotCompanySafetyManager::getCompanyId, companyId)
|
||||
.eq(HotCompanySafetyManager::getCompanyHead, 1L)
|
||||
.eq(HotCompanySafetyManager::getIsDeleted, 0L)
|
||||
.and(w -> {
|
||||
w.eq(HotCompanySafetyManager::getPhone, oldMobile);
|
||||
if (oldUserId != null) {
|
||||
w.or().eq(HotCompanySafetyManager::getUserId, oldUserId);
|
||||
}
|
||||
});
|
||||
int deleted = hotCompanySafetyManagerMapper.delete(wrapper);
|
||||
if (deleted > 0) {
|
||||
log.info("[企业负责人] 清理旧负责人安全管理人员记录 companyId={}, oldMobile={}, oldUserId={}, deleted={}",
|
||||
companyId, oldMobile, oldUserId, deleted);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
|
||||
@@ -142,7 +142,7 @@ public class HotCompanyChangeHistoryServiceImpl implements IHotCompanyChangeHist
|
||||
lqw.like(StringUtils.isNotBlank(bo.getName()), HotCompanyChangeHistory::getName, bo.getName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getPhone()), HotCompanyChangeHistory::getPhone, bo.getPhone());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getChangeType()), HotCompanyChangeHistory::getChangeType, bo.getChangeType());
|
||||
lqw.orderByDesc(HotCompanyChangeHistory::getChangeTime);
|
||||
lqw.orderByDesc(HotCompanyChangeHistory::getChangeTime, HotCompanyChangeHistory::getId);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ public class HotCompanyPermissionGrantServiceImpl implements IHotCompanyPermissi
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getPermissionCode()), HotCompanyPermissionGrant::getPermissionCode, bo.getPermissionCode());
|
||||
lqw.eq(bo.getStatus() != null, HotCompanyPermissionGrant::getStatus, bo.getStatus());
|
||||
lqw.eq(HotCompanyPermissionGrant::getIsDeleted, 0L);
|
||||
lqw.orderByDesc(HotCompanyPermissionGrant::getCreateTime);
|
||||
lqw.orderByDesc(HotCompanyPermissionGrant::getCreateTime, HotCompanyPermissionGrant::getId);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ public class HotCompanyPolicyServiceImpl implements IHotCompanyPolicyService {
|
||||
.select(HotCompanyPolicy::getOrderNum)
|
||||
.eq(HotCompanyPolicy::getCompanyId, bo.getCompanyId())
|
||||
.eq(HotCompanyPolicy::getPolicyType, bo.getPolicyType())
|
||||
.orderByDesc(HotCompanyPolicy::getOrderNum)
|
||||
.orderByDesc(HotCompanyPolicy::getOrderNum, HotCompanyPolicy::getId)
|
||||
.last("limit 1"));
|
||||
long maxOrder = (maxOrderPolicy != null && maxOrderPolicy.getOrderNum() != null) ? maxOrderPolicy.getOrderNum() : 0L;
|
||||
add.setOrderNum(maxOrder + 1);
|
||||
|
||||
@@ -451,6 +451,8 @@ public class HotCompanySafetyManagerServiceImpl implements IHotCompanySafetyMana
|
||||
userId = sysUser.getUserId();
|
||||
}
|
||||
|
||||
validateManagerUniqueness(add.getCompanyId(), add.getPhone(), userId, null);
|
||||
|
||||
// 初始化或更新子密码(特定企业的登录密码)
|
||||
String subPassword;
|
||||
if (StringUtils.isNotBlank(add.getLoginPassword())) {
|
||||
@@ -521,6 +523,9 @@ public class HotCompanySafetyManagerServiceImpl implements IHotCompanySafetyMana
|
||||
if (before == null) {
|
||||
throw new ServiceException("安全管理人员不存在");
|
||||
}
|
||||
Long finalCompanyId = update.getCompanyId() != null ? update.getCompanyId() : before.getCompanyId();
|
||||
String finalPhone = StringUtils.isNotBlank(update.getPhone()) ? update.getPhone() : before.getPhone();
|
||||
validateManagerUniqueness(finalCompanyId, finalPhone, before.getUserId(), update.getId());
|
||||
// 参考新增:编辑时如果更换部门,且目标部门暂无负责人、当前人员又不是负责人,则不允许变更
|
||||
boolean deptChanged = update.getDeptId() != null && !Objects.equals(update.getDeptId(), before.getDeptId());
|
||||
Long finalIsDepartmentHead = update.getIsDepartmentHead() != null ? update.getIsDepartmentHead() : before.getIsDepartmentHead();
|
||||
@@ -575,6 +580,39 @@ public class HotCompanySafetyManagerServiceImpl implements IHotCompanySafetyMana
|
||||
);
|
||||
}
|
||||
|
||||
private void validateManagerUniqueness(Long companyId, String phone, Long userId, Long excludeId) {
|
||||
if (companyId == null) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isNotBlank(phone)) {
|
||||
LambdaQueryWrapper<HotCompanySafetyManager> phoneWrapper = Wrappers.<HotCompanySafetyManager>lambdaQuery()
|
||||
.eq(HotCompanySafetyManager::getCompanyId, companyId)
|
||||
.eq(HotCompanySafetyManager::getPhone, phone)
|
||||
.eq(HotCompanySafetyManager::getIsDeleted, 0L);
|
||||
if (excludeId != null) {
|
||||
phoneWrapper.ne(HotCompanySafetyManager::getId, excludeId);
|
||||
}
|
||||
if (baseMapper.selectCount(phoneWrapper) > 0) {
|
||||
throw new ServiceException("同一公司下手机号不允许重复");
|
||||
}
|
||||
}
|
||||
if (userId == null) {
|
||||
return;
|
||||
}
|
||||
LambdaQueryWrapper<HotCompanySafetyManager> userWrapper = Wrappers.<HotCompanySafetyManager>lambdaQuery()
|
||||
.eq(HotCompanySafetyManager::getCompanyId, companyId)
|
||||
.eq(HotCompanySafetyManager::getUserId, userId)
|
||||
.eq(HotCompanySafetyManager::getIsDeleted, 0L)
|
||||
.eq(HotCompanySafetyManager::getStatus, 1L)
|
||||
.and(w -> w.eq(HotCompanySafetyManager::getIsResigned, 0L).or().isNull(HotCompanySafetyManager::getIsResigned));
|
||||
if (excludeId != null) {
|
||||
userWrapper.ne(HotCompanySafetyManager::getId, excludeId);
|
||||
}
|
||||
if (baseMapper.selectCount(userWrapper) > 0) {
|
||||
throw new ServiceException("同一公司下该用户已存在有效的安全管理人员记录");
|
||||
}
|
||||
}
|
||||
|
||||
private void syncUserAndRecordHistory(HotCompanySafetyManager update, HotCompanySafetyManager before, String changeReason, String beforeBusiness) {
|
||||
SysUser sysUser = findUserByPhone(before.getPhone());
|
||||
if (sysUser == null) {
|
||||
@@ -689,7 +727,7 @@ public class HotCompanySafetyManagerServiceImpl implements IHotCompanySafetyMana
|
||||
userService.resetUserPwd(sysUser.getUserId(), BCrypt.hashpw(newPwd), before.getCompanyId());
|
||||
|
||||
// 不需要单独更新 sysUser 密码,resetUserPwd 已经处理
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean handlePhoneChange(HotCompanySafetyManager update, HotCompanySafetyManager before, SysUser sysUser) {
|
||||
|
||||
@@ -88,7 +88,7 @@ public class HotVehicleAnnualReviewServiceImpl implements IHotVehicleAnnualRevie
|
||||
return baseMapper.selectVoOne(new LambdaQueryWrapper<HotVehicleAnnualReview>()
|
||||
.eq(HotVehicleAnnualReview::getVehicleId, vehicleId)
|
||||
.eq(HotVehicleAnnualReview::getIsDeleted, 0L)
|
||||
.orderByDesc(HotVehicleAnnualReview::getReviewDate)
|
||||
.orderByDesc(HotVehicleAnnualReview::getReviewDate, HotVehicleAnnualReview::getId)
|
||||
.last("LIMIT 1"));
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ public class HotVehicleAnnualReviewServiceImpl implements IHotVehicleAnnualRevie
|
||||
LambdaQueryWrapper<HotVehicleAnnualReview> lqw = new LambdaQueryWrapper<HotVehicleAnnualReview>()
|
||||
.eq(HotVehicleAnnualReview::getVehicleId, vehicleId)
|
||||
.eq(HotVehicleAnnualReview::getIsDeleted, 0L)
|
||||
.orderByDesc(HotVehicleAnnualReview::getReviewDate)
|
||||
.orderByDesc(HotVehicleAnnualReview::getReviewDate, HotVehicleAnnualReview::getId)
|
||||
.last("LIMIT 1");
|
||||
if (startDate != null) {
|
||||
lqw.ge(HotVehicleAnnualReview::getReviewDate, startDate);
|
||||
|
||||
@@ -82,7 +82,7 @@ public class HotVehicleChangeServiceImpl implements IHotVehicleChangeService {
|
||||
private LambdaQueryWrapper<HotVehicleChange> buildQueryWrapper(HotVehicleChangeBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotVehicleChange> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(HotVehicleChange::getCreateTime);
|
||||
lqw.orderByDesc(HotVehicleChange::getCreateTime, HotVehicleChange::getId);
|
||||
lqw.eq(bo.getCompanyId() != null, HotVehicleChange::getCompanyId, bo.getCompanyId());
|
||||
lqw.eq(bo.getVehicleId() != null, HotVehicleChange::getVehicleId, bo.getVehicleId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getPlateNumber()), HotVehicleChange::getPlateNumber, bo.getPlateNumber());
|
||||
|
||||
@@ -226,7 +226,7 @@ public class HotVehicleClaimServiceImpl implements IHotVehicleClaimService {
|
||||
public HotVehicleClaimVo queryLatestByVehicleId(String vehicleId) {
|
||||
return baseMapper.selectVoOne(new LambdaQueryWrapper<HotVehicleClaim>()
|
||||
.eq(HotVehicleClaim::getVehicleId, vehicleId)
|
||||
.orderByDesc(HotVehicleClaim::getIncidentTime)
|
||||
.orderByDesc(HotVehicleClaim::getIncidentTime, HotVehicleClaim::getId)
|
||||
.last("LIMIT 1"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ public class HotVehicleMaintenanceServiceImpl implements IHotVehicleMaintenanceS
|
||||
return baseMapper.selectVoOne(new LambdaQueryWrapper<HotVehicleMaintenance>()
|
||||
.eq(HotVehicleMaintenance::getVehicleId, vehicleId)
|
||||
.eq(HotVehicleMaintenance::getIsDeleted, 0L)
|
||||
.orderByDesc(HotVehicleMaintenance::getFinishTime)
|
||||
.orderByDesc(HotVehicleMaintenance::getFinishTime, HotVehicleMaintenance::getId)
|
||||
.last("LIMIT 1"));
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,16 @@ public class HotVehicleController extends BaseController {
|
||||
return hotVehicleService.queryPageListByStatus(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询公司车辆信息列表(状态为数组,不过滤已绑定驾驶员)
|
||||
*/
|
||||
//@SaCheckPermission("resourceManagement:vehicle:list")
|
||||
@GetMapping("/listByStatusAll")
|
||||
@Operation(summary = "查询公司车辆信息列表(状态为数组,不过滤已绑定驾驶员)")
|
||||
public TableDataInfo<HotVehicleVo> listByStatusAll(HotVehicleStatusBo bo, PageQuery pageQuery) {
|
||||
return hotVehicleService.queryPageListByStatusAll(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前企业可绑定的车辆列表
|
||||
*/
|
||||
|
||||
@@ -64,6 +64,15 @@ public interface IHotVehicleService {
|
||||
*/
|
||||
TableDataInfo<HotVehicleVo> queryPageListByStatus(HotVehicleStatusBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 分页查询公司车辆信息列表(不过滤已绑定驾驶员)
|
||||
*
|
||||
* @param bo 查询条件 车辆状态为字符串逗号拼接
|
||||
* @param pageQuery 分页参数
|
||||
* @return 公司车辆信息分页列表
|
||||
*/
|
||||
TableDataInfo<HotVehicleVo> queryPageListByStatusAll(HotVehicleStatusBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询当前企业可绑定的车辆列表
|
||||
*
|
||||
|
||||
@@ -195,7 +195,15 @@ public class HotVehicleServiceImpl implements IHotVehicleService {
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<HotVehicleVo> queryPageListByStatus(HotVehicleStatusBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<HotVehicle> lqw = buildQueryWrapperByStatus(bo);
|
||||
LambdaQueryWrapper<HotVehicle> lqw = buildQueryWrapperByStatus(bo, true);
|
||||
Page<HotVehicleVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
fillCurrentBindingPersonName(result.getRecords());
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<HotVehicleVo> queryPageListByStatusAll(HotVehicleStatusBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<HotVehicle> lqw = buildQueryWrapperByStatus(bo, false);
|
||||
Page<HotVehicleVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
fillCurrentBindingPersonName(result.getRecords());
|
||||
return TableDataInfo.build(result);
|
||||
@@ -212,6 +220,7 @@ public class HotVehicleServiceImpl implements IHotVehicleService {
|
||||
LambdaQueryWrapper<HotVehicle> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByAsc(HotVehicle::getArchiveNo)
|
||||
.orderByAsc(HotVehicle::getPlateNumber)
|
||||
.orderByAsc(HotVehicle::getId)
|
||||
.eq(bo.getCompanyId() != null, HotVehicle::getCompanyId, bo.getCompanyId())
|
||||
.eq(HotVehicle::getVehicleStatus, 1L)
|
||||
.eq(HotVehicle::getOperationStatus, 1L)
|
||||
@@ -238,7 +247,8 @@ public class HotVehicleServiceImpl implements IHotVehicleService {
|
||||
.eq(HotVehicle::getCompanyId, companyId)
|
||||
.eq(HotVehicle::getIsDeleted, 0L)
|
||||
.orderByAsc(HotVehicle::getArchiveNo)
|
||||
.orderByAsc(HotVehicle::getPlateNumber));
|
||||
.orderByAsc(HotVehicle::getPlateNumber)
|
||||
.orderByAsc(HotVehicle::getId));
|
||||
|
||||
List<DriverBindingVehicleItemVo> boundVehicleList = new ArrayList<>();
|
||||
List<DriverBindingVehicleItemVo> bindableVehicleList = new ArrayList<>();
|
||||
@@ -266,7 +276,8 @@ public class HotVehicleServiceImpl implements IHotVehicleService {
|
||||
.eq(HotVehicle::getCompanyId, companyId)
|
||||
.eq(HotVehicle::getIsDeleted, 0L)
|
||||
.orderByAsc(HotVehicle::getArchiveNo)
|
||||
.orderByAsc(HotVehicle::getPlateNumber));
|
||||
.orderByAsc(HotVehicle::getPlateNumber)
|
||||
.orderByAsc(HotVehicle::getId));
|
||||
List<DriverBindingVehicleItemVo> boundVehicleList = new ArrayList<>();
|
||||
for (HotVehicle vehicle : companyVehicles) {
|
||||
if (splitCsv(vehicle.getCurrentDriver()).contains(driverId)) {
|
||||
@@ -330,7 +341,8 @@ public class HotVehicleServiceImpl implements IHotVehicleService {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotVehicle> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByAsc(HotVehicle::getOperationStatus)
|
||||
.orderByAsc(HotVehicle::getArchiveNo);
|
||||
.orderByAsc(HotVehicle::getArchiveNo)
|
||||
.orderByAsc(HotVehicle::getId);
|
||||
lqw.eq(bo.getCompanyId() != null, HotVehicle::getCompanyId, bo.getCompanyId());
|
||||
lqw.in(CollUtil.isNotEmpty(bo.getIds()), HotVehicle::getId, bo.getIds());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getGpsParams()), HotVehicle::getGpsParams, bo.getGpsParams());
|
||||
@@ -413,18 +425,20 @@ public class HotVehicleServiceImpl implements IHotVehicleService {
|
||||
return lqw;
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<HotVehicle> buildQueryWrapperByStatus(HotVehicleStatusBo bo) {
|
||||
private LambdaQueryWrapper<HotVehicle> buildQueryWrapperByStatus(HotVehicleStatusBo bo, boolean onlyUnboundDriver) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotVehicle> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(HotVehicle::getCreateTime);
|
||||
lqw.orderByDesc(HotVehicle::getCreateTime, HotVehicle::getId);
|
||||
lqw.eq(bo.getCompanyId() != null, HotVehicle::getCompanyId, bo.getCompanyId());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getGpsParams()), HotVehicle::getGpsParams, bo.getGpsParams());
|
||||
lqw.eq(bo.getIsTrailer() != null, HotVehicle::getIsTrailer, bo.getIsTrailer());
|
||||
lqw.eq(bo.getVehicleStatus() != null, HotVehicle::getVehicleStatus, bo.getVehicleStatus());
|
||||
lqw.in(HotVehicle::getOperationStatus, Arrays.asList(bo.getOperationStatus().split(",")));
|
||||
lqw.and(wrapper -> wrapper.isNull(HotVehicle::getCurrentDriver)
|
||||
.or()
|
||||
.eq(HotVehicle::getCurrentDriver, ""));
|
||||
if (onlyUnboundDriver) {
|
||||
lqw.and(wrapper -> wrapper.isNull(HotVehicle::getCurrentDriver)
|
||||
.or()
|
||||
.eq(HotVehicle::getCurrentDriver, ""));
|
||||
}
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getBodyImageUrls()), HotVehicle::getBodyImageUrls, bo.getBodyImageUrls());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getOtherAttachmentUrls()), HotVehicle::getOtherAttachmentUrls, bo.getOtherAttachmentUrls());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getColor()), HotVehicle::getColor, bo.getColor());
|
||||
|
||||
@@ -129,7 +129,7 @@ public class HotVehicleMileageServiceImpl implements IHotVehicleMileageService {
|
||||
public List<HotVehicleMileageVo> queryListByVehicleId(String vehicleId) {
|
||||
LambdaQueryWrapper<HotVehicleMileage> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(HotVehicleMileage::getVehicleId, vehicleId);
|
||||
lqw.orderByDesc(HotVehicleMileage::getStartDate);
|
||||
lqw.orderByDesc(HotVehicleMileage::getStartDate, HotVehicleMileage::getId);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ public class HotVehicleRepairServiceImpl implements IHotVehicleRepairService {
|
||||
public HotVehicleRepairVo queryLatestByVehicleId(String vehicleId) {
|
||||
return baseMapper.selectVoOne(new LambdaQueryWrapper<HotVehicleRepair>()
|
||||
.eq(HotVehicleRepair::getVehicleId, vehicleId)
|
||||
.orderByDesc(HotVehicleRepair::getFinishDate)
|
||||
.orderByDesc(HotVehicleRepair::getFinishDate, HotVehicleRepair::getId)
|
||||
.last("LIMIT 1"));
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ public class HotAccidentArchiveServiceImpl implements IHotAccidentArchiveService
|
||||
private LambdaQueryWrapper<HotAccidentArchive> buildQueryWrapper(HotAccidentArchiveBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotAccidentArchive> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(HotAccidentArchive::getAccidentTime);
|
||||
lqw.orderByDesc(HotAccidentArchive::getAccidentTime, HotAccidentArchive::getId);
|
||||
if (bo.getAccidentTime() != null) {
|
||||
java.util.Calendar calendarStart = java.util.Calendar.getInstance();
|
||||
calendarStart.setTime(bo.getAccidentTime());
|
||||
|
||||
@@ -122,7 +122,7 @@ public class HotHiddenDangerServiceImpl implements IHotHiddenDangerService {
|
||||
} else if (hasEndTime) {
|
||||
lqw.le(HotHiddenDanger::getCheckTime, endTime);
|
||||
}
|
||||
lqw.orderByDesc(HotHiddenDanger::getCreateTime);
|
||||
lqw.orderByDesc(HotHiddenDanger::getCreateTime, HotHiddenDanger::getId);
|
||||
lqw.eq(bo.getCompanyId() != null, HotHiddenDanger::getCompanyId, bo.getCompanyId());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDangerNo()), HotHiddenDanger::getDangerNo, bo.getDangerNo());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getDangerName()), HotHiddenDanger::getDangerName, bo.getDangerName());
|
||||
|
||||
@@ -131,11 +131,12 @@ public class HotHiddenDangerInspectionController extends BaseController {
|
||||
@GetMapping("/hidden-danger-plans/page")
|
||||
@Operation(
|
||||
summary = "移动端分页查询隐患排查计划列表",
|
||||
description = "权限说明:驾驶员仅可查看本人及所属车辆当月全部计划和历史未做计划;管理员可查看企业当月全部计划和历史未做计划。"
|
||||
description = "权限说明:驾驶员仅可查看当前处于原始周期或补查周期内、且属于本人及所属车辆的计划;管理员可查看企业内当前处于有效时间范围的计划。"
|
||||
)
|
||||
public TableDataInfo<HotHiddenDangerInspectionVo> hiddenDangerPlanPage(
|
||||
@RequestParam(value = "keyword", required = false) String keyword,
|
||||
@RequestParam(value = "planId", required = false) Long planId,
|
||||
PageQuery pageQuery) {
|
||||
return hotHiddenDangerInspectionService.queryMobilePlanPage(keyword, pageQuery);
|
||||
return hotHiddenDangerInspectionService.queryMobilePlanPage(keyword, planId, pageQuery);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,16 @@ public class HotHiddenDangerInspection extends BaseEntity {
|
||||
*/
|
||||
private Date checkDate;
|
||||
|
||||
/**
|
||||
* 是否补查期间处理:0否 1是
|
||||
*/
|
||||
private Long isRecheckProcessed;
|
||||
|
||||
/**
|
||||
* 补查处理时间
|
||||
*/
|
||||
private Date recheckProcessedTime;
|
||||
|
||||
/**
|
||||
* 评估人id
|
||||
*/
|
||||
@@ -150,4 +160,39 @@ public class HotHiddenDangerInspection extends BaseEntity {
|
||||
* 流程状态
|
||||
*/
|
||||
private String flowStatus;
|
||||
|
||||
/**
|
||||
* 提交版本号
|
||||
*/
|
||||
private Long submitVersion;
|
||||
|
||||
/**
|
||||
* 审核结果(PASS=通过 REJECT=驳回)
|
||||
*/
|
||||
private String auditResult;
|
||||
|
||||
/**
|
||||
* 驳回次数
|
||||
*/
|
||||
private Long rejectCount;
|
||||
|
||||
/**
|
||||
* 最近一次驳回原因
|
||||
*/
|
||||
private String lastRejectReason;
|
||||
|
||||
/**
|
||||
* 最近一次驳回时间
|
||||
*/
|
||||
private Date lastRejectTime;
|
||||
|
||||
/**
|
||||
* 最近一次驳回人ID
|
||||
*/
|
||||
private Long lastRejectById;
|
||||
|
||||
/**
|
||||
* 最近一次驳回人姓名
|
||||
*/
|
||||
private String lastRejectByName;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.hotwj.platform.securityManagement.hiddenDangerInspection.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 隐患排查审核驳回历史对象 hot_hidden_danger_inspection_audit_history
|
||||
*
|
||||
* @author shihongwei
|
||||
* @date 2026-05-30
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("hot_hidden_danger_inspection_audit_history")
|
||||
public class HotHiddenDangerInspectionAuditHistory extends BaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 隐患排查主单ID
|
||||
*/
|
||||
private Long inspectionId;
|
||||
|
||||
/**
|
||||
* 公司ID
|
||||
*/
|
||||
private Long companyId;
|
||||
|
||||
/**
|
||||
* 计划ID
|
||||
*/
|
||||
private Long planId;
|
||||
|
||||
/**
|
||||
* 排查项目
|
||||
*/
|
||||
private String projectName;
|
||||
|
||||
/**
|
||||
* 排查项目ID
|
||||
*/
|
||||
private String projectId;
|
||||
|
||||
/**
|
||||
* 排查类型(1=公司 2=车辆 3=人员)
|
||||
*/
|
||||
private Long projectType;
|
||||
|
||||
/**
|
||||
* 提交版本号
|
||||
*/
|
||||
private Long submitVersion;
|
||||
|
||||
/**
|
||||
* 审核轮次
|
||||
*/
|
||||
private Long auditRound;
|
||||
|
||||
/**
|
||||
* 审核结果(REJECT)
|
||||
*/
|
||||
private String auditResult;
|
||||
|
||||
/**
|
||||
* 驳回原因
|
||||
*/
|
||||
private String rejectReason;
|
||||
|
||||
/**
|
||||
* 审核日期
|
||||
*/
|
||||
private Date auditDate;
|
||||
|
||||
/**
|
||||
* 审核人ID
|
||||
*/
|
||||
private Long approverId;
|
||||
|
||||
/**
|
||||
* 审核人姓名
|
||||
*/
|
||||
private String approverName;
|
||||
|
||||
/**
|
||||
* 审核人签名
|
||||
*/
|
||||
private String approverSignImgUrl;
|
||||
|
||||
/**
|
||||
* 审核时是否存在隐患
|
||||
*/
|
||||
private Long auditHasDanger;
|
||||
|
||||
/**
|
||||
* 当次提交快照JSON
|
||||
*/
|
||||
private String submitSnapshotJson;
|
||||
|
||||
/**
|
||||
* 排查内容JSON
|
||||
*/
|
||||
private String checkContentJson;
|
||||
|
||||
/**
|
||||
* 隐患描述
|
||||
*/
|
||||
private String dangerDesc;
|
||||
|
||||
/**
|
||||
* 附件
|
||||
*/
|
||||
private String attachmentUrl;
|
||||
|
||||
/**
|
||||
* 排查人签名
|
||||
*/
|
||||
private String signImgUrl;
|
||||
|
||||
/**
|
||||
* 排查人ID
|
||||
*/
|
||||
private String checkerId;
|
||||
|
||||
/**
|
||||
* 排查人姓名
|
||||
*/
|
||||
private String checkerName;
|
||||
|
||||
/**
|
||||
* 排查日期
|
||||
*/
|
||||
private Date checkDate;
|
||||
|
||||
/**
|
||||
* 0=正常,1=已删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Long isDeleted;
|
||||
}
|
||||
@@ -86,6 +86,16 @@ public class HotHiddenDangerInspectionBo extends BaseEntity {
|
||||
// @NotNull(message = "排查日期不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Date checkDate;
|
||||
|
||||
/**
|
||||
* 是否补查期间处理:0否 1是
|
||||
*/
|
||||
private Long isRecheckProcessed;
|
||||
|
||||
/**
|
||||
* 补查处理时间
|
||||
*/
|
||||
private Date recheckProcessedTime;
|
||||
|
||||
/**
|
||||
* 评估人id
|
||||
*/
|
||||
@@ -159,6 +169,41 @@ public class HotHiddenDangerInspectionBo extends BaseEntity {
|
||||
*/
|
||||
private String flowStatus;
|
||||
|
||||
/**
|
||||
* 提交版本号
|
||||
*/
|
||||
private Long submitVersion;
|
||||
|
||||
/**
|
||||
* 审核结果(PASS=通过 REJECT=驳回)
|
||||
*/
|
||||
private String auditResult;
|
||||
|
||||
/**
|
||||
* 驳回次数
|
||||
*/
|
||||
private Long rejectCount;
|
||||
|
||||
/**
|
||||
* 最近一次驳回原因
|
||||
*/
|
||||
private String lastRejectReason;
|
||||
|
||||
/**
|
||||
* 最近一次驳回时间
|
||||
*/
|
||||
private Date lastRejectTime;
|
||||
|
||||
/**
|
||||
* 最近一次驳回人ID
|
||||
*/
|
||||
private Long lastRejectById;
|
||||
|
||||
/**
|
||||
* 最近一次驳回人姓名
|
||||
*/
|
||||
private String lastRejectByName;
|
||||
|
||||
|
||||
/**
|
||||
* 流程任务ID
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.hotwj.platform.securityManagement.hiddenDangerInspection.domain.vo;
|
||||
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerInspection.domain.HotHiddenDangerInspectionAuditHistory;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 隐患排查审核驳回历史视图对象
|
||||
*
|
||||
* @author shihongwei
|
||||
* @date 2026-05-30
|
||||
*/
|
||||
@Data
|
||||
@AutoMapper(target = HotHiddenDangerInspectionAuditHistory.class)
|
||||
public class HotHiddenDangerInspectionAuditHistoryVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
|
||||
private Long inspectionId;
|
||||
|
||||
private Long companyId;
|
||||
|
||||
private Long planId;
|
||||
|
||||
private String projectName;
|
||||
|
||||
private String projectId;
|
||||
|
||||
private Long projectType;
|
||||
|
||||
private Long submitVersion;
|
||||
|
||||
private Long auditRound;
|
||||
|
||||
private String auditResult;
|
||||
|
||||
private String rejectReason;
|
||||
|
||||
private Date auditDate;
|
||||
|
||||
private Long approverId;
|
||||
|
||||
private String approverName;
|
||||
|
||||
private String approverSignImgUrl;
|
||||
|
||||
private Long auditHasDanger;
|
||||
|
||||
private String submitSnapshotJson;
|
||||
|
||||
private String checkContentJson;
|
||||
|
||||
private String dangerDesc;
|
||||
|
||||
private String attachmentUrl;
|
||||
|
||||
private String signImgUrl;
|
||||
|
||||
private String checkerId;
|
||||
|
||||
private String checkerName;
|
||||
|
||||
private Date checkDate;
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
@@ -93,6 +94,18 @@ public class HotHiddenDangerInspectionVo implements Serializable {
|
||||
@ExcelProperty(value = "排查日期")
|
||||
private Date checkDate;
|
||||
|
||||
/**
|
||||
* 是否补查期间处理:0否 1是
|
||||
*/
|
||||
@ExcelProperty(value = "是否补查期间处理")
|
||||
private Long isRecheckProcessed;
|
||||
|
||||
/**
|
||||
* 补查处理时间
|
||||
*/
|
||||
@ExcelProperty(value = "补查处理时间")
|
||||
private Date recheckProcessedTime;
|
||||
|
||||
/**
|
||||
* 评估人id
|
||||
*/
|
||||
@@ -178,6 +191,41 @@ public class HotHiddenDangerInspectionVo implements Serializable {
|
||||
@ExcelProperty(value = "流程状态")
|
||||
private String flowStatus;
|
||||
|
||||
/**
|
||||
* 提交版本号
|
||||
*/
|
||||
private Long submitVersion;
|
||||
|
||||
/**
|
||||
* 审核结果(PASS=通过 REJECT=驳回)
|
||||
*/
|
||||
private String auditResult;
|
||||
|
||||
/**
|
||||
* 驳回次数
|
||||
*/
|
||||
private Long rejectCount;
|
||||
|
||||
/**
|
||||
* 最近一次驳回原因
|
||||
*/
|
||||
private String lastRejectReason;
|
||||
|
||||
/**
|
||||
* 最近一次驳回时间
|
||||
*/
|
||||
private Date lastRejectTime;
|
||||
|
||||
/**
|
||||
* 最近一次驳回人ID
|
||||
*/
|
||||
private Long lastRejectById;
|
||||
|
||||
/**
|
||||
* 最近一次驳回人姓名
|
||||
*/
|
||||
private String lastRejectByName;
|
||||
|
||||
/**
|
||||
* 流程任务ID
|
||||
*/
|
||||
@@ -192,4 +240,9 @@ public class HotHiddenDangerInspectionVo implements Serializable {
|
||||
private Integer todoSortGroup;
|
||||
|
||||
private String todoSortLabel;
|
||||
|
||||
/**
|
||||
* 审核不通过历史
|
||||
*/
|
||||
private List<HotHiddenDangerInspectionAuditHistoryVo> rejectHistoryList;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.hotwj.platform.securityManagement.hiddenDangerInspection.mapper;
|
||||
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerInspection.domain.HotHiddenDangerInspectionAuditHistory;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerInspection.domain.vo.HotHiddenDangerInspectionAuditHistoryVo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 隐患排查审核驳回历史Mapper接口
|
||||
*
|
||||
* @author shihongwei
|
||||
* @date 2026-05-30
|
||||
*/
|
||||
@Mapper
|
||||
public interface HotHiddenDangerInspectionAuditHistoryMapper
|
||||
extends BaseMapperPlus<HotHiddenDangerInspectionAuditHistory, HotHiddenDangerInspectionAuditHistoryVo> {
|
||||
}
|
||||
@@ -23,6 +23,6 @@ public interface HotHiddenDangerInspectionMapper extends BaseMapperPlus<HotHidde
|
||||
@Param("isAdmin") Boolean isAdmin,
|
||||
@Param("driverId") String driverId,
|
||||
@Param("vehicleId") String vehicleId,
|
||||
@Param("keyword") String keyword,
|
||||
@Param("currentMonth") String currentMonth);
|
||||
@Param("planId") Long planId,
|
||||
@Param("keyword") String keyword);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public interface IHotHiddenDangerInspectionService {
|
||||
*/
|
||||
TableDataInfo<HotHiddenDangerInspectionVo> queryPageList(HotHiddenDangerInspectionBo bo, PageQuery pageQuery);
|
||||
|
||||
TableDataInfo<HotHiddenDangerInspectionVo> queryMobilePlanPage(String keyword, PageQuery pageQuery);
|
||||
TableDataInfo<HotHiddenDangerInspectionVo> queryMobilePlanPage(String keyword, Long planId, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的隐患排查-排查项目列表
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.hotwj.platform.securityManagement.hiddenDangerInspection.service.impl;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
@@ -10,9 +11,15 @@ import com.hotwj.platform.integration.ocr.SignatureVerifyService;
|
||||
import com.hotwj.platform.noticeManagerment.systemNotification.domain.bo.HotSystemNotificationGroupBo;
|
||||
import com.hotwj.platform.noticeManagerment.systemNotification.service.IHotSystemNotificationService;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerInspection.domain.HotHiddenDangerInspection;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerInspection.domain.HotHiddenDangerInspectionAuditHistory;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerInspection.domain.bo.HotHiddenDangerInspectionBo;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerInspection.domain.vo.HotHiddenDangerInspectionAuditHistoryVo;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerInspection.domain.vo.HotHiddenDangerInspectionVo;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerInspection.mapper.HotHiddenDangerInspectionAuditHistoryMapper;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerInspection.mapper.HotHiddenDangerInspectionMapper;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerPlan.domain.HotHiddenDangerPlan;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerPlan.mapper.HotHiddenDangerPlanMapper;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerPlan.service.HiddenDangerPlanTimeWindowHelper;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerInspection.service.IHotHiddenDangerInspectionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -25,8 +32,9 @@ import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.YearMonth;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -42,9 +50,12 @@ import java.util.Map;
|
||||
public class HotHiddenDangerInspectionServiceImpl implements IHotHiddenDangerInspectionService {
|
||||
|
||||
private final HotHiddenDangerInspectionMapper baseMapper;
|
||||
private final HotHiddenDangerInspectionAuditHistoryMapper historyMapper;
|
||||
private final ISysFlowService flowService;
|
||||
private final IHotSystemNotificationService notificationService;
|
||||
private final SignatureVerifyService signatureVerifyService;
|
||||
private final HotHiddenDangerPlanMapper planMapper;
|
||||
private final HiddenDangerPlanTimeWindowHelper timeWindowHelper;
|
||||
|
||||
/**
|
||||
* 查询隐患排查-排查项目
|
||||
@@ -55,10 +66,11 @@ public class HotHiddenDangerInspectionServiceImpl implements IHotHiddenDangerIns
|
||||
@Override
|
||||
public HotHiddenDangerInspectionVo queryById(Long id) {
|
||||
HotHiddenDangerInspectionVo vo = baseMapper.selectVoById(id);
|
||||
if (vo != null && StringUtils.isNotBlank(vo.getInstanceId())) {
|
||||
String userId = LoginHelper.getBusinessUserId();
|
||||
vo.setTaskId(flowService.getTaskId(vo.getInstanceId(), userId));
|
||||
if (vo == null) {
|
||||
return null;
|
||||
}
|
||||
vo.setRejectHistoryList(queryRejectHistoryList(id));
|
||||
fillTaskId(vo, LoginHelper.getBusinessUserId());
|
||||
return vo;
|
||||
}
|
||||
|
||||
@@ -80,7 +92,7 @@ public class HotHiddenDangerInspectionServiceImpl implements IHotHiddenDangerIns
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<HotHiddenDangerInspectionVo> queryMobilePlanPage(String keyword, PageQuery pageQuery) {
|
||||
public TableDataInfo<HotHiddenDangerInspectionVo> queryMobilePlanPage(String keyword, Long planId, PageQuery pageQuery) {
|
||||
Long companyId = LoginHelper.getCompanyId();
|
||||
if (companyId == null) {
|
||||
throw new ServiceException("当前登录用户无公司信息");
|
||||
@@ -93,7 +105,6 @@ public class HotHiddenDangerInspectionServiceImpl implements IHotHiddenDangerIns
|
||||
driverId = driver.getId();
|
||||
vehicleId = driver.getVehicleId();
|
||||
}
|
||||
String currentMonth = YearMonth.now().toString();
|
||||
Page<HotHiddenDangerInspectionVo> page = pageQuery.build();
|
||||
List<HotHiddenDangerInspectionVo> rows = baseMapper.selectMobilePlanPage(
|
||||
page,
|
||||
@@ -101,8 +112,8 @@ public class HotHiddenDangerInspectionServiceImpl implements IHotHiddenDangerIns
|
||||
!isDriver,
|
||||
driverId,
|
||||
vehicleId,
|
||||
StringUtils.trimToNull(keyword),
|
||||
currentMonth
|
||||
planId,
|
||||
StringUtils.trimToNull(keyword)
|
||||
);
|
||||
page.setRecords(rows);
|
||||
fillFlowExtras(rows);
|
||||
@@ -156,11 +167,11 @@ public class HotHiddenDangerInspectionServiceImpl implements IHotHiddenDangerIns
|
||||
if (vo == null) {
|
||||
continue;
|
||||
}
|
||||
if (StringUtils.isNotBlank(vo.getInstanceId())) {
|
||||
vo.setTaskId(flowService.getTaskId(vo.getInstanceId(), userId));
|
||||
}
|
||||
fillTaskId(vo, userId);
|
||||
if (StringUtils.isBlank(vo.getFlowStatus())) {
|
||||
if (vo.getStatus() == null || vo.getStatus() == 0L) {
|
||||
if ("REJECT".equalsIgnoreCase(vo.getAuditResult())) {
|
||||
vo.setFlowStatus("REJECTED");
|
||||
} else if (vo.getStatus() == null || vo.getStatus() == 0L || vo.getStatus() == 1L) {
|
||||
vo.setFlowStatus("TODO");
|
||||
} else if (vo.getStatus() == 3L || vo.getStatus() == 9L) {
|
||||
vo.setFlowStatus("DONE");
|
||||
@@ -195,36 +206,66 @@ public class HotHiddenDangerInspectionServiceImpl implements IHotHiddenDangerIns
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean updateByBo(HotHiddenDangerInspectionBo bo) {
|
||||
HotHiddenDangerInspection original = baseMapper.selectById(bo.getId());
|
||||
if (original == null) {
|
||||
throw new ServiceException("排查记录不存在");
|
||||
}
|
||||
HotHiddenDangerPlan plan = getPlanByInspectionOrThrow(original);
|
||||
Date now = new Date();
|
||||
if (!timeWindowHelper.canProcess(now, plan)) {
|
||||
throw new ServiceException("当前计划未处于可处理时间范围内");
|
||||
}
|
||||
HotHiddenDangerInspection update = MapstructUtils.convert(bo, HotHiddenDangerInspection.class);
|
||||
validEntityBeforeSave(update);
|
||||
markRecheckProcessIfNeeded(update, original, plan, now);
|
||||
String signImgUrl = bo.getSignImgUrl();
|
||||
if (DriverLoginContextHelper.isDriverPort() && StringUtils.isNotBlank(signImgUrl)) {
|
||||
String checkerName = bo.getCheckerName();
|
||||
|
||||
if (original == null || StringUtils.isBlank(checkerName)) {
|
||||
if (StringUtils.isBlank(checkerName)) {
|
||||
throw new ServiceException("排查人姓名不能为空");
|
||||
}
|
||||
signatureVerifyService.validateSelfSignature(parseSignatureOssId(signImgUrl), checkerName);
|
||||
}
|
||||
boolean flag = baseMapper.updateById(update) > 0;
|
||||
if (flag && (original == null || StringUtils.isBlank(original.getInstanceId()))) {
|
||||
if (flag && shouldResumeRejectedFlow(original)) {
|
||||
resumeRejectedFlow(original);
|
||||
} else if (flag && shouldStartAuditFlow(original)) {
|
||||
String initiator = String.valueOf(LoginHelper.getBusinessUserId());
|
||||
String approverId = bo.getApproverId() != null ? String.valueOf(bo.getApproverId()) : null;
|
||||
if (StringUtils.isBlank(approverId)) {
|
||||
throw new ServiceException("请选择审核人");
|
||||
}
|
||||
Long nextSubmitVersion = buildNextSubmitVersion(original);
|
||||
String instanceId = flowService.startFlow(
|
||||
"HIDDEN_DANGER_CHECK",
|
||||
String.valueOf(update.getId()),
|
||||
update.getCompanyId(),
|
||||
String.valueOf(original.getId()),
|
||||
original.getCompanyId(),
|
||||
initiator,
|
||||
approverId
|
||||
);
|
||||
update.setInstanceId(instanceId);
|
||||
update.setFlowStatus("SUBMITTED");
|
||||
baseMapper.updateById(update);
|
||||
baseMapper.update(
|
||||
null,
|
||||
Wrappers.<HotHiddenDangerInspection>lambdaUpdate()
|
||||
.eq(HotHiddenDangerInspection::getId, original.getId())
|
||||
.set(HotHiddenDangerInspection::getStatus, 2L)
|
||||
.set(HotHiddenDangerInspection::getInstanceId, instanceId)
|
||||
.set(HotHiddenDangerInspection::getFlowStatus, "SUBMITTED")
|
||||
.set(HotHiddenDangerInspection::getSubmitVersion, nextSubmitVersion)
|
||||
.set(HotHiddenDangerInspection::getAuditDate, null)
|
||||
.set(HotHiddenDangerInspection::getAuditConclusion, null)
|
||||
.set(HotHiddenDangerInspection::getApproverSignImgUrl, null)
|
||||
.set(HotHiddenDangerInspection::getAuditHasDanger, null)
|
||||
.set(HotHiddenDangerInspection::getAuditResult, null)
|
||||
.set(HotHiddenDangerInspection::getEvaluatorId, null)
|
||||
.set(HotHiddenDangerInspection::getEvaluatorName, null)
|
||||
.set(HotHiddenDangerInspection::getLastRejectReason, null)
|
||||
.set(HotHiddenDangerInspection::getLastRejectTime, null)
|
||||
.set(HotHiddenDangerInspection::getLastRejectById, null)
|
||||
.set(HotHiddenDangerInspection::getLastRejectByName, null)
|
||||
);
|
||||
|
||||
try {
|
||||
HotSystemNotificationGroupBo bos = new HotSystemNotificationGroupBo();
|
||||
@@ -242,6 +283,25 @@ public class HotHiddenDangerInspectionServiceImpl implements IHotHiddenDangerIns
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
/**
|
||||
* 标记是否需要补查处理
|
||||
*/
|
||||
private void markRecheckProcessIfNeeded(HotHiddenDangerInspection update,
|
||||
HotHiddenDangerInspection original,
|
||||
HotHiddenDangerPlan plan,
|
||||
Date now) {
|
||||
if (update == null || original == null || plan == null || now == null) {
|
||||
return;
|
||||
}
|
||||
if (!timeWindowHelper.isInRecheckWindow(now, plan)) {
|
||||
return;
|
||||
}
|
||||
if (Long.valueOf(1L).equals(original.getIsRecheckProcessed())) {
|
||||
return;
|
||||
}
|
||||
update.setIsRecheckProcessed(1L);
|
||||
update.setRecheckProcessedTime(now);
|
||||
}
|
||||
|
||||
private Long parseSignatureOssId(String signImgUrl) {
|
||||
String first = signImgUrl.split(",")[0].trim();
|
||||
@@ -254,26 +314,273 @@ public class HotHiddenDangerInspectionServiceImpl implements IHotHiddenDangerIns
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void audit(HotHiddenDangerInspectionBo bo) {
|
||||
// 1. 校验参数
|
||||
if (bo.getTaskId() == null) {
|
||||
if (StringUtils.isBlank(bo.getTaskId())) {
|
||||
throw new ServiceException("流程任务ID不能为空");
|
||||
}
|
||||
|
||||
// 2. 更新业务数据
|
||||
HotHiddenDangerInspection update = MapstructUtils.convert(bo, HotHiddenDangerInspection.class);
|
||||
boolean flag = baseMapper.updateById(update) > 0;
|
||||
|
||||
if (flag) {
|
||||
// 4. 完成流程任务
|
||||
// 如果有隐患,我们认为流程是"驳回"的(需要整改)
|
||||
boolean auditPass = bo.getAuditHasDanger() != null && bo.getAuditHasDanger() == 0L;
|
||||
flowService.audit(
|
||||
bo.getTaskId(),
|
||||
auditPass,
|
||||
bo.getAuditConclusion(),
|
||||
LoginHelper.getBusinessUserId()
|
||||
);
|
||||
if (bo.getId() == null) {
|
||||
throw new ServiceException("排查记录ID不能为空");
|
||||
}
|
||||
HotHiddenDangerInspection original = baseMapper.selectById(bo.getId());
|
||||
if (original == null) {
|
||||
throw new ServiceException("排查记录不存在");
|
||||
}
|
||||
String auditResult = normalizeAuditResult(bo);
|
||||
String auditConclusion = StringUtils.trimToNull(bo.getAuditConclusion());
|
||||
Date auditDate = bo.getAuditDate() != null ? bo.getAuditDate() : new Date();
|
||||
if ("PASS".equals(auditResult)) {
|
||||
if (bo.getAuditHasDanger() == null) {
|
||||
throw new ServiceException("请选择是否存在隐患");
|
||||
}
|
||||
if (bo.getAuditHasDanger() == 1L && bo.getEvaluatorId() == null) {
|
||||
throw new ServiceException("请选择评估人");
|
||||
}
|
||||
baseMapper.update(
|
||||
null,
|
||||
Wrappers.<HotHiddenDangerInspection>lambdaUpdate()
|
||||
.eq(HotHiddenDangerInspection::getId, original.getId())
|
||||
.set(HotHiddenDangerInspection::getApproverId, bo.getApproverId())
|
||||
.set(HotHiddenDangerInspection::getApproverName, bo.getApproverName())
|
||||
.set(HotHiddenDangerInspection::getAuditDate, auditDate)
|
||||
.set(HotHiddenDangerInspection::getAuditConclusion, auditConclusion)
|
||||
.set(HotHiddenDangerInspection::getApproverSignImgUrl, bo.getApproverSignImgUrl())
|
||||
.set(HotHiddenDangerInspection::getAuditHasDanger, bo.getAuditHasDanger())
|
||||
.set(HotHiddenDangerInspection::getEvaluatorId, bo.getEvaluatorId())
|
||||
.set(HotHiddenDangerInspection::getEvaluatorName, bo.getEvaluatorName())
|
||||
.set(HotHiddenDangerInspection::getAuditResult, "PASS")
|
||||
);
|
||||
flowService.audit(
|
||||
bo.getTaskId(),
|
||||
true,
|
||||
auditConclusion,
|
||||
LoginHelper.getBusinessUserId()
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isBlank(auditConclusion)) {
|
||||
throw new ServiceException("审核不通过原因不能为空");
|
||||
}
|
||||
|
||||
long nextRejectCount = original.getRejectCount() == null ? 1L : original.getRejectCount() + 1L;
|
||||
baseMapper.update(
|
||||
null,
|
||||
Wrappers.<HotHiddenDangerInspection>lambdaUpdate()
|
||||
.eq(HotHiddenDangerInspection::getId, original.getId())
|
||||
.set(HotHiddenDangerInspection::getApproverId, bo.getApproverId())
|
||||
.set(HotHiddenDangerInspection::getApproverName, bo.getApproverName())
|
||||
.set(HotHiddenDangerInspection::getStatus, 10L)
|
||||
.set(HotHiddenDangerInspection::getFlowStatus, "REJECTED")
|
||||
.set(HotHiddenDangerInspection::getAuditDate, auditDate)
|
||||
.set(HotHiddenDangerInspection::getAuditConclusion, auditConclusion)
|
||||
.set(HotHiddenDangerInspection::getApproverSignImgUrl, bo.getApproverSignImgUrl())
|
||||
.set(HotHiddenDangerInspection::getAuditHasDanger, null)
|
||||
.set(HotHiddenDangerInspection::getEvaluatorId, null)
|
||||
.set(HotHiddenDangerInspection::getEvaluatorName, null)
|
||||
.set(HotHiddenDangerInspection::getAuditResult, "REJECT")
|
||||
.set(HotHiddenDangerInspection::getRejectCount, nextRejectCount)
|
||||
.set(HotHiddenDangerInspection::getLastRejectReason, auditConclusion)
|
||||
.set(HotHiddenDangerInspection::getLastRejectTime, auditDate)
|
||||
.set(HotHiddenDangerInspection::getLastRejectById, bo.getApproverId())
|
||||
.set(HotHiddenDangerInspection::getLastRejectByName, bo.getApproverName())
|
||||
);
|
||||
bo.setAuditConclusion(auditConclusion);
|
||||
saveRejectHistory(original, bo, nextRejectCount, auditDate);
|
||||
flowService.audit(
|
||||
bo.getTaskId(),
|
||||
false,
|
||||
auditConclusion,
|
||||
LoginHelper.getBusinessUserId()
|
||||
);
|
||||
}
|
||||
|
||||
private boolean shouldStartAuditFlow(HotHiddenDangerInspection original) {
|
||||
if (original == null || StringUtils.isNotBlank(original.getInstanceId())) {
|
||||
return false;
|
||||
}
|
||||
Long status = original.getStatus();
|
||||
return status == null || status == 0L || status == 1L || status == 10L || "REJECTED".equalsIgnoreCase(original.getFlowStatus());
|
||||
}
|
||||
|
||||
private boolean shouldResumeRejectedFlow(HotHiddenDangerInspection original) {
|
||||
if (original == null || StringUtils.isBlank(original.getInstanceId())) {
|
||||
return false;
|
||||
}
|
||||
Long status = original.getStatus();
|
||||
return status != null && status == 10L && "REJECTED".equalsIgnoreCase(original.getFlowStatus());
|
||||
}
|
||||
|
||||
private void resumeRejectedFlow(HotHiddenDangerInspection original) {
|
||||
String currentUserId = LoginHelper.getBusinessUserId();
|
||||
String taskId = flowService.getTaskId(original.getInstanceId(), currentUserId);
|
||||
if (StringUtils.isBlank(taskId)) {
|
||||
taskId = flowService.getTaskIdByBusinessId("HIDDEN_DANGER_CHECK", String.valueOf(original.getId()), currentUserId);
|
||||
}
|
||||
if (StringUtils.isBlank(taskId)) {
|
||||
taskId = flowService.getCurrentTaskIdByBusinessId("HIDDEN_DANGER_CHECK", String.valueOf(original.getId()));
|
||||
}
|
||||
if (StringUtils.isBlank(taskId)) {
|
||||
throw new ServiceException("当前记录未找到待处理任务,无法重新提交");
|
||||
}
|
||||
String submitOperatorId = currentUserId;
|
||||
var task = flowService.getTaskById(taskId);
|
||||
if (task == null) {
|
||||
throw new ServiceException("当前记录未找到待处理任务,无法重新提交");
|
||||
}
|
||||
if (!StringUtils.equals(task.getApproverId(), currentUserId)) {
|
||||
if (!DriverLoginContextHelper.isDriverPort() && !canResubmitRejectedRecord(original, currentUserId)) {
|
||||
throw new ServiceException("当前用户无权重新提交该记录");
|
||||
}
|
||||
submitOperatorId = task.getApproverId();
|
||||
}
|
||||
baseMapper.update(
|
||||
null,
|
||||
Wrappers.<HotHiddenDangerInspection>lambdaUpdate()
|
||||
.eq(HotHiddenDangerInspection::getId, original.getId())
|
||||
.set(HotHiddenDangerInspection::getStatus, 2L)
|
||||
.set(HotHiddenDangerInspection::getFlowStatus, "SUBMITTED")
|
||||
.set(HotHiddenDangerInspection::getAuditDate, null)
|
||||
.set(HotHiddenDangerInspection::getAuditConclusion, null)
|
||||
.set(HotHiddenDangerInspection::getApproverSignImgUrl, null)
|
||||
.set(HotHiddenDangerInspection::getAuditHasDanger, null)
|
||||
.set(HotHiddenDangerInspection::getAuditResult, null)
|
||||
.set(HotHiddenDangerInspection::getEvaluatorId, null)
|
||||
.set(HotHiddenDangerInspection::getEvaluatorName, null)
|
||||
);
|
||||
flowService.audit(taskId, true, "重新提交", submitOperatorId);
|
||||
}
|
||||
|
||||
private boolean canResubmitRejectedRecord(HotHiddenDangerInspection original, String currentUserId) {
|
||||
if (original == null || StringUtils.isBlank(currentUserId)) {
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.equals(original.getCheckerId(), currentUserId)) {
|
||||
return true;
|
||||
}
|
||||
if (original.getCreateBy() != null && StringUtils.equals(String.valueOf(original.getCreateBy()), currentUserId)) {
|
||||
return true;
|
||||
}
|
||||
if (DriverLoginContextHelper.isDriverPort()) {
|
||||
try {
|
||||
HotDriver currentDriver = DriverLoginContextHelper.getCurrentDriver();
|
||||
if (currentDriver != null && StringUtils.equals(currentDriver.getId(), original.getCheckerId())) {
|
||||
return true;
|
||||
}
|
||||
if (currentDriver != null && original.getCreateBy() != null
|
||||
&& StringUtils.equals(currentDriver.getId(), String.valueOf(original.getCreateBy()))) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Resolve current driver for hidden danger resubmit failed, inspectionId={}", original.getId(), e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Long buildNextSubmitVersion(HotHiddenDangerInspection original) {
|
||||
if (original == null || original.getSubmitVersion() == null || original.getSubmitVersion() < 1L) {
|
||||
return 1L;
|
||||
}
|
||||
return original.getSubmitVersion() + 1L;
|
||||
}
|
||||
|
||||
private String normalizeAuditResult(HotHiddenDangerInspectionBo bo) {
|
||||
if (StringUtils.isNotBlank(bo.getAuditResult())) {
|
||||
return bo.getAuditResult().trim().toUpperCase();
|
||||
}
|
||||
if (bo.getAuditHasDanger() != null && bo.getAuditHasDanger() == 0L) {
|
||||
return "PASS";
|
||||
}
|
||||
return "REJECT";
|
||||
}
|
||||
|
||||
private void saveRejectHistory(HotHiddenDangerInspection original, HotHiddenDangerInspectionBo bo, Long auditRound, Date auditDate) {
|
||||
HotHiddenDangerInspectionAuditHistory history = new HotHiddenDangerInspectionAuditHistory();
|
||||
history.setInspectionId(original.getId());
|
||||
history.setCompanyId(original.getCompanyId());
|
||||
history.setPlanId(original.getPlanId());
|
||||
history.setProjectName(original.getProjectName());
|
||||
history.setProjectId(original.getProjectId());
|
||||
history.setProjectType(original.getProjectType());
|
||||
history.setSubmitVersion(original.getSubmitVersion() == null ? 1L : original.getSubmitVersion());
|
||||
history.setAuditRound(auditRound);
|
||||
history.setAuditResult("REJECT");
|
||||
history.setRejectReason(bo.getAuditConclusion());
|
||||
history.setAuditDate(auditDate);
|
||||
history.setApproverId(bo.getApproverId());
|
||||
history.setApproverName(bo.getApproverName());
|
||||
history.setApproverSignImgUrl(bo.getApproverSignImgUrl());
|
||||
history.setAuditHasDanger(bo.getAuditHasDanger());
|
||||
history.setSubmitSnapshotJson(buildSubmitSnapshotJson(original));
|
||||
history.setCheckContentJson(original.getCheckContentJson());
|
||||
history.setDangerDesc(original.getDangerDesc());
|
||||
history.setAttachmentUrl(original.getAttachmentUrl());
|
||||
history.setSignImgUrl(original.getSignImgUrl());
|
||||
history.setCheckerId(original.getCheckerId());
|
||||
history.setCheckerName(original.getCheckerName());
|
||||
history.setCheckDate(original.getCheckDate());
|
||||
historyMapper.insert(history);
|
||||
}
|
||||
|
||||
private String buildSubmitSnapshotJson(HotHiddenDangerInspection original) {
|
||||
Map<String, Object> snapshot = new LinkedHashMap<>();
|
||||
snapshot.put("inspectionId", original.getId());
|
||||
snapshot.put("companyId", original.getCompanyId());
|
||||
snapshot.put("planId", original.getPlanId());
|
||||
snapshot.put("projectName", original.getProjectName());
|
||||
snapshot.put("projectId", original.getProjectId());
|
||||
snapshot.put("projectType", original.getProjectType());
|
||||
snapshot.put("submitVersion", original.getSubmitVersion());
|
||||
snapshot.put("checkContentJson", original.getCheckContentJson());
|
||||
snapshot.put("dangerDesc", original.getDangerDesc());
|
||||
snapshot.put("attachmentUrl", original.getAttachmentUrl());
|
||||
snapshot.put("signImgUrl", original.getSignImgUrl());
|
||||
snapshot.put("checkerId", original.getCheckerId());
|
||||
snapshot.put("checkerName", original.getCheckerName());
|
||||
snapshot.put("checkDate", original.getCheckDate());
|
||||
return JSONUtil.toJsonStr(snapshot);
|
||||
}
|
||||
|
||||
private List<HotHiddenDangerInspectionAuditHistoryVo> queryRejectHistoryList(Long inspectionId) {
|
||||
return historyMapper.selectVoList(
|
||||
Wrappers.<HotHiddenDangerInspectionAuditHistory>lambdaQuery()
|
||||
.eq(HotHiddenDangerInspectionAuditHistory::getInspectionId, inspectionId)
|
||||
.eq(HotHiddenDangerInspectionAuditHistory::getIsDeleted, 0L)
|
||||
.orderByDesc(HotHiddenDangerInspectionAuditHistory::getAuditRound)
|
||||
.orderByDesc(HotHiddenDangerInspectionAuditHistory::getCreateTime)
|
||||
.orderByDesc(HotHiddenDangerInspectionAuditHistory::getId)
|
||||
);
|
||||
}
|
||||
|
||||
private void fillTaskId(HotHiddenDangerInspectionVo vo, String userId) {
|
||||
if (vo == null || StringUtils.isBlank(userId)) {
|
||||
return;
|
||||
}
|
||||
String taskId = null;
|
||||
if (StringUtils.isNotBlank(vo.getInstanceId())) {
|
||||
taskId = flowService.getTaskId(vo.getInstanceId(), userId);
|
||||
}
|
||||
if (StringUtils.isBlank(taskId) && vo.getId() != null) {
|
||||
taskId = flowService.getTaskIdByBusinessId("HIDDEN_DANGER_CHECK", String.valueOf(vo.getId()), userId);
|
||||
}
|
||||
if (StringUtils.isBlank(taskId) && vo.getId() != null) {
|
||||
taskId = flowService.getCurrentTaskIdByBusinessId("HIDDEN_DANGER_CHECK", String.valueOf(vo.getId()));
|
||||
}
|
||||
vo.setTaskId(taskId);
|
||||
}
|
||||
|
||||
private HotHiddenDangerPlan getPlanByInspectionOrThrow(HotHiddenDangerInspection inspection) {
|
||||
if (inspection == null || inspection.getPlanId() == null) {
|
||||
throw new ServiceException("排查计划不存在");
|
||||
}
|
||||
HotHiddenDangerPlan plan = planMapper.selectOne(
|
||||
Wrappers.<HotHiddenDangerPlan>lambdaQuery()
|
||||
.eq(HotHiddenDangerPlan::getId, inspection.getPlanId())
|
||||
.eq(HotHiddenDangerPlan::getIsDeleted, 0L)
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
if (plan == null) {
|
||||
throw new ServiceException("排查计划不存在");
|
||||
}
|
||||
return plan;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.hotwj.platform.securityManagement.hiddenDangerPlan.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerPlan.domain.bo.HotHiddenDangerPlanBo;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerPlan.domain.bo.HotHiddenDangerPlanRecheckBo;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerPlan.domain.bo.HotHiddenDangerPlanRecheckCloseBo;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerPlan.domain.vo.HotHiddenDangerPlanVo;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerPlan.service.IHotHiddenDangerPlanService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -130,6 +132,39 @@ public class HotHiddenDangerPlanController extends BaseController {
|
||||
return toAjax(hotHiddenDangerPlanService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启补查
|
||||
*/
|
||||
@Log(title = "隐患排查补查", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/recheck/open")
|
||||
@Operation(summary = "开启隐患排查补查")
|
||||
public R<Void> openRecheck(@Validated @RequestBody HotHiddenDangerPlanRecheckBo bo) {
|
||||
return toAjax(hotHiddenDangerPlanService.openRecheck(bo.getPlanId(), bo.getRecheckStartTime(), bo.getRecheckEndTime()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改补查
|
||||
*/
|
||||
@Log(title = "隐患排查补查", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/recheck/update")
|
||||
@Operation(summary = "修改隐患排查补查")
|
||||
public R<Void> updateRecheck(@Validated @RequestBody HotHiddenDangerPlanRecheckBo bo) {
|
||||
return toAjax(hotHiddenDangerPlanService.updateRecheck(bo.getPlanId(), bo.getRecheckStartTime(), bo.getRecheckEndTime()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭补查
|
||||
*/
|
||||
@Log(title = "隐患排查补查", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/recheck/close")
|
||||
@Operation(summary = "关闭隐患排查补查")
|
||||
public R<Void> closeRecheck(@Validated @RequestBody HotHiddenDangerPlanRecheckCloseBo bo) {
|
||||
return toAjax(hotHiddenDangerPlanService.closeRecheck(bo.getPlanId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除隐患排查
|
||||
*
|
||||
|
||||
@@ -60,6 +60,21 @@ public class HotHiddenDangerPlan extends BaseEntity {
|
||||
*/
|
||||
private Date endDate;
|
||||
|
||||
/**
|
||||
* 是否开启补查:0否 1是
|
||||
*/
|
||||
private Long isRecheck;
|
||||
|
||||
/**
|
||||
* 补查开始时间
|
||||
*/
|
||||
private Date recheckStartTime;
|
||||
|
||||
/**
|
||||
* 补查结束时间
|
||||
*/
|
||||
private Date recheckEndTime;
|
||||
|
||||
/**
|
||||
* 进度 0=待处理 1=审核中 2=评估 3=治理 4=复查 5=完结
|
||||
*/
|
||||
|
||||
@@ -63,6 +63,21 @@ public class HotHiddenDangerPlanBo extends BaseEntity {
|
||||
@NotNull(message = "结束日期不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Date endDate;
|
||||
|
||||
/**
|
||||
* 是否开启补查:0否 1是
|
||||
*/
|
||||
private Long isRecheck;
|
||||
|
||||
/**
|
||||
* 补查开始时间
|
||||
*/
|
||||
private Date recheckStartTime;
|
||||
|
||||
/**
|
||||
* 补查结束时间
|
||||
*/
|
||||
private Date recheckEndTime;
|
||||
|
||||
/**
|
||||
* 进度 0=待处理 1=审核中 2=评估 3=治理 4=复查 5=完结
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.hotwj.platform.securityManagement.hiddenDangerPlan.domain.bo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 隐患排查补查开启/修改请求对象
|
||||
*
|
||||
* @author shihongwei
|
||||
* @date 2026-06-03
|
||||
*/
|
||||
@Data
|
||||
public class HotHiddenDangerPlanRecheckBo {
|
||||
|
||||
/**
|
||||
* 计划ID
|
||||
*/
|
||||
@NotNull(message = "计划ID不能为空")
|
||||
private Long planId;
|
||||
|
||||
/**
|
||||
* 补查开始时间
|
||||
*/
|
||||
@NotNull(message = "补查开始时间不能为空")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date recheckStartTime;
|
||||
|
||||
/**
|
||||
* 补查结束时间
|
||||
*/
|
||||
@NotNull(message = "补查结束时间不能为空")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date recheckEndTime;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.hotwj.platform.securityManagement.hiddenDangerPlan.domain.bo;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 隐患排查补查关闭请求对象
|
||||
*
|
||||
* @author shihongwei
|
||||
* @date 2026-06-03
|
||||
*/
|
||||
@Data
|
||||
public class HotHiddenDangerPlanRecheckCloseBo {
|
||||
|
||||
/**
|
||||
* 计划ID
|
||||
*/
|
||||
@NotNull(message = "计划ID不能为空")
|
||||
private Long planId;
|
||||
}
|
||||
@@ -67,6 +67,24 @@ public class HotHiddenDangerPlanVo implements Serializable {
|
||||
@ExcelProperty(value = "结束日期")
|
||||
private Date endDate;
|
||||
|
||||
/**
|
||||
* 是否开启补查:0否 1是
|
||||
*/
|
||||
@ExcelProperty(value = "是否开启补查")
|
||||
private Long isRecheck;
|
||||
|
||||
/**
|
||||
* 补查开始时间
|
||||
*/
|
||||
@ExcelProperty(value = "补查开始时间")
|
||||
private Date recheckStartTime;
|
||||
|
||||
/**
|
||||
* 补查结束时间
|
||||
*/
|
||||
@ExcelProperty(value = "补查结束时间")
|
||||
private Date recheckEndTime;
|
||||
|
||||
/**
|
||||
* 进度 0=待处理 1=审核中 2=评估 3=治理 4=复查 5=完结
|
||||
*/
|
||||
@@ -97,5 +115,23 @@ public class HotHiddenDangerPlanVo implements Serializable {
|
||||
@ExcelProperty(value = "计划周期Key")
|
||||
private String planDateKey;
|
||||
|
||||
/**
|
||||
* 已完成数
|
||||
*/
|
||||
@ExcelProperty(value = "已完成数")
|
||||
private Long completedCount;
|
||||
|
||||
/**
|
||||
* 未完成数
|
||||
*/
|
||||
@ExcelProperty(value = "未完成数")
|
||||
private Long pendingCount;
|
||||
|
||||
/**
|
||||
* 待审核人数
|
||||
*/
|
||||
@ExcelProperty(value = "待审核人数")
|
||||
private Long pendingAuditCount;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -2,9 +2,15 @@ package com.hotwj.platform.securityManagement.hiddenDangerPlan.mapper;
|
||||
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerPlan.domain.HotHiddenDangerPlan;
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerPlan.domain.vo.HotHiddenDangerPlanVo;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 隐患排查Mapper接口
|
||||
*
|
||||
@@ -14,4 +20,8 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
@Mapper
|
||||
public interface HotHiddenDangerPlanMapper extends BaseMapperPlus<HotHiddenDangerPlan, HotHiddenDangerPlanVo> {
|
||||
|
||||
Page<HotHiddenDangerPlanVo> queryPageList(Page<HotHiddenDangerPlanVo> page,
|
||||
@Param(Constants.WRAPPER) Wrapper<HotHiddenDangerPlan> queryWrapper);
|
||||
|
||||
List<HotHiddenDangerPlanVo> queryList(@Param(Constants.WRAPPER) Wrapper<HotHiddenDangerPlan> queryWrapper);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.hotwj.platform.securityManagement.hiddenDangerPlan.service;
|
||||
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerPlan.domain.HotHiddenDangerPlan;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 隐患排查计划时间窗口判定
|
||||
*
|
||||
* @author shihongwei
|
||||
* @date 2026-06-03
|
||||
*/
|
||||
@Component
|
||||
public class HiddenDangerPlanTimeWindowHelper {
|
||||
|
||||
/**
|
||||
* 是否在原始时间窗口内
|
||||
*/
|
||||
public boolean isInOriginalWindow(Date now, HotHiddenDangerPlan plan) {
|
||||
if (now == null || plan == null || plan.getStartDate() == null || plan.getEndDate() == null) {
|
||||
return false;
|
||||
}
|
||||
return !now.before(plan.getStartDate()) && !now.after(plan.getEndDate());
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否在补查时间窗口内
|
||||
*/
|
||||
public boolean isInRecheckWindow(Date now, HotHiddenDangerPlan plan) {
|
||||
if (now == null || plan == null) {
|
||||
return false;
|
||||
}
|
||||
if (!Long.valueOf(1L).equals(plan.getIsRecheck())) {
|
||||
return false;
|
||||
}
|
||||
if (plan.getRecheckStartTime() == null || plan.getRecheckEndTime() == null) {
|
||||
return false;
|
||||
}
|
||||
return !now.before(plan.getRecheckStartTime()) && !now.after(plan.getRecheckEndTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否在有效时间窗口内
|
||||
*/
|
||||
public boolean isInEffectiveWindow(Date now, HotHiddenDangerPlan plan) {
|
||||
return isInOriginalWindow(now, plan) || isInRecheckWindow(now, plan);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否可以在有效时间窗口内处理
|
||||
*/
|
||||
public boolean canProcess(Date now, HotHiddenDangerPlan plan) {
|
||||
return isInEffectiveWindow(now, plan);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否应该在司机端展示
|
||||
*/
|
||||
public boolean shouldDisplayToDriver(Date now, HotHiddenDangerPlan plan) {
|
||||
return isInEffectiveWindow(now, plan);
|
||||
}
|
||||
}
|
||||
@@ -69,6 +69,34 @@ public interface IHotHiddenDangerPlanService {
|
||||
*/
|
||||
void generatePlan(Long companyId);
|
||||
|
||||
/**
|
||||
* 开启补查
|
||||
*
|
||||
* @param planId 计划ID
|
||||
* @param recheckStartTime 补查开始时间
|
||||
* @param recheckEndTime 补查结束时间
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean openRecheck(Long planId, java.util.Date recheckStartTime, java.util.Date recheckEndTime);
|
||||
|
||||
/**
|
||||
* 修改补查
|
||||
*
|
||||
* @param planId 计划ID
|
||||
* @param recheckStartTime 补查开始时间
|
||||
* @param recheckEndTime 补查结束时间
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean updateRecheck(Long planId, java.util.Date recheckStartTime, java.util.Date recheckEndTime);
|
||||
|
||||
/**
|
||||
* 关闭补查
|
||||
*
|
||||
* @param planId 计划ID
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean closeRecheck(Long planId);
|
||||
|
||||
/**
|
||||
* 校验并批量删除隐患排查信息
|
||||
*
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.hotwj.platform.config.hiddenDangerCheckConfig.service.IHotHiddenDange
|
||||
import com.hotwj.platform.driverManagement.driver.domain.bo.HotDriverBo;
|
||||
import com.hotwj.platform.driverManagement.driver.domain.vo.HotDriverVo;
|
||||
import com.hotwj.platform.driverManagement.driver.service.IHotDriverService;
|
||||
import com.hotwj.platform.common.helper.DriverLoginContextHelper;
|
||||
import com.hotwj.platform.noticeManagerment.systemNotification.domain.bo.HotSystemNotificationGroupBo;
|
||||
import com.hotwj.platform.noticeManagerment.systemNotification.service.IHotSystemNotificationService;
|
||||
import com.hotwj.platform.resourceManagement.company.domain.vo.SysCompanyVo;
|
||||
@@ -33,6 +34,7 @@ import com.hotwj.platform.securityManagement.hiddenDangerPlan.mapper.HotHiddenDa
|
||||
import com.hotwj.platform.securityManagement.hiddenDangerPlan.service.IHotHiddenDangerPlanService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
@@ -43,6 +45,7 @@ import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.IsoFields;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -90,7 +93,7 @@ public class HotHiddenDangerPlanServiceImpl implements IHotHiddenDangerPlanServi
|
||||
@Override
|
||||
public TableDataInfo<HotHiddenDangerPlanVo> queryPageList(HotHiddenDangerPlanBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<HotHiddenDangerPlan> lqw = buildQueryWrapper(bo);
|
||||
Page<HotHiddenDangerPlanVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
Page<HotHiddenDangerPlanVo> result = baseMapper.queryPageList(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@@ -103,7 +106,7 @@ public class HotHiddenDangerPlanServiceImpl implements IHotHiddenDangerPlanServi
|
||||
@Override
|
||||
public List<HotHiddenDangerPlanVo> queryList(HotHiddenDangerPlanBo bo) {
|
||||
LambdaQueryWrapper<HotHiddenDangerPlan> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
return baseMapper.queryList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,6 +186,45 @@ public class HotHiddenDangerPlanServiceImpl implements IHotHiddenDangerPlanServi
|
||||
processCompanyPlan(companyConfig, checkConfigsMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean openRecheck(Long planId, Date recheckStartTime, Date recheckEndTime) {
|
||||
HotHiddenDangerPlan plan = getPlanOrThrow(planId);
|
||||
validateRecheckTime(recheckStartTime, recheckEndTime);
|
||||
return baseMapper.update(
|
||||
null,
|
||||
Wrappers.<HotHiddenDangerPlan>lambdaUpdate()
|
||||
.eq(HotHiddenDangerPlan::getId, plan.getId())
|
||||
.set(HotHiddenDangerPlan::getIsRecheck, 1L)
|
||||
.set(HotHiddenDangerPlan::getRecheckStartTime, recheckStartTime)
|
||||
.set(HotHiddenDangerPlan::getRecheckEndTime, recheckEndTime)
|
||||
) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateRecheck(Long planId, Date recheckStartTime, Date recheckEndTime) {
|
||||
HotHiddenDangerPlan plan = getPlanOrThrow(planId);
|
||||
validateRecheckTime(recheckStartTime, recheckEndTime);
|
||||
return baseMapper.update(
|
||||
null,
|
||||
Wrappers.<HotHiddenDangerPlan>lambdaUpdate()
|
||||
.eq(HotHiddenDangerPlan::getId, plan.getId())
|
||||
.set(HotHiddenDangerPlan::getIsRecheck, 1L)
|
||||
.set(HotHiddenDangerPlan::getRecheckStartTime, recheckStartTime)
|
||||
.set(HotHiddenDangerPlan::getRecheckEndTime, recheckEndTime)
|
||||
) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean closeRecheck(Long planId) {
|
||||
HotHiddenDangerPlan plan = getPlanOrThrow(planId);
|
||||
return baseMapper.update(
|
||||
null,
|
||||
Wrappers.<HotHiddenDangerPlan>lambdaUpdate()
|
||||
.eq(HotHiddenDangerPlan::getId, plan.getId())
|
||||
.set(HotHiddenDangerPlan::getIsRecheck, 0L)
|
||||
) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理单个公司的排查计划
|
||||
*/
|
||||
@@ -299,7 +341,7 @@ public class HotHiddenDangerPlanServiceImpl implements IHotHiddenDangerPlanServi
|
||||
lqw.eq(HotHiddenDangerPlan::getCompanyId, companyId);
|
||||
lqw.eq(HotHiddenDangerPlan::getIsDeleted, 0L);
|
||||
lqw.eq(HotHiddenDangerPlan::getPlanDateKey, timeInfo.getPlanDateKey());
|
||||
lqw.orderByDesc(HotHiddenDangerPlan::getCreateTime);
|
||||
lqw.orderByDesc(HotHiddenDangerPlan::getCreateTime, HotHiddenDangerPlan::getId);
|
||||
lqw.last("LIMIT 1");
|
||||
return baseMapper.selectOne(lqw);
|
||||
}
|
||||
@@ -511,19 +553,39 @@ public class HotHiddenDangerPlanServiceImpl implements IHotHiddenDangerPlanServi
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<HotHiddenDangerPlan> buildQueryWrapper(HotHiddenDangerPlanBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotHiddenDangerPlan> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(HotHiddenDangerPlan::getCreateTime);
|
||||
lqw.orderByDesc(HotHiddenDangerPlan::getCreateTime, HotHiddenDangerPlan::getId);
|
||||
lqw.eq(bo.getCompanyId() != null, HotHiddenDangerPlan::getCompanyId, bo.getCompanyId());
|
||||
lqw.eq(bo.getInspectId() != null, HotHiddenDangerPlan::getInspectId, bo.getInspectId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getPlanName()), HotHiddenDangerPlan::getPlanName, bo.getPlanName());
|
||||
lqw.eq(bo.getStartDate() != null, HotHiddenDangerPlan::getStartDate, bo.getStartDate());
|
||||
lqw.eq(bo.getEndDate() != null, HotHiddenDangerPlan::getEndDate, bo.getEndDate());
|
||||
lqw.eq(bo.getIsRecheck() != null, HotHiddenDangerPlan::getIsRecheck, bo.getIsRecheck());
|
||||
lqw.eq(bo.getProgress() != null, HotHiddenDangerPlan::getProgress, bo.getProgress());
|
||||
lqw.eq(bo.getIsDeleted() != null, HotHiddenDangerPlan::getIsDeleted, bo.getIsDeleted());
|
||||
if (shouldLimitToEffectiveWindow()) {
|
||||
Date now = new Date();
|
||||
lqw.and(wrapper -> wrapper
|
||||
.and(original -> original
|
||||
.le(HotHiddenDangerPlan::getStartDate, now)
|
||||
.ge(HotHiddenDangerPlan::getEndDate, now))
|
||||
.or(recheck -> recheck
|
||||
.eq(HotHiddenDangerPlan::getIsRecheck, 1L)
|
||||
.le(HotHiddenDangerPlan::getRecheckStartTime, now)
|
||||
.ge(HotHiddenDangerPlan::getRecheckEndTime, now))
|
||||
);
|
||||
}
|
||||
return lqw;
|
||||
}
|
||||
|
||||
private boolean shouldLimitToEffectiveWindow() {
|
||||
try {
|
||||
return DriverLoginContextHelper.isDriverPort();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增隐患排查
|
||||
*
|
||||
@@ -626,6 +688,34 @@ public class HotHiddenDangerPlanServiceImpl implements IHotHiddenDangerPlanServi
|
||||
//TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
private HotHiddenDangerPlan getPlanOrThrow(Long planId) {
|
||||
if (planId == null) {
|
||||
throw new ServiceException("计划ID不能为空");
|
||||
}
|
||||
HotHiddenDangerPlan plan = baseMapper.selectOne(
|
||||
Wrappers.<HotHiddenDangerPlan>lambdaQuery()
|
||||
.eq(HotHiddenDangerPlan::getId, planId)
|
||||
.eq(HotHiddenDangerPlan::getIsDeleted, 0L)
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
if (plan == null) {
|
||||
throw new ServiceException("排查计划不存在");
|
||||
}
|
||||
return plan;
|
||||
}
|
||||
|
||||
private void validateRecheckTime(Date recheckStartTime, Date recheckEndTime) {
|
||||
if (recheckStartTime == null) {
|
||||
throw new ServiceException("补查开始时间不能为空");
|
||||
}
|
||||
if (recheckEndTime == null) {
|
||||
throw new ServiceException("补查结束时间不能为空");
|
||||
}
|
||||
if (!recheckEndTime.after(recheckStartTime)) {
|
||||
throw new ServiceException("补查结束时间必须晚于补查开始时间");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除隐患排查信息
|
||||
*
|
||||
|
||||
@@ -88,7 +88,7 @@ public class HotTrainingServiceImpl implements IHotTrainingService {
|
||||
private LambdaQueryWrapper<HotTraining> buildQueryWrapper(HotTrainingBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<HotTraining> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(HotTraining::getCreateTime);
|
||||
lqw.orderByDesc(HotTraining::getCreateTime, HotTraining::getId);
|
||||
lqw.eq(bo.getCompanyId() != null, HotTraining::getCompanyId, bo.getCompanyId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getPlanName()), HotTraining::getPlanName, bo.getPlanName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getPersonType()), HotTraining::getPersonType, bo.getPersonType());
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.hotwj.platform.securityManagement.training.support;
|
||||
|
||||
import com.hotwj.platform.config.companyBasicConfig.domain.bo.HotCompanyBasicConfigBo;
|
||||
import com.hotwj.platform.config.companyBasicConfig.domain.vo.HotCompanyBasicConfigVo;
|
||||
import com.hotwj.platform.config.companyBasicConfig.service.IHotCompanyBasicConfigService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class StudyForbidPeriodSupport {
|
||||
|
||||
public static final String FORBID_STUDY_MESSAGE = "当前处于禁学时间";
|
||||
|
||||
private static final Long STATUS_ENABLED = 1L;
|
||||
private static final DateTimeFormatter TIME_FORMATTER_MINUTE = DateTimeFormatter.ofPattern("H:mm");
|
||||
private static final DateTimeFormatter TIME_FORMATTER_SECOND = DateTimeFormatter.ofPattern("H:mm:ss");
|
||||
|
||||
private final IHotCompanyBasicConfigService companyBasicConfigService;
|
||||
|
||||
public void checkStudyAllowed(Long companyId) {
|
||||
String forbidMessage = getForbidStudyMessage(companyId);
|
||||
if (StringUtils.isNotBlank(forbidMessage)) {
|
||||
throw new ServiceException(forbidMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public String getForbidStudyMessage(Long companyId) {
|
||||
if (companyId == null) {
|
||||
return null;
|
||||
}
|
||||
HotCompanyBasicConfigVo config = getCompanyBasicConfig(companyId);
|
||||
if (config == null || !STATUS_ENABLED.equals(config.getForbidPeriodEnabled())) {
|
||||
return null;
|
||||
}
|
||||
if (!isNowInForbidPeriod(config.getForbidStartTime(), config.getForbidEndTime())) {
|
||||
return null;
|
||||
}
|
||||
return FORBID_STUDY_MESSAGE;
|
||||
}
|
||||
|
||||
private HotCompanyBasicConfigVo getCompanyBasicConfig(Long companyId) {
|
||||
HotCompanyBasicConfigBo bo = new HotCompanyBasicConfigBo();
|
||||
bo.setCompanyId(companyId);
|
||||
bo.setIsDeleted(0L);
|
||||
List<HotCompanyBasicConfigVo> configs = companyBasicConfigService.queryList(bo);
|
||||
if (configs == null || configs.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return configs.get(0);
|
||||
}
|
||||
|
||||
private boolean isNowInForbidPeriod(String forbidStartTime, String forbidEndTime) {
|
||||
LocalTime startTime = parseTime(forbidStartTime);
|
||||
LocalTime endTime = parseTime(forbidEndTime);
|
||||
if (startTime == null || endTime == null) {
|
||||
return false;
|
||||
}
|
||||
LocalTime now = LocalTime.now();
|
||||
if (startTime.equals(endTime)) {
|
||||
return true;
|
||||
}
|
||||
if (startTime.isBefore(endTime)) {
|
||||
return !now.isBefore(startTime) && !now.isAfter(endTime);
|
||||
}
|
||||
return !now.isBefore(startTime) || !now.isAfter(endTime);
|
||||
}
|
||||
|
||||
private LocalTime parseTime(String value) {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return LocalTime.parse(value, TIME_FORMATTER_SECOND);
|
||||
} catch (DateTimeParseException ignored) {
|
||||
}
|
||||
try {
|
||||
return LocalTime.parse(value, TIME_FORMATTER_MINUTE);
|
||||
} catch (DateTimeParseException ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.hotwj.platform.securityManagement.trainingAnswer.controller;
|
||||
import com.hotwj.platform.securityManagement.trainingAnswer.domain.bo.SubmitTrainingAnswerBo;
|
||||
import com.hotwj.platform.securityManagement.trainingAnswer.domain.bo.TrainingAnswerRecordBo;
|
||||
import com.hotwj.platform.securityManagement.trainingAnswer.domain.vo.HotTrainingAnswerRecordVo;
|
||||
import com.hotwj.platform.securityManagement.trainingAnswer.domain.vo.HotTrainingWrongQuestionReviewVo;
|
||||
import com.hotwj.platform.securityManagement.trainingAnswer.service.IHotTrainingAnswerRecordService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
@@ -12,6 +13,7 @@ import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
@@ -20,6 +22,7 @@ import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -138,4 +141,16 @@ public class HotTrainingAnswerRecordController extends BaseController {
|
||||
public R<Void> submit(@RequestBody @Validated(AddGroup.class) SubmitTrainingAnswerBo bo) {
|
||||
return toAjax(hotTrainingAnswerRecordService.submitWithSignature(bo));
|
||||
}
|
||||
|
||||
@GetMapping("/wrongQuestion/review")
|
||||
@Operation(summary = "查询错题回顾(当前用户)")
|
||||
public R<List<HotTrainingWrongQuestionReviewVo>> wrongQuestionReview(TrainingAnswerRecordBo bo) {
|
||||
Long companyId = LoginHelper.getCompanyId();
|
||||
String userId = LoginHelper.getBusinessUserId();
|
||||
if (StringUtils.isBlank(userId)) {
|
||||
userId = LoginHelper.getUserIdStr();
|
||||
}
|
||||
List<HotTrainingWrongQuestionReviewVo> result = hotTrainingAnswerRecordService.queryWrongQuestionReview(companyId, userId, bo);
|
||||
return R.ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +130,16 @@ public class HotTrainingAnswerRecord extends BaseEntity {
|
||||
*/
|
||||
private Date answerTime;
|
||||
|
||||
/**
|
||||
* 错误次数
|
||||
*/
|
||||
private Integer errorCount;
|
||||
|
||||
/**
|
||||
* 错误答案,逗号拼接
|
||||
*/
|
||||
private String errorAnswers;
|
||||
|
||||
/**
|
||||
* 0=正常, 1=已删除
|
||||
*/
|
||||
|
||||
@@ -73,6 +73,10 @@ public class TrainingAnswerRecordBo extends BaseEntity {
|
||||
|
||||
private Date answerTime;
|
||||
|
||||
private Integer errorCount;
|
||||
|
||||
private String errorAnswers;
|
||||
|
||||
private Long isDeleted;
|
||||
|
||||
}
|
||||
|
||||
@@ -216,5 +216,7 @@ public class HotTrainingAnswerRecordVo implements Serializable {
|
||||
|
||||
private Boolean passed;
|
||||
|
||||
private Integer errorCount;
|
||||
|
||||
private String errorAnswers;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.hotwj.platform.securityManagement.trainingAnswer.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class HotTrainingWrongQuestionReviewVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long questionId;
|
||||
private String questionType;
|
||||
private String questionDesc;
|
||||
private String imageUrl;
|
||||
|
||||
private String optionA;
|
||||
private String optionB;
|
||||
private String optionC;
|
||||
private String optionD;
|
||||
private String optionE;
|
||||
private String optionF;
|
||||
|
||||
private String correctAnswers;
|
||||
private String analysis;
|
||||
|
||||
private Integer errorCount;
|
||||
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.hotwj.platform.securityManagement.trainingAnswer.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.hotwj.platform.securityManagement.trainingAnswer.domain.HotTrainingAnswerRecord;
|
||||
import com.hotwj.platform.securityManagement.trainingAnswer.domain.bo.TrainingAnswerRecordBo;
|
||||
import com.hotwj.platform.securityManagement.trainingAnswer.domain.vo.HotTrainingAnswerRecordVo;
|
||||
import com.hotwj.platform.securityManagement.trainingAnswer.domain.vo.HotTrainingWrongQuestionReviewVo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
@@ -27,4 +30,8 @@ public interface HotTrainingAnswerRecordMapper extends BaseMapperPlus<HotTrainin
|
||||
@Param("userId") String userId
|
||||
);
|
||||
|
||||
java.util.List<HotTrainingWrongQuestionReviewVo> selectWrongQuestionReviewList(@Param("companyId") Long companyId,
|
||||
@Param("userId") String userId,
|
||||
@Param("bo") TrainingAnswerRecordBo bo);
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.hotwj.platform.securityManagement.trainingAnswer.service;
|
||||
import com.hotwj.platform.securityManagement.trainingAnswer.domain.bo.TrainingAnswerRecordBo;
|
||||
import com.hotwj.platform.securityManagement.trainingAnswer.domain.bo.SubmitTrainingAnswerBo;
|
||||
import com.hotwj.platform.securityManagement.trainingAnswer.domain.vo.HotTrainingAnswerRecordVo;
|
||||
import com.hotwj.platform.securityManagement.trainingAnswer.domain.vo.HotTrainingWrongQuestionReviewVo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
@@ -84,4 +85,6 @@ public interface IHotTrainingAnswerRecordService {
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean submitWithSignature(SubmitTrainingAnswerBo bo);
|
||||
|
||||
List<HotTrainingWrongQuestionReviewVo> queryWrongQuestionReview(Long companyId, String userId, TrainingAnswerRecordBo bo);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user