package com.gkhy.exam.system.service.impl; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.gkhy.exam.common.api.CommonPage; import com.gkhy.exam.common.api.CommonResult; import com.gkhy.exam.common.exception.ApiException; import com.gkhy.exam.common.utils.PageUtils; import com.gkhy.exam.common.utils.SecurityUtils; import com.gkhy.exam.system.domain.*; import com.gkhy.exam.system.domain.vo.DeptDetialVo; import com.gkhy.exam.system.mapper.InternalAuditCarryMapper; import com.gkhy.exam.system.mapper.InternalAuditCheckCatalogueMapper; import com.gkhy.exam.system.mapper.InternalAuditCheckContentMapper; import com.gkhy.exam.system.mapper.SysClauseManagementMapper; import com.gkhy.exam.system.service.InternalAuditCarryService; import com.gkhy.exam.system.service.InternalAuditCheckService; import org.checkerframework.checker.units.qual.A; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @Service public class InternalAuditCarryServiceImpl extends ServiceImpl implements InternalAuditCarryService { @Autowired private InternalAuditCarryMapper carryMapper; @Autowired private InternalAuditCheckService internalAuditCheckService; @Autowired private SysClauseManagementMapper sysClauseManagementMapper; @Autowired private InternalAuditCheckCatalogueMapper checkCatalogueMapper; @Autowired private InternalAuditCheckContentMapper checkContentMapper; @Autowired private SysDeptServiceImpl sysDeptService; @Override public CommonPage selectCarryList(InternalAuditCarry carry) { if (!SecurityUtils.adminUser()){ if (carry.getCompanyId()==null){ throw new ApiException("非管理员操作,企业id不可为空"); } } PageUtils.startPage(); List internalAuditCarries = carryMapper.selectCarryList(carry); for (InternalAuditCarry internalAuditCarry : internalAuditCarries) { List internalAuditCarryDepts = carryMapper.selectCarryDeptList(internalAuditCarry.getId()); internalAuditCarry.setDeptList(internalAuditCarryDepts); } return CommonPage.restPage(internalAuditCarries); } @Override public CommonResult insertCarry(InternalAuditCarry carry) { List internalAuditCarries = carryMapper.selectList(Wrappers.lambdaQuery() .eq(InternalAuditCarry::getCompanyId, carry.getCompanyId()) .eq(InternalAuditCarry::getYear, carry.getYear()) .eq(InternalAuditCarry::getDelFlag,1)); if (internalAuditCarries.size()>0){ throw new ApiException("当前企业已有相关数据"); } carry.setCreateBy(SecurityUtils.getUsername()); carry.setCreateTime(LocalDateTime.now()); carryMapper.insert(carry); List deptList = carry.getDeptList(); for (InternalAuditCarryDept internalAuditCarryDept : deptList) { internalAuditCarryDept.setCarryId(carry.getId()); } carryMapper.insertCarryDept(deptList); saveInternalAuditCheck(carry); return CommonResult.success(); } private CommonResult saveInternalAuditCheck(InternalAuditCarry carry) { // 2. 空指针防护:避免deptList为null导致循环NPE List deptList = carry.getDeptList(); if (CollectionUtils.isEmpty(deptList)) { return CommonResult.success(); } for (InternalAuditCarryDept internalAuditCarryDept : deptList) { // 3. 跳过空的部门项,避免后续NPE if (internalAuditCarryDept == null) { continue; } InternalAuditCheck internalAuditCheck = new InternalAuditCheck(); // 基础字段赋值(保留原逻辑,无改动) internalAuditCheck.setCompanyId(carry.getCompanyId()); internalAuditCheck.setYear(carry.getYear()); internalAuditCheck.setDeptId(internalAuditCarryDept.getDeptId()); internalAuditCheck.setPersonId(internalAuditCarryDept.getCheckId()); internalAuditCheck.setCheckTime(internalAuditCarryDept.getDate()); // 4. 时间字段安全赋值:避免date/startTime/endTime为null导致atTime()报错 LocalDate checkDate = internalAuditCarryDept.getDate(); LocalTime startTime = internalAuditCarryDept.getStartTime(); LocalTime endTime = internalAuditCarryDept.getEndTime(); if (checkDate != null && startTime != null) { internalAuditCheck.setStartTime(checkDate.atTime(startTime)); } if (checkDate != null && endTime != null) { internalAuditCheck.setEndTime(checkDate.atTime(endTime)); } // 5. 部门ID转换安全处理:避免非数字字符串导致NumberFormatException Integer deptId1 = internalAuditCarryDept.getDeptId(); Long deptId; try { deptId = Long.valueOf(deptId1); } catch (NumberFormatException e) { continue; } // 6. 查询结果空防护:避免deptDetialVo为null导致后续getSysDeptResponsibilitys()报错 DeptDetialVo deptDetialVo = sysDeptService.selectDeptById(deptId); if (deptDetialVo == null) { continue; } List sysDeptResponsibilitys = deptDetialVo.getSysDeptResponsibilitys(); List internalAuditCheckCatalogues = new ArrayList<>(); // 7. 责任项列表空防护:避免循环null集合 if (!CollectionUtils.isEmpty(sysDeptResponsibilitys)) { for (SysDeptResponsibility sysDeptResponsibility : sysDeptResponsibilitys) { if (sysDeptResponsibility == null) { continue; } InternalAuditCheckCatalogue internalAuditCheckCatalogue = new InternalAuditCheckCatalogue(); // 8. clauseId安全转换:避免null导致Math.toIntExact()报错 Long clauseId = sysDeptResponsibility.getClauseId(); if (clauseId != null) { internalAuditCheckCatalogue.setCatalogueId(Math.toIntExact(clauseId)); } else { continue; } // 9. 条款查询结果空防护:避免sysClauseManagement为null导致getPoints()报错 SysClauseManagement sysClauseManagement = sysClauseManagementMapper.selectById(clauseId); if (sysClauseManagement == null) { continue; } // 简化集合创建(原逻辑不变,仅优化初始化) List internalAuditCheckContents = new ArrayList<>(); InternalAuditCheckContent internalAuditCheckContent = new InternalAuditCheckContent(); internalAuditCheckContent.setPointKey(sysClauseManagement.getPoints()); internalAuditCheckContents.add(internalAuditCheckContent); internalAuditCheckCatalogue.setCheckContents(internalAuditCheckContents); internalAuditCheckCatalogues.add(internalAuditCheckCatalogue); } } internalAuditCheck.setCheckCatalogues(internalAuditCheckCatalogues); internalAuditCheckService.insertInternalAuditCheck(internalAuditCheck); } return CommonResult.success(); } @Override public CommonResult updateCarry(InternalAuditCarry carry) { carry.setUpdateBy(SecurityUtils.getUsername()); carry.setUpdateTime(LocalDateTime.now()); carryMapper.updateById(carry); List deptList = carry.getDeptList(); for (InternalAuditCarryDept internalAuditCarryDept : deptList) { internalAuditCarryDept.setCarryId(carry.getId()); } Integer i = carryMapper.deletedCarryDeptByCarryId(carry.getId()); carryMapper.insertCarryDept(deptList); updateInternalAuditCheck(carry); return CommonResult.success(); } private CommonResult updateInternalAuditCheck(InternalAuditCarry carry) { // 2. 空指针防护:避免deptList为null导致循环NPE List deptList = carry.getDeptList(); if (CollectionUtils.isEmpty(deptList)) { log.warn("保存/更新内部审计检查:部门列表为空,companyId={}, year={}"); return CommonResult.success(); } for (InternalAuditCarryDept internalAuditCarryDept : deptList) { // 3. 跳过空的部门项,避免后续NPE if (internalAuditCarryDept == null) { log.warn("保存/更新内部审计检查:部门项为null,跳过"); continue; } InternalAuditCheck internalAuditCheck = new InternalAuditCheck(); // 基础字段赋值(保留原逻辑不变) internalAuditCheck.setCompanyId(carry.getCompanyId()); internalAuditCheck.setYear(carry.getYear()); internalAuditCheck.setDeptId(internalAuditCarryDept.getDeptId()); internalAuditCheck.setPersonId(internalAuditCarryDept.getCheckId()); internalAuditCheck.setCheckTime(internalAuditCarryDept.getDate()); // 4. 时间字段安全赋值:避免date/startTime/endTime为null导致atTime()报错 LocalDate checkDate = internalAuditCarryDept.getDate(); LocalTime startTime = internalAuditCarryDept.getStartTime(); LocalTime endTime = internalAuditCarryDept.getEndTime(); if (checkDate != null && startTime != null) { internalAuditCheck.setStartTime(checkDate.atTime(startTime)); } else { log.warn("保存/更新内部审计检查:开始时间构造失败(日期/时段为空),deptId={}"); } if (checkDate != null && endTime != null) { internalAuditCheck.setEndTime(checkDate.atTime(endTime)); } else { log.warn("保存/更新内部审计检查:结束时间构造失败(日期/时段为空),deptId={}"); } // 5. 部门ID转换安全处理:避免非数字字符串导致NumberFormatException Integer deptIdStr = internalAuditCarryDept.getDeptId(); Long deptId; try { deptId = Long.valueOf(deptIdStr); } catch (NumberFormatException e) { continue; } // 6. 查询部门详情空防护:避免deptDetialVo为null导致后续NPE DeptDetialVo deptDetialVo = sysDeptService.selectDeptById(deptId); if (deptDetialVo == null) { log.warn("保存/更新内部审计检查:未查询到部门详情,deptId={}"); continue; } List sysDeptResponsibilitys = deptDetialVo.getSysDeptResponsibilitys(); List internalAuditCheckCatalogues = new ArrayList<>(); // 7. 构建查询条件(保留原逻辑,仅优化日志) Map queryMap = new HashMap<>(); queryMap.put("dept_id", internalAuditCheck.getDeptId()); queryMap.put("year", internalAuditCheck.getYear()); queryMap.put("company_id", internalAuditCheck.getCompanyId()); queryMap.put("del_flag", 0); List internalAuditChecks = internalAuditCheckService.selectByMap(queryMap); log.debug("保存/更新内部审计检查:查询已有记录,条件={},查询结果数={}"); // 9. 循环构建新检查项(增加多层空防护) if (!CollectionUtils.isEmpty(sysDeptResponsibilitys)) { for (SysDeptResponsibility sysDeptResponsibility : sysDeptResponsibilitys) { if (sysDeptResponsibility == null) { log.warn("保存/更新内部审计检查:部门责任项为null,跳过"); continue; } // 防护:clauseId为空跳过,避免Math.toIntExact()报错 Long clauseId = sysDeptResponsibility.getClauseId(); if (clauseId == null) { log.warn("保存/更新内部审计检查:条款ID为空,跳过该责任项"); continue; } InternalAuditCheckCatalogue catalogue = new InternalAuditCheckCatalogue(); catalogue.setCatalogueId(Math.toIntExact(clauseId)); // 防护:条款查询为空跳过,避免getPoints()报错 SysClauseManagement clauseManagement = sysClauseManagementMapper.selectById(clauseId); if (clauseManagement == null) { continue; } // 构建检查内容(保留原逻辑) List checkContents = new ArrayList<>(); InternalAuditCheckContent content = new InternalAuditCheckContent(); content.setPointKey(clauseManagement.getPoints()); checkContents.add(content); catalogue.setCheckContents(checkContents); internalAuditCheckCatalogues.add(catalogue); } } else { log.debug("保存/更新内部审计检查:部门无责任项,deptId={}"); } // 8. 批量加载详情 + 合并已有检查项(关键防护:避免internalAuditChecks为空导致get(0)索引越界) if (!CollectionUtils.isEmpty(internalAuditChecks)) { batchLoadCheckDetails(internalAuditChecks); InternalAuditCheck firstCheck = internalAuditChecks.get(0); List existingCatalogues = firstCheck.getCheckCatalogues(); // 仅当旧数据非空、且新数据已存在时,才筛选合并旧数据 if (!CollectionUtils.isEmpty(existingCatalogues) && !internalAuditCheckCatalogues.isEmpty()) { // 提取新数据的所有catalogue_id(用Set实现O(1)快速匹配) Set newCatalogueIds = internalAuditCheckCatalogues.stream() .map(InternalAuditCheckCatalogue::getCatalogueId) .collect(Collectors.toSet()); // 筛选旧数据:仅保留与新数据catalogue_id匹配的记录(避免无用旧数据) List matchedOldCatalogues = existingCatalogues.stream() .filter(oldCata -> newCatalogueIds.contains(oldCata.getCatalogueId())) .collect(Collectors.toList()); // 合并筛选后的旧数据(新数据已在列表中,旧数据仅加匹配项) internalAuditCheckCatalogues.addAll(matchedOldCatalogues); } else if (CollectionUtils.isEmpty(internalAuditCheckCatalogues)) { log.warn("保存/更新内部审计检查:无新构建的检查项,不合并旧数据,deptId={}, year={}"); } else { log.warn("保存/更新内部审计检查:已有记录无检查项,deptId={}, year={}"); } } // 去重优化:按catalogue_id可靠去重(核心修改:替代distinct(),避免依赖equals/hashCode) List uniqueCatalogues = internalAuditCheckCatalogues.stream() .collect(Collectors.toMap( InternalAuditCheckCatalogue::getCatalogueId, // 唯一键:catalogue_id(确保去重逻辑) Function.identity(), // 值:检查项对象 (oldVal, newVal) -> newVal // 冲突策略:保留新数据(如需保留旧数据,改为oldVal) )) .values() .stream() .collect(Collectors.toList()); // 最终设置(新数据全部保留,旧数据仅保留匹配项) internalAuditCheck.setCheckCatalogues(uniqueCatalogues); internalAuditCheck.setCheckCatalogues(uniqueCatalogues); // 新增/更新判断(保留原逻辑,增加日志) if (CollectionUtils.isEmpty(internalAuditChecks)) { internalAuditCheckService.insertInternalAuditCheck(internalAuditCheck); } else { InternalAuditCheck existingCheck = internalAuditChecks.get(0); internalAuditCheck.setId(existingCheck.getId()); internalAuditCheckService.updateByYearAndDeptId(internalAuditCheck); } } return CommonResult.success(); } private void batchLoadCheckDetails(List checks) { //收集所有检查ID List checkIds = checks.stream() .map(InternalAuditCheck::getId) .collect(Collectors.toList()); //批量查询所有目录 List allCatalogues = checkCatalogueMapper.selectByCheckIds(checkIds); if (CollectionUtils.isEmpty(allCatalogues)) { return; } //收集所有目录ID List catalogueIds = allCatalogues.stream() .map(InternalAuditCheckCatalogue::getId) .collect(Collectors.toList()); //批量查询所有内容 List allContents = checkContentMapper.selectByCatalogueIds(catalogueIds); //按目录ID分组内容 Map> contentMap = allContents.stream() .collect(Collectors.groupingBy(InternalAuditCheckContent::getCheckCatalogueId)); //按检查ID分组目录 Map> catalogueMap = allCatalogues.stream() .collect(Collectors.groupingBy(InternalAuditCheckCatalogue::getCheckId)); //组装数据 for (InternalAuditCheck check : checks) { List catalogues = catalogueMap.get(check.getId()); if (!CollectionUtils.isEmpty(catalogues)) { for (InternalAuditCheckCatalogue catalogue : catalogues) { List contents = contentMap.get(catalogue.getId()); catalogue.setCheckContents(contents != null ? contents : new ArrayList<>()); } check.setCheckCatalogues(catalogues); } } } @Override public CommonResult deletedCarry(Integer carryId) { InternalAuditCarry internalAuditCarry = new InternalAuditCarry(); internalAuditCarry.setId(carryId); internalAuditCarry.setDelFlag(2); internalAuditCarry.setUpdateBy(SecurityUtils.getUsername()); internalAuditCarry.setUpdateTime(LocalDateTime.now()); carryMapper.updateById(internalAuditCarry); return CommonResult.success(); } }