From 1ceb785c537ef3ab9deabe1e7525d2c9c1b2e0d8 Mon Sep 17 00:00:00 2001 From: buaixuexideshitongxue <2936013465@qq.com> Date: Wed, 29 Apr 2026 16:41:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E9=99=A4=E5=BC=80=E5=88=9D=E6=A0=B8?= =?UTF-8?q?=E6=83=85=E5=86=B5=E3=80=81=E5=85=B6=E4=BD=99=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/ComplaintCollectionController.java | 17 + .../supervision/job/MailBoxCaptureJob.java | 49 ++ .../supervision/pojo/dto/MailBoxSyncDto.java | 29 + .../pojo/dto/NegativeDataOnlyDto.java | 361 +++++++++ .../pojo/entity/mailbox/MailBlame.java | 8 + .../pojo/param/MailQueryParam.java | 5 + .../repository/mail/MailResourceService.java | 1 + .../service/MailBoxCaptureService.java | 723 ++++++++++++++++++ .../supervision/service/NegativeService.java | 134 +++- 9 files changed, 1326 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/biutag/supervision/job/MailBoxCaptureJob.java create mode 100644 src/main/java/com/biutag/supervision/pojo/dto/MailBoxSyncDto.java create mode 100644 src/main/java/com/biutag/supervision/pojo/dto/NegativeDataOnlyDto.java create mode 100644 src/main/java/com/biutag/supervision/service/MailBoxCaptureService.java diff --git a/src/main/java/com/biutag/supervision/controller/data/ComplaintCollectionController.java b/src/main/java/com/biutag/supervision/controller/data/ComplaintCollectionController.java index e4f2d3f..ee67d1a 100644 --- a/src/main/java/com/biutag/supervision/controller/data/ComplaintCollectionController.java +++ b/src/main/java/com/biutag/supervision/controller/data/ComplaintCollectionController.java @@ -8,6 +8,7 @@ import com.biutag.supervision.pojo.request.complaintCollection.*; import com.biutag.supervision.pojo.vo.complaintCollection.ComplaintCollectionDetailVo; import com.biutag.supervision.pojo.vo.complaintCollection.ComplaintCollectionMailRepeattVo; import com.biutag.supervision.pojo.vo.complaintCollection.ComplaintCollectionWatchDetailVO; +import com.biutag.supervision.service.MailBoxCaptureService; import com.biutag.supervision.service.complaintCollection.ComplaintCollectionService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -19,6 +20,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.time.LocalDateTime; + /** * @ClassName ComplaintCollectionController * @Description 涉访涉诉控制层 @@ -36,6 +39,8 @@ public class ComplaintCollectionController { private final Job job; + private final MailBoxCaptureService mailBoxCaptureService; + @Operation(description = "添加") @PostMapping("/addComplaintCollection") public Result addComplaintCollection(@RequestBody ComplaintCollectionAddRequest request){ @@ -64,6 +69,18 @@ public class ComplaintCollectionController { if ("我要下发".equals(request.getPersonInfo())){ complaintCollectionService.addNegativeTemp(request); } + if ("阶段1".equals(request.getPersonInfo())){ + LocalDateTime start = request.getCreateTimeList().get(0); + LocalDateTime end = request.getCreateTimeList().get(1); + mailBoxCaptureService.captureMayorMailbox(start, end); + } + if ("阶段2".equals(request.getPersonInfo())){ + LocalDateTime start = request.getCreateTimeList().get(0); + LocalDateTime end = request.getCreateTimeList().get(1); + mailBoxCaptureService.syncBlameAndFiles(start, end); + } + + return Result.success(complaintCollectionService.getComplaintCollectionPageNew(request)); } diff --git a/src/main/java/com/biutag/supervision/job/MailBoxCaptureJob.java b/src/main/java/com/biutag/supervision/job/MailBoxCaptureJob.java new file mode 100644 index 0000000..3397d21 --- /dev/null +++ b/src/main/java/com/biutag/supervision/job/MailBoxCaptureJob.java @@ -0,0 +1,49 @@ +package com.biutag.supervision.job; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +import com.biutag.supervision.service.MailBoxCaptureService; + +/** + * @ClassName MailBoxCaptureJob + * @Description 局长信箱数据抓取定时任务 + * - 阶段1(每天2点):抓取来信,创建 Negative + ComplaintCollection + * - 阶段2(每天3点):同步涉及人和核查附件 + * @Author shihao + * @Date 2026/4/28 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class MailBoxCaptureJob { + + private final MailBoxCaptureService mailBoxCaptureService; + + /** + * 阶段1:抓取来信 + * 每天凌晨2点执行 + */ + @Scheduled(cron = "0 0 2 * * ?") + public void mailBoxCaptureCompletedToNegative() { + LocalDateTime start = LocalDate.now().minusDays(1).atStartOfDay(); + LocalDateTime end = LocalDate.now().atStartOfDay(); + mailBoxCaptureService.captureMayorMailbox(start, end); + } + + /** + * 阶段2:同步涉及人和核查附件 + * 每天凌晨3点执行 + */ + @Scheduled(cron = "0 0 3 * * ?") + public void syncBlameAndFilesForCompletedMails() { + LocalDateTime start = LocalDate.now().minusDays(1).atStartOfDay(); + LocalDateTime end = LocalDate.now().atStartOfDay(); + mailBoxCaptureService.syncBlameAndFiles(start, end); + } +} diff --git a/src/main/java/com/biutag/supervision/pojo/dto/MailBoxSyncDto.java b/src/main/java/com/biutag/supervision/pojo/dto/MailBoxSyncDto.java new file mode 100644 index 0000000..510a54e --- /dev/null +++ b/src/main/java/com/biutag/supervision/pojo/dto/MailBoxSyncDto.java @@ -0,0 +1,29 @@ +package com.biutag.supervision.pojo.dto; + +import com.biutag.supervision.pojo.entity.ComplaintCollection; +import com.biutag.supervision.pojo.entity.mailbox.Mail; +import com.biutag.supervision.pojo.entity.mailbox.MailBlame; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * 局长信箱阶段2同步数据DTO + * 用于在循环内传递同步所需的数据 + */ +@Getter +@Setter +@Schema(description = "局长信箱阶段2同步数据DTO") +public class MailBoxSyncDto { + + @Schema(description = "投诉举报收集表记录") + private ComplaintCollection cc; + + @Schema(description = "局长信箱邮件数据") + private Mail mail; + + @Schema(description = "涉及人列表") + private List mailBlames; +} diff --git a/src/main/java/com/biutag/supervision/pojo/dto/NegativeDataOnlyDto.java b/src/main/java/com/biutag/supervision/pojo/dto/NegativeDataOnlyDto.java new file mode 100644 index 0000000..ae88119 --- /dev/null +++ b/src/main/java/com/biutag/supervision/pojo/dto/NegativeDataOnlyDto.java @@ -0,0 +1,361 @@ +package com.biutag.supervision.pojo.dto; + +import com.biutag.supervision.constants.enums.ProblemSourcesEnum; +import com.biutag.supervision.pojo.dto.flow.VerifyData; +import com.biutag.supervision.pojo.entity.NegativeBlame; +import com.biutag.supervision.pojo.entity.NegativeFile; +import com.biutag.supervision.pojo.entity.NegativeThingFile; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + * Negative纯数据保存DTO - 所有字段通过传参,不写死任何值 + */ +@Setter +@Getter +@Schema(description = "Negative纯数据保存DTO") +public class NegativeDataOnlyDto { + + // ========== Negative主表所有字段 ========== + + @Schema(description = "主键(可传可不传,不传则自动生成)") + private String id; + + @Schema(description = "样本来源编号") + private String originId; + + @Schema(description = "编号") + private String serialNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") + @Schema(description = "问题发生时间") + private LocalDateTime happenTime; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") + @Schema(description = "问题发现时间") + private LocalDateTime discoveryTime; + + /** + * @see ProblemSourcesEnum + */ + @Schema(description = "问题来源code") + private String problemSourcesCode; + /** + * @see ProblemSourcesEnum + */ + + @Schema(description = "问题来源") + private String problemSources; + + @Schema(description = "业务类型code") + private String businessTypeCode; + + @Schema(description = "业务类别名称") + private String businessTypeName; + + @Schema(description = "涉嫌问题(列表,会转成逗号分隔字符串)") + private List involveProblem = new ArrayList<>(); + + @Schema(description = "涉及警种名称") + private String policeTypeName; + + @Schema(description = "涉及警种") + private String policeType; + + @Schema(description = "涉及单位名称") + private String involveDepartName; + + @Schema(description = "涉及单位id") + private String involveDepartId; + + @Schema(description = "联系电话") + private String contactPhone; + + @Schema(description = "反映人姓名") + private String responderName; + + @Schema(description = "反映人身份证") + private String responderIdCard; + + @Schema(description = "简要描述") + private String thingDesc; + + @Schema(description = "填写人姓名") + private String fillName; + + @Schema(description = "填写人部门id") + private String fillDepartId; + + @Schema(description = "填写人部门名称") + private String fillDeaprtName; + + @Schema(description = "审核人姓名") + private String checkName; + + @Schema(description = "审核人身份证") + private String checkIdCode; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") + @Schema(description = "创建时间(不传则自动填充)") + private LocalDateTime crtTime; + + @Schema(description = "更新人姓名") + private String updName; + + @Schema(description = "更新人") + private String updUser; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") + @Schema(description = "更新时间(不传则自动填充)") + private LocalDateTime updTime; + + @Schema(description = "状态") + private String status; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "预留字段") + private String reserve; + + @Schema(description = "核查情况") + private String checkStatus; + + @Schema(description = "核查情况名称") + private String checkStatusName; + + @Schema(description = "核查结论code") + private String checkStatusCode; + + @Schema(description = "完善状态") + private String completeStatus; + + @Schema(description = "最后编辑人员") + private String lastEditName; + + @Schema(description = "任务ID") + private String taskId; + + @Schema(description = "督察主题code") + private String supervisionSubjectCode; + + @Schema(description = "督察主题名称") + private String supervisionSubjectName; + + @Schema(description = "是否整改code") + private String isRectifyCode; + + @Schema(description = "是否整改名称") + private String isRectifyName; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") + @Schema(description = "办结时间") + private LocalDateTime completeDate; + + @Schema(description = "督察报告id") + private String reportId; + + @Schema(description = "流程key") + private String flowKey; + + @Schema(description = "主办层级") + private String hostLevel; + + @Schema(description = "办理时限") + private String timeLimit; + + @Schema(description = "最大签收时长(天)") + private Integer maxSignDuration; + + @Schema(description = "最大办理时长(天)") + private Integer maxHandleDuration; + + @Schema(description = "最大延期时长(天)") + private Integer maxExtensionDuration; + + @Schema(description = "审批流程") + private String approvalFlow; + + @Schema(description = "核查情况描述") + private String checkStatusDesc; + + @Schema(description = "整改情况描述") + private String rectifyDesc; + + @Schema(description = "整改限制天数") + private Integer rectifyRestrictionDays; + + @Schema(description = "追责对象") + private String accountabilityTarget; + + @Schema(description = "办理状态") + private String processingStatus; + + @Schema(description = "延期申请ID") + private Integer negativeExtensionApplyId; + + @Schema(description = "是否能申请延期") + private Boolean extensionApplyFlag; + + @Schema(description = "延期天数") + private Integer extensionDays; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") + @Schema(description = "市局下发时间") + private LocalDateTime firstDistributeTime; + + @Schema(description = "是否二级机构办理") + private Boolean isSecondHandle; + + @Schema(description = "二级办理单位id") + private String handleSecondDepartId; + + @Schema(description = "二级办理单位名称") + private String handleSecondDepartName; + + @Schema(description = "三级办理单位id") + private String handleThreeDepartId; + + @Schema(description = "三级办理单位名称") + private String handleThreeDepartName; + + @Schema(description = "涉及案件/警情编号") + private String caseNumber; + + @Schema(description = "办理超时(秒)") + private Long handleTimeout; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") + @Schema(description = "申请办结时间") + private LocalDateTime handleTime; + + @Schema(description = "当前处理对象") + private String currentProcessingObject; + + @Schema(description = "专项督察") + private String specialSupervision; + + @Schema(description = "通报期数") + private String reportNumber; + + @Schema(description = "核查办理情况") + private String verifySituation; + + @Schema(description = "佐证材料情况") + private String verifyFileSituation; + + @Schema(description = "单位会签ID") + private Integer countersignApplyId; + + @Schema(description = "创建单位层级") + private Integer crtDepartLevel; + + @Schema(description = "市局下发意见") + private String firstDistributeComments; + + @Schema(description = "是否抽检") + private Boolean spotCheckFlag; + + @Schema(description = "抽检结果") + private String spotCheckResult; + + @Schema(description = "抽检情况") + private String spotCheckDesc; + + @Schema(description = "未整改原因") + private String unrectifyReason; + + @Schema(description = "二级部门id") + private String secondInvolveDepartId; + + @Schema(description = "三级部门id") + private String threeInvolveDepartId; + + @Schema(description = "经办人") + private String handlePolices; + + @Schema(description = "剩余办理时间") + private Long handleRemainingTime; + + @Schema(description = "样本ID") + private Integer sampleId; + + @Schema(description = "下发问题(JSON)") + private List problems; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") + @Schema(description = "核查时间") + private LocalDateTime verifyTime; + + @Schema(description = "项目名称") + private String projectName; + + @Schema(description = "涉及问题金额") + private Double involveMoney; + + @Schema(description = "化解情况") + private String resolveSituation; + + @Schema(description = "当前状态") + private String resolveStatus; + + @Schema(description = "接访领导姓名") + private String visitingLeaderName; + + @Schema(description = "接访领导工号") + private String visitingLeaderEmpNo; + + @Schema(description = "12337办理结果") + private String handleResult12337; + + @Schema(description = "12337办理结果分组") + private String handleResult12337Group; + + @Schema(description = "涉及人员是否领导班子") + private String verifiedIsLeader; + + @Schema(description = "办理结果") + private String processResult; + + @Schema(description = "处分处理情况") + private String disciplinaryActionDesc; + + @Schema(description = "来源类型") + private String sourceType; + + @Schema(description = "来源类型名称") + private String sourceTypeDesc; + + @Schema(description = "下发单位id") + private String issuingDepartId; + + @Schema(description = "下发单位名称") + private String issuingDepartName; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") + @Schema(description = "最后一次审批节点操作时间") + private LocalDateTime latestProcessTime; + + @Schema(description = "二级审批累计时长(秒)") + private Long secondApprovalTime; + + @Schema(description = "市局审批累计时长(秒)") + private Long firstApproveTime; + + // ========== 关联表 ========== + + @Schema(description = "涉及人员列表") + private List blames = new ArrayList<>(); + + @Schema(description = "事件附件列表") + private List thingFiles = new ArrayList<>(); + + @Schema(description = "核查附件列表") + private List files = new ArrayList<>(); +} diff --git a/src/main/java/com/biutag/supervision/pojo/entity/mailbox/MailBlame.java b/src/main/java/com/biutag/supervision/pojo/entity/mailbox/MailBlame.java index d276c84..0afdc39 100644 --- a/src/main/java/com/biutag/supervision/pojo/entity/mailbox/MailBlame.java +++ b/src/main/java/com/biutag/supervision/pojo/entity/mailbox/MailBlame.java @@ -43,4 +43,12 @@ public class MailBlame { * 创建时间 */ private LocalDateTime createTime; + + + private String leaderEmpNo; + + + private String leaderName; + + private String leaderIdCode; } diff --git a/src/main/java/com/biutag/supervision/pojo/param/MailQueryParam.java b/src/main/java/com/biutag/supervision/pojo/param/MailQueryParam.java index 1502356..f5be264 100644 --- a/src/main/java/com/biutag/supervision/pojo/param/MailQueryParam.java +++ b/src/main/java/com/biutag/supervision/pojo/param/MailQueryParam.java @@ -73,4 +73,9 @@ public class MailQueryParam extends BasePage{ @Schema(description = "身份证ids") private Set contactIdCards; + + /** + * 信件状态 + */ + private String mailState; } diff --git a/src/main/java/com/biutag/supervision/repository/mail/MailResourceService.java b/src/main/java/com/biutag/supervision/repository/mail/MailResourceService.java index 4dad089..b9508f5 100644 --- a/src/main/java/com/biutag/supervision/repository/mail/MailResourceService.java +++ b/src/main/java/com/biutag/supervision/repository/mail/MailResourceService.java @@ -39,6 +39,7 @@ public class MailResourceService extends BaseDAO { queryWrapper.eq(StrUtil.isNotBlank(param.getContactName()), Mail::getContactName, param.getContactName()); queryWrapper.eq(StrUtil.isNotBlank(param.getContactPhone()), Mail::getContactPhone, param.getContactPhone()); queryWrapper.eq(StrUtil.isNotBlank(param.getContent()), Mail::getContent, param.getContent()); + queryWrapper.eq(StrUtil.isNotBlank(param.getMailState()), Mail::getMailState, param.getMailState()); if (!param.getMailTime().isEmpty() && param.getMailTime().size() >= 2) { queryWrapper.between(Mail::getMailTime, param.getMailTime().get(0), param.getMailTime().get(1)); } diff --git a/src/main/java/com/biutag/supervision/service/MailBoxCaptureService.java b/src/main/java/com/biutag/supervision/service/MailBoxCaptureService.java new file mode 100644 index 0000000..c5dd30a --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/MailBoxCaptureService.java @@ -0,0 +1,723 @@ +package com.biutag.supervision.service; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson2.JSON; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.biutag.supervision.constants.enums.AccountabilityTargetEnum; +import com.biutag.supervision.constants.enums.BusinessTypeEnum; +import com.biutag.supervision.constants.enums.ProblemSourcesEnum; +import com.biutag.supervision.mapper.MailBlameMapper; +import com.biutag.supervision.pojo.dto.MailBoxSyncDto; +import com.biutag.supervision.pojo.dto.NegativeDataOnlyDto; +import com.biutag.supervision.pojo.dto.mail.MailAttachmentDTO; +import com.biutag.supervision.pojo.entity.*; +import com.biutag.supervision.pojo.entity.mailbox.Mail; +import com.biutag.supervision.pojo.entity.mailbox.MailBlame; +import com.biutag.supervision.pojo.enums.complaintCollection.ComplaintCollectionSourceTableEnum; +import com.biutag.supervision.pojo.enums.negative.NegativeSourceTypeEnum; +import com.biutag.supervision.pojo.param.ComplaintCollection.ComplaintCollectionQueryParam; +import com.biutag.supervision.pojo.param.ComplaintCollection.ComplaintCollectionUpdateParam; +import com.biutag.supervision.pojo.param.MailQueryParam; +import com.biutag.supervision.pojo.param.SupDepartQueryParam; +import com.biutag.supervision.pojo.param.SupExternalDepartQueryParam; +import com.biutag.supervision.repository.complaintCollection.ComplaintCollectionResourceService; +import com.biutag.supervision.repository.mail.MailResourceService; +import com.biutag.supervision.repository.supExternalDepart.SupExternalDepartResourceService; +import com.biutag.supervision.repository.supdepart.SupDepartResourceService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.support.TransactionTemplate; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * @ClassName MailBoxCaptureService + * @Description 局长信箱数据抓取业务逻辑 + * - 阶段1:抓取来信,创建 Negative 主表 + 来信附件 + ComplaintCollection + * - 阶段2:同步办结后的涉及人和核查附件 + * @Author shihao + * @Date 2026/4/28 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class MailBoxCaptureService { + + private final NegativeService negativeService; + private final NegativeBlameService blameService; + private final NegativeProblemRelationService negativeProblemRelationService; + private final NegativeFileService fileService; + private final MailService mailService; + private final MailResourceService mailResourceService; + private final SupDepartResourceService supDepartResourceService; + private final SupExternalDepartResourceService supExternalDepartResourceService; + private final ComplaintCollectionResourceService complaintCollectionResourceService; + private final MailBlameMapper mailBlameMapper; + private final SupPoliceService supPoliceService; + private final SupDictHandleResultMapingService dictHandleResultMapingService; + private final SupDictProblemTypeMapingService dictProblemTypeMapingService; + private final SupDictProblemTypeService problemTypeService; + private final TransactionTemplate transactionTemplate; + + // ==================== 阶段1:抓取来信 ==================== + + /** + * 抓取来信并创建 ComplaintCollection 和 Negative + */ + public void captureMayorMailbox(LocalDateTime start, LocalDateTime end) { + log.info("【局长信箱抓取新信件】时间范围 {} ~ {}", start, end); + long startTimeMillis = System.currentTimeMillis(); + + try { + // 1. 查询来信的信件 + List mailList = queryNewMails(start, end); + if (CollectionUtil.isEmpty(mailList)) { + log.warn("【局长信箱已办结抓取】未查询到任何投诉举报信件数据,任务结束"); + return; + } + log.info("【局长信箱抓取新信件】查询到投诉举报信件信件数量:{}", mailList.size()); + + // 3. 遍历处理 + int successCount = 0; + int skipCount = 0; + int failCount = 0; + + for (Mail mail : mailList) { + try { + // 每条记录在独立事务中执行 + boolean success = Boolean.TRUE.equals(transactionTemplate.execute(status -> { + return doCaptureSingleMail(mail); + })); + if (success) { + successCount++; + log.debug("【局长信箱抓取新信件】处理成功: mailId={}", mail.getId()); + } else { + skipCount++; + log.debug("【局长信箱抓取新信件】处理跳过: mailId={}", mail.getId()); + } + } catch (Exception e) { + failCount++; + log.error("【局长信箱抓取新信件】处理失败: mailId={}, error={}", mail.getId(), e.getMessage(), e); + } + } + + // 4. 输出统计 + long cost = System.currentTimeMillis() - startTimeMillis; + log.info("【局长信箱抓取新信件】完成,总数:{},成功:{},跳过:{},失败:{},耗时:{}ms", + mailList.size(), successCount, skipCount, failCount, cost); + + } catch (Exception e) { + log.error("【局长信箱抓取新信件】任务执行过程中发生严重异常,任务中断", e); + throw e; + } + } + + // ==================== 阶段2:同步涉及人、核查附件、核查情况 ==================== + + /** + * 同步办结后的涉及人和核查附件 + */ + public void syncBlameAndFiles(LocalDateTime start, LocalDateTime end) { + log.info("【阶段2同步】时间范围 {} ~ {}", start, end); + long startTimeMillis = System.currentTimeMillis(); + + try { + // 1. 从 ComplaintCollection 查询局长信箱记录 + List completedList = queryCompletedMailbox(); + if (CollectionUtil.isEmpty(completedList)) { + log.warn("【阶段2同步】未查询到任何需要同步的数据,任务结束"); + return; + } + log.info("【阶段2同步】查询到需要同步数量:{}", completedList.size()); + + // 2. 遍历处理(每条记录独立事务) + int successCount = 0; + int skipCount = 0; + int failCount = 0; + + for (ComplaintCollection cc : completedList) { + try { + String originId = cc.getOriginId(); + // 查询信件 + MailQueryParam param = new MailQueryParam(); + param.setId(originId); + param.setMailState("completion"); + List mailList = mailResourceService.query(param); + if (CollectionUtil.isEmpty(mailList)) { + log.info("【阶段2同步】无对应办结Mail:originId=" + originId); + continue; + } + Mail mail = mailList.get(0); + + // 查询涉及人 + LambdaQueryWrapper mailBlameLambdaQueryWrapper = new LambdaQueryWrapper<>(); + mailBlameLambdaQueryWrapper.eq(MailBlame::getMailId, mail.getId()); + List mailBlames = mailBlameMapper.selectList(mailBlameLambdaQueryWrapper); + + // 构建 DTO + MailBoxSyncDto dto = new MailBoxSyncDto(); + dto.setCc(cc); + dto.setMail(mail); + dto.setMailBlames(mailBlames); + + // 每条记录在独立事务中执行 + boolean success = Boolean.TRUE.equals(transactionTemplate.execute(status -> { + return doSyncSingleRecord(dto); + })); + if (success) { + successCount++; + log.debug("【阶段2同步】处理成功: ccId={}", cc.getId()); + } else { + skipCount++; + log.debug("【阶段2同步】处理跳过: ccId={}", cc.getId()); + } + } catch (Exception e) { + failCount++; + log.error("【阶段2同步】处理失败: ccId={}, error={}", cc.getId(), e.getMessage(), e); + } + } + // 3. 输出统计 + long cost = System.currentTimeMillis() - startTimeMillis; + log.info("【阶段2同步】完成,总数:{},成功:{},跳过:{},失败:{},耗时:{}ms", + completedList.size(), successCount, skipCount, failCount, cost); + } catch (Exception e) { + log.error("【阶段2同步】任务执行过程中发生严重异常,任务中断", e); + throw e; + } + } + + // ==================== 查询相关 ==================== + + /** + * 从 ComplaintCollection 查询局长信箱记录 + */ + private List queryCompletedMailbox() { + ComplaintCollectionQueryParam param = new ComplaintCollectionQueryParam(); + param.setSourceTable(ComplaintCollectionSourceTableEnum.MAYOR_MAILBOX.getCode()); + param.setBlameSyncStatus("0"); // 未同步 + return complaintCollectionResourceService.query(param); + } + + /** + * 查询来信时间范围内的信件(按来信时间查询) + */ + private List queryNewMails(LocalDateTime start, LocalDateTime end) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(Mail::getMailLevel, "涉警投诉"); + queryWrapper.between(Mail::getMailTime, start, end); + return mailService.list(queryWrapper); + } + + /** + * 判重检查:检查是否已处理 + */ + private boolean isAlreadyProcessed(Mail mail) { + boolean exists = negativeService.exists(mail.getId()); + if (exists) { + log.debug("【局长信箱已办结抓取】跳过(已处理): mailId={}", mail.getId()); + } + return exists; + } + + // ==================== 单位查询 ==================== + + /** + * 根据外部单位ID查询单位实体(外部ID -> 内部ID -> 部门实体) + * + * @return 部门实体,找不到时返回 null(由调用方决定如何处理) + */ + private SupDepart getDepartByExternalId(Integer externalId) { + if (externalId == null) { + log.warn("【局长信箱已办结抓取】外部单位ID为空"); + return null; + } + // 1. 通过外部ID查询映射表,获取内部ID + SupExternalDepart externalDepart = findExternalDepart(externalId); + if (externalDepart == null) { + log.warn("【局长信箱已办结抓取】未找到SupExternalDepart映射,externalId={}", externalId); + return null; + } + String internalId = externalDepart.getInternalId(); + if (StrUtil.isBlank(internalId)) { + log.warn("【局长信箱已办结抓取】SupExternalDepart.internalId为空,externalId={}", externalId); + return null; + } + // 2. 通过内部ID查询部门实体 + SupDepart depart = findDepartById(internalId); + if (depart == null) { + log.warn("【局长信箱已办结抓取】未找到单位,internalId={}", internalId); + return null; + } + return depart; + } + + /** + * 根据外部ID查询单位映射 + * + * @return 单位映射,找不到时返回 null + */ + private SupExternalDepart findExternalDepart(Integer externalId) { + SupExternalDepartQueryParam queryParam = new SupExternalDepartQueryParam(); + queryParam.setSource("局长信箱"); + queryParam.setExternalIds(Collections.singleton(String.valueOf(externalId))); + List list = supExternalDepartResourceService.query(queryParam); + if (CollectionUtil.isEmpty(list)) { + return null; + } + return list.get(0); + } + + /** + * 根据内部ID查询部门 + */ + private SupDepart findDepartById(String id) { + SupDepartQueryParam queryParam = new SupDepartQueryParam(); + queryParam.setId(id); + List list = supDepartResourceService.query(queryParam); + if (CollectionUtil.isEmpty(list)) { + return null; + } + return list.get(0); + } + + // ==================== 阶段1 抓取方法 ==================== + + /** + * 单条记录的抓取逻辑(独立事务执行) + */ + public boolean doCaptureSingleMail(Mail mail) { + // 1. 判重检查 + if (isAlreadyProcessed(mail)) { + return false; + } + + // 2. 查询单位信息 + SupDepart secondDepart = getDepartByExternalId(mail.getSecondDeptId()); + SupDepart thirdDepart = getDepartByExternalId(mail.getThreeDeptId()); + + // 2.1 如果单位信息获取失败,抛出异常触发回滚 + if (secondDepart == null || thirdDepart == null) { + throw new RuntimeException("单位映射缺失: mailId=" + mail.getId()); + } + + // 3. 构建并保存 Negative(阶段1:主表 + 来信附件) + NegativeDataOnlyDto dto = buildNegativeDto(mail, secondDepart, thirdDepart); + Negative negative = negativeService.saveNegativeMain(dto); + negativeService.saveThingFiles(dto, negative.getId()); + + // 4. 保存 ComplaintCollection + ComplaintCollection cc = buildComplaintCollection(mail, negative.getId(), secondDepart, thirdDepart); + complaintCollectionResourceService.saveOrUpdateComplaintCollection(Collections.singletonList(cc)); + return true; + } + + // ==================== 阶段2 同步方法 ==================== + + /** + * 单条记录的同步逻辑(独立事务执行) + */ + private boolean doSyncSingleRecord(MailBoxSyncDto dto) { + ComplaintCollection cc = dto.getCc(); + Mail mail = dto.getMail(); + List mailBlames = dto.getMailBlames(); + + // 1. 通过 originId 找到对应的 Negative(只有阶段1创建过的才同步) + Negative negative = negativeService.getByOriginId(cc.getOriginId()); + if (negative == null) { + log.warn("【阶段2同步】无对应Negative,跳过: originId={}", cc.getOriginId()); + return false; + } + + // 2. 组装数据并保存 + syncBlame(mail, negative.getId(), mailBlames); + syncFiles(mail, negative.getId()); + + // 3. 同步核查情况到 Negative + syncCheckStatus(mail, negative); + + // 4. 更新同步标记(所有同步操作成功后) + updateSyncTag(cc); + return true; + } + + /** + * 同步涉及人 + */ + private List syncBlame(Mail mail, String negativeId, List mailBlames) { + // 幂等性检查:已存在则跳过 + LambdaQueryWrapper existWrapper = new LambdaQueryWrapper<>(); + existWrapper.eq(NegativeBlame::getNegativeId, negativeId); + if (blameService.count(existWrapper) > 0) { + log.info("【阶段2同步】涉及人已存在,跳过: negativeId={}", negativeId); + return Collections.emptyList(); + } + + // mailBlames 已由调用方在事务外查询好 + if (CollectionUtil.isEmpty(mailBlames)) { + return Collections.emptyList(); + } + + List result = new ArrayList<>(); + for (MailBlame blame : mailBlames) { + // 通过姓名+警号查询 SupPolice 获取完整信息 + LambdaQueryWrapper supPoliceLambdaQueryWrapper = new LambdaQueryWrapper<>(); + supPoliceLambdaQueryWrapper.eq(SupPolice::getIdCode, blame.getBlameIdCode()); + supPoliceLambdaQueryWrapper.last("limit 1"); + SupPolice police = supPoliceService.getOne(supPoliceLambdaQueryWrapper); + if (Objects.isNull(police)) { + log.warn("【阶段2同步】未找到该警员的数据! blameName={}, blameEmpNo={}", blame.getBlameName(), blame.getBlameEmpNo()); + continue; + } + + NegativeBlame negativeBlame = new NegativeBlame(); + negativeBlame.setBlameId(IdUtil.getSnowflakeNextIdStr()); + negativeBlame.setNegativeId(negativeId); + negativeBlame.setType("personal"); + negativeBlame.setBlameEmpNo(police.getEmpNo()); + negativeBlame.setBlameIdCode(police.getIdCode()); + negativeBlame.setBlameName(police.getName()); + negativeBlame.setCrtTime(LocalDateTime.now()); + negativeBlame.setUpdTime(LocalDateTime.now()); + negativeBlame.setLeadEmpNo(blame.getLeaderEmpNo()); + negativeBlame.setLeadName(blame.getLeaderName()); + negativeBlame.setLeadIdCode(blame.getLeaderIdCode()); + negativeBlame.setIvPersonType(police.getPersonType()); + + // 责任追究映射 + if (StrUtil.isNotBlank(blame.getVerifyPunish())) { + try { + List externalNames = JSON.parseArray(blame.getVerifyPunish(), String.class); + List dictHandleResultMapings = dictHandleResultMapingService.list(externalNames); + negativeBlame.setHandleResultCode( + dictHandleResultMapings.stream() + .map(SupDictHandleResultMaping::getInternalId) + .collect(Collectors.joining(",")) + ); + negativeBlame.setHandleResultName( + dictHandleResultMapings.stream() + .map(SupDictHandleResultMaping::getInternalName) + .collect(Collectors.joining("、")) + ); + } catch (Exception e) { + log.warn("【阶段2同步】责任追究映射失败: verifyPunish={}", blame.getVerifyPunish(), e); + } + } + + // 查证属实问题映射 - 创建 NegativeProblemRelation + if (StrUtil.isNotBlank(blame.getVerifyProblem())) { + try { + List externalNames = JSON.parseArray(blame.getVerifyProblem(), String.class); + List problemTypeMapings = dictProblemTypeMapingService.list(externalNames); + for (SupDictProblemTypeMaping problemTypeMaping : problemTypeMapings) { + SupDictProblemType threeProblem = problemTypeService.getById(problemTypeMaping.getInternalId()); + if (threeProblem == null) { + log.warn("【阶段2同步】未找到三级问题类型: internalId={}", problemTypeMaping.getInternalId()); + continue; + } + NegativeProblemRelation problemRelation = new NegativeProblemRelation(); + problemRelation.setBlameId(negativeBlame.getBlameId()); + problemRelation.setNegativeId(negativeId); + problemRelation.setThreeLevelCode(threeProblem.getId()); + problemRelation.setThreeLevelContent(threeProblem.getName()); + // 二级 + String parentCode = threeProblem.getParentCode(); + SupDictProblemType twoProblem = null; + if (StrUtil.isNotBlank(parentCode)) { + twoProblem = problemTypeService.getById(parentCode); + if (twoProblem != null) { + problemRelation.setTwoLevelCode(twoProblem.getId()); + problemRelation.setTwoLevelContent(twoProblem.getName()); + } + } + // 一级 + if (twoProblem != null) { + String twoParentCode = twoProblem.getParentCode(); + if (StrUtil.isNotBlank(twoParentCode)) { + SupDictProblemType oneProblem = problemTypeService.getById(twoParentCode); + if (oneProblem != null) { + problemRelation.setOneLevelCode(oneProblem.getId()); + problemRelation.setOneLevelContent(oneProblem.getName()); + } + } + } + negativeProblemRelationService.save(problemRelation); + } + } catch (Exception e) { + log.warn("【阶段2同步】查证属实问题映射失败: verifyProblem={}", blame.getVerifyProblem(), e); + } + } + + // 保存 NegativeBlame + blameService.save(negativeBlame); + result.add(negativeBlame); + log.debug("【阶段2同步】保存涉及人: negativeId={}, blameName={}", negativeId, negativeBlame.getBlameName()); + } + return result; + } + + /** + * 同步核查情况:Mail 表的核查字段 -> Negative 表 + */ + private void syncCheckStatus(Mail mail, Negative negative) { + String checkStatus = null; + String checkStatusName = null; + String checkStatusCode = null; + + // 核查情况映射 + String verifyIsTrue = mail.getVerifyIsTrue(); + if ("属实".equals(verifyIsTrue)) { + checkStatus = "1"; + checkStatusName = "属实"; + checkStatusCode = "1"; + } else if ("基本属实".equals(verifyIsTrue)) { + checkStatus = "2"; + checkStatusName = "部分属实"; + checkStatusCode = "2"; + } else if ("不属实".equals(verifyIsTrue)) { + checkStatus = "3"; + checkStatusName = "不属实"; + checkStatusCode = "5"; + } + + // 核查结论(优先 verifyDetails,其次 completionComment) + String checkStatusDesc = null; + if (StrUtil.isNotBlank(mail.getVerifyDetails())) { + checkStatusDesc = mail.getVerifyDetails(); + } else if (StrUtil.isNotBlank(mail.getCompletionComment())) { + checkStatusDesc = mail.getCompletionComment(); + } + + // 只有存在核查情况时才更新 + if (checkStatus != null || StrUtil.isNotBlank(checkStatusDesc)) { + // 防御编程:使用 updateById 确保只更新单条记录 + negative.setCheckStatus(checkStatus); + negative.setCheckStatusName(checkStatusName); + negative.setCheckStatusDesc(checkStatusDesc); + negative.setCheckStatusCode(checkStatusCode); + boolean updated = negativeService.updateById(negative); + if (updated) { + log.debug("【阶段2同步】更新核查情况: negativeId={}, checkStatus={}, checkStatusDesc={}", + negative.getId(), checkStatus, checkStatusDesc); + } else { + log.warn("【阶段2同步】更新核查情况失败,Negative不存在或已被删除: negativeId={}", negative.getId()); + } + } + } + + /** + * 同步涉及人:MailBlame -> NegativeBlame(组装并保存) + * 参照 MailService#saveMailbox 的 for 循环逻辑 + */ + + /** + * 同步核查附件:Mail.verifyAttachments -> NegativeFile(组装并保存) + */ + private void syncFiles(Mail mail, String negativeId) { + if (StrUtil.isBlank(mail.getVerifyAttachments())) { + return; + } + + List attachments = JSON.parseArray(mail.getVerifyAttachments(), MailAttachmentDTO.class); + if (CollectionUtil.isEmpty(attachments)) { + return; + } + + // 幂等性检查:如果该 Negative 已有附件,直接跳过 + long existingCount = fileService.count( + new LambdaQueryWrapper().eq(NegativeFile::getNegtiveId, negativeId) + ); + if (existingCount > 0) { + log.info("【阶段2同步】附件已存在,跳过: negativeId={}", negativeId); + return; + } + + for (MailAttachmentDTO att : attachments) { + NegativeFile file = new NegativeFile(); + file.setFileId(IdUtil.getSnowflakeNextIdStr()); + file.setNegtiveId(negativeId); + file.setFileName(StrUtil.isNotBlank(att.getOriginFilename()) ? att.getOriginFilename() : getFileName(att.getFilepath())); + file.setFilePath(buildFileUrl(att)); + file.setCrtTime(LocalDateTime.now()); + fileService.save(file); + log.debug("【阶段2同步】保存核查附件: negativeId={}, fileName={}", negativeId, file.getFileName()); + } + } + + /** + * 更新同步标记(所有同步操作成功后) + * + * @param cc + */ + private void updateSyncTag(ComplaintCollection cc) { + ComplaintCollectionUpdateParam complaintCollectionUpdateParam = new ComplaintCollectionUpdateParam(); + complaintCollectionUpdateParam.setId(cc.getId()); + complaintCollectionUpdateParam.setBlameSyncStatus("1"); + boolean updated = complaintCollectionResourceService.updateSelectiveById(complaintCollectionUpdateParam); + if (!updated) { + throw new RuntimeException("更新blameSyncStatus失败: ccId=" + cc.getId()); + } + } + + /** + * 构建文件完整URL + */ + private String buildFileUrl(MailAttachmentDTO att) { + String filepath = null; + if (StrUtil.isNotBlank(att.getDocxFilepath())) { + filepath = "http://65.47.60.145/lan-api/api/file/stream/" + att.getDocxFilepath(); + } else if (StrUtil.isNotBlank(att.getFilepath())) { + filepath = "http://65.47.60.145/lan-api/api/file/stream/" + att.getFilepath(); + } + return filepath; + } + + // ==================== 组装 ==================== + + /** + * 构建 NegativeDataOnlyDto + */ + private NegativeDataOnlyDto buildNegativeDto(Mail mail, SupDepart secondDepart, SupDepart thirdDepart) { + NegativeDataOnlyDto dto = new NegativeDataOnlyDto(); + // 基础字段 + dto.setOriginId(mail.getId()); + dto.setDiscoveryTime(mail.getMailTime()); + // 创建时间以来信时间为准 + dto.setCrtTime(mail.getMailTime()); + dto.setProblemSourcesCode(ProblemSourcesEnum.JZXX.getValue()); + dto.setProblemSources(ProblemSourcesEnum.JZXX.getLabel()); + // 业务类型(其他) + dto.setBusinessTypeCode(BusinessTypeEnum.QT.getValue()); + dto.setBusinessTypeName(BusinessTypeEnum.QT.getLabel()); + // 追责对象(涉及个人) + dto.setAccountabilityTarget(AccountabilityTargetEnum.PERSONAL.getValue()); + // 反映人信息 + dto.setResponderName(mail.getContactName()); + dto.setContactPhone(mail.getContactPhone()); + // 办理状态(已完成) + dto.setProcessingStatus("completed"); + // 来信内容 + dto.setThingDesc(mail.getContent()); + + // 涉及单位设置 + dto.setInvolveDepartId(thirdDepart.getId()); + dto.setInvolveDepartName(thirdDepart.getName()); + // 办理单位设置 + dto.setHandleSecondDepartId(secondDepart.getId()); + dto.setHandleSecondDepartName(secondDepart.getName()); + dto.setHandleThreeDepartId(thirdDepart.getId()); + dto.setHandleThreeDepartName(thirdDepart.getName()); + + // 来信附件 + dto.setThingFiles(buildThingFiles(mail.getAttachments())); + + // 来源字段 + dto.setSourceType(NegativeSourceTypeEnum.COMPLAINT_REPORT.getCode()); + dto.setSourceTypeDesc(NegativeSourceTypeEnum.COMPLAINT_REPORT.getDesc()); +// dto.setIssuingDepartId("-1"); +// dto.setIssuingDepartName("自定抓取"); + return dto; + } + + /** + * 构建问题附件列表 + */ + private List buildThingFiles(String attachmentsJson) { + List attachments = parseAttachments(attachmentsJson); + if (CollectionUtil.isEmpty(attachments)) { + return Collections.emptyList(); + } + List list = new ArrayList<>(); + for (MailAttachmentDTO att : attachments) { + NegativeThingFile file = new NegativeThingFile(); + file.setFileName(StrUtil.isNotBlank(att.getOriginFilename()) ? att.getOriginFilename() : getFileName(att.getFilepath())); + file.setFilePath(att.getFilepath()); + file.setCreateTime(LocalDateTime.now()); + list.add(file); + } + return list; + } + + /** + * 解析附件 JSON + */ + private List parseAttachments(String json) { + if (StrUtil.isBlank(json)) { + return Collections.emptyList(); + } + try { + List list = JSON.parseArray(json, MailAttachmentDTO.class); + list.forEach(item -> { + String filepath = null; + if (StrUtil.isNotBlank(item.getDocxFilepath())) { + filepath = "http://65.47.60.145/lan-api/api/file/stream/" + item.getDocxFilepath(); + } else { + filepath = "http://65.47.60.145/lan-api/api/file/stream/" + item.getFilepath(); + } + item.setFilepath(filepath); + }); + return list; + } catch (Exception e) { + log.warn("【局长信箱已办结抓取】附件JSON解析失败,json={}", json, e); + return Collections.emptyList(); + } + } + + /** + * 从路径获取文件名 + */ + private String getFileName(String path) { + if (path == null) return null; + int index = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\')); + return index == -1 ? path : path.substring(index + 1); + } + + // ==================== ComplaintCollection 组装 ==================== + + /** + * 构建 ComplaintCollection + */ + private ComplaintCollection buildComplaintCollection(Mail mail, String negativeId, SupDepart secondDepart, SupDepart thirdDepart) { + ComplaintCollection cc = new ComplaintCollection(); + // 设置问题编号 + cc.setNegativeId(negativeId); + cc.setOriginId(mail.getId()); + // 问题来源信息 + String sfssSourceTableSubOne = getSfssSourceTableSubOne(mail.getSource()); + cc.setSourceTable(ComplaintCollectionSourceTableEnum.MAYOR_MAILBOX.getCode()); + cc.setSourceTableSubOne(sfssSourceTableSubOne); + // 单位信息 + cc.setSecondDepartId(secondDepart.getId()); + cc.setSecondDepartName(secondDepart.getShortName()); + cc.setThirdDepartId(thirdDepart.getId()); + cc.setThirdDepartName(thirdDepart.getShortName()); + // 创建时间用来信时间 + cc.setCreateTime(mail.getMailTime()); + cc.setCreateBy("自动抓取"); + + // 身份证 + cc.setResponderIdCode(mail.getContactIdCard()); + return cc; + } + + + private String getSfssSourceTableSubOne(String str) { + if ("厅长信箱".equals(str)) { + return "23_tz"; + } + if ("mailbox".equals(str)) { + return "23_jz"; + } + if ("110_report_complaints".equals(str)) { + return "23_jb"; + } + return ""; + } +} diff --git a/src/main/java/com/biutag/supervision/service/NegativeService.java b/src/main/java/com/biutag/supervision/service/NegativeService.java index c286351..4ad7969 100644 --- a/src/main/java/com/biutag/supervision/service/NegativeService.java +++ b/src/main/java/com/biutag/supervision/service/NegativeService.java @@ -23,6 +23,7 @@ import com.biutag.supervision.pojo.domain.CountersignApply; import com.biutag.supervision.pojo.domain.NegativeDetail; import com.biutag.supervision.pojo.domain.NegativeVo; import com.biutag.supervision.pojo.dto.ActionDto; +import com.biutag.supervision.pojo.dto.NegativeDataOnlyDto; import com.biutag.supervision.pojo.dto.NegativeDto; import com.biutag.supervision.pojo.dto.complaintCollection.ComplaintCollectionPageDTO; import com.biutag.supervision.pojo.dto.flow.FirstDistributeData; @@ -188,7 +189,7 @@ public class NegativeService extends ServiceImpl { } public Negative getByOriginId(String originId) { - return getOne(new LambdaUpdateWrapper().eq(Negative::getOriginId, originId)); + return getOne(new LambdaQueryWrapper().eq(Negative::getOriginId, originId).last("LIMIT 1")); } private final SupDictDataService dictDataService; @@ -552,4 +553,135 @@ public class NegativeService extends ServiceImpl { ComplaintCollectionPageDTO complaintCollectionPageDTO = records.get(0); detail.setComplaintCollectionPageDTO(complaintCollectionPageDTO); } + + + + /** + * 保存主表数据 + * + * @param dto 保存参数 + * @return 保存的Negative实体 + */ + public Negative saveNegativeMain(NegativeDataOnlyDto dto) { + Negative negative = new Negative(); + BeanUtil.copyProperties(dto, negative); + + if (StrUtil.isBlank(negative.getId())) { + negative.setId(IdUtil.getSnowflakeNextIdStr()); + } + + LocalDateTime now = LocalDateTime.now(); + if (negative.getCrtTime() == null) { + negative.setCrtTime(now); + } + if (negative.getUpdTime() == null) { + negative.setUpdTime(now); + } + + // 处理涉及单位层级 + if (StrUtil.isNotBlank(dto.getInvolveDepartId()) && StrUtil.isBlank(negative.getSecondInvolveDepartId()) && StrUtil.isBlank(negative.getThreeInvolveDepartId())) { + SupDepart depart = departService.getById(dto.getInvolveDepartId()); + if (depart != null) { + if (DepartLevelEnum.SECOND.getValue().equals(depart.getLevel())) { + negative.setSecondInvolveDepartId(depart.getId()); + negative.setThreeInvolveDepartId(null); + } else if (DepartLevelEnum.THREE.getValue().equals(depart.getLevel())) { + negative.setThreeInvolveDepartId(depart.getId()); + negative.setSecondInvolveDepartId(depart.getPid()); + } + } + } + + // 处理列表字段转字符串 + if (CollectionUtil.isNotEmpty(dto.getInvolveProblem())) { + negative.setInvolveProblem(String.join(",", dto.getInvolveProblem())); + } + if (CollectionUtil.isNotEmpty(dto.getProblems())) { + negative.setProblems(JSON.toJSONString(dto.getProblems())); + } + + save(negative); + return negative; + } + + /** + * 保存来信附件 + */ + public void saveThingFiles(NegativeDataOnlyDto dto, String negativeId) { + if (dto.getThingFiles().isEmpty()) { + return; + } + LocalDateTime now = LocalDateTime.now(); + List files = dto.getThingFiles().stream().map(item -> { + NegativeThingFile negativeThingFile = new NegativeThingFile(); + BeanUtil.copyProperties(item, negativeThingFile); + negativeThingFile.setNegativeId(negativeId); + if (negativeThingFile.getCreateTime() == null) { + negativeThingFile.setCreateTime(now); + } + return negativeThingFile; + }).toList(); + thingFileService.saveBatch(files); + } + + /** + * 保存涉及人 + */ + public void saveBlames(NegativeDataOnlyDto dto, String negativeId) { + if (dto.getBlames().isEmpty()) { + return; + } + LocalDateTime now = LocalDateTime.now(); + List blames = dto.getBlames().stream().map(item -> { + NegativeBlame blame = new NegativeBlame(); + BeanUtil.copyProperties(item, blame); + blame.setNegativeId(negativeId); + if (blame.getCrtTime() == null) { + blame.setCrtTime(now); + } + return blame; + }).toList(); + blameService.saveBatch(blames); + } + + /** + * 保存核查附件 + */ + public void saveFiles(NegativeDataOnlyDto dto, String negativeId) { + if (dto.getFiles().isEmpty()) { + return; + } + LocalDateTime now = LocalDateTime.now(); + List files = dto.getFiles().stream().map(item -> { + NegativeFile file = new NegativeFile(); + BeanUtil.copyProperties(item, file); + file.setNegtiveId(negativeId); + if (file.getCrtTime() == null) { + file.setCrtTime(now); + } + return file; + }).toList(); + fileService.saveBatch(files); + } + + /** + * 纯数据保存 - 不触发工作流和历史记录 + * 兼容旧方法,内部调用拆分的4个方法 + * + * @param dto 保存参数 + * @return 保存的Negative实体 + */ + @Transactional(rollbackFor = Exception.class) + public Negative saveDataOnly(NegativeDataOnlyDto dto) { + Negative negative = saveNegativeMain(dto); + saveThingFiles(dto, negative.getId()); + saveBlames(dto, negative.getId()); + saveFiles(dto, negative.getId()); + return negative; + } + + + + + }