package com.ruoyi.safe.service.impl; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.safe.mapper.SafeFacilityInspectionMapper; import com.ruoyi.safe.mapper.SafeFacilityInspectionTaskMapper; import com.ruoyi.safe.pojo.SafeFacilityInspection; import com.ruoyi.safe.pojo.SafeFacilityInspectionTask; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.Serializable; import java.time.DayOfWeek; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.util.HashSet; import java.util.Set; @Component @DisallowConcurrentExecution public class SafeFacilityInspectionTaskJob implements Job, Serializable { private static final long serialVersionUID = 1L; private static final DateTimeFormatter CODE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); @Autowired private SafeFacilityInspectionTaskMapper safeFacilityInspectionTaskMapper; @Autowired private SafeFacilityInspectionMapper safeFacilityInspectionMapper; @Override public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); Long taskId = jobDataMap.getLong("taskId"); try { SafeFacilityInspectionTask task = safeFacilityInspectionTaskMapper.selectById(taskId); if (task == null || Integer.valueOf(0).equals(task.getIsEnabled())) { return; } LocalDateTime executionTime = LocalDateTime.now(); SafeFacilityInspection inspection = createFacilityInspection(task, executionTime); safeFacilityInspectionMapper.insert(inspection); task.setLastExecutionTime(executionTime); task.setNextExecutionTime(calculateNextExecutionTime( task.getFrequencyType(), task.getFrequencyDetail(), executionTime )); safeFacilityInspectionTaskMapper.updateById(task); } catch (Exception e) { throw new JobExecutionException(e); } } private SafeFacilityInspection createFacilityInspection(SafeFacilityInspectionTask task, LocalDateTime executionTime) { SafeFacilityInspection inspection = new SafeFacilityInspection(); inspection.setScheduleTaskId(task.getId()); inspection.setInspectionCode("SSXJ-" + executionTime.format(CODE_FORMATTER) + "-" + task.getId()); inspection.setFacilityId(task.getFacilityId()); inspection.setInspectionType("定期巡检"); inspection.setInspectionProject(task.getInspectionProject()); inspection.setPlanTime(task.getNextExecutionTime() != null ? task.getNextExecutionTime() : executionTime); inspection.setInspectorId(task.getInspectorId()); inspection.setCheckDesc(buildCheckDesc(task)); inspection.setStatus("待巡检"); inspection.setCreateUser(task.getCreateUser()); inspection.setUpdateUser(task.getCreateUser()); inspection.setCreateTime(executionTime); inspection.setUpdateTime(executionTime); inspection.setTenantId(task.getTenantId()); inspection.setDeptId(task.getDeptId()); return inspection; } private String buildCheckDesc(SafeFacilityInspectionTask task) { String desc = "自动生成自定时任务ID: " + task.getId(); if (StringUtils.isNotBlank(task.getRemark())) { desc = desc + ";" + task.getRemark(); } return desc; } private LocalDateTime calculateNextExecutionTime(String frequencyType, String frequencyDetail, LocalDateTime currentTime) { return switch (frequencyType) { case "DAILY" -> calculateDailyNextTime(frequencyDetail, currentTime); case "WEEKLY" -> calculateWeeklyNextTime(frequencyDetail, currentTime); case "MONTHLY" -> calculateMonthlyNextTime(frequencyDetail, currentTime); default -> throw new IllegalArgumentException("不支持的频率类型: " + frequencyType); }; } private LocalDateTime calculateDailyNextTime(String timeStr, LocalDateTime current) { LocalTime executionTime = LocalTime.parse(timeStr); LocalDateTime nextTime = LocalDateTime.of(current.toLocalDate(), executionTime); return current.isBefore(nextTime) ? nextTime : nextTime.plusDays(1); } private LocalDateTime calculateWeeklyNextTime(String detail, LocalDateTime current) { String[] parts = detail.split(","); LocalTime time = LocalTime.parse(parts[1].trim()); Set targetDays = parseDayOfWeeks(parts[0]); LocalDateTime nextTime = current; while (true) { nextTime = nextTime.plusDays(1); if (targetDays.contains(nextTime.getDayOfWeek())) { return LocalDateTime.of(nextTime.toLocalDate(), time); } if (nextTime.isAfter(current.plusYears(1))) { throw new RuntimeException("无法找到下次执行时间"); } } } private LocalDateTime calculateMonthlyNextTime(String detail, LocalDateTime current) { String[] parts = detail.split(","); int dayOfMonth = Integer.parseInt(parts[0].trim()); LocalTime time = LocalTime.parse(parts[1].trim()); YearMonth currentMonth = YearMonth.from(current); for (int i = 0; i < 24; i++) { YearMonth targetMonth = currentMonth.plusMonths(i); if (dayOfMonth > targetMonth.lengthOfMonth()) { continue; } LocalDateTime candidate = LocalDateTime.of( targetMonth.getYear(), targetMonth.getMonthValue(), dayOfMonth, time.getHour(), time.getMinute() ); if (current.isBefore(candidate)) { return candidate; } } throw new IllegalArgumentException("无法计算下次执行时间"); } private Set parseDayOfWeeks(String dayOfWeekStr) { Set days = new HashSet<>(); String[] dayStrs = dayOfWeekStr.split("\\|"); for (String dayStr : dayStrs) { switch (dayStr.trim()) { case "MON" -> days.add(DayOfWeek.MONDAY); case "TUE" -> days.add(DayOfWeek.TUESDAY); case "WED" -> days.add(DayOfWeek.WEDNESDAY); case "THU" -> days.add(DayOfWeek.THURSDAY); case "FRI" -> days.add(DayOfWeek.FRIDAY); case "SAT" -> days.add(DayOfWeek.SATURDAY); case "SUN" -> days.add(DayOfWeek.SUNDAY); default -> throw new IllegalArgumentException("无效的星期几: " + dayStr); } } return days; } }