| | |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.common.utils.bean.BeanUtils; |
| | | import com.ruoyi.inspectiontask.dto.TimingTaskDto; |
| | | import com.ruoyi.inspectiontask.mapper.InspectionTaskMapper; |
| | | import com.ruoyi.inspectiontask.mapper.TimingTaskMapper; |
| | | import com.ruoyi.inspectiontask.pojo.TimingTask; |
| | | import com.ruoyi.inspectiontask.service.TimingTaskService; |
| | | import com.ruoyi.project.system.domain.SysUser; |
| | | import com.ruoyi.project.system.mapper.SysUserMapper; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.quartz.SchedulerException; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | |
| | | */ |
| | | @Service |
| | | @Slf4j |
| | | @RequiredArgsConstructor |
| | | public class TimingTaskServiceImpl extends ServiceImpl<TimingTaskMapper, TimingTask> implements TimingTaskService { |
| | | |
| | | @Autowired |
| | | private TimingTaskMapper timingTaskMapper; |
| | | |
| | | @Autowired |
| | | private InspectionTaskMapper inspectionTaskMapper; |
| | | |
| | | @Autowired |
| | | private TimingTaskScheduler timingTaskScheduler; |
| | | |
| | | @Autowired |
| | | private SysUserMapper sysUserMapper; |
| | | private final TimingTaskMapper timingTaskMapper; |
| | | private final TimingTaskScheduler timingTaskScheduler; |
| | | private final SysUserMapper sysUserMapper; |
| | | private final com.ruoyi.device.mapper.DeviceLedgerMapper deviceLedgerMapper; |
| | | private static final int ENABLED = 1; |
| | | private static final int DISABLED = 0; |
| | | |
| | | |
| | | @Override |
| | |
| | | if (StringUtils.isNotBlank(timingTask.getTaskName())) { |
| | | queryWrapper.like(TimingTask::getTaskName, timingTask.getTaskName()); |
| | | } |
| | | if (StringUtils.isNotBlank(timingTask.getInspectionProject())) { |
| | | queryWrapper.like(TimingTask::getInspectionProject, timingTask.getInspectionProject()); |
| | | } |
| | | if (timingTask.getIsEnabled() != null) { |
| | | queryWrapper.eq(TimingTask::getIsEnabled, timingTask.getIsEnabled()); |
| | | } |
| | | queryWrapper.orderByDesc(TimingTask::getCreateTime); |
| | | IPage<TimingTask> taskPage = timingTaskMapper.selectPage(page, queryWrapper); |
| | | |
| | | // 2. 如果没有数据,直接返回空分页 |
| | |
| | | @Override |
| | | @Transactional |
| | | public int addOrEditTimingTask(TimingTaskDto timingTaskDto) throws SchedulerException { |
| | | TimingTask oldTimingTask = null; |
| | | if (Objects.nonNull(timingTaskDto.getId())) { |
| | | oldTimingTask = timingTaskMapper.selectById(timingTaskDto.getId()); |
| | | if (oldTimingTask == null) { |
| | | throw new IllegalArgumentException("定时任务不存在"); |
| | | } |
| | | } |
| | | validateDeviceExists(timingTaskDto, oldTimingTask); |
| | | TimingTask timingTask = new TimingTask(); |
| | | BeanUtils.copyProperties(timingTaskDto, timingTask); |
| | | timingTask.setIsEnabled(resolveEnabledValue(timingTask.getIsEnabled(), oldTimingTask)); |
| | | timingTask.setActive(ENABLED == timingTask.getIsEnabled()); |
| | | // 1. 解析字符串为 LocalDate(只包含年月日) |
| | | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); |
| | | LocalDate localDate = LocalDate.now(); |
| | |
| | | // 设置创建人信息和默认值 |
| | | if (Objects.isNull(timingTaskDto.getId())) { |
| | | timingTask.setRegistrationDate(LocalDate.now()); |
| | | timingTask.setActive(true); |
| | | |
| | | // 计算首次执行时间 |
| | | LocalDateTime firstExecutionTime = calculateFirstExecutionTime(timingTask); |
| | | timingTask.setNextExecutionTime(firstExecutionTime); |
| | | int result = timingTaskMapper.insert(timingTask); |
| | | if (result > 0) { |
| | | if (result > 0 && isEnabled(timingTask.getIsEnabled(), timingTask.isActive())) { |
| | | // 新增成功后添加到调度器 |
| | | timingTaskScheduler.scheduleTimingTask(timingTask); |
| | | } |
| | |
| | | |
| | | int result = timingTaskMapper.updateById(timingTask); |
| | | if (result > 0) { |
| | | // 更新成功后重新调度任务 |
| | | timingTaskScheduler.rescheduleTimingTask(timingTask); |
| | | boolean oldEnabled = isEnabled(oldTimingTask == null ? null : oldTimingTask.getIsEnabled(), oldTimingTask != null && oldTimingTask.isActive()); |
| | | boolean newEnabled = isEnabled(timingTask.getIsEnabled(), timingTask.isActive()); |
| | | if (!newEnabled) { |
| | | timingTaskScheduler.unscheduleTimingTask(timingTask.getId()); |
| | | } else if (oldEnabled) { |
| | | // 更新成功后重新调度任务 |
| | | timingTaskScheduler.rescheduleTimingTask(timingTask); |
| | | } else { |
| | | // 从禁用改为启用时重新创建调度任务 |
| | | timingTaskScheduler.scheduleTimingTask(timingTask); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | } |
| | | |
| | | private void validateDeviceExists(TimingTaskDto timingTaskDto, TimingTask oldTimingTask) { |
| | | Integer taskId = timingTaskDto.getTaskId(); |
| | | if (taskId == null && oldTimingTask != null) { |
| | | taskId = oldTimingTask.getTaskId(); |
| | | } |
| | | if (taskId == null || taskId <= 0) { |
| | | return; |
| | | } |
| | | if (deviceLedgerMapper.selectById(taskId.longValue()) == null) { |
| | | throw new IllegalArgumentException("所选设备不存在,请重新选择"); |
| | | } |
| | | } |
| | | |
| | |
| | | // 如果是每月执行,计算下个月的具体日期 |
| | | return calculateMonthlyFirstExecution(task.getFrequencyDetail()); |
| | | } else if ("QUARTERLY".equals(frequencyType)) { |
| | | // 自定义频率,如每小时、每30分钟等 |
| | | return calculateCustomFirstExecution(task.getFrequencyDetail()); |
| | | } else if ("YEARLY".equals(frequencyType)) { |
| | | return calculateAnnualFirstExecution(task.getFrequencyDetail()); |
| | | } else { |
| | | throw new IllegalArgumentException("不支持的频率类型: " + task.getFrequencyType()); |
| | | } |
| | |
| | | } |
| | | |
| | | return targetDateTime; |
| | | } |
| | | |
| | | private LocalDateTime calculateAnnualFirstExecution(String frequencyDetail) { |
| | | String[] parts = frequencyDetail.split(","); |
| | | if (parts.length != 3) { |
| | | throw new IllegalArgumentException("参数格式错误,应为'12,31,09:00'格式"); |
| | | } |
| | | |
| | | int month; |
| | | int day; |
| | | try { |
| | | month = Integer.parseInt(parts[0].trim()); |
| | | day = Integer.parseInt(parts[1].trim()); |
| | | } catch (NumberFormatException e) { |
| | | throw new IllegalArgumentException("月份或日期格式错误", e); |
| | | } |
| | | if (month < 1 || month > 12 || day < 1 || day > 31) { |
| | | throw new IllegalArgumentException("月份必须在1-12之间,日期必须在1-31之间"); |
| | | } |
| | | |
| | | LocalTime time = LocalTime.parse(parts[2].trim(), DateTimeFormatter.ofPattern("HH:mm")); |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | int year = now.getYear(); |
| | | LocalDateTime target = LocalDateTime.of(LocalDate.of(year, month, Math.min(day, YearMonth.of(year, month).lengthOfMonth())), time); |
| | | return target.isAfter(now) ? target : LocalDateTime.of(LocalDate.of(year + 1, month, |
| | | Math.min(day, YearMonth.of(year + 1, month).lengthOfMonth())), time); |
| | | } |
| | | |
| | | private LocalDateTime calculateCustomFirstExecution(String frequencyDetail) { |
| | |
| | | return days; |
| | | } |
| | | |
| | | private Integer resolveEnabledValue(Integer requestEnabled, TimingTask oldTimingTask) { |
| | | if (requestEnabled != null) { |
| | | return requestEnabled; |
| | | } |
| | | if (oldTimingTask != null) { |
| | | if (oldTimingTask.getIsEnabled() != null) { |
| | | return oldTimingTask.getIsEnabled(); |
| | | } |
| | | return oldTimingTask.isActive() ? ENABLED : DISABLED; |
| | | } |
| | | return ENABLED; |
| | | } |
| | | |
| | | private boolean isEnabled(Integer enabledValue, boolean activeFallback) { |
| | | if (enabledValue != null) { |
| | | return ENABLED == enabledValue; |
| | | } |
| | | return activeFallback; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |