diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfCpPlanController.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfCpPlanController.java index 09bff449..39ed6fad 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfCpPlanController.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfCpPlanController.java @@ -98,7 +98,7 @@ public class AppEnfCpPlanController extends EfcodeCpPlanController { */ @GetMapping("/autoMatchReserve") public R autoMatchReserve() { - cpPlanService.autoMatchReserve(true, true, true); + cpPlanService.autoMatchReserveV3(true, true, true); return R.ok(); } } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/CpPlanAutoMatchJob.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/CpPlanAutoMatchJob.java index f5c7d217..7b3c06dc 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/CpPlanAutoMatchJob.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/CpPlanAutoMatchJob.java @@ -24,7 +24,7 @@ public class CpPlanAutoMatchJob { */ public void execute() { log.info("[CpPlanAutoMatchJob] 定时任务触发:计划自动匹配预约"); - cpPlanService.autoMatchReserve(false, true, true); + cpPlanService.autoMatchReserveV3(false, true, true); } /** @@ -32,6 +32,6 @@ public class CpPlanAutoMatchJob { */ public void executeForce() { log.info("[CpPlanAutoMatchJob] 强制触发:计划自动匹配预约"); - cpPlanService.autoMatchReserve(true, true, true); + cpPlanService.autoMatchReserveV3(true, true, true); } } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpPlanService.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpPlanService.java index 3691c4ca..7ceec814 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpPlanService.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpPlanService.java @@ -88,7 +88,7 @@ public interface IEfcodeCpPlanService { * @param insertReserve 是否将预约记录插入数据库;为false时仅计算匹配结果不落库 * @return 按 planGroupId 分组的预约记录列表(key=planGroupId, value=该组预约记录) */ - Map> autoMatchReserve(boolean forceMatch, boolean updatePlan, boolean insertReserve); + //Map> autoMatchReserve(boolean forceMatch, boolean updatePlan, boolean insertReserve); @Transactional(rollbackFor = Exception.class) Map> autoMatchReserveV3(boolean forceMatch, boolean updatePlan, boolean insertReserve); @@ -102,7 +102,7 @@ public interface IEfcodeCpPlanService { * @param insertReserve 是否将预约记录插入数据库;为false时仅计算匹配结果不落库 * @return 按 planGroupId 分组的预约记录列表 */ - Map> autoMatchReserveV2(boolean forceMatch, boolean updatePlan, boolean insertReserve); + //Map> autoMatchReserveV2(boolean forceMatch, boolean updatePlan, boolean insertReserve); /** * 计划到期自动生成任务 diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java index 6791c6ad..f9741081 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java @@ -587,160 +587,160 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService { * @param insertReserve 是否将预约记录插入数据库;为false时仅计算匹配结果不落库 * @return 按 planGroupId 分组的预约记录列表 */ - @Transactional(rollbackFor = Exception.class) - @Override - public Map> autoMatchReserve(boolean forceMatch, boolean updatePlan, boolean insertReserve) { - log.info("[CpPlan] 开始执行计划自动匹配预约, forceMatch={}, updatePlan={}, insertReserve={}", forceMatch, updatePlan, insertReserve); - Map> resultMap = new HashMap<>(); - - // 1. 日期校验:如果不是强制匹配,则判断当前天数是否等于 CP_SETTING_AUTO_MATCH_START - if (!forceMatch) { - int autoMatchStart = cpSettingService.getAutoMatchStart(); - int today = LocalDate.now().getDayOfMonth(); - if (today != autoMatchStart) { - log.info("[CpPlan] 当前日期{}号,不等于设定的自动匹配日期{}号,跳过执行", today, autoMatchStart); - return resultMap; - } - } - - // 2. 获取最大联合单位数量 - int maxAutoMatchUnionUnit = cpSettingService.getMaxAutoMatchUnionUnit(); - - // 3. 查询待匹配的计划:plan_date > 当前时间 且 system_reserved=0, reserve_status=1, is_public=1, is_union=1 - Date now = new Date(); - LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.gt(EfcodeCpPlan::getPlanDate, now); - lqw.eq(EfcodeCpPlan::getSystemReserved, 0L); - lqw.eq(EfcodeCpPlan::getReserveStatus, 1L); - lqw.eq(EfcodeCpPlan::getIsPublic, 1L); - lqw.eq(EfcodeCpPlan::getIsUnion, 1L); - lqw.eq(EfcodeCpPlan::getIsDelete, 0L); - lqw.orderByAsc(EfcodeCpPlan::getPlanDate); - List pendingPlans = baseMapper.selectList(lqw); - - if (pendingPlans.isEmpty()) { - log.info("[CpPlan] 没有找到待匹配的计划记录,执行结束"); - return resultMap; - } - log.info("[CpPlan] 共查询到{}条待匹配计划", pendingPlans.size()); - - // 4. 已处理过的“企业+周”组合(同一轮中同企业同周不重复处理,但不同周分别匹配) - Set processedKeys = new HashSet<>(); - int matchedCount = 0; - - for (EfcodeCpPlan plan : pendingPlans) { - String enterpriseNumber = plan.getEnterpriseNumber(); - if (StringUtils.isBlank(enterpriseNumber)) { - continue; - } - - // 5. 查找计划所在自然周(周一~周日)内同企业、不同执法单位的其他待匹配计划 - LocalDate planLocalDate = plan.getPlanDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); - LocalDate weekStartDate = planLocalDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); - LocalDate weekEndDate = planLocalDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)); - - // 按“企业+周起始日”去重,同企业同周只处理一次 - String processKey = enterpriseNumber + "_" + weekStartDate; - if (processedKeys.contains(processKey)) { - continue; - } - Date weekStart = Date.from(weekStartDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); - Date weekEnd = Date.from(weekEndDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); - - LambdaQueryWrapper weekLqw = Wrappers.lambdaQuery(); - weekLqw.ge(EfcodeCpPlan::getPlanDate, weekStart); - weekLqw.le(EfcodeCpPlan::getPlanDate, weekEnd); - weekLqw.eq(EfcodeCpPlan::getEnterpriseNumber, enterpriseNumber); - weekLqw.eq(EfcodeCpPlan::getSystemReserved, 0L); - weekLqw.eq(EfcodeCpPlan::getReserveStatus, 1L); - weekLqw.eq(EfcodeCpPlan::getIsPublic, 1L); - weekLqw.eq(EfcodeCpPlan::getIsUnion, 1L); - weekLqw.eq(EfcodeCpPlan::getIsDelete, 0L); - weekLqw.orderByAsc(EfcodeCpPlan::getPlanDate); - List samePlans = baseMapper.selectList(weekLqw); - - // 6. 按不同执法单位去重,取不同 bureau_dept_id 的计划 - List distinctUnitPlans = new ArrayList<>(); - Set seenBureauDeptIds = new HashSet<>(); - for (EfcodeCpPlan sp : samePlans) { - if (!seenBureauDeptIds.contains(sp.getBureauDeptId())) { - seenBureauDeptIds.add(sp.getBureauDeptId()); - distinctUnitPlans.add(sp); - } - // 限制最大联合数量 - if (distinctUnitPlans.size() >= maxAutoMatchUnionUnit) { - break; - } - } - - // 7. 如果只有一个单位的计划,说明没有可联合的,跳过 - if (distinctUnitPlans.size() <= 1) { - log.debug("[CpPlan] 企业[{}]一周内只有1个单位的计划,跳过", enterpriseNumber); - continue; - } - - // 8. 生成预约记录 - 使用同一个 plan_group_id - String planGroupId = "Temp"+"_"+UUID.randomUUID().toString().replace("-", ""); - Date reserveTime = new Date(); - List groupReserves = new ArrayList<>(); - - // 拼接参与单位名称,用于 opMessage - String unitNames = distinctUnitPlans.stream() - .map(EfcodeCpPlan::getBureauDeptName) - .filter(StringUtils::isNotBlank) - .collect(Collectors.joining(",")); - String opMessage = "由于计划执法时间安排较近,系统推荐进行联合,参与单位为:" + unitNames + ".请确认."; - - for (int i = 0; i < distinctUnitPlans.size(); i++) { - EfcodeCpPlan matchedPlan = distinctUnitPlans.get(i); - EfcodeCpReserve reserve = new EfcodeCpReserve(); - reserve.setPlanId(matchedPlan.getId()); - reserve.setPlanGroupId(planGroupId); - reserve.setReserveTime(reserveTime); - reserve.setOpStatus(3L); // 待确认 - reserve.setOpOrder(0L); // 系统匹配默认为0 - reserve.setOpMessage(opMessage); - reserve.setOpSetDate(matchedPlan.getPlanDate()); - reserve.setOpSetTime(matchedPlan.getPlanTime()); - reserve.setResFrom(1L); // 系统匹配 - reserve.setSenderId("from_system"); - reserve.setReceiverId(String.valueOf(matchedPlan.getCreateBy())); - - if (insertReserve) { - efcodeCpReserveMapper.insert(reserve); - } - groupReserves.add(reserve); - } - - // 9. 更新计划: 将同企业一周内所有待匹配计划标记为已系统匹配,防止重复匹配 - if (updatePlan) { - for (EfcodeCpPlan sp : samePlans) { - EfcodeCpPlan planUpdate = new EfcodeCpPlan(); - planUpdate.setId(sp.getId()); - planUpdate.setSystemReserved(1L); - baseMapper.updateById(planUpdate); - } - // 被选中参与联合的计划额外更新 reserve_status=2(预约中) - for (EfcodeCpPlan dp : distinctUnitPlans) { - EfcodeCpPlan planUpdate = new EfcodeCpPlan(); - planUpdate.setId(dp.getId()); - planUpdate.setReserveStatus(2L); - baseMapper.updateById(planUpdate); - } - } - - resultMap.put(planGroupId, groupReserves); - - // 标记该企业已处理 - processedKeys.add(enterpriseNumber); - matchedCount++; - log.info("[CpPlan] 企业[{}]匹配成功,联合{}个单位,planGroupId={}", - enterpriseNumber, distinctUnitPlans.size(), planGroupId); - } - - log.info("[CpPlan] 计划自动匹配预约执行完毕,共匹配{}组联合预约", matchedCount); - return resultMap; - } +// @Transactional(rollbackFor = Exception.class) +// @Override +// public Map> autoMatchReserve(boolean forceMatch, boolean updatePlan, boolean insertReserve) { +// log.info("[CpPlan] 开始执行计划自动匹配预约, forceMatch={}, updatePlan={}, insertReserve={}", forceMatch, updatePlan, insertReserve); +// Map> resultMap = new HashMap<>(); +// +// // 1. 日期校验:如果不是强制匹配,则判断当前天数是否等于 CP_SETTING_AUTO_MATCH_START +// if (!forceMatch) { +// int autoMatchStart = cpSettingService.getAutoMatchStart(); +// int today = LocalDate.now().getDayOfMonth(); +// if (today != autoMatchStart) { +// log.info("[CpPlan] 当前日期{}号,不等于设定的自动匹配日期{}号,跳过执行", today, autoMatchStart); +// return resultMap; +// } +// } +// +// // 2. 获取最大联合单位数量 +// int maxAutoMatchUnionUnit = cpSettingService.getMaxAutoMatchUnionUnit(); +// +// // 3. 查询待匹配的计划:plan_date > 当前时间 且 system_reserved=0, reserve_status=1, is_public=1, is_union=1 +// Date now = new Date(); +// LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); +// lqw.gt(EfcodeCpPlan::getPlanDate, now); +// lqw.eq(EfcodeCpPlan::getSystemReserved, 0L); +// lqw.eq(EfcodeCpPlan::getReserveStatus, 1L); +// lqw.eq(EfcodeCpPlan::getIsPublic, 1L); +// lqw.eq(EfcodeCpPlan::getIsUnion, 1L); +// lqw.eq(EfcodeCpPlan::getIsDelete, 0L); +// lqw.orderByAsc(EfcodeCpPlan::getPlanDate); +// List pendingPlans = baseMapper.selectList(lqw); +// +// if (pendingPlans.isEmpty()) { +// log.info("[CpPlan] 没有找到待匹配的计划记录,执行结束"); +// return resultMap; +// } +// log.info("[CpPlan] 共查询到{}条待匹配计划", pendingPlans.size()); +// +// // 4. 已处理过的“企业+周”组合(同一轮中同企业同周不重复处理,但不同周分别匹配) +// Set processedKeys = new HashSet<>(); +// int matchedCount = 0; +// +// for (EfcodeCpPlan plan : pendingPlans) { +// String enterpriseNumber = plan.getEnterpriseNumber(); +// if (StringUtils.isBlank(enterpriseNumber)) { +// continue; +// } +// +// // 5. 查找计划所在自然周(周一~周日)内同企业、不同执法单位的其他待匹配计划 +// LocalDate planLocalDate = plan.getPlanDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); +// LocalDate weekStartDate = planLocalDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); +// LocalDate weekEndDate = planLocalDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)); +// +// // 按“企业+周起始日”去重,同企业同周只处理一次 +// String processKey = enterpriseNumber + "_" + weekStartDate; +// if (processedKeys.contains(processKey)) { +// continue; +// } +// Date weekStart = Date.from(weekStartDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); +// Date weekEnd = Date.from(weekEndDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); +// +// LambdaQueryWrapper weekLqw = Wrappers.lambdaQuery(); +// weekLqw.ge(EfcodeCpPlan::getPlanDate, weekStart); +// weekLqw.le(EfcodeCpPlan::getPlanDate, weekEnd); +// weekLqw.eq(EfcodeCpPlan::getEnterpriseNumber, enterpriseNumber); +// weekLqw.eq(EfcodeCpPlan::getSystemReserved, 0L); +// weekLqw.eq(EfcodeCpPlan::getReserveStatus, 1L); +// weekLqw.eq(EfcodeCpPlan::getIsPublic, 1L); +// weekLqw.eq(EfcodeCpPlan::getIsUnion, 1L); +// weekLqw.eq(EfcodeCpPlan::getIsDelete, 0L); +// weekLqw.orderByAsc(EfcodeCpPlan::getPlanDate); +// List samePlans = baseMapper.selectList(weekLqw); +// +// // 6. 按不同执法单位去重,取不同 bureau_dept_id 的计划 +// List distinctUnitPlans = new ArrayList<>(); +// Set seenBureauDeptIds = new HashSet<>(); +// for (EfcodeCpPlan sp : samePlans) { +// if (!seenBureauDeptIds.contains(sp.getBureauDeptId())) { +// seenBureauDeptIds.add(sp.getBureauDeptId()); +// distinctUnitPlans.add(sp); +// } +// // 限制最大联合数量 +// if (distinctUnitPlans.size() >= maxAutoMatchUnionUnit) { +// break; +// } +// } +// +// // 7. 如果只有一个单位的计划,说明没有可联合的,跳过 +// if (distinctUnitPlans.size() <= 1) { +// log.debug("[CpPlan] 企业[{}]一周内只有1个单位的计划,跳过", enterpriseNumber); +// continue; +// } +// +// // 8. 生成预约记录 - 使用同一个 plan_group_id +// String planGroupId = "Temp"+"_"+UUID.randomUUID().toString().replace("-", ""); +// Date reserveTime = new Date(); +// List groupReserves = new ArrayList<>(); +// +// // 拼接参与单位名称,用于 opMessage +// String unitNames = distinctUnitPlans.stream() +// .map(EfcodeCpPlan::getBureauDeptName) +// .filter(StringUtils::isNotBlank) +// .collect(Collectors.joining(",")); +// String opMessage = "由于计划执法时间安排较近,系统推荐进行联合,参与单位为:" + unitNames + ".请确认."; +// +// for (int i = 0; i < distinctUnitPlans.size(); i++) { +// EfcodeCpPlan matchedPlan = distinctUnitPlans.get(i); +// EfcodeCpReserve reserve = new EfcodeCpReserve(); +// reserve.setPlanId(matchedPlan.getId()); +// reserve.setPlanGroupId(planGroupId); +// reserve.setReserveTime(reserveTime); +// reserve.setOpStatus(3L); // 待确认 +// reserve.setOpOrder(0L); // 系统匹配默认为0 +// reserve.setOpMessage(opMessage); +// reserve.setOpSetDate(matchedPlan.getPlanDate()); +// reserve.setOpSetTime(matchedPlan.getPlanTime()); +// reserve.setResFrom(1L); // 系统匹配 +// reserve.setSenderId("from_system"); +// reserve.setReceiverId(String.valueOf(matchedPlan.getCreateBy())); +// +// if (insertReserve) { +// efcodeCpReserveMapper.insert(reserve); +// } +// groupReserves.add(reserve); +// } +// +// // 9. 更新计划: 将同企业一周内所有待匹配计划标记为已系统匹配,防止重复匹配 +// if (updatePlan) { +// for (EfcodeCpPlan sp : samePlans) { +// EfcodeCpPlan planUpdate = new EfcodeCpPlan(); +// planUpdate.setId(sp.getId()); +// planUpdate.setSystemReserved(1L); +// baseMapper.updateById(planUpdate); +// } +// // 被选中参与联合的计划额外更新 reserve_status=2(预约中) +// for (EfcodeCpPlan dp : distinctUnitPlans) { +// EfcodeCpPlan planUpdate = new EfcodeCpPlan(); +// planUpdate.setId(dp.getId()); +// planUpdate.setReserveStatus(2L); +// baseMapper.updateById(planUpdate); +// } +// } +// +// resultMap.put(planGroupId, groupReserves); +// +// // 标记该企业已处理 +// processedKeys.add(enterpriseNumber); +// matchedCount++; +// log.info("[CpPlan] 企业[{}]匹配成功,联合{}个单位,planGroupId={}", +// enterpriseNumber, distinctUnitPlans.size(), planGroupId); +// } +// +// log.info("[CpPlan] 计划自动匹配预约执行完毕,共匹配{}组联合预约", matchedCount); +// return resultMap; +// } @Transactional(rollbackFor = Exception.class) @Override @@ -1003,188 +1003,188 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService { * @param insertReserve 是否将预约记录插入数据库;为false时仅计算匹配结果不落库 * @return 按 planGroupId 分组的预约记录列表 */ - @Transactional(rollbackFor = Exception.class) - @Override - public Map> autoMatchReserveV2(boolean forceMatch, boolean updatePlan, boolean insertReserve) { - log.info("[CpPlan-V2] 开始执行计划自动匹配预约, forceMatch={}, updatePlan={}, insertReserve={}", forceMatch, updatePlan, insertReserve); - Map> resultMap = new HashMap<>(); - - // 1. 日期校验:如果不是强制匹配,则判断当前天数是否等于 CP_SETTING_AUTO_MATCH_START - if (!forceMatch) { - int autoMatchStart = cpSettingService.getAutoMatchStart(); - int today = LocalDate.now().getDayOfMonth(); - if (today != autoMatchStart) { - log.info("[CpPlan-V2] 当前日期{}号,不等于设定的自动匹配日期{}号,跳过执行", today, autoMatchStart); - return resultMap; - } - } - - // 2. 获取最大联合单位数量 - int maxUnionUnit = cpSettingService.getMaxUnionUnit(); - - // 2.1 获取系统匹配预约周数范围 - int systemMatchWeeks = cpSettingService.getSystemMatchWeeks(); - log.info("[CpPlan-V2] 系统匹配周数范围={}", systemMatchWeeks); - - // 3. 查询待匹配的计划:plan_date > 当前时间 且 system_reserved=0, manual_reserved=0, reserve_status=1, is_public=1, is_union=1 - Date now = new Date(); - LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.gt(EfcodeCpPlan::getPlanDate, now); - lqw.eq(EfcodeCpPlan::getSystemReserved, 0L); - lqw.eq(EfcodeCpPlan::getManualReserved, 0L); - lqw.eq(EfcodeCpPlan::getReserveStatus, 1L); - lqw.eq(EfcodeCpPlan::getIsPublic, 1L); - lqw.eq(EfcodeCpPlan::getIsUnion, 1L); - lqw.eq(EfcodeCpPlan::getIsDelete, 0L); - lqw.orderByAsc(EfcodeCpPlan::getPlanDate); - List pendingPlans = baseMapper.selectList(lqw); - - if (pendingPlans.isEmpty()) { - log.info("[CpPlan-V2] 没有找到待匹配的计划记录,执行结束"); - return resultMap; - } - log.info("[CpPlan-V2] 共查询到{}条待匹配计划", pendingPlans.size()); - - // 4. 已处理过的"企业+周"组合,同企业同周只处理一次 - Set processedKeys = new HashSet<>(); - int matchedCount = 0; - - for (EfcodeCpPlan plan : pendingPlans) { - String enterpriseNumber = plan.getEnterpriseNumber(); - if (StringUtils.isBlank(enterpriseNumber)) { - continue; - } - - // 5. 计算计划所在的时间范围:以计划所在自然周的周一为起始,向后扩展 systemMatchWeeks 周 - LocalDate planLocalDate = plan.getPlanDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); - LocalDate weekStartDate = planLocalDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); - LocalDate weekEndDate = weekStartDate.plusWeeks(systemMatchWeeks).minusDays(1); // 扩展N周后的周日 - - // 按"企业+周起始日"去重,同企业同周只处理一次 - String processKey = enterpriseNumber + "_" + weekStartDate; - if (processedKeys.contains(processKey)) { - continue; - } - processedKeys.add(processKey); - - // 6. 查找该自然周内同企业的所有待匹配计划 - Date weekStart = Date.from(weekStartDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); - Date weekEnd = Date.from(weekEndDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); - - LambdaQueryWrapper weekLqw = Wrappers.lambdaQuery(); - weekLqw.ge(EfcodeCpPlan::getPlanDate, weekStart); - weekLqw.le(EfcodeCpPlan::getPlanDate, weekEnd); - weekLqw.eq(EfcodeCpPlan::getEnterpriseNumber, enterpriseNumber); - weekLqw.eq(EfcodeCpPlan::getSystemReserved, 0L); - weekLqw.eq(EfcodeCpPlan::getManualReserved, 0L); - weekLqw.eq(EfcodeCpPlan::getReserveStatus, 1L); - weekLqw.eq(EfcodeCpPlan::getIsPublic, 1L); - weekLqw.eq(EfcodeCpPlan::getIsUnion, 1L); - weekLqw.eq(EfcodeCpPlan::getIsDelete, 0L); - weekLqw.orderByAsc(EfcodeCpPlan::getPlanDate); - List samePlans = baseMapper.selectList(weekLqw); - - // 7. 按 bureau_dept_id 去重,每个单位取一条代表计划 - List distinctUnitPlans = new ArrayList<>(); - Set seenBureauDeptIds = new HashSet<>(); - for (EfcodeCpPlan sp : samePlans) { - String deptId = sp.getBureauDeptId(); - if (StringUtils.isNotBlank(deptId) && !seenBureauDeptIds.contains(deptId)) { - seenBureauDeptIds.add(deptId); - distinctUnitPlans.add(sp); - } - } - - // 8. 只有1个单位的计划,无法联合,跳过 - if (distinctUnitPlans.size() <= 1) { - log.debug("[CpPlan-V2] 企业[{}] 周[{}~{}]内只有1个单位的计划,跳过", enterpriseNumber, weekStartDate, weekEndDate); - continue; - } - - // 9. 按最大联合单位数量分组 - List> groups = new ArrayList<>(); - for (int i = 0; i < distinctUnitPlans.size(); i += maxUnionUnit) { - int end = Math.min(i + maxUnionUnit, distinctUnitPlans.size()); - List group = distinctUnitPlans.subList(i, end); - if (group.size() >= 2) { - groups.add(new ArrayList<>(group)); - } - } - - if (groups.isEmpty()) { - continue; - } - - // 10. 为每组生成预约记录 - Set matchedPlanIds = new HashSet<>(); - for (List group : groups) { - String planGroupId = "Temp" + "_" + UUID.randomUUID().toString().replace("-", ""); - Date reserveTime = new Date(); - List groupReserves = new ArrayList<>(); - - String unitNames = group.stream() - .map(EfcodeCpPlan::getBureauDeptName) - .filter(StringUtils::isNotBlank) - .collect(Collectors.joining(",")); - String opMessage = "由于计划执法时间安排较近,系统推荐进行联合,参与单位为:" + unitNames + ".请确认."; - - for (EfcodeCpPlan matchedPlan : group) { - EfcodeCpReserve reserve = new EfcodeCpReserve(); - reserve.setPlanId(matchedPlan.getId()); - reserve.setPlanGroupId(planGroupId); - reserve.setReserveTime(reserveTime); - reserve.setOpStatus(3L); // 待确认 - reserve.setOpOrder(0L); // 系统匹配默认为0 - reserve.setOpMessage(opMessage); - reserve.setOpSetDate(matchedPlan.getPlanDate()); - reserve.setOpSetTime(matchedPlan.getPlanTime()); - reserve.setResFrom(1L); // 系统匹配 - reserve.setSenderId("from_system"); - reserve.setReceiverId(String.valueOf(matchedPlan.getCreateBy())); - - if (insertReserve) { - efcodeCpReserveMapper.insert(reserve); - } - groupReserves.add(reserve); - } - - // 更新被选中参与联合的计划: reserve_status=2(预约中), system_reserved=1 - if (updatePlan) { - for (EfcodeCpPlan dp : group) { - EfcodeCpPlan planUpdate = new EfcodeCpPlan(); - planUpdate.setId(dp.getId()); - planUpdate.setReserveStatus(2L); - planUpdate.setSystemReserved(1L); - baseMapper.updateById(planUpdate); - matchedPlanIds.add(dp.getId()); - } - } - - resultMap.put(planGroupId, groupReserves); - matchedCount++; - log.info("[CpPlan-V2] 企业[{}] 周[{}~{}] 匹配成功,联合{}个单位,planGroupId={}", - enterpriseNumber, weekStartDate, weekEndDate, group.size(), planGroupId); - } - - // 11. 将已成功匹配的单位在该企业该周内的所有计划标记为 system_reserved=1,防止重复匹配 - if (updatePlan && !groups.isEmpty()) { - for (EfcodeCpPlan sp : samePlans) { - if (matchedPlanIds.contains(sp.getId())) { - continue; - } - if (seenBureauDeptIds.contains(sp.getBureauDeptId())) { - EfcodeCpPlan planUpdate = new EfcodeCpPlan(); - planUpdate.setId(sp.getId()); - planUpdate.setSystemReserved(1L); - baseMapper.updateById(planUpdate); - } - } - } - } - - log.info("[CpPlan-V2] 计划自动匹配预约执行完毕,共匹配{}组联合预约", matchedCount); - return resultMap; - } +// @Transactional(rollbackFor = Exception.class) +// @Override +// public Map> autoMatchReserveV2(boolean forceMatch, boolean updatePlan, boolean insertReserve) { +// log.info("[CpPlan-V2] 开始执行计划自动匹配预约, forceMatch={}, updatePlan={}, insertReserve={}", forceMatch, updatePlan, insertReserve); +// Map> resultMap = new HashMap<>(); +// +// // 1. 日期校验:如果不是强制匹配,则判断当前天数是否等于 CP_SETTING_AUTO_MATCH_START +// if (!forceMatch) { +// int autoMatchStart = cpSettingService.getAutoMatchStart(); +// int today = LocalDate.now().getDayOfMonth(); +// if (today != autoMatchStart) { +// log.info("[CpPlan-V2] 当前日期{}号,不等于设定的自动匹配日期{}号,跳过执行", today, autoMatchStart); +// return resultMap; +// } +// } +// +// // 2. 获取最大联合单位数量 +// int maxUnionUnit = cpSettingService.getMaxUnionUnit(); +// +// // 2.1 获取系统匹配预约周数范围 +// int systemMatchWeeks = cpSettingService.getSystemMatchWeeks(); +// log.info("[CpPlan-V2] 系统匹配周数范围={}", systemMatchWeeks); +// +// // 3. 查询待匹配的计划:plan_date > 当前时间 且 system_reserved=0, manual_reserved=0, reserve_status=1, is_public=1, is_union=1 +// Date now = new Date(); +// LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); +// lqw.gt(EfcodeCpPlan::getPlanDate, now); +// lqw.eq(EfcodeCpPlan::getSystemReserved, 0L); +// lqw.eq(EfcodeCpPlan::getManualReserved, 0L); +// lqw.eq(EfcodeCpPlan::getReserveStatus, 1L); +// lqw.eq(EfcodeCpPlan::getIsPublic, 1L); +// lqw.eq(EfcodeCpPlan::getIsUnion, 1L); +// lqw.eq(EfcodeCpPlan::getIsDelete, 0L); +// lqw.orderByAsc(EfcodeCpPlan::getPlanDate); +// List pendingPlans = baseMapper.selectList(lqw); +// +// if (pendingPlans.isEmpty()) { +// log.info("[CpPlan-V2] 没有找到待匹配的计划记录,执行结束"); +// return resultMap; +// } +// log.info("[CpPlan-V2] 共查询到{}条待匹配计划", pendingPlans.size()); +// +// // 4. 已处理过的"企业+周"组合,同企业同周只处理一次 +// Set processedKeys = new HashSet<>(); +// int matchedCount = 0; +// +// for (EfcodeCpPlan plan : pendingPlans) { +// String enterpriseNumber = plan.getEnterpriseNumber(); +// if (StringUtils.isBlank(enterpriseNumber)) { +// continue; +// } +// +// // 5. 计算计划所在的时间范围:以计划所在自然周的周一为起始,向后扩展 systemMatchWeeks 周 +// LocalDate planLocalDate = plan.getPlanDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); +// LocalDate weekStartDate = planLocalDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); +// LocalDate weekEndDate = weekStartDate.plusWeeks(systemMatchWeeks).minusDays(1); // 扩展N周后的周日 +// +// // 按"企业+周起始日"去重,同企业同周只处理一次 +// String processKey = enterpriseNumber + "_" + weekStartDate; +// if (processedKeys.contains(processKey)) { +// continue; +// } +// processedKeys.add(processKey); +// +// // 6. 查找该自然周内同企业的所有待匹配计划 +// Date weekStart = Date.from(weekStartDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); +// Date weekEnd = Date.from(weekEndDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); +// +// LambdaQueryWrapper weekLqw = Wrappers.lambdaQuery(); +// weekLqw.ge(EfcodeCpPlan::getPlanDate, weekStart); +// weekLqw.le(EfcodeCpPlan::getPlanDate, weekEnd); +// weekLqw.eq(EfcodeCpPlan::getEnterpriseNumber, enterpriseNumber); +// weekLqw.eq(EfcodeCpPlan::getSystemReserved, 0L); +// weekLqw.eq(EfcodeCpPlan::getManualReserved, 0L); +// weekLqw.eq(EfcodeCpPlan::getReserveStatus, 1L); +// weekLqw.eq(EfcodeCpPlan::getIsPublic, 1L); +// weekLqw.eq(EfcodeCpPlan::getIsUnion, 1L); +// weekLqw.eq(EfcodeCpPlan::getIsDelete, 0L); +// weekLqw.orderByAsc(EfcodeCpPlan::getPlanDate); +// List samePlans = baseMapper.selectList(weekLqw); +// +// // 7. 按 bureau_dept_id 去重,每个单位取一条代表计划 +// List distinctUnitPlans = new ArrayList<>(); +// Set seenBureauDeptIds = new HashSet<>(); +// for (EfcodeCpPlan sp : samePlans) { +// String deptId = sp.getBureauDeptId(); +// if (StringUtils.isNotBlank(deptId) && !seenBureauDeptIds.contains(deptId)) { +// seenBureauDeptIds.add(deptId); +// distinctUnitPlans.add(sp); +// } +// } +// +// // 8. 只有1个单位的计划,无法联合,跳过 +// if (distinctUnitPlans.size() <= 1) { +// log.debug("[CpPlan-V2] 企业[{}] 周[{}~{}]内只有1个单位的计划,跳过", enterpriseNumber, weekStartDate, weekEndDate); +// continue; +// } +// +// // 9. 按最大联合单位数量分组 +// List> groups = new ArrayList<>(); +// for (int i = 0; i < distinctUnitPlans.size(); i += maxUnionUnit) { +// int end = Math.min(i + maxUnionUnit, distinctUnitPlans.size()); +// List group = distinctUnitPlans.subList(i, end); +// if (group.size() >= 2) { +// groups.add(new ArrayList<>(group)); +// } +// } +// +// if (groups.isEmpty()) { +// continue; +// } +// +// // 10. 为每组生成预约记录 +// Set matchedPlanIds = new HashSet<>(); +// for (List group : groups) { +// String planGroupId = "Temp" + "_" + UUID.randomUUID().toString().replace("-", ""); +// Date reserveTime = new Date(); +// List groupReserves = new ArrayList<>(); +// +// String unitNames = group.stream() +// .map(EfcodeCpPlan::getBureauDeptName) +// .filter(StringUtils::isNotBlank) +// .collect(Collectors.joining(",")); +// String opMessage = "由于计划执法时间安排较近,系统推荐进行联合,参与单位为:" + unitNames + ".请确认."; +// +// for (EfcodeCpPlan matchedPlan : group) { +// EfcodeCpReserve reserve = new EfcodeCpReserve(); +// reserve.setPlanId(matchedPlan.getId()); +// reserve.setPlanGroupId(planGroupId); +// reserve.setReserveTime(reserveTime); +// reserve.setOpStatus(3L); // 待确认 +// reserve.setOpOrder(0L); // 系统匹配默认为0 +// reserve.setOpMessage(opMessage); +// reserve.setOpSetDate(matchedPlan.getPlanDate()); +// reserve.setOpSetTime(matchedPlan.getPlanTime()); +// reserve.setResFrom(1L); // 系统匹配 +// reserve.setSenderId("from_system"); +// reserve.setReceiverId(String.valueOf(matchedPlan.getCreateBy())); +// +// if (insertReserve) { +// efcodeCpReserveMapper.insert(reserve); +// } +// groupReserves.add(reserve); +// } +// +// // 更新被选中参与联合的计划: reserve_status=2(预约中), system_reserved=1 +// if (updatePlan) { +// for (EfcodeCpPlan dp : group) { +// EfcodeCpPlan planUpdate = new EfcodeCpPlan(); +// planUpdate.setId(dp.getId()); +// planUpdate.setReserveStatus(2L); +// planUpdate.setSystemReserved(1L); +// baseMapper.updateById(planUpdate); +// matchedPlanIds.add(dp.getId()); +// } +// } +// +// resultMap.put(planGroupId, groupReserves); +// matchedCount++; +// log.info("[CpPlan-V2] 企业[{}] 周[{}~{}] 匹配成功,联合{}个单位,planGroupId={}", +// enterpriseNumber, weekStartDate, weekEndDate, group.size(), planGroupId); +// } +// +// // 11. 将已成功匹配的单位在该企业该周内的所有计划标记为 system_reserved=1,防止重复匹配 +// if (updatePlan && !groups.isEmpty()) { +// for (EfcodeCpPlan sp : samePlans) { +// if (matchedPlanIds.contains(sp.getId())) { +// continue; +// } +// if (seenBureauDeptIds.contains(sp.getBureauDeptId())) { +// EfcodeCpPlan planUpdate = new EfcodeCpPlan(); +// planUpdate.setId(sp.getId()); +// planUpdate.setSystemReserved(1L); +// baseMapper.updateById(planUpdate); +// } +// } +// } +// } +// +// log.info("[CpPlan-V2] 计划自动匹配预约执行完毕,共匹配{}组联合预约", matchedCount); +// return resultMap; +// } /** * 计划到期自动生成任务