package com.ruoyi.inspectiontask.service.impl; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.device.mapper.DeviceLedgerMapper; import com.ruoyi.device.pojo.DeviceLedger; import com.ruoyi.inspectiontask.mapper.InspectionTaskMapper; import com.ruoyi.inspectiontask.mapper.TimingTaskMapper; import com.ruoyi.inspectiontask.pojo.InspectionTask; import com.ruoyi.inspectiontask.pojo.TimingTask; import com.ruoyi.inspectiontask.service.TimingTaskService; 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.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import java.io.Serializable; import java.math.BigDecimal; import java.time.DayOfWeek; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.YearMonth; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @Component @DisallowConcurrentExecution public class TimingTaskJob implements Job, Serializable { private static final long serialVersionUID = 1L; @Autowired private TimingTaskMapper timingTaskMapper; @Autowired private TimingTaskService timingTaskService; @Autowired private InspectionTaskMapper inspectionTaskMapper; @Autowired private JdbcTemplate jdbcTemplate; @Autowired private DeviceLedgerMapper deviceLedgerMapper; @Override public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); Long taskId = jobDataMap.getLong("taskId"); try { String sql = "SELECT * FROM timing_task WHERE id = ?"; List tasks = jdbcTemplate.query( sql, new BeanPropertyRowMapper<>(TimingTask.class), taskId ); TimingTask timingTask = tasks.isEmpty() ? null : tasks.get(0); if (timingTask == null) { throw new RuntimeException("定时任务不存在: " + taskId); } List deviceIds = resolveTaskIds(timingTask); if (deviceIds.isEmpty()) { throw new RuntimeException("设备不存在: " + taskId); } for (Long deviceId : deviceIds) { DeviceLedger deviceLedger = deviceLedgerMapper.selectById(deviceId); if (deviceLedger == null) { continue; } int count = getDeviceCount(deviceLedger.getNumber()); for (int i = 0; i < count; i++) { inspectionTaskMapper.insert(createInspectionTask(timingTask, deviceLedger)); } } if (!tasks.isEmpty()) { LocalDateTime lastExecutionTime = LocalDateTime.now(); LocalDateTime nextExecutionTime = calculateNextExecutionTime( timingTask.getFrequencyType(), timingTask.getFrequencyDetail(), lastExecutionTime ); String updateSql = "UPDATE timing_task SET last_execution_time = ?, next_execution_time = ? WHERE id = ?"; jdbcTemplate.update(updateSql, lastExecutionTime, nextExecutionTime, taskId); } } catch (Exception e) { throw new JobExecutionException(e); } } private List resolveTaskIds(TimingTask timingTask) { if (StringUtils.isNotBlank(timingTask.getTaskIdsStr())) { return Arrays.stream(timingTask.getTaskIdsStr().split(",")) .filter(StringUtils::isNotBlank) .map(String::trim) .map(Long::valueOf) .distinct() .collect(Collectors.toList()); } if (timingTask.getTaskId() != null) { return new ArrayList<>(Arrays.asList(timingTask.getTaskId().longValue())); } return new ArrayList<>(); } private int getDeviceCount(BigDecimal number) { if (number == null) { return 1; } int count = number.intValue(); return count > 0 ? count : 1; } private InspectionTask createInspectionTask(TimingTask timingTask, DeviceLedger deviceLedger) { InspectionTask inspectionTask = new InspectionTask(); inspectionTask.setTaskName(deviceLedger.getDeviceName()); inspectionTask.setTaskId(deviceLedger.getId().intValue()); inspectionTask.setAreaId(deviceLedger.getAreaId()); inspectionTask.setInspectorId(timingTask.getInspectorIds()); inspectionTask.setInspectionLocation(timingTask.getInspectionLocation()); inspectionTask.setRemarks("定时生成设备巡检任务 ID: " + timingTask.getId()); inspectionTask.setRegistrantId(timingTask.getRegistrantId()); inspectionTask.setRegistrant(timingTask.getRegistrant()); inspectionTask.setFrequencyType(timingTask.getFrequencyType()); inspectionTask.setFrequencyDetail(timingTask.getFrequencyDetail()); inspectionTask.setTenantId(timingTask.getTenantId()); return inspectionTask; } private LocalDateTime calculateNextExecutionTime(String frequencyType, String frequencyDetail, LocalDateTime currentTime) { try { switch (frequencyType) { case "DAILY": return calculateDailyNextTime(frequencyDetail, currentTime); case "WEEKLY": return calculateWeeklyNextTime(frequencyDetail, currentTime); case "MONTHLY": return calculateMonthlyNextTime(frequencyDetail, currentTime); case "QUARTERLY": return calculateQuarterlyNextTime(frequencyDetail, currentTime); case "YEARLY": return calculateYearlyNextTime(frequencyDetail, currentTime); default: throw new IllegalArgumentException("涓嶆敮鎸佺殑棰戠巼绫诲瀷: " + frequencyType); } } catch (Exception e) { throw new RuntimeException("璁$畻涓嬫鎵ц鏃堕棿澶辫触: " + e.getMessage(), e); } } 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(","); String dayOfWeekStr = parts[0]; LocalTime time = LocalTime.parse(parts[1]); Set targetDays = parseDayOfWeeks(dayOfWeekStr); 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]); LocalTime time = LocalTime.parse(parts[1]); return current.plusMonths(1) .withDayOfMonth(Math.min(dayOfMonth, current.plusMonths(1).toLocalDate().lengthOfMonth())) .with(time); } private LocalDateTime calculateQuarterlyNextTime(String detail, LocalDateTime current) { String[] parts = detail.split(","); int quarterMonth = Integer.parseInt(parts[0]); int dayOfMonth = Integer.parseInt(parts[1]); LocalTime time = LocalTime.parse(parts[2]); int currentMonthInQuarter = (current.getMonthValue() - 1) % 3 + 1; YearMonth targetYearMonth; if (currentMonthInQuarter < quarterMonth) { targetYearMonth = YearMonth.from(current).plusMonths(quarterMonth - currentMonthInQuarter); } else { targetYearMonth = YearMonth.from(current).plusMonths(3 - currentMonthInQuarter + quarterMonth); } int adjustedDay = Math.min(dayOfMonth, targetYearMonth.lengthOfMonth()); return LocalDateTime.of( targetYearMonth.getYear(), targetYearMonth.getMonthValue(), adjustedDay, time.getHour(), time.getMinute() ); } private LocalDateTime calculateYearlyNextTime(String detail, LocalDateTime current) { String[] parts = detail.split(","); int month = Integer.parseInt(parts[0]); int dayOfMonth = Integer.parseInt(parts[1]); LocalTime time = LocalTime.parse(parts[2]); YearMonth targetYearMonth = YearMonth.of(current.getYear(), month); int adjustedDay = Math.min(dayOfMonth, targetYearMonth.lengthOfMonth()); LocalDateTime target = LocalDateTime.of(current.getYear(), month, adjustedDay, time.getHour(), time.getMinute()); if (!target.isAfter(current)) { targetYearMonth = YearMonth.of(current.getYear() + 1, month); adjustedDay = Math.min(dayOfMonth, targetYearMonth.lengthOfMonth()); target = LocalDateTime.of(current.getYear() + 1, month, adjustedDay, time.getHour(), time.getMinute()); } return target; } private Set parseDayOfWeeks(String dayOfWeekStr) { Set days = new HashSet<>(); String[] dayStrs = dayOfWeekStr.split("\\|"); for (String dayStr : dayStrs) { switch (dayStr) { case "MON": days.add(DayOfWeek.MONDAY); break; case "TUE": days.add(DayOfWeek.TUESDAY); break; case "WED": days.add(DayOfWeek.WEDNESDAY); break; case "THU": days.add(DayOfWeek.THURSDAY); break; case "FRI": days.add(DayOfWeek.FRIDAY); break; case "SAT": days.add(DayOfWeek.SATURDAY); break; case "SUN": days.add(DayOfWeek.SUNDAY); break; default: throw new IllegalArgumentException("鏃犳晥鐨勬槦鏈? " + dayStr); } } return days; } }