package com.ruoyi.inspectiontask.service.impl; 
 | 
  
 | 
import com.ruoyi.inspectiontask.pojo.TimingTask; 
 | 
import org.quartz.*; 
 | 
import org.springframework.beans.factory.annotation.Autowired; 
 | 
import org.springframework.stereotype.Service; 
 | 
  
 | 
import java.time.LocalTime; 
 | 
import java.time.ZoneId; 
 | 
import java.time.format.DateTimeParseException; 
 | 
import java.util.Arrays; 
 | 
import java.util.Date; 
 | 
import java.util.stream.Collectors; 
 | 
  
 | 
@Service 
 | 
public class TimingTaskScheduler { 
 | 
  
 | 
    @Autowired 
 | 
    private Scheduler scheduler; 
 | 
  
 | 
    /** 
 | 
     * 添加新任务到调度器 
 | 
     */ 
 | 
    public void scheduleTimingTask(TimingTask task) throws SchedulerException { 
 | 
        JobDetail jobDetail = buildJobDetail(task); 
 | 
        Trigger trigger = buildJobTrigger(task, jobDetail); 
 | 
        scheduler.scheduleJob(jobDetail, trigger); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 更新已有任务 
 | 
     */ 
 | 
    public void rescheduleTimingTask(TimingTask task) throws SchedulerException { 
 | 
        TriggerKey triggerKey = new TriggerKey("trigger_" + task.getId()); 
 | 
  
 | 
        // 获取现有触发器并转换为 CronTrigger 
 | 
        Trigger oldTrigger = scheduler.getTrigger(triggerKey); 
 | 
        if (!(oldTrigger instanceof CronTrigger)) { 
 | 
            throw new SchedulerException("Existing trigger is not a CronTrigger"); 
 | 
        } 
 | 
  
 | 
        // 构建新触发器 
 | 
        Trigger newTrigger = TriggerBuilder.newTrigger() 
 | 
                .withIdentity(triggerKey) 
 | 
                .withDescription(task.getTaskName()) 
 | 
                .withSchedule(CronScheduleBuilder.cronSchedule(convertToCronExpression(task))) 
 | 
                .startAt(Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant())) 
 | 
                .forJob(oldTrigger.getJobKey()) 
 | 
                .build(); 
 | 
  
 | 
        scheduler.rescheduleJob(triggerKey, newTrigger); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 暂停任务 
 | 
     */ 
 | 
    public void pauseTimingTask(Long taskId) throws SchedulerException { 
 | 
        JobKey jobKey = new JobKey("timingTask_" + taskId); 
 | 
        scheduler.pauseJob(jobKey); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 恢复任务 
 | 
     */ 
 | 
    public void resumeTimingTask(Long taskId) throws SchedulerException { 
 | 
        JobKey jobKey = new JobKey("timingTask_" + taskId); 
 | 
        scheduler.resumeJob(jobKey); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 删除任务 
 | 
     */ 
 | 
    public void unscheduleTimingTask(Long taskId) throws SchedulerException { 
 | 
        JobKey jobKey = new JobKey("timingTask_" + taskId); 
 | 
        scheduler.deleteJob(jobKey); 
 | 
    } 
 | 
  
 | 
    private JobDetail buildJobDetail(TimingTask task) { 
 | 
        JobDataMap jobDataMap = new JobDataMap(); 
 | 
        jobDataMap.put("taskId", task.getId()); 
 | 
  
 | 
        return JobBuilder.newJob(TimingTaskJob.class) 
 | 
                .withIdentity("timingTask_" + task.getId()) 
 | 
                .withDescription(task.getTaskName()) 
 | 
                .usingJobData(jobDataMap) 
 | 
                .storeDurably() 
 | 
                .build(); 
 | 
    } 
 | 
  
 | 
    private Trigger buildJobTrigger(TimingTask task, JobDetail jobDetail) { 
 | 
        String cronExpression = convertToCronExpression(task); 
 | 
  
 | 
            TriggerBuilder<CronTrigger> triggerBuilder = TriggerBuilder.newTrigger() 
 | 
                .withIdentity("trigger_" + task.getId()) 
 | 
                .withDescription(task.getTaskName()) 
 | 
                .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)); 
 | 
  
 | 
        if (jobDetail != null) { 
 | 
            triggerBuilder.forJob(jobDetail); 
 | 
        } 
 | 
  
 | 
        if (task.getNextExecutionTime() != null) { 
 | 
            triggerBuilder.startAt(Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant())); 
 | 
        } 
 | 
  
 | 
        return triggerBuilder.build(); 
 | 
    } 
 | 
    private String convertToCronExpression(TimingTask task) { 
 | 
        // 参数校验 
 | 
        if (task == null || task.getFrequencyType() == null || task.getFrequencyDetail() == null) { 
 | 
            throw new IllegalArgumentException("任务参数不能为空"); 
 | 
        } 
 | 
  
 | 
        // 使用switch确保条件互斥 
 | 
        String frequencyType = task.getFrequencyType().toUpperCase(); // 统一转为大写比较 
 | 
        switch (frequencyType) { 
 | 
            case "DAILY": 
 | 
                return convertDailyToCron(task.getFrequencyDetail()); 
 | 
            case "WEEKLY": 
 | 
                return convertWeeklyToCron(task.getFrequencyDetail()); 
 | 
            case "MONTHLY": 
 | 
                return convertMonthlyToCron(task.getFrequencyDetail()); 
 | 
            case "QUARTERLY": 
 | 
                return convertQuarterlyToCron(task.getFrequencyDetail()); 
 | 
            default: 
 | 
                throw new IllegalArgumentException("不支持的频率类型: " + task.getFrequencyType()); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    // 每日任务转换 
 | 
    private String convertDailyToCron(String frequencyDetail) { 
 | 
        LocalTime time = parseTime(frequencyDetail); 
 | 
        return String.format("0 %d %d * * ?", time.getMinute(), time.getHour()); 
 | 
    } 
 | 
  
 | 
    // 每周任务转换 
 | 
    private String convertWeeklyToCron(String frequencyDetail) { 
 | 
        String[] parts = validateAndSplit(frequencyDetail, ",", 2); 
 | 
        String daysOfWeek = convertDayNamesToCron(parts[0]); 
 | 
        LocalTime time = parseTime(parts[1]); 
 | 
        return String.format("0 %d %d ? * %s", time.getMinute(), time.getHour(), daysOfWeek); 
 | 
    } 
 | 
  
 | 
    // 每月任务转换 
 | 
    private String convertMonthlyToCron(String frequencyDetail) { 
 | 
        String[] parts = validateAndSplit(frequencyDetail, ",", 2); 
 | 
        int day = validateDayOfMonth(parts[0]); 
 | 
        LocalTime time = parseTime(parts[1]); 
 | 
        return String.format("0 %d %d %d * ?", time.getMinute(), time.getHour(), day); 
 | 
    } 
 | 
  
 | 
    // 每季度任务转换 
 | 
    private String convertQuarterlyToCron(String frequencyDetail) { 
 | 
        String[] parts = validateAndSplit(frequencyDetail, ",", 3); 
 | 
        int month = validateMonth(parts[0]);  // 验证月份(1-12) 
 | 
        int day = validateDayOfMonth(parts[1]);  // 验证日期 
 | 
        LocalTime time = parseTime(parts[2]);  // 解析时间 
 | 
  
 | 
        // 计算季度起始月份(1月=1, 4月=4, 7月=7, 10月=10) 
 | 
        int quarterStartMonth = ((month - 1) / 3) * 3 + 1; 
 | 
  
 | 
        return String.format("0 %d %d %d %d/3 ?", 
 | 
                time.getMinute(), 
 | 
                time.getHour(), 
 | 
                day, 
 | 
                quarterStartMonth); 
 | 
    } 
 | 
  
 | 
    // 新增验证月份的方法(1-12) 
 | 
    private int validateMonth(String monthStr) { 
 | 
        try { 
 | 
            int month = Integer.parseInt(monthStr); 
 | 
            if (month < 1 || month > 12) { 
 | 
                throw new IllegalArgumentException("月份必须在1-12之间"); 
 | 
            } 
 | 
            return month; 
 | 
        } catch (NumberFormatException e) { 
 | 
            throw new IllegalArgumentException("无效的月份格式"); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    // 辅助方法:解析时间 
 | 
    private LocalTime parseTime(String timeStr) { 
 | 
        try { 
 | 
            return LocalTime.parse(timeStr); 
 | 
        } catch (DateTimeParseException e) { 
 | 
            throw new IllegalArgumentException("时间格式必须为HH:mm", e); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    // 辅助方法:验证并分割字符串 
 | 
    private String[] validateAndSplit(String input, String delimiter, int expectedParts) { 
 | 
        String[] parts = input.split(delimiter); 
 | 
        if (parts.length != expectedParts) { 
 | 
            throw new IllegalArgumentException( 
 | 
                    String.format("格式错误,应为%d部分用'%s'分隔", expectedParts, delimiter)); 
 | 
        } 
 | 
        return parts; 
 | 
    } 
 | 
  
 | 
    // 辅助方法:验证月份中的日 
 | 
    private int validateDayOfMonth(String dayStr) { 
 | 
        int day = Integer.parseInt(dayStr); 
 | 
        if (day < 1 || day > 31) { 
 | 
            throw new IllegalArgumentException("日期必须在1-31之间"); 
 | 
        } 
 | 
        return day; 
 | 
    } 
 | 
  
 | 
    // 辅助方法:验证季度中的月 
 | 
    private int validateMonthInQuarter(String monthStr) { 
 | 
        int month = Integer.parseInt(monthStr); 
 | 
        if (month < 1 || month > 3) { 
 | 
            throw new IllegalArgumentException("季度月份必须是1、2或3"); 
 | 
        } 
 | 
        return month; 
 | 
    } 
 | 
  
 | 
    // 转换星期几名称 
 | 
    private String convertDayNamesToCron(String dayNames) { 
 | 
        return Arrays.stream(dayNames.split("\\|")) 
 | 
                .map(this::convertSingleDayName) 
 | 
                .collect(Collectors.joining(",")); 
 | 
    } 
 | 
  
 | 
    // 转换单个星期几名称 
 | 
    private String convertSingleDayName(String dayName) { 
 | 
        switch (dayName.toUpperCase()) { 
 | 
            case "MON": return "MON"; 
 | 
            case "TUE": return "TUE"; 
 | 
            case "WED": return "WED"; 
 | 
            case "THU": return "THU"; 
 | 
            case "FRI": return "FRI"; 
 | 
            case "SAT": return "SAT"; 
 | 
            case "SUN": return "SUN"; 
 | 
            default: throw new IllegalArgumentException("无效的星期几: " + dayName); 
 | 
        } 
 | 
    } 
 | 
} 
 |