隐患排查初版
This commit is contained in:
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` 推断审核结果。
|
||||
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` = 1
|
||||
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 = 1;
|
||||
-- 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='隐患排查审核驳回历史表';
|
||||
@@ -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(1L);
|
||||
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);
|
||||
|
||||
@@ -150,4 +150,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;
|
||||
}
|
||||
@@ -159,6 +159,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;
|
||||
|
||||
|
||||
/**
|
||||
@@ -178,6 +179,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 +228,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> {
|
||||
}
|
||||
@@ -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,8 +11,11 @@ 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.hiddenDangerInspection.service.IHotHiddenDangerInspectionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -27,6 +31,8 @@ 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,6 +48,7 @@ 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;
|
||||
@@ -55,10 +62,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;
|
||||
}
|
||||
|
||||
@@ -156,11 +164,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 +203,58 @@ 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("排查记录不存在");
|
||||
}
|
||||
HotHiddenDangerInspection update = MapstructUtils.convert(bo, HotHiddenDangerInspection.class);
|
||||
validEntityBeforeSave(update);
|
||||
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 && 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();
|
||||
@@ -254,26 +284,176 @@ 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;
|
||||
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(),
|
||||
auditPass,
|
||||
bo.getAuditConclusion(),
|
||||
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::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 || "REJECTED".equalsIgnoreCase(original.getFlowStatus());
|
||||
}
|
||||
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
vo.setTaskId(taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user