| | |
| | | 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.*; |
| | | 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 // 禁止并发执行同一个Job |
| | | public class TimingTaskJob implements Job { |
| | | @DisallowConcurrentExecution |
| | | public class TimingTaskJob implements Job, Serializable { |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Autowired |
| | | private |
| | | TimingTaskService timingTaskService; |
| | | 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 { |
| | |
| | | Long taskId = jobDataMap.getLong("taskId"); |
| | | |
| | | try { |
| | | // 1. 获取定时任务详情 |
| | | TimingTask timingTask = timingTaskService.getById(taskId); |
| | | if (timingTask == null || !timingTask.isActive()) { |
| | | return; |
| | | String sql = "SELECT * FROM timing_task WHERE id = ?"; |
| | | List<TimingTask> tasks = jdbcTemplate.query( |
| | | sql, |
| | | new BeanPropertyRowMapper<>(TimingTask.class), |
| | | taskId |
| | | ); |
| | | TimingTask timingTask = tasks.isEmpty() ? null : tasks.get(0); |
| | | if (timingTask == null) { |
| | | throw new JobExecutionException("鎵句笉鍒板畾鏃朵换鍔? " + taskId); |
| | | } |
| | | |
| | | // 2. 创建并保存巡检任务记录 - 这就是您提供的代码应该放的位置 |
| | | InspectionTask inspectionTask = createInspectionTask(timingTask); |
| | | inspectionTaskMapper.insert(inspectionTask); |
| | | List<Long> deviceIds = resolveTaskIds(timingTask); |
| | | if (deviceIds.isEmpty()) { |
| | | throw new JobExecutionException("瀹氭椂浠诲姟鏈厤缃澶? " + taskId); |
| | | } |
| | | |
| | | // 3. 更新定时任务的执行时间 |
| | | timingTaskService.updateTaskExecutionTime(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)); |
| | | } |
| | | } |
| | | |
| | | // 4. 记录执行日志 |
| | | // timingTaskService.recordExecutionLog(taskId, true, "任务执行成功,生成巡检任务ID: " + inspectionTask.getId()); |
| | | |
| | | 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) { |
| | | // timingTaskService.recordExecutionLog(taskId, false, "任务执行失败: " + e.getMessage()); |
| | | throw new JobExecutionException(e); |
| | | } |
| | | } |
| | | |
| | | // 这就是您提供的代码封装成的方法 |
| | | private InspectionTask createInspectionTask(TimingTask timingTask) { |
| | | InspectionTask inspectionTask = new InspectionTask(); |
| | | private List<Long> 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<>(); |
| | | } |
| | | |
| | | // 复制基本属性 |
| | | inspectionTask.setTaskName(timingTask.getTaskName()); |
| | | 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.setRemarks("鑷姩鐢熸垚鑷畾鏃朵换鍔D: " + 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<DayOfWeek> 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<DayOfWeek> parseDayOfWeeks(String dayOfWeekStr) { |
| | | Set<DayOfWeek> 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; |
| | | } |
| | | } |