From ac0c567b2a8ebebb46bb9f8d2ac9f9c4c62a1058 Mon Sep 17 00:00:00 2001 From: tianxinlei Date: Sat, 23 May 2026 13:58:51 +0800 Subject: [PATCH] =?UTF-8?q?5-23=20=E4=BF=AE=E6=AD=A3=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../job/FeedbackExceptionCheckJob.java | 5 +- .../job/TaskStatusUpdateJob.java | 8 +- .../web/tasklist/FeedbackController.java | 2 +- .../web/tasklist/StatisticsController.java | 10 +- .../tasklist/FeedbackExceptionCheckExe.java | 166 +++++++++--------- .../tasklist/TaskListStatusUpdateExe.java | 9 +- .../gateway/tasklist/TaskListGateway.java | 11 ++ .../domain/model/tasklist/TaskListE.java | 6 +- .../domain/util/FeedbackCycleUtil.java | 87 +++++---- .../tasklist/TaskListGatewayImpl.java | 14 ++ .../mapper/tasklist/TaskListMapper.java | 2 + .../impl/tasklist/TaskListRepositoryImpl.java | 5 + .../tasklist/TaskListRepository.java | 2 + .../mapper/tasklist/TaskListMapper.xml | 6 + 14 files changed, 194 insertions(+), 139 deletions(-) diff --git a/web-adapter/src/main/java/com/zcloud/safetyDutyList/job/FeedbackExceptionCheckJob.java b/web-adapter/src/main/java/com/zcloud/safetyDutyList/job/FeedbackExceptionCheckJob.java index b3e2242..2249634 100644 --- a/web-adapter/src/main/java/com/zcloud/safetyDutyList/job/FeedbackExceptionCheckJob.java +++ b/web-adapter/src/main/java/com/zcloud/safetyDutyList/job/FeedbackExceptionCheckJob.java @@ -10,7 +10,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; /** - * 安全责任清单 - 定时任务2:反馈异常检测 + * 安全责任清单 - 定时任务:反馈异常检测 *

* 执行周期:每月1日0时(cron = "0 0 0 1 * ?") *

@@ -35,9 +35,6 @@ public class FeedbackExceptionCheckJob implements Job { *

* 由XXL-Job调度框架调用,执行反馈异常检测逻辑。 * 执行成功返回SUCCESS,异常时返回FAIL及错误信息。 - * - * @param param XXL-Job传入的参数(当前任务未使用) - * @return 执行结果,成功返回ReturnT.SUCCESS,失败返回ReturnT.FAIL_CODE及异常信息 */ @Override @JobRegister(cron = "0 55 10 * * ?", jobDesc = "安全责任清单-反馈异常检测", triggerStatus = 1) diff --git a/web-adapter/src/main/java/com/zcloud/safetyDutyList/job/TaskStatusUpdateJob.java b/web-adapter/src/main/java/com/zcloud/safetyDutyList/job/TaskStatusUpdateJob.java index c1ffa02..eff8110 100644 --- a/web-adapter/src/main/java/com/zcloud/safetyDutyList/job/TaskStatusUpdateJob.java +++ b/web-adapter/src/main/java/com/zcloud/safetyDutyList/job/TaskStatusUpdateJob.java @@ -10,7 +10,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; /** - * 安全责任清单 - 定时任务1:更新清单状态和任务状态 + * 安全责任清单 - 定时任务:更新清单状态和任务状态 *

* 执行周期:每月1日0时(cron = "0 0 0 1 * ?") *

@@ -43,12 +43,12 @@ public class TaskStatusUpdateJob implements Job { @JobRegister(cron = "0 0 0 1 * ?", jobDesc = "安全责任清单-更新清单和任务状态", triggerStatus = 1) @XxlJob("com.zcloud.safetyDutyList.job.TaskStatusUpdateJob") public ReturnT execute(String param) { - log.info("【安全责任清单】开始执行更新清单和任务状态定时任务"); + log.info("【定时任务-安全责任清单-检测任务完成】开始执行更新清单和任务状态定时任务"); try { taskListService.updateExpiredTaskListStatus(); - log.info("【安全责任清单】更新清单和任务状态定时任务执行完成"); + log.info("【定时任务-安全责任清单-检测任务完成】更新清单和任务状态定时任务执行完成"); } catch (Exception e) { - log.error("【安全责任清单】更新清单和任务状态定时任务执行异常", e); + log.error("【定时任务-安全责任清单-检测任务完成】更新清单和任务状态定时任务执行异常", e); return new ReturnT<>(ReturnT.FAIL_CODE, e.getMessage()); } return ReturnT.SUCCESS; diff --git a/web-adapter/src/main/java/com/zcloud/safetyDutyList/web/tasklist/FeedbackController.java b/web-adapter/src/main/java/com/zcloud/safetyDutyList/web/tasklist/FeedbackController.java index add1f9c..1f1fad5 100644 --- a/web-adapter/src/main/java/com/zcloud/safetyDutyList/web/tasklist/FeedbackController.java +++ b/web-adapter/src/main/java/com/zcloud/safetyDutyList/web/tasklist/FeedbackController.java @@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.*; /** * 执行反馈控制器 *

- * 提供反馈提交、反馈列表查询、反馈周期分组查询、反馈异常记录查询等接口, + * 提供反馈提交、反馈列表查询、反馈周期分组查询、反馈详情等接口, * 委托TaskListServiceI处理业务逻辑。 */ @Api(tags = "执行反馈") diff --git a/web-adapter/src/main/java/com/zcloud/safetyDutyList/web/tasklist/StatisticsController.java b/web-adapter/src/main/java/com/zcloud/safetyDutyList/web/tasklist/StatisticsController.java index b2c028b..938d8a6 100644 --- a/web-adapter/src/main/java/com/zcloud/safetyDutyList/web/tasklist/StatisticsController.java +++ b/web-adapter/src/main/java/com/zcloud/safetyDutyList/web/tasklist/StatisticsController.java @@ -17,11 +17,11 @@ import org.springframework.web.bind.annotation.*; public class StatisticsController { private final TaskListServiceI taskListService; - @ApiOperation("获取统计信息") - @PostMapping("/list") - public MultiResponse statistics(@RequestBody TaskListStatisticsQry qry) { - return taskListService.statistics(qry); - } +// @ApiOperation("获取统计信息") +// @PostMapping("/list") +// public MultiResponse statistics(@RequestBody TaskListStatisticsQry qry) { +// return taskListService.statistics(qry); +// } @ApiOperation("获取企业统计(股份端)") @PostMapping("/corpStatistics") diff --git a/web-app/src/main/java/com/zcloud/safetyDutyList/command/tasklist/FeedbackExceptionCheckExe.java b/web-app/src/main/java/com/zcloud/safetyDutyList/command/tasklist/FeedbackExceptionCheckExe.java index 64c01b8..fa3667e 100644 --- a/web-app/src/main/java/com/zcloud/safetyDutyList/command/tasklist/FeedbackExceptionCheckExe.java +++ b/web-app/src/main/java/com/zcloud/safetyDutyList/command/tasklist/FeedbackExceptionCheckExe.java @@ -4,9 +4,11 @@ import com.zcloud.safetyDutyList.domain.enums.ExceptionTypeEnum; import com.zcloud.safetyDutyList.domain.gateway.tasklist.FeedbackExceptionGateway; import com.zcloud.safetyDutyList.domain.gateway.tasklist.FeedbackGateway; import com.zcloud.safetyDutyList.domain.gateway.tasklist.TaskDetailGateway; +import com.zcloud.safetyDutyList.domain.gateway.tasklist.TaskListGateway; import com.zcloud.safetyDutyList.domain.model.tasklist.FeedbackE; import com.zcloud.safetyDutyList.domain.model.tasklist.FeedbackExceptionE; import com.zcloud.safetyDutyList.domain.model.tasklist.TaskDetailE; +import com.zcloud.safetyDutyList.domain.model.tasklist.TaskListE; import com.zcloud.safetyDutyList.domain.util.FeedbackCycleUtil; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -19,20 +21,23 @@ import java.util.List; /** * 反馈异常检测执行器 *

- * 处理定时任务2的业务逻辑:检测所有进行中任务的反馈异常情况。 + * 处理定时任务2的业务逻辑:检测已下发清单下所有任务的反馈异常情况。 *

* 处理流程: - * 1. 查询所有进行中的任务(task_status=1) - * 2. 根据每个任务的反馈周期类型(feedback_cycle_type)计算上一阶段的周期标识 - * 3. 检查上一阶段是否已存在异常记录,避免重复添加 - * 4. 检查上一阶段是否有反馈记录,若无则判定为异常 - * 5. 为异常任务创建反馈异常记录,写入safety_accountability_feedback_exception表 + * 1. 查询所有已下发且周期时间完整的清单(issue_status=1, period_start_time/end_time不为空) + * 2. 遍历每个清单,获取其下所有任务 + * 3. 对每个任务,以清单的周期起始时间判断是否仍处于首个反馈周期内 + * 4. 若仍处于首周期,跳过(首周期尚未结束,不应判定异常) + * 5. 若已过首周期,计算上一阶段周期标识,检查是否有反馈记录 + * 6. 若上一阶段无反馈且无异常记录,则创建反馈异常记录 *

- * 反馈周期判定规则: - * feedback_cycle_type=1(每月):每个月都需要反馈至少一次,上一阶段=上个月 - * feedback_cycle_type=2(每季度):每个季度都需要反馈至少一次,上一阶段=上个季度 - * feedback_cycle_type=3(每半年):每半年都需要反馈至少一次,上一阶段=上个半年 - * feedback_cycle_type=4(年):一年内必须反馈至少一次,上一阶段=去年 + * 首周期判断逻辑(以清单periodStartTime为准): + * 将periodStartTime和当前时间分别生成周期标识,若相同则仍在首周期内。 + * 例如:清单起始时间2026年7月,当前2026年7月12日: + * 每月→首周期=2026-07=当前周期→跳过 + * 每季度→首周期=2026-Q3=当前周期→跳过 + * 每半年→首周期=2026-H2=当前周期→跳过 + * 每年→首周期=2026-Y=当前周期→跳过 *

* 事务控制:整个检测过程在同一事务中执行,确保异常记录写入的原子性 */ @@ -41,79 +46,101 @@ import java.util.List; @AllArgsConstructor public class FeedbackExceptionCheckExe { - /** 任务详情网关,用于查询进行中的任务列表 */ + private final TaskListGateway taskListGateway; + private final TaskDetailGateway taskDetailGateway; - /** 反馈网关,用于查询任务的反馈记录 */ private final FeedbackGateway feedbackGateway; - /** 反馈异常网关,用于查询已有异常记录和新增异常记录 */ private final FeedbackExceptionGateway feedbackExceptionGateway; /** * 执行反馈异常检测 *

- * 遍历所有进行中的任务,根据反馈周期类型判断上一阶段是否有反馈记录, - * 若无反馈则创建反馈异常记录。 + * 遍历所有已下发且周期时间完整的清单,对每个清单下的任务进行反馈异常检测。 */ @Transactional(rollbackFor = Exception.class) public void execute() { - // 步骤1:获取所有进行中的任务 - List inProgressTasks = taskDetailGateway.listInProgress(); - if (inProgressTasks == null || inProgressTasks.isEmpty()) { - log.info("【安全责任清单】没有进行中的任务需要检测"); + + // 查询所有已下发且周期时间完整的清单 + List issuedList = taskListGateway.listIssuedWithPeriod(); + if (issuedList == null || issuedList.isEmpty()) { + log.info("【定时任务-安全责任清单-检测反馈异常】没有已下发且周期时间完整的清单需要检测"); return; } - log.info("【安全责任清单】查询到{}条进行中任务需要检测反馈异常", inProgressTasks.size()); - for (TaskDetailE taskDetail : inProgressTasks) { - Integer feedbackCycleType = taskDetail.getFeedbackCycleType(); - // 反馈周期类型为空则跳过,无法判定异常 - if (feedbackCycleType == null) { - log.warn("【安全责任清单】任务[{}]反馈周期类型为空,跳过检测", taskDetail.getTaskDetailId()); + log.info("【定时任务-安全责任清单-检测反馈异常】查询到{}条已下发清单需要检测反馈异常", issuedList.size()); + + // 遍历每个清单 + for (TaskListE taskList : issuedList) { + + // 获取清单下的任务 + List taskDetails = taskDetailGateway.listByTaskListId(taskList.getTaskListId()); + if (taskDetails == null || taskDetails.isEmpty()) { continue; } - // 步骤2:根据反馈周期类型计算上一阶段的周期标识 - // 例如:每月->上月"2026-04",每季度->上季度"2026-Q1",每半年->上半年"2025-H2",每年->去年"2025" - String previousPeriodFlag = FeedbackCycleUtil.generatePreviousPeriodFlag(feedbackCycleType); - if (previousPeriodFlag == null) { - log.warn("【安全责任清单】任务[{}]无法生成上一阶段周期标识,feedbackCycleType={}", - taskDetail.getTaskDetailId(), feedbackCycleType); - continue; - } - - // 步骤3:检查上一阶段是否已有异常记录,避免重复添加 - boolean alreadyHasException = checkExistingException(taskDetail.getTaskDetailId(), previousPeriodFlag); - if (alreadyHasException) { - log.info("【安全责任清单】任务[{}]在周期[{}]已存在异常记录,跳过", - taskDetail.getTaskDetailId(), previousPeriodFlag); - continue; - } - - // 步骤4:获取该任务的反馈列表,判断上一阶段是否有反馈记录 - boolean hasFeedback = checkPreviousPeriodFeedback(taskDetail.getTaskDetailId(), previousPeriodFlag); - - if (!hasFeedback) { - // 步骤5:上一阶段无反馈记录,判定为异常,添加反馈异常记录 - createFeedbackException(taskDetail, previousPeriodFlag); - log.info("【安全责任清单】任务[{}]在周期[{}]未反馈,已添加异常记录", - taskDetail.getTaskDetailId(), previousPeriodFlag); - } else { - log.info("【安全责任清单】任务[{}]在周期[{}]已正常反馈", - taskDetail.getTaskDetailId(), previousPeriodFlag); + // 遍历每个任务 + for (TaskDetailE taskDetail : taskDetails) { + checkTaskFeedback(taskList, taskDetail); } } } + /** + * 检测单个任务的反馈异常 + * + * @param taskList 所属清单(用于获取周期起始时间) + * @param taskDetail 任务详情 + */ + private void checkTaskFeedback(TaskListE taskList, TaskDetailE taskDetail) { + Integer feedbackCycleType = taskDetail.getFeedbackCycleType(); + if (feedbackCycleType == null) { + log.warn("【定时任务-安全责任清单-检测反馈异常】任务[{}]反馈周期类型为空,跳过检测", taskDetail.getTaskDetailId()); + return; + } + + // 当前时间处于首周期,跳过 + if (FeedbackCycleUtil.isFirstCycle(feedbackCycleType, taskList.getPeriodStartTime())) { + log.info("【定时任务-安全责任清单-检测反馈异常】清单[{}]任务[{}]周期类型为{},仍处于首周期内,跳过检测", + taskList.getTaskListId(), taskDetail.getTaskDetailId(), feedbackCycleType); + return; + } + + // 上一阶段周期标识 + String previousPeriodFlag = FeedbackCycleUtil.generatePreviousPeriodFlag(feedbackCycleType); + if (previousPeriodFlag == null) { + log.warn("【定时任务-安全责任清单-检测反馈异常】任务[{}]无法生成上一阶段周期标识,feedbackCycleType={}", + taskDetail.getTaskDetailId(), feedbackCycleType); + return; + } + + // 异常记录是否存在 + boolean alreadyHasException = checkExistingException(taskDetail.getTaskDetailId(), previousPeriodFlag); + if (alreadyHasException) { + log.info("【定时任务-安全责任清单-检测反馈异常】任务[{}]在周期[{}]已存在异常记录,跳过", + taskDetail.getTaskDetailId(), previousPeriodFlag); + return; + } + + // 上一阶段周期标识对应的反馈记录是否存在 + boolean hasFeedback = checkPreviousPeriodFeedback(taskDetail.getTaskDetailId(), previousPeriodFlag); + + if (!hasFeedback) { + createFeedbackException(taskDetail, previousPeriodFlag); + log.info("【定时任务-安全责任清单-检测反馈异常】任务[{}]在周期[{}]未反馈,已添加异常记录", + taskDetail.getTaskDetailId(), previousPeriodFlag); + } else { + log.info("【定时任务-安全责任清单-检测反馈异常】任务[{}]在周期[{}]已正常反馈", + taskDetail.getTaskDetailId(), previousPeriodFlag); + } + } + /** * 检查上一阶段是否已有异常记录 - *

- * 查询该任务的所有异常记录,筛选出与上一阶段周期标识匹配的记录, - * 若存在则说明该阶段的异常已被记录,无需重复添加。 * * @param taskDetailId 任务详情ID - * @param previousPeriodFlag 上一阶段的周期标识(如"2026-04"、"2026-Q1"等) + * @param previousPeriodFlag 上一阶段的周期标识 * @return true-已存在异常记录,false-不存在异常记录 */ private boolean checkExistingException(String taskDetailId, String previousPeriodFlag) { @@ -121,19 +148,15 @@ public class FeedbackExceptionCheckExe { if (exceptionList == null || exceptionList.isEmpty()) { return false; } - // 遍历异常记录,判断是否存在与上一阶段周期标识匹配的记录 return exceptionList.stream() .anyMatch(e -> previousPeriodFlag.equals(e.getExceptionPeriodFlag())); } /** * 检查上一阶段是否有反馈记录 - *

- * 查询该任务的所有反馈记录,筛选出与上一阶段周期标识匹配的记录, - * 若存在至少一条则说明该阶段已正常反馈。 * * @param taskDetailId 任务详情ID - * @param previousPeriodFlag 上一阶段的周期标识(如"2026-04"、"2026-Q1"等) + * @param previousPeriodFlag 上一阶段的周期标识 * @return true-存在反馈记录,false-不存在反馈记录 */ private boolean checkPreviousPeriodFeedback(String taskDetailId, String previousPeriodFlag) { @@ -141,23 +164,12 @@ public class FeedbackExceptionCheckExe { if (feedbackList == null || feedbackList.isEmpty()) { return false; } - // 遍历反馈记录,判断是否存在与上一阶段周期标识匹配的反馈 return feedbackList.stream() .anyMatch(f -> previousPeriodFlag.equals(f.getFeedbackPeriodFlag())); } /** * 创建反馈异常记录 - *

- * 当检测到任务在上一阶段未提交反馈时,创建一条反馈异常记录, - * 写入safety_accountability_feedback_exception表。 - *

- * 记录内容包括: - * - 任务详情ID和清单ID:关联到具体的任务和清单 - * - 异常周期标识:标识哪个周期未反馈 - * - 异常周期起止时间:该周期的起止时间范围 - * - 异常类型:未按时反馈(1) - * - 异常时间:当前检测时间 * * @param taskDetail 未按时反馈的任务详情 * @param previousPeriodFlag 上一阶段的周期标识 @@ -166,21 +178,17 @@ public class FeedbackExceptionCheckExe { FeedbackExceptionE exceptionE = new FeedbackExceptionE(); exceptionE.init(); - // 设置关联的任务详情ID和清单ID exceptionE.setTaskDetailId(taskDetail.getTaskDetailId()); exceptionE.setTaskListId(taskDetail.getTaskListId()); - // 设置异常周期标识(如"2026-04"、"2026-Q1"等) exceptionE.setExceptionPeriodFlag(previousPeriodFlag); - // 根据周期标识计算该周期的起止时间,用于记录异常的时间范围 LocalDateTime[] periodTime = FeedbackCycleUtil.getPeriodTime(previousPeriodFlag); - if (periodTime != null) { + if (periodTime != null && periodTime.length == 2) { exceptionE.setExceptionPeriodStartTime(periodTime[0]); exceptionE.setExceptionPeriodEndTime(periodTime[1]); } - // 设置异常类型为"未按时反馈",异常时间为当前时间 exceptionE.setExceptionType(ExceptionTypeEnum.NOT_FEEDBACK.getCode()); exceptionE.setExceptionTime(LocalDateTime.now()); diff --git a/web-app/src/main/java/com/zcloud/safetyDutyList/command/tasklist/TaskListStatusUpdateExe.java b/web-app/src/main/java/com/zcloud/safetyDutyList/command/tasklist/TaskListStatusUpdateExe.java index a15f948..fbd43b2 100644 --- a/web-app/src/main/java/com/zcloud/safetyDutyList/command/tasklist/TaskListStatusUpdateExe.java +++ b/web-app/src/main/java/com/zcloud/safetyDutyList/command/tasklist/TaskListStatusUpdateExe.java @@ -47,16 +47,17 @@ public class TaskListStatusUpdateExe { // 步骤1:查询所有状态为进行中(status=1)且周期结束时间(period_end_time)小于当前时间的清单 List expiredList = taskListGateway.listExpiredInProgress(); if (expiredList == null || expiredList.isEmpty()) { - log.info("【安全责任清单】没有需要更新的过期清单"); + log.info("【定时任务-安全责任清单-检测任务完成】没有需要更新的过期清单"); return; } - log.info("【安全责任清单】查询到{}条过期清单需要更新状态", expiredList.size()); + + log.info("【定时任务-安全责任清单-检测任务完成】查询到{}条过期清单需要更新状态", expiredList.size()); for (TaskListE taskListE : expiredList) { // 步骤2:将清单状态从进行中(1)更新为已完成(2) taskListE.setStatus(TaskStatusEnum.COMPLETED.getCode()); taskListGateway.update(taskListE); - log.info("【安全责任清单】清单[{}]状态已更新为已完成", taskListE.getTaskListId()); + log.info("【定时任务-安全责任清单-检测任务完成】清单[{}]状态已更新为已完成", taskListE.getTaskListId()); // 步骤3:查询该清单下所有任务详情,将进行中的任务更新为已完成 List detailList = taskDetailGateway.listByTaskListId(taskListE.getTaskListId()); @@ -66,7 +67,7 @@ public class TaskListStatusUpdateExe { if (TaskStatusEnum.IN_PROGRESS.getCode().equals(detailE.getTaskStatus())) { detailE.setTaskStatus(TaskStatusEnum.COMPLETED.getCode()); taskDetailGateway.update(detailE); - log.info("【安全责任清单】任务[{}]状态已更新为已完成", detailE.getTaskDetailId()); + log.info("【定时任务-安全责任清单-检测任务完成】任务[{}]状态已更新为已完成", detailE.getTaskDetailId()); } } } diff --git a/web-domain/src/main/java/com/zcloud/safetyDutyList/domain/gateway/tasklist/TaskListGateway.java b/web-domain/src/main/java/com/zcloud/safetyDutyList/domain/gateway/tasklist/TaskListGateway.java index ad5bb32..0ebdc60 100644 --- a/web-domain/src/main/java/com/zcloud/safetyDutyList/domain/gateway/tasklist/TaskListGateway.java +++ b/web-domain/src/main/java/com/zcloud/safetyDutyList/domain/gateway/tasklist/TaskListGateway.java @@ -68,4 +68,15 @@ public interface TaskListGateway { * @return 已过期的进行中清单列表 */ List listExpiredInProgress(); + + /** + * 查询所有已下发且周期时间完整的清单 + *

+ * 查询条件:issue_status=1(已下发)且 period_start_time IS NOT NULL 且 period_end_time IS NOT NULL + * 且 period_end_time不超过当前时间1个月(超过1个月不再检测异常) + * 用于定时任务2:反馈异常检测,以清单周期起始时间判断是否跳过检测 + * + * @return 已下发且周期时间完整的清单列表 + */ + List listIssuedWithPeriod(); } diff --git a/web-domain/src/main/java/com/zcloud/safetyDutyList/domain/model/tasklist/TaskListE.java b/web-domain/src/main/java/com/zcloud/safetyDutyList/domain/model/tasklist/TaskListE.java index 2fdf81a..9b1bc75 100644 --- a/web-domain/src/main/java/com/zcloud/safetyDutyList/domain/model/tasklist/TaskListE.java +++ b/web-domain/src/main/java/com/zcloud/safetyDutyList/domain/model/tasklist/TaskListE.java @@ -25,9 +25,9 @@ public class TaskListE extends BaseE { private Integer status; private LocalDateTime periodStartTime; private LocalDateTime periodEndTime; - private BigDecimal score; - private Long scoreUserId; - private Long scoreDepartmentId; + private BigDecimal ratingScore; + private Long ratingUserId; + private Long ratingDepartmentId; private Long createCorpId; private Long createDepartmentId; private Long createUserId; diff --git a/web-domain/src/main/java/com/zcloud/safetyDutyList/domain/util/FeedbackCycleUtil.java b/web-domain/src/main/java/com/zcloud/safetyDutyList/domain/util/FeedbackCycleUtil.java index de8ea34..471bd0a 100644 --- a/web-domain/src/main/java/com/zcloud/safetyDutyList/domain/util/FeedbackCycleUtil.java +++ b/web-domain/src/main/java/com/zcloud/safetyDutyList/domain/util/FeedbackCycleUtil.java @@ -16,7 +16,7 @@ import java.time.LocalDateTime; * 每月: "2026-05" (年-月) * 每季度: "2026-Q1" (年-季度,Q1=1-3月,Q2=4-6月,Q3=7-9月,Q4=10-12月) * 每半年: "2026-H1" (年-半年,H1=1-6月,H2=7-12月) - * 每年: "2026" (年) + * 每年: "2026-Y" (年-Y) */ public class FeedbackCycleUtil { @@ -26,26 +26,21 @@ public class FeedbackCycleUtil { * 根据周期标识的格式自动识别周期类型,返回该周期的起始时间和结束时间。 * 起始时间为该周期第一天的00:00:00,结束时间为该周期最后一天的23:59:59。 * - * @param periodFlag 周期标识(如"2026-05"、"2026-Q1"、"2026-H1"、"2026") + * @param periodFlag 周期标识(如"2026-05"、"2026-Q1"、"2026-H1"、"2026-Y") * @return 长度为2的LocalDateTime数组,[0]=起始时间,[1]=结束时间;若无法识别则返回null */ public static LocalDateTime[] getPeriodTime(String periodFlag) { if (periodFlag == null || periodFlag.isEmpty()) { return null; } - // 根据周期标识中的特征字符判断周期类型 if (periodFlag.contains("-Q")) { - // 包含"-Q"标识,为季度周期(如"2026-Q1") return getQuarterPeriod(periodFlag); } else if (periodFlag.contains("-H")) { - // 包含"-H"标识,为半年周期(如"2026-H1") return getHalfYearPeriod(periodFlag); - } else if (periodFlag.contains("-") && periodFlag.length() == 7) { - // 包含"-"且长度为7,为月度周期(如"2026-05") - return getMonthPeriod(periodFlag); - } else if (periodFlag.length() == 4) { - // 长度为4的纯数字,为年度周期(如"2026") + } else if (periodFlag.contains("-Y")) { return getYearPeriod(periodFlag); + } else if (periodFlag.contains("-") && periodFlag.length() == 7) { + return getMonthPeriod(periodFlag); } return null; } @@ -62,9 +57,7 @@ public class FeedbackCycleUtil { String[] parts = periodFlag.split("-"); int year = Integer.parseInt(parts[0]); int month = Integer.parseInt(parts[1]); - // 起始时间:该月1日00:00:00 LocalDateTime start = LocalDateTime.of(year, month, 1, 0, 0, 0); - // 结束时间:该月最后一天23:59:59 LocalDateTime end = LocalDateTime.of(year, month, LocalDate.of(year, month, 1).lengthOfMonth(), 23, 59, 59); return new LocalDateTime[]{start, end}; } @@ -84,12 +77,9 @@ public class FeedbackCycleUtil { String[] parts = periodFlag.split("-Q"); int year = Integer.parseInt(parts[0]); int quarter = Integer.parseInt(parts[1]); - // 计算季度的起始月份和结束月份 int startMonth = (quarter - 1) * 3 + 1; int endMonth = startMonth + 2; - // 起始时间:季度首月1日00:00:00 LocalDateTime start = LocalDateTime.of(year, startMonth, 1, 0, 0, 0); - // 结束时间:季度末月最后一天23:59:59 LocalDateTime end = LocalDateTime.of(year, endMonth, LocalDate.of(year, endMonth, 1).lengthOfMonth(), 23, 59, 59); return new LocalDateTime[]{start, end}; } @@ -109,12 +99,9 @@ public class FeedbackCycleUtil { String[] parts = periodFlag.split("-H"); int year = Integer.parseInt(parts[0]); int half = Integer.parseInt(parts[1]); - // 计算半年的起始月份和结束月份 int startMonth = (half - 1) * 6 + 1; int endMonth = startMonth + 5; - // 起始时间:半年首月1日00:00:00 LocalDateTime start = LocalDateTime.of(year, startMonth, 1, 0, 0, 0); - // 结束时间:半年末月最后一天23:59:59 LocalDateTime end = LocalDateTime.of(year, endMonth, LocalDate.of(year, endMonth, 1).lengthOfMonth(), 23, 59, 59); return new LocalDateTime[]{start, end}; } @@ -122,16 +109,15 @@ public class FeedbackCycleUtil { /** * 解析年度周期的起止时间 *

- * 例如:"2026" -> [2026-01-01 00:00:00, 2026-12-31 23:59:59] + * 例如:"2026-Y" -> [2026-01-01 00:00:00, 2026-12-31 23:59:59] * - * @param periodFlag 年度周期标识(格式:"yyyy") + * @param periodFlag 年度周期标识(格式:"yyyy-Y") * @return 起止时间数组 */ private static LocalDateTime[] getYearPeriod(String periodFlag) { - int year = Integer.parseInt(periodFlag); - // 起始时间:1月1日00:00:00 + String yearStr = periodFlag.replace("-Y", ""); + int year = Integer.parseInt(yearStr); LocalDateTime start = LocalDateTime.of(year, 1, 1, 0, 0, 0); - // 结束时间:12月31日23:59:59 LocalDateTime end = LocalDateTime.of(year, 12, 31, 23, 59, 59); return new LocalDateTime[]{start, end}; } @@ -143,7 +129,7 @@ public class FeedbackCycleUtil { * feedbackCycle=1(每月): "2026-05" * feedbackCycle=2(每季度): "2026-Q1" * feedbackCycle=3(每半年): "2026-H1" - * feedbackCycle=4(每年): "2026" + * feedbackCycle=4(每年): "2026-Y" * * @param feedbackCycle 反馈周期类型(1-每月,2-每季度,3-每半年,4-每年) * @param time 参考时间,若为null则使用当前时间 @@ -156,21 +142,15 @@ public class FeedbackCycleUtil { int year = time.getYear(); switch (feedbackCycle) { case 1: - // 每月:格式为"年-月",如"2026-05" return String.format("%d-%02d", year, time.getMonthValue()); case 2: - // 每季度:格式为"年-Q季度",如"2026-Q1" - // 季度计算:(月份-1)/3 + 1,如5月=(5-1)/3+1=Q2 int quarter = (time.getMonthValue() - 1) / 3 + 1; return String.format("%d-Q%d", year, quarter); case 3: - // 每半年:格式为"年-H半年",如"2026-H1" - // 1-6月为H1,7-12月为H2 int half = time.getMonthValue() <= 6 ? 1 : 2; return String.format("%d-H%d", year, half); case 4: - // 每年:格式为"年",如"2026" - return String.valueOf(year); + return String.format("%d-Y", year); default: return null; } @@ -185,7 +165,7 @@ public class FeedbackCycleUtil { * feedbackCycle=1(每月): 上个月,如当前2026-05则返回"2026-04" * feedbackCycle=2(每季度): 上个季度,如当前Q1则返回上年Q4,当前Q2则返回当年Q1 * feedbackCycle=3(每半年): 上个半年,如当前H1则返回上年H2,当前H2则返回当年H1 - * feedbackCycle=4(每年): 去年,如当前2026则返回"2025" + * feedbackCycle=4(每年): 去年,如当前2026-Y则返回"2025-Y" * * @param feedbackCycle 反馈周期类型(1-每月,2-每季度,3-每半年,4-每年) * @return 上一阶段周期标识,若周期类型不合法则返回null @@ -194,12 +174,9 @@ public class FeedbackCycleUtil { LocalDateTime now = LocalDateTime.now(); switch (feedbackCycle) { case 1: - // 每月:回退一个月,如2026-05 -> 2026-04 LocalDateTime lastMonth = now.minusMonths(1); return String.format("%d-%02d", lastMonth.getYear(), lastMonth.getMonthValue()); case 2: - // 每季度:回退一个季度 - // 若当前为Q1(1-3月),则上一季度为上年的Q4;否则为当年的上一季度 int currentQuarter = (now.getMonthValue() - 1) / 3 + 1; if (currentQuarter == 1) { return String.format("%d-Q4", now.getYear() - 1); @@ -207,8 +184,6 @@ public class FeedbackCycleUtil { return String.format("%d-Q%d", now.getYear(), currentQuarter - 1); } case 3: - // 每半年:回退一个半年 - // 若当前为H1(1-6月),则上一半年为上年的H2;否则为当年的H1 int currentHalf = now.getMonthValue() <= 6 ? 1 : 2; if (currentHalf == 1) { return String.format("%d-H2", now.getYear() - 1); @@ -216,13 +191,47 @@ public class FeedbackCycleUtil { return String.format("%d-H1", now.getYear()); } case 4: - // 每年:回退一年,如2026 -> 2025 - return String.valueOf(now.getYear() - 1); + return String.format("%d-Y", now.getYear() - 1); default: return null; } } + /** + * 判断当前时间是否仍处于清单的首个反馈周期内 + *

+ * 用于反馈异常检测定时任务,判断是否应该检查上一周期的反馈情况。 + * 如果当前时间仍处于清单的首个反馈周期内,说明该周期尚未结束,不应检测异常; + * 只有当首个反馈周期已结束,进入第二个或之后的周期时,才需要检测上一周期。 + *

+ * 判断方式:根据清单周期起始时间生成"首周期标识",根据当前时间生成"当前周期标识", + * 若两者相同则说明仍在首周期内,应跳过检测。 + *

+ * 示例(清单周期起始时间为2026年7月,当前时间为2026年7月12日): + * 每月→首周期=2026-07,当前=2026-07 → 相同 → 跳过 + * 每季度→首周期=2026-Q3,当前=2026-Q3 → 相同 → 跳过 + * 每半年→首周期=2026-H2,当前=2026-H2 → 相同 → 跳过 + * 每年→首周期=2026-Y,当前=2026-Y → 相同 → 跳过 + *

+ * 示例(清单周期起始时间为2026年7月,当前时间为2026年8月1日): + * 每月→首周期=2026-07,当前=2026-08 → 不同 → 检查2026-07 + * 每季度→首周期=2026-Q3,当前=2026-Q3 → 相同 → 跳过 + * 每半年→首周期=2026-H2,当前=2026-H2 → 相同 → 跳过 + * 每年→首周期=2026-Y,当前=2026-Y → 相同 → 跳过 + * + * @param feedbackCycle 反馈周期类型(1-每月,2-每季度,3-每半年,4-每年) + * @param periodStartTime 清单周期起始时间 + * @return true-仍在首周期内应跳过检测,false-首周期已结束应检测上一周期 + */ + public static boolean isFirstCycle(Integer feedbackCycle, LocalDateTime periodStartTime) { + if (periodStartTime == null) { + return true; + } + String firstCycleFlag = generatePeriodFlag(feedbackCycle, periodStartTime); + String currentCycleFlag = generatePeriodFlag(feedbackCycle, LocalDateTime.now()); + return firstCycleFlag != null && firstCycleFlag.equals(currentCycleFlag); + } + /** * 判断给定周期标识是否为当前周期 *

diff --git a/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/gatewayimpl/tasklist/TaskListGatewayImpl.java b/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/gatewayimpl/tasklist/TaskListGatewayImpl.java index 94ff3ca..f887909 100644 --- a/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/gatewayimpl/tasklist/TaskListGatewayImpl.java +++ b/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/gatewayimpl/tasklist/TaskListGatewayImpl.java @@ -144,4 +144,18 @@ public class TaskListGatewayImpl implements TaskListGateway { } return eList; } + + @Override + public List listIssuedWithPeriod() { + List doList = taskListRepository.listIssuedWithPeriod(); + List eList = new ArrayList<>(); + if (doList != null) { + for (TaskListDO d : doList) { + TaskListE e = new TaskListE(); + BeanUtils.copyProperties(d, e); + eList.add(e); + } + } + return eList; + } } diff --git a/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/persistence/mapper/tasklist/TaskListMapper.java b/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/persistence/mapper/tasklist/TaskListMapper.java index 1502cfc..9c2eed8 100644 --- a/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/persistence/mapper/tasklist/TaskListMapper.java +++ b/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/persistence/mapper/tasklist/TaskListMapper.java @@ -32,6 +32,8 @@ public interface TaskListMapper extends BaseMapper { List listExpiredInProgress(); + List listIssuedWithPeriod(); + IPage corpStatistics(IPage iPage, Map params); IPage evaluationList(IPage iPage, Map params); diff --git a/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/persistence/repository/impl/tasklist/TaskListRepositoryImpl.java b/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/persistence/repository/impl/tasklist/TaskListRepositoryImpl.java index e378189..697715e 100644 --- a/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/persistence/repository/impl/tasklist/TaskListRepositoryImpl.java +++ b/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/persistence/repository/impl/tasklist/TaskListRepositoryImpl.java @@ -73,6 +73,11 @@ public class TaskListRepositoryImpl extends BaseRepositoryImpl listIssuedWithPeriod() { + return taskListMapper.listIssuedWithPeriod(); + } + @Override public PageResponse corpStatistics(Map params) { IPage iPage = new Query().getPage(params); diff --git a/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/persistence/repository/tasklist/TaskListRepository.java b/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/persistence/repository/tasklist/TaskListRepository.java index 3251e6b..69da2e7 100644 --- a/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/persistence/repository/tasklist/TaskListRepository.java +++ b/web-infrastructure/src/main/java/com/zcloud/safetyDutyList/persistence/repository/tasklist/TaskListRepository.java @@ -32,6 +32,8 @@ public interface TaskListRepository extends BaseRepository { List listExpiredInProgress(); + List listIssuedWithPeriod(); + PageResponse corpStatistics(Map params); PageResponse evaluationList(Map params); diff --git a/web-infrastructure/src/main/resources/mapper/tasklist/TaskListMapper.xml b/web-infrastructure/src/main/resources/mapper/tasklist/TaskListMapper.xml index c8e2b3e..bee0101 100644 --- a/web-infrastructure/src/main/resources/mapper/tasklist/TaskListMapper.xml +++ b/web-infrastructure/src/main/resources/mapper/tasklist/TaskListMapper.xml @@ -141,6 +141,12 @@ WHERE status = 1 AND issue_status = 1 AND (period_end_time IS NOT NULL AND period_end_time < NOW()) + +