From 83f457a2128e6964b829a76a347b9f000218e14e Mon Sep 17 00:00:00 2001
From: maven <2163098428@qq.com>
Date: 星期四, 25 九月 2025 09:26:56 +0800
Subject: [PATCH] yys  修改巡检bug

---
 src/main/java/com/ruoyi/inspectiontask/service/impl/QuartzConfig.java          |   50 ++++
 src/main/java/com/ruoyi/inspectiontask/mapper/TimingTaskMapper.java            |    6 
 src/main/java/com/ruoyi/inspectiontask/pojo/InspectionTask.java                |    7 
 src/main/resources/mapper/inspectiontask/TimingTaskMapper.xml                  |    8 
 src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java |  102 +++++++++
 src/main/java/com/ruoyi/inspectiontask/pojo/TimingTask.java                    |    7 
 src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java         |  208 ++++++++++++++++++
 src/main/java/com/ruoyi/inspectiontask/pojo/QrCodeScanRecord.java              |    6 
 src/main/java/com/ruoyi/inspectiontask/service/impl/SpringContextHolder.java   |   20 +
 src/main/java/com/ruoyi/inspectiontask/pojo/QrCode.java                        |    2 
 src/main/resources/application-hckx.yml                                        |  219 +++++++++++++++++++
 11 files changed, 620 insertions(+), 15 deletions(-)

diff --git a/src/main/java/com/ruoyi/inspectiontask/mapper/TimingTaskMapper.java b/src/main/java/com/ruoyi/inspectiontask/mapper/TimingTaskMapper.java
index 94e41e8..13a011b 100644
--- a/src/main/java/com/ruoyi/inspectiontask/mapper/TimingTaskMapper.java
+++ b/src/main/java/com/ruoyi/inspectiontask/mapper/TimingTaskMapper.java
@@ -2,10 +2,16 @@
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.ruoyi.inspectiontask.pojo.TimingTask;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * @author :yys
  * @date : 2025/9/19 10:47
  */
+@Mapper
 public interface TimingTaskMapper extends BaseMapper<TimingTask> {
+
+    TimingTask getTaskById(@Param("id") Long id);
+
 }
diff --git a/src/main/java/com/ruoyi/inspectiontask/pojo/InspectionTask.java b/src/main/java/com/ruoyi/inspectiontask/pojo/InspectionTask.java
index 74fd9d2..232b5a5 100644
--- a/src/main/java/com/ruoyi/inspectiontask/pojo/InspectionTask.java
+++ b/src/main/java/com/ruoyi/inspectiontask/pojo/InspectionTask.java
@@ -26,8 +26,11 @@
     @TableId(type = IdType.AUTO)
     private Long id;
 
-    @ApiModelProperty(value = "宸℃浠诲姟鍚嶇О")
+    @ApiModelProperty(value = "璁惧鍚嶇О")
     private String taskName;
+
+    @ApiModelProperty(value = "璁惧id")
+    private Integer taskId;
 
     @ApiModelProperty(value = "宸℃浜篒D")
     private String inspectorId;
@@ -76,6 +79,6 @@
 
     @ApiModelProperty(value = "绉熸埛")
     @TableField(fill = FieldFill.INSERT)
-    private Integer tenantId;
+    private Long tenantId;
 
 }
diff --git a/src/main/java/com/ruoyi/inspectiontask/pojo/QrCode.java b/src/main/java/com/ruoyi/inspectiontask/pojo/QrCode.java
index be2abbf..2065e2e 100644
--- a/src/main/java/com/ruoyi/inspectiontask/pojo/QrCode.java
+++ b/src/main/java/com/ruoyi/inspectiontask/pojo/QrCode.java
@@ -37,7 +37,7 @@
 
     @ApiModelProperty(value = "绉熸埛ID锛岀敤浜庡绉熸埛闅旂")
     @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT)
-    private Integer tenantId;
+    private Long tenantId;
 
     @ApiModelProperty(value = "杞垹闄ゆ爣蹇楋紝0=鏈垹闄わ紝1=宸插垹闄�")
     private Integer deleted;
diff --git a/src/main/java/com/ruoyi/inspectiontask/pojo/QrCodeScanRecord.java b/src/main/java/com/ruoyi/inspectiontask/pojo/QrCodeScanRecord.java
index a84a658..2c1e3fe 100644
--- a/src/main/java/com/ruoyi/inspectiontask/pojo/QrCodeScanRecord.java
+++ b/src/main/java/com/ruoyi/inspectiontask/pojo/QrCodeScanRecord.java
@@ -32,6 +32,12 @@
     @ApiModelProperty(value = "鎵爜浜虹敤鎴稩D")
     private Long scannerId;
 
+    @ApiModelProperty(value = "璁惧鍚嶇О")
+    private String deviceName;
+
+    @ApiModelProperty(value = "璁惧id")
+    private Integer deviceId;
+
     @ApiModelProperty(value = "瀹為檯鎵爜鏃堕棿")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
diff --git a/src/main/java/com/ruoyi/inspectiontask/pojo/TimingTask.java b/src/main/java/com/ruoyi/inspectiontask/pojo/TimingTask.java
index 41099ea..f9bf88e 100644
--- a/src/main/java/com/ruoyi/inspectiontask/pojo/TimingTask.java
+++ b/src/main/java/com/ruoyi/inspectiontask/pojo/TimingTask.java
@@ -30,8 +30,11 @@
     @TableId(type = IdType.AUTO)
     private Long id;
 
-    @ApiModelProperty(value = "浠诲姟鍚嶇О")
+    @ApiModelProperty(value = "璁惧鍚嶇О")
     private String taskName;
+
+    @ApiModelProperty(value = "璁惧id")
+    private Integer taskId;
 
     @ApiModelProperty(value = "宸℃浜�")
     private String inspectorIds;
@@ -92,6 +95,6 @@
 
     @ApiModelProperty(value = "绉熸埛ID")
     @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT)
-    private Integer tenantId;
+    private Long tenantId;
 
 }
diff --git a/src/main/java/com/ruoyi/inspectiontask/service/impl/QuartzConfig.java b/src/main/java/com/ruoyi/inspectiontask/service/impl/QuartzConfig.java
new file mode 100644
index 0000000..da332f1
--- /dev/null
+++ b/src/main/java/com/ruoyi/inspectiontask/service/impl/QuartzConfig.java
@@ -0,0 +1,50 @@
+package com.ruoyi.inspectiontask.service.impl;
+
+import org.quartz.spi.TriggerFiredBundle;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+import org.springframework.scheduling.quartz.SpringBeanJobFactory;
+
+@Configuration
+public class QuartzConfig {
+    @Autowired
+    private ApplicationContext applicationContext;
+
+    @Bean
+    public SchedulerFactoryBean schedulerFactoryBean() {
+        SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
+
+        // 閰嶇疆SpringBeanJobFactory锛岀敤浜庢敮鎸丣ob涓殑渚濊禆娉ㄥ叆
+        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
+        jobFactory.setApplicationContext(applicationContext);
+        schedulerFactory.setJobFactory(jobFactory);
+
+        // 鍏朵粬閰嶇疆...
+        return schedulerFactory;
+    }
+
+    // 鑷畾涔塉obFactory锛屾敮鎸佽嚜鍔ㄦ敞鍏�
+    public static class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory
+            implements ApplicationContextAware {
+
+        private transient AutowireCapableBeanFactory beanFactory;
+
+        @Override
+        public void setApplicationContext(ApplicationContext applicationContext) {
+            this.beanFactory = applicationContext.getAutowireCapableBeanFactory();
+        }
+
+        @Override
+        protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
+            Object jobInstance = super.createJobInstance(bundle);
+            // 灏咼ob瀹炰緥浜ょ粰Spring瀹瑰櫒绠$悊锛屼娇鍏惰兘澶熻繘琛屼緷璧栨敞鍏�
+            beanFactory.autowireBean(jobInstance);
+            return jobInstance;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/inspectiontask/service/impl/SpringContextHolder.java b/src/main/java/com/ruoyi/inspectiontask/service/impl/SpringContextHolder.java
new file mode 100644
index 0000000..e245130
--- /dev/null
+++ b/src/main/java/com/ruoyi/inspectiontask/service/impl/SpringContextHolder.java
@@ -0,0 +1,20 @@
+package com.ruoyi.inspectiontask.service.impl;
+
+import org.quartz.JobExecutionContext;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SpringContextHolder implements ApplicationContextAware {
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public void setApplicationContext(ApplicationContext context) {
+        applicationContext = context;
+    }
+
+    public static <T> T getBean(Class<T> clazz) {
+        return applicationContext.getBean(clazz);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java
index efcd90f..1cfc748 100644
--- a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java
+++ b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java
@@ -1,42 +1,97 @@
 package com.ruoyi.inspectiontask.service.impl;
 
 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.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import javax.sql.DataSource;
+import java.time.DayOfWeek;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.YearMonth;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 @Component
 @DisallowConcurrentExecution // 绂佹骞跺彂鎵ц鍚屼竴涓狫ob
 public class TimingTaskJob implements Job {
 
     @Autowired
-    private
-    TimingTaskService timingTaskService;
+    private TimingTaskMapper timingTaskMapper;
+
+    @Autowired
+    private TimingTaskService timingTaskService;
 
     @Autowired
     private InspectionTaskMapper inspectionTaskMapper;
 
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
     @Override
     public void execute(JobExecutionContext context) throws JobExecutionException {
         JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
+        // 淇绫诲瀷杞崲閿欒锛屾纭幏鍙杢askId
         Long taskId = jobDataMap.getLong("taskId");
 
         try {
-            // 1. 鑾峰彇瀹氭椂浠诲姟璇︽儏
-            TimingTask timingTask = timingTaskService.getById(taskId);
-            if (timingTask == null || !timingTask.isActive()) {
-                return;
+            // 3. 灏濊瘯鏌ヨ浣犵殑涓氬姟鏁版嵁
+            // 閫氳繃JDBC妯℃澘鏌ヨ瀹氭椂浠诲姟淇℃伅锛屼娇鐢ㄥ弬鏁板寲鏌ヨ闃叉SQL娉ㄥ叆
+            String yourSql = "SELECT * FROM timing_task where id = ?";
+            List<TimingTask> tasks = jdbcTemplate.query(
+                    yourSql,
+                    new BeanPropertyRowMapper<>(TimingTask.class),
+                    taskId
+            );
+            TimingTask timingTask = tasks.isEmpty() ? null : tasks.get(0);
+            if (timingTask == null) {
+                throw new JobExecutionException("鎵句笉鍒板畾鏃朵换鍔�: " + taskId);
             }
+            
+//            if (!timingTask.isActive()) {
+//                throw new JobExecutionException("瀹氭椂浠诲姟宸茬鐢�: " + taskId);
+//            }
 
             // 2. 鍒涘缓骞朵繚瀛樺贰妫�浠诲姟璁板綍 - 杩欏氨鏄偍鎻愪緵鐨勪唬鐮佸簲璇ユ斁鐨勪綅缃�
             InspectionTask inspectionTask = createInspectionTask(timingTask);
             inspectionTaskMapper.insert(inspectionTask);
 
             // 3. 鏇存柊瀹氭椂浠诲姟鐨勬墽琛屾椂闂�
-            timingTaskService.updateTaskExecutionTime(taskId);
+            if (!tasks.isEmpty()) {
+                TimingTask task = tasks.get(0);
+
+                // 鏇存柊鏈�鍚庢墽琛屾椂闂翠负褰撳墠鏃堕棿
+                LocalDateTime lastExecutionTime = LocalDateTime.now();
+
+                // 璁$畻涓嬫鎵ц鏃堕棿
+                LocalDateTime nextExecutionTime = calculateNextExecutionTime(
+                        task.getFrequencyType(),
+                        task.getFrequencyDetail(),
+                        lastExecutionTime
+                );
+
+                // 鎵ц鏇存柊鎿嶄綔
+                String updateSql = "UPDATE timing_task " +
+                        "SET last_execution_time = ?, next_execution_time = ? " +
+                        "WHERE id = ?";
+
+                jdbcTemplate.update(
+                        updateSql,
+                        lastExecutionTime,
+                        nextExecutionTime,
+                        taskId
+                );
+            }
+//            timingTaskService.updateTaskExecutionTime(taskId);
 
             // 4. 璁板綍鎵ц鏃ュ織
 //            timingTaskService.recordExecutionLog(taskId, true, "浠诲姟鎵ц鎴愬姛锛岀敓鎴愬贰妫�浠诲姟ID: " + inspectionTask.getId());
@@ -53,13 +108,152 @@
 
         // 澶嶅埗鍩烘湰灞炴��
         inspectionTask.setTaskName(timingTask.getTaskName());
+        inspectionTask.setTaskId(timingTask.getTaskId());
         inspectionTask.setInspectorId(timingTask.getInspectorIds());
         inspectionTask.setInspectionLocation(timingTask.getInspectionLocation());
         inspectionTask.setRemarks("鑷姩鐢熸垚鑷畾鏃朵换鍔D: " + timingTask.getId());
         inspectionTask.setRegistrantId(timingTask.getRegistrantId());
         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);
+                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); // 瑙f瀽鏍煎紡 "HH:mm"
+        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];  // 濡� "MON" 鎴� "MON|WED|FRI"
+        LocalTime time = LocalTime.parse(parts[1]); // 鏃堕棿閮ㄥ垎
+
+        // 瑙f瀽鏄熸湡鍑�(鏀寔澶氫釜鏄熸湡)
+        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]);
+
+        // 浠庝笅涓湀寮�濮嬭绠�
+        LocalDateTime nextTime = current.plusMonths(1)
+                .withDayOfMonth(Math.min(dayOfMonth, current.plusMonths(1).toLocalDate().lengthOfMonth()))
+                .with(time);
+
+        return nextTime;
+    }
+
+    /**
+     * 璁$畻姣忓搴︿换鍔$殑涓嬫鎵ц鏃堕棿
+     */
+    private LocalDateTime calculateQuarterlyNextTime(String detail, LocalDateTime current) {
+        String[] parts = detail.split(",");
+        int quarterMonth = Integer.parseInt(parts[0]); // 1=绗�1涓湀锛�2=绗�2涓湀锛�3=绗�3涓湀
+        int dayOfMonth = Integer.parseInt(parts[1]);
+        LocalTime time = LocalTime.parse(parts[2]);
+
+        // 璁$畻褰撳墠瀛e害
+        int currentQuarter = (current.getMonthValue() - 1) / 3 + 1;
+        int currentMonthInQuarter = (current.getMonthValue() - 1) % 3 + 1;
+
+        YearMonth targetYearMonth;
+        if (currentMonthInQuarter < quarterMonth) {
+            // 鏈搴﹀唴杩樻湁鎵ц鏈轰細
+            targetYearMonth = YearMonth.from(current)
+                    .plusMonths(quarterMonth - currentMonthInQuarter);
+        } else {
+            // 闇�瑕佸埌涓嬩釜瀛e害
+            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()
+        );
+    }
+
+    /**
+     * 瑙f瀽鏄熸湡鍑犲瓧绗︿覆
+     */
+    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;
+    }
 }
diff --git a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
index 857a4ee..33c815e 100644
--- a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
+++ b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
@@ -19,6 +19,7 @@
 import org.springframework.transaction.annotation.Transactional;
 
 import java.time.*;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -76,7 +77,7 @@
         // 4. 鎵归噺鏌ヨ鐢ㄦ埛淇℃伅
         Map<Long, String> userNickNameMap = new HashMap<>();
         if (!userIds.isEmpty()) {
-            List<SysUser> users = sysUserMapper.selectUserByIds((List<Long>) userIds);
+            List<SysUser> users = sysUserMapper.selectUserByIds((new ArrayList<>(userIds)));
             users.forEach(user -> userNickNameMap.put(user.getUserId(), user.getNickName()));
         }
 
@@ -173,12 +174,107 @@
         return now.isBefore(todayExecution) ? todayExecution : todayExecution.plusDays(1);
     }
 
+    // 鏄犲皠鏄熸湡绠�鍐欎笌DayOfWeek
+    private static final Map<String, DayOfWeek> WEEK_DAY_MAP = new HashMap<>();
+    static {
+        WEEK_DAY_MAP.put("MON", DayOfWeek.MONDAY);
+        WEEK_DAY_MAP.put("TUE", DayOfWeek.TUESDAY);
+        WEEK_DAY_MAP.put("WED", DayOfWeek.WEDNESDAY);
+        WEEK_DAY_MAP.put("THU", DayOfWeek.THURSDAY);
+        WEEK_DAY_MAP.put("FRI", DayOfWeek.FRIDAY);
+        WEEK_DAY_MAP.put("SAT", DayOfWeek.SATURDAY);
+        WEEK_DAY_MAP.put("SUN", DayOfWeek.SUNDAY);
+    }
+
     private LocalDateTime calculateWeeklyFirstExecution(String frequencyDetail) {
-        return null;
+        // 瑙f瀽杈撳叆鍙傛暟
+        String[] parts = frequencyDetail.split(",");
+        if (parts.length != 2) {
+            throw new IllegalArgumentException("鍙傛暟鏍煎紡閿欒锛屽簲涓�'MON,13:43'鏍煎紡");
+        }
+
+        String weekDayStr = parts[0].trim();
+        String timeStr = parts[1].trim();
+
+        // 鑾峰彇瀵瑰簲鐨勬槦鏈熷嚑
+        DayOfWeek targetDay = WEEK_DAY_MAP.get(weekDayStr);
+        if (targetDay == null) {
+            throw new IllegalArgumentException("鏃犳晥鐨勬槦鏈熺畝鍐�: " + weekDayStr);
+        }
+
+        // 瑙f瀽鏃堕棿
+        LocalTime targetTime = LocalTime.parse(timeStr, DateTimeFormatter.ofPattern("HH:mm"));
+
+        // 鑾峰彇褰撳墠鏃堕棿
+        LocalDateTime now = LocalDateTime.now();
+        LocalDateTime targetDateTime = now.with(targetDay).with(targetTime);
+
+        // 濡傛灉璁$畻鍑虹殑鏃堕棿鍦ㄥ綋鍓嶆椂闂翠箣鍓嶏紝鍒欏姞涓�鍛�
+        if (targetDateTime.isBefore(now)) {
+            targetDateTime = targetDateTime.plusWeeks(1);
+        }
+
+        return targetDateTime;
     }
 
     private LocalDateTime calculateMonthlyFirstExecution(String frequencyDetail) {
-        return null;
+        // 瑙f瀽杈撳叆鍙傛暟
+        String[] parts = frequencyDetail.split(",");
+        if (parts.length != 2) {
+            throw new IllegalArgumentException("鍙傛暟鏍煎紡閿欒锛屽簲涓�'03,17:00'鏍煎紡");
+        }
+
+        String dayStr = parts[0].trim();
+        String timeStr = parts[1].trim();
+
+        // 瑙f瀽鏃ユ湡
+        int dayOfMonth;
+        try {
+            dayOfMonth = Integer.parseInt(dayStr);
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("鏃犳晥鐨勬棩鏈熸牸寮�: " + dayStr, e);
+        }
+
+        // 楠岃瘉鏃ユ湡鏈夋晥鎬э紙1-31涔嬮棿锛�
+        if (dayOfMonth < 1 || dayOfMonth > 31) {
+            throw new IllegalArgumentException("鏃ユ湡蹇呴』鍦�1-31涔嬮棿: " + dayOfMonth);
+        }
+
+        // 瑙f瀽鏃堕棿
+        LocalTime targetTime;
+        try {
+            targetTime = LocalTime.parse(timeStr, DateTimeFormatter.ofPattern("HH:mm"));
+        } catch (DateTimeException e) {
+            throw new IllegalArgumentException("鏃犳晥鐨勬椂闂存牸寮�: " + timeStr, e);
+        }
+
+        // 鑾峰彇褰撳墠鏃堕棿
+        LocalDateTime now = LocalDateTime.now();
+        LocalDateTime targetDateTime = now.withDayOfMonth(dayOfMonth).with(targetTime);
+
+        // 妫�鏌ユ棩鏈熸槸鍚﹁鑷姩璋冩暣锛堝31鏃ュ湪灏忔湀浼氳璋冩暣锛�
+        boolean isDateAdjusted = targetDateTime.getDayOfMonth() != dayOfMonth;
+
+        // 濡傛灉鐩爣鏃堕棿鍦ㄥ綋鍓嶆椂闂翠箣鍓嶏紝鎴栬�呮棩鏈熻绯荤粺鑷姩璋冩暣浜�
+        if (targetDateTime.isBefore(now) || isDateAdjusted) {
+            // 璁$畻涓嬩釜鏈堢殑鏃ユ湡
+            LocalDateTime nextMonth = now.plusMonths(1);
+            // 灏濊瘯璁剧疆涓嬩釜鏈堢殑鐩爣鏃ユ湡
+            LocalDateTime nextMonthTarget = nextMonth.withDayOfMonth(dayOfMonth).with(targetTime);
+
+            // 濡傛灉涓嬩釜鏈堢殑鏃ユ湡涔熻璋冩暣浜嗭紝灏辩敤涓嬩釜鏈堢殑鏈�鍚庝竴澶�
+            if (nextMonthTarget.getDayOfMonth() != dayOfMonth) {
+                // 姝g‘鑾峰彇涓嬩釜鏈堢殑鏈�鍚庝竴澶╋紙淇isLeapYear璋冪敤闂锛�
+                int lastDayOfMonth = nextMonth.getMonth().length(
+                        Year.of(nextMonth.getYear()).isLeap()
+                );
+                nextMonthTarget = nextMonth.withDayOfMonth(lastDayOfMonth).with(targetTime);
+            }
+
+            targetDateTime = nextMonthTarget;
+        }
+
+        return targetDateTime;
     }
 
     private LocalDateTime calculateCustomFirstExecution(String frequencyDetail) {
diff --git a/src/main/resources/application-hckx.yml b/src/main/resources/application-hckx.yml
new file mode 100644
index 0000000..cd680c8
--- /dev/null
+++ b/src/main/resources/application-hckx.yml
@@ -0,0 +1,219 @@
+# 椤圭洰鐩稿叧閰嶇疆
+ruoyi:
+  # 鍚嶇О
+  name: RuoYi
+  # 鐗堟湰
+  version: 3.8.9
+  # 鐗堟潈骞翠唤
+  copyrightYear: 2025
+  # 鏂囦欢璺緞 绀轰緥锛� Windows閰嶇疆D:/ruoyi/uploadPath锛孡inux閰嶇疆 /home/ruoyi/uploadPath锛�
+  profile: /javaWork/product-inventory-management/file
+
+  # 鑾峰彇ip鍦板潃寮�鍏�
+  addressEnabled: false
+  # 楠岃瘉鐮佺被鍨� math 鏁板瓧璁$畻 char 瀛楃楠岃瘉
+  captchaType: math
+
+# 寮�鍙戠幆澧冮厤缃�
+server:
+  # 鏈嶅姟鍣ㄧ殑HTTP绔彛锛岄粯璁や负8080
+  port: 9090
+  servlet:
+    # 搴旂敤鐨勮闂矾寰�
+    context-path: /
+  tomcat:
+    # tomcat鐨刄RI缂栫爜
+    uri-encoding: UTF-8
+    # 杩炴帴鏁版弧鍚庣殑鎺掗槦鏁帮紝榛樿涓�100
+    accept-count: 1000
+    threads:
+      # tomcat鏈�澶х嚎绋嬫暟锛岄粯璁や负200
+      max: 800
+      # Tomcat鍚姩鍒濆鍖栫殑绾跨▼鏁帮紝榛樿鍊�10
+      min-spare: 100
+
+# 鏃ュ織閰嶇疆
+logging:
+  level:
+    com.ruoyi: warn
+    org.springframework: warn
+
+minio:
+  endpoint: http://114.132.189.42/
+  port: 7019
+  secure: false
+  accessKey: admin
+  secretKey: 12345678
+  preview-expiry: 24 # 棰勮鍦板潃榛樿24灏忔椂
+  default-bucket: uploadPath
+# 鐢ㄦ埛閰嶇疆
+user:
+  password:
+    # 瀵嗙爜鏈�澶ч敊璇鏁�
+    maxRetryCount: 5
+    # 瀵嗙爜閿佸畾鏃堕棿锛堥粯璁�10鍒嗛挓锛�
+    lockTime: 10
+
+# Spring閰嶇疆
+spring:
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.cj.jdbc.Driver
+    druid:
+      # 涓诲簱鏁版嵁婧�
+      master:
+        url: jdbc:mysql://192.168.1.185:3306/product-inventory-management-hckx?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: root
+        password: xd@123456..
+      # 浠庡簱鏁版嵁婧�
+      slave:
+        # 浠庢暟鎹簮寮�鍏�/榛樿鍏抽棴
+        enabled: false
+        url:
+        username:
+        password:
+      # 鍒濆杩炴帴鏁�
+      initialSize: 5
+      # 鏈�灏忚繛鎺ユ睜鏁伴噺
+      minIdle: 10
+      # 鏈�澶ц繛鎺ユ睜鏁伴噺
+      maxActive: 20
+      # 閰嶇疆鑾峰彇杩炴帴绛夊緟瓒呮椂鐨勬椂闂�
+      maxWait: 60000
+      # 閰嶇疆杩炴帴瓒呮椂鏃堕棿
+      connectTimeout: 30000
+      # 閰嶇疆缃戠粶瓒呮椂鏃堕棿
+      socketTimeout: 60000
+      # 閰嶇疆闂撮殧澶氫箙鎵嶈繘琛屼竴娆℃娴嬶紝妫�娴嬮渶瑕佸叧闂殑绌洪棽杩炴帴锛屽崟浣嶆槸姣
+      timeBetweenEvictionRunsMillis: 60000
+      # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�灏忕敓瀛樼殑鏃堕棿锛屽崟浣嶆槸姣
+      minEvictableIdleTimeMillis: 300000
+      # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�澶х敓瀛樼殑鏃堕棿锛屽崟浣嶆槸姣
+      maxEvictableIdleTimeMillis: 900000
+      # 閰嶇疆妫�娴嬭繛鎺ユ槸鍚︽湁鏁�
+      validationQuery: SELECT 1 FROM DUAL
+      testWhileIdle: true
+      testOnBorrow: false
+      testOnReturn: false
+      webStatFilter:
+        enabled: true
+      statViewServlet:
+        enabled: true
+        # 璁剧疆鐧藉悕鍗曪紝涓嶅~鍒欏厑璁告墍鏈夎闂�
+        allow:
+        url-pattern: /druid/*
+        # 鎺у埗鍙扮鐞嗙敤鎴峰悕鍜屽瘑鐮�
+        login-username: ruoyi
+        login-password: 123456
+      filter:
+        stat:
+          enabled: true
+          # 鎱QL璁板綍
+          log-slow-sql: true
+          slow-sql-millis: 1000
+          merge-sql: true
+        wall:
+          config:
+            multi-statement-allow: true
+  # 璧勬簮淇℃伅
+  messages:
+    # 鍥介檯鍖栬祫婧愭枃浠惰矾寰�
+    basename: i18n/messages
+  # 鏂囦欢涓婁紶
+  servlet:
+    multipart:
+      # 鍗曚釜鏂囦欢澶у皬
+      max-file-size: 1GB
+      # 璁剧疆鎬讳笂浼犵殑鏂囦欢澶у皬
+      max-request-size: 2GB
+  # 鏈嶅姟妯″潡
+  devtools:
+    restart:
+      # 鐑儴缃插紑鍏�
+      enabled: false
+  # redis 閰嶇疆
+  redis:
+    # 鍦板潃
+#    host: 127.0.0.1
+    host: 192.168.1.185
+    # 绔彛锛岄粯璁や负6379
+    port: 6379
+    # 鏁版嵁搴撶储寮�
+    database: 12
+    # 瀵嗙爜
+#    password: root2022!
+    password:
+
+    # 杩炴帴瓒呮椂鏃堕棿
+    timeout: 10s
+    lettuce:
+      pool:
+        # 杩炴帴姹犱腑鐨勬渶灏忕┖闂茶繛鎺�
+        min-idle: 0
+        # 杩炴帴姹犱腑鐨勬渶澶х┖闂茶繛鎺�
+        max-idle: 8
+        # 杩炴帴姹犵殑鏈�澶ф暟鎹簱杩炴帴鏁�
+        max-active: 8
+        # #杩炴帴姹犳渶澶ч樆濉炵瓑寰呮椂闂达紙浣跨敤璐熷�艰〃绀烘病鏈夐檺鍒讹級
+        max-wait: -1ms
+
+# token閰嶇疆
+token:
+  # 浠ょ墝鑷畾涔夋爣璇�
+  header: Authorization
+  # 浠ょ墝瀵嗛挜
+  secret: abcdefghijklmnopqrstuvwxyz
+  # 浠ょ墝鏈夋晥鏈燂紙榛樿30鍒嗛挓锛�
+  expireTime: 450
+  
+# MyBatis Plus閰嶇疆
+mybatis-plus:
+  # 鎼滅储鎸囧畾鍖呭埆鍚�   鏍规嵁鑷繁鐨勯」鐩潵
+  typeAliasesPackage: com.ruoyi.**.pojo
+  # 閰嶇疆mapper鐨勬壂鎻忥紝鎵惧埌鎵�鏈夌殑mapper.xml鏄犲皠鏂囦欢
+  mapperLocations: classpath*:mapper/**/*Mapper.xml
+  # 鍔犺浇鍏ㄥ眬鐨勯厤缃枃浠�
+  configLocation: classpath:mybatis/mybatis-config.xml
+  global-config:
+    enable-sql-runner: true
+    db-config:
+      id-type: auto
+  
+# PageHelper鍒嗛〉鎻掍欢
+pagehelper:
+  helperDialect: mysql
+  supportMethodsArguments: true
+  params: count=countSql
+
+# Swagger閰嶇疆
+swagger:
+  # 鏄惁寮�鍚痵wagger
+  enabled: true
+  # 璇锋眰鍓嶇紑
+  pathMapping: /dev-api
+
+# 闃叉XSS鏀诲嚮
+xss:
+  # 杩囨护寮�鍏�
+  enabled: true
+  # 鎺掗櫎閾炬帴锛堝涓敤閫楀彿鍒嗛殧锛�
+  excludes: /system/notice
+  # 鍖归厤閾炬帴
+  urlPatterns: /system/*,/monitor/*,/tool/*
+  
+# 浠g爜鐢熸垚
+gen:
+  # 浣滆��
+  author: ruoyi
+  # 榛樿鐢熸垚鍖呰矾寰� system 闇�鏀规垚鑷繁鐨勬ā鍧楀悕绉� 濡� system monitor tool
+  packageName: com.ruoyi.project.system
+  # 鑷姩鍘婚櫎琛ㄥ墠缂�锛岄粯璁ゆ槸true
+  autoRemovePre: false
+  # 琛ㄥ墠缂�锛堢敓鎴愮被鍚嶄笉浼氬寘鍚〃鍓嶇紑锛屽涓敤閫楀彿鍒嗛殧锛�
+  tablePrefix: sys_
+  # 鏄惁鍏佽鐢熸垚鏂囦欢瑕嗙洊鍒版湰鍦帮紙鑷畾涔夎矾寰勶級锛岄粯璁や笉鍏佽
+  allowOverwrite: false
+
+file:
+  temp-dir: /javaWork/product-inventory-management/file/temp/uploads
+  upload-dir: /javaWork/product-inventory-management/file/prod/uploads
\ No newline at end of file
diff --git a/src/main/resources/mapper/inspectiontask/TimingTaskMapper.xml b/src/main/resources/mapper/inspectiontask/TimingTaskMapper.xml
new file mode 100644
index 0000000..bb74e0e
--- /dev/null
+++ b/src/main/resources/mapper/inspectiontask/TimingTaskMapper.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.inspectiontask.mapper.TimingTaskMapper">
+
+    <select id="getTaskById" resultType="com.ruoyi.inspectiontask.pojo.TimingTask" useCache="false">
+        SELECT * FROM timing_task WHERE id = #{id}
+    </select>
+</mapper>
\ No newline at end of file

--
Gitblit v1.9.3