| | |
| | | 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.InternalAuditCarry; |
| | | import com.gkhy.exam.system.domain.InternalAuditCarryDept; |
| | | 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.util.List; |
| | | import java.time.LocalTime; |
| | | import java.util.*; |
| | | import java.util.function.Function; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @Service |
| | | public class InternalAuditCarryServiceImpl extends ServiceImpl<InternalAuditCarryMapper, InternalAuditCarry> 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) { |
| | |
| | | internalAuditCarryDept.setCarryId(carry.getId()); |
| | | } |
| | | carryMapper.insertCarryDept(deptList); |
| | | |
| | | saveInternalAuditCheck(carry); |
| | | |
| | | return CommonResult.success(); |
| | | } |
| | | |
| | | private CommonResult saveInternalAuditCheck(InternalAuditCarry carry) { |
| | | // 2. 空指针防护:避免deptList为null导致循环NPE |
| | | List<InternalAuditCarryDept> 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<SysDeptResponsibility> sysDeptResponsibilitys = deptDetialVo.getSysDeptResponsibilitys(); |
| | | List<InternalAuditCheckCatalogue> 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<InternalAuditCheckContent> 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(); |
| | | } |
| | | |
| | |
| | | } |
| | | Integer i = carryMapper.deletedCarryDeptByCarryId(carry.getId()); |
| | | carryMapper.insertCarryDept(deptList); |
| | | |
| | | updateInternalAuditCheck(carry); |
| | | return CommonResult.success(); |
| | | } |
| | | |
| | | private CommonResult updateInternalAuditCheck(InternalAuditCarry carry) { |
| | | // 2. 空指针防护:避免deptList为null导致循环NPE |
| | | List<InternalAuditCarryDept> 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<SysDeptResponsibility> sysDeptResponsibilitys = deptDetialVo.getSysDeptResponsibilitys(); |
| | | |
| | | List<InternalAuditCheckCatalogue> internalAuditCheckCatalogues = new ArrayList<>(); |
| | | |
| | | // 7. 构建查询条件(保留原逻辑,仅优化日志) |
| | | Map<String, Object> 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<InternalAuditCheck> 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<InternalAuditCheckContent> 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<InternalAuditCheckCatalogue> existingCatalogues = firstCheck.getCheckCatalogues(); |
| | | |
| | | // 仅当旧数据非空、且新数据已存在时,才筛选合并旧数据 |
| | | if (!CollectionUtils.isEmpty(existingCatalogues) && !internalAuditCheckCatalogues.isEmpty()) { |
| | | // 提取新数据的所有catalogue_id(用Set实现O(1)快速匹配) |
| | | Set<Integer> newCatalogueIds = internalAuditCheckCatalogues.stream() |
| | | .map(InternalAuditCheckCatalogue::getCatalogueId) |
| | | .collect(Collectors.toSet()); |
| | | |
| | | // 筛选旧数据:仅保留与新数据catalogue_id匹配的记录(避免无用旧数据) |
| | | List<InternalAuditCheckCatalogue> 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<InternalAuditCheckCatalogue> 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<InternalAuditCheck> checks) { |
| | | //收集所有检查ID |
| | | List<Integer> checkIds = checks.stream() |
| | | .map(InternalAuditCheck::getId) |
| | | .collect(Collectors.toList()); |
| | | |
| | | //批量查询所有目录 |
| | | List<InternalAuditCheckCatalogue> allCatalogues = checkCatalogueMapper.selectByCheckIds(checkIds); |
| | | |
| | | if (CollectionUtils.isEmpty(allCatalogues)) { |
| | | return; |
| | | } |
| | | |
| | | //收集所有目录ID |
| | | List<Integer> catalogueIds = allCatalogues.stream() |
| | | .map(InternalAuditCheckCatalogue::getId) |
| | | .collect(Collectors.toList()); |
| | | |
| | | //批量查询所有内容 |
| | | List<InternalAuditCheckContent> allContents = checkContentMapper.selectByCatalogueIds(catalogueIds); |
| | | |
| | | //按目录ID分组内容 |
| | | Map<Integer, List<InternalAuditCheckContent>> contentMap = allContents.stream() |
| | | .collect(Collectors.groupingBy(InternalAuditCheckContent::getCheckCatalogueId)); |
| | | |
| | | //按检查ID分组目录 |
| | | Map<Integer, List<InternalAuditCheckCatalogue>> catalogueMap = allCatalogues.stream() |
| | | .collect(Collectors.groupingBy(InternalAuditCheckCatalogue::getCheckId)); |
| | | |
| | | //组装数据 |
| | | for (InternalAuditCheck check : checks) { |
| | | List<InternalAuditCheckCatalogue> catalogues = catalogueMap.get(check.getId()); |
| | | if (!CollectionUtils.isEmpty(catalogues)) { |
| | | for (InternalAuditCheckCatalogue catalogue : catalogues) { |
| | | List<InternalAuditCheckContent> 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(); |