From 1a89a2eca92540f2a6e9ed5c140b00610f2f4bfc Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 13 四月 2026 14:11:50 +0800
Subject: [PATCH] yys 1.设备巡检,保养加入年维度
---
src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java | 241 +++++++++++---------------
src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java | 43 ++++
src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java | 33 ++
src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java | 19 ++
src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskScheduler.java | 184 +++++++------------
5 files changed, 258 insertions(+), 262 deletions(-)
diff --git a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java
index 0cabd36..69ba222 100644
--- a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java
+++ b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java
@@ -140,6 +140,8 @@
return calculateMonthlyNextTime(frequencyDetail, currentTime);
case "QUARTERLY":
return calculateQuarterlyNextTime(frequencyDetail, currentTime);
+ case "YEARLY":
+ return calculateYearlyNextTime(frequencyDetail, currentTime);
default:
throw new IllegalArgumentException("涓嶆敮鎸佺殑棰戠巼绫诲瀷: " + frequencyType);
}
@@ -205,6 +207,23 @@
);
}
+ 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("\\|");
diff --git a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java
index 384862b..da24a2e 100644
--- a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java
+++ b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java
@@ -2,7 +2,17 @@
import com.ruoyi.device.pojo.MaintenanceTask;
import lombok.extern.slf4j.Slf4j;
-import org.quartz.*;
+import org.quartz.CronScheduleBuilder;
+import org.quartz.CronTrigger;
+import org.quartz.JobBuilder;
+import org.quartz.JobDataMap;
+import org.quartz.JobDetail;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.Trigger;
+import org.quartz.TriggerBuilder;
+import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -13,10 +23,6 @@
import java.util.Date;
import java.util.stream.Collectors;
-/**
- * @author :yys
- * @date : 2025/12/22 15:16
- */
@Service
@Slf4j
public class MaintenanceTaskScheduler {
@@ -24,133 +30,95 @@
@Autowired
private Scheduler scheduler;
- /**
- * 娣诲姞鏂颁换鍔″埌璋冨害鍣�
- */
- public void scheduleMaintenanceTask(MaintenanceTask task){
+ public void scheduleMaintenanceTask(MaintenanceTask task) {
try {
JobDetail jobDetail = buildJobDetail(task);
Trigger trigger = buildJobTrigger(task, jobDetail);
scheduler.scheduleJob(jobDetail, trigger);
- }catch (SchedulerException e){
- log.error("SchedulerException scheduleMaintenanceTask ERROR",e);
+ } catch (SchedulerException e) {
+ log.error("SchedulerException scheduleMaintenanceTask ERROR", e);
throw new RuntimeException(e);
}
}
- /**
- * 鏇存柊宸叉湁浠诲姟
- */
- public void rescheduleMaintenanceTask(MaintenanceTask task){
- try{
- TriggerKey triggerKey = new TriggerKey("triggerMaintenanceTask_" + task.getId());
-
- // 鑾峰彇鐜版湁瑙﹀彂鍣ㄥ苟杞崲涓� CronTrigger
- Trigger oldTrigger = scheduler.getTrigger(triggerKey);
- if (!(oldTrigger instanceof CronTrigger)) {
- throw new SchedulerException("Existing trigger is not a CronTrigger");
- }
-
- // 3. 鏋勫缓CronTrigger锛岀‘淇濇寔涔呭寲閰嶇疆
- CronTrigger newTrigger = TriggerBuilder.newTrigger()
- .withIdentity(triggerKey) // 鍞竴鏍囪瘑锛岀敤浜庢寔涔呭寲瀛樺偍
- .withDescription(task.getTaskName() + "_TRIGGER") // 瑙﹀彂鍣ㄦ弿杩�
- .forJob(oldTrigger.getJobKey()) // 鍏宠仈瀵瑰簲鐨凧ob
- .withSchedule(CronScheduleBuilder
- .cronSchedule(convertToCronExpression(task)) // 閿欒繃鎵ц鏃剁殑绛栫暐锛堟牴鎹笟鍔¤皟鏁达級
- )
- // 4. 璁剧疆寮�濮嬫椂闂达紙鑻ヤ负null鍒欑珛鍗崇敓鏁堬級
- .startAt(task.getNextExecutionTime() != null
- ? Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant())
- : new Date())
- .build();
- scheduler.rescheduleJob(triggerKey, newTrigger);
- }catch (SchedulerException e){
- log.error("SchedulerException rescheduleMaintenanceTask ERROR",e);
- throw new RuntimeException(e);
- }
- }
-
- /**
- * 鏆傚仠浠诲姟
- */
- public void pauseMaintenanceTask(Long taskId) throws SchedulerException {
- JobKey jobKey = new JobKey("MaintenanceTask_" + taskId);
- scheduler.pauseJob(jobKey);
- }
-
- /**
- * 鎭㈠浠诲姟
- */
- public void resumeMaintenanceTask(Long taskId) throws SchedulerException {
- JobKey jobKey = new JobKey("MaintenanceTask_" + taskId);
- scheduler.resumeJob(jobKey);
- }
-
- /**
- * 鍒犻櫎浠诲姟
- */
- public void unscheduleMaintenanceTask(Long taskId){
+ public void rescheduleMaintenanceTask(MaintenanceTask task) {
try {
- JobKey jobKey = new JobKey("MaintenanceTask_" + taskId);
- scheduler.deleteJob(jobKey);
- }catch (SchedulerException e){
- log.error("SchedulerException unscheduleMaintenanceTask ERROR",e);
+ TriggerKey triggerKey = new TriggerKey("triggerMaintenanceTask_" + task.getId());
+ Trigger oldTrigger = scheduler.getTrigger(triggerKey);
+ if (!(oldTrigger instanceof CronTrigger)) {
+ throw new SchedulerException("Existing trigger is not a CronTrigger");
+ }
+
+ CronTrigger newTrigger = TriggerBuilder.newTrigger()
+ .withIdentity(triggerKey)
+ .withDescription(task.getTaskName() + "_TRIGGER")
+ .forJob(oldTrigger.getJobKey())
+ .withSchedule(CronScheduleBuilder.cronSchedule(convertToCronExpression(task)))
+ .startAt(task.getNextExecutionTime() != null
+ ? Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant())
+ : new Date())
+ .build();
+ scheduler.rescheduleJob(triggerKey, newTrigger);
+ } catch (SchedulerException e) {
+ log.error("SchedulerException rescheduleMaintenanceTask ERROR", e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void pauseMaintenanceTask(Long taskId) throws SchedulerException {
+ scheduler.pauseJob(new JobKey("MaintenanceTask_" + taskId));
+ }
+
+ public void resumeMaintenanceTask(Long taskId) throws SchedulerException {
+ scheduler.resumeJob(new JobKey("MaintenanceTask_" + taskId));
+ }
+
+ public void unscheduleMaintenanceTask(Long taskId) {
+ try {
+ scheduler.deleteJob(new JobKey("MaintenanceTask_" + taskId));
+ } catch (SchedulerException e) {
+ log.error("SchedulerException unscheduleMaintenanceTask ERROR", e);
throw new RuntimeException(e);
}
}
private JobDetail buildJobDetail(MaintenanceTask task) {
- // 1. 鏋勫缓鍞竴JobKey锛堝熀浜庝换鍔D锛岀‘淇濋噸鍚悗鑳借瘑鍒級
JobKey jobKey = new JobKey("MaintenanceTask_" + task.getId());
-
- // 2. 灏佽浠诲姟鏁版嵁锛堜粎浣跨敤鍩烘湰绫诲瀷锛岀‘淇濆彲搴忓垪鍖栵級
JobDataMap jobDataMap = new JobDataMap();
- jobDataMap.put("maintenanceTaskId", task.getId()); // 浠诲姟ID锛圠ong锛屽彲搴忓垪鍖栵級
- jobDataMap.put("taskName", task.getTaskName()); // 浠诲姟鍚嶇О锛圫tring锛屽彲搴忓垪鍖栵級
- jobDataMap.put("taskType", task.getFrequencyType()); // 浠诲姟绫诲瀷锛圫tring锛�
- // 鎸夐渶娣诲姞鍏朵粬蹇呰鐨勫熀鏈被鍨嬪弬鏁�
+ jobDataMap.put("maintenanceTaskId", task.getId());
+ jobDataMap.put("taskName", task.getTaskName());
+ jobDataMap.put("taskType", task.getFrequencyType());
- // 3. 鏋勫缓JobDetail锛岃缃寔涔呭寲鐩稿叧灞炴��
return JobBuilder.newJob(MaintenanceTaskJob.class)
- .withIdentity(jobKey) // 鍞竴鏍囪瘑锛岀敤浜庢寔涔呭寲瀛樺偍
- .withDescription(task.getTaskName()) // 浠诲姟鎻忚堪锛屽瓨鍏ユ暟鎹簱
- .usingJobData(jobDataMap) // 缁戝畾浠诲姟鏁版嵁
- .storeDurably(true) // 鍗充娇娌℃湁瑙﹀彂鍣ㄥ叧鑱斾篃鎸佷箙鍖栦繚瀛�
- .requestRecovery(true) // 褰撹皟搴﹀櫒宕╂簝鍚庢仮澶嶆椂锛岄噸鏂版墽琛屾湭瀹屾垚鐨勪换鍔�
+ .withIdentity(jobKey)
+ .withDescription(task.getTaskName())
+ .usingJobData(jobDataMap)
+ .storeDurably(true)
+ .requestRecovery(true)
.build();
}
private Trigger buildJobTrigger(MaintenanceTask task, JobDetail jobDetail) {
- // 1. 鏋勫缓鍞竴TriggerKey锛堝熀浜庝换鍔D锛�
TriggerKey triggerKey = new TriggerKey("triggerMaintenanceTask_" + task.getId());
-
- // 2. 鐢熸垚Cron琛ㄨ揪寮忥紙鍘熼�昏緫涓嶅彉锛�
String cronExpression = convertToCronExpression(task);
-
- // 3. 鏋勫缓CronTrigger锛岀‘淇濇寔涔呭寲閰嶇疆
return TriggerBuilder.newTrigger()
- .withIdentity(triggerKey) // 鍞竴鏍囪瘑锛岀敤浜庢寔涔呭寲瀛樺偍
- .withDescription(task.getTaskName() + "_TRIGGER") // 瑙﹀彂鍣ㄦ弿杩�
- .forJob(jobDetail) // 鍏宠仈瀵瑰簲鐨凧ob
- .withSchedule(CronScheduleBuilder
- .cronSchedule(cronExpression)
- .withMisfireHandlingInstructionDoNothing() // 閿欒繃鎵ц鏃剁殑绛栫暐锛堟牴鎹笟鍔¤皟鏁达級
- )
- // 4. 璁剧疆寮�濮嬫椂闂达紙鑻ヤ负null鍒欑珛鍗崇敓鏁堬級
+ .withIdentity(triggerKey)
+ .withDescription(task.getTaskName() + "_TRIGGER")
+ .forJob(jobDetail)
+ .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)
+ .withMisfireHandlingInstructionDoNothing())
.startAt(task.getNextExecutionTime() != null
? Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant())
: new Date())
.build();
}
+
private String convertToCronExpression(MaintenanceTask task) {
- // 鍙傛暟鏍¢獙
if (task == null || task.getFrequencyType() == null || task.getFrequencyDetail() == null) {
throw new IllegalArgumentException("浠诲姟鍙傛暟涓嶈兘涓虹┖");
}
- // 浣跨敤switch纭繚鏉′欢浜掓枼
- String frequencyType = task.getFrequencyType().toUpperCase(); // 缁熶竴杞负澶у啓姣旇緝
+ String frequencyType = task.getFrequencyType().toUpperCase();
switch (frequencyType) {
case "DAILY":
return convertDailyToCron(task.getFrequencyDetail());
@@ -160,18 +128,18 @@
return convertMonthlyToCron(task.getFrequencyDetail());
case "QUARTERLY":
return convertQuarterlyToCron(task.getFrequencyDetail());
+ case "YEARLY":
+ return convertYearlyToCron(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]);
@@ -179,7 +147,6 @@
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]);
@@ -187,29 +154,29 @@
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]); // 瑙f瀽鏃堕棿
+ int month = validateMonth(parts[0]);
+ int day = validateDayOfMonth(parts[1]);
+ LocalTime time = parseTime(parts[2]);
- // 璁$畻瀛e害璧峰鏈堜唤(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);
+ return String.format("0 %d %d %d %d/3 ?", time.getMinute(), time.getHour(), day, quarterStartMonth);
}
- // 鏂板楠岃瘉鏈堜唤鐨勬柟娉�(1-12)
+ private String convertYearlyToCron(String frequencyDetail) {
+ String[] parts = validateAndSplit(frequencyDetail, ",", 3);
+ int month = validateMonth(parts[0]);
+ int day = validateDayOfMonth(parts[1]);
+ LocalTime time = parseTime(parts[2]);
+ return String.format("0 %d %d %d %d ?", time.getMinute(), time.getHour(), day, month);
+ }
+
private int validateMonth(String monthStr) {
try {
int month = Integer.parseInt(monthStr);
if (month < 1 || month > 12) {
- throw new IllegalArgumentException("鏈堜唤蹇呴』鍦�1-12涔嬮棿");
+ throw new IllegalArgumentException("鏈堜唤蹇呴』鍦� 1-12 涔嬮棿");
}
return month;
} catch (NumberFormatException e) {
@@ -217,62 +184,54 @@
}
}
- // 杈呭姪鏂规硶锛氳В鏋愭椂闂�
private LocalTime parseTime(String timeStr) {
try {
return LocalTime.parse(timeStr);
} catch (DateTimeParseException e) {
- throw new IllegalArgumentException("鏃堕棿鏍煎紡蹇呴』涓篐H:mm", 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));
+ 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涔嬮棿");
+ 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("瀛e害鏈堜唤蹇呴』鏄�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);
+ 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);
}
}
-
-}
+}
\ 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 b32f82b..5d13ffa 100644
--- a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java
+++ b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java
@@ -66,12 +66,12 @@
);
TimingTask timingTask = tasks.isEmpty() ? null : tasks.get(0);
if (timingTask == null) {
- throw new JobExecutionException("鎵句笉鍒板畾鏃朵换鍔�: " + taskId);
+ throw new JobExecutionException("閹靛彞绗夐崚鏉跨暰閺冩湹鎹㈤崝? " + taskId);
}
List<Long> deviceIds = resolveTaskIds(timingTask);
if (deviceIds.isEmpty()) {
- throw new JobExecutionException("瀹氭椂浠诲姟鏈厤缃澶�: " + taskId);
+ throw new JobExecutionException("鐎规碍妞傛禒璇插閺堫亪鍘ょ純顔款啎婢�? " + taskId);
}
for (Long deviceId : deviceIds) {
@@ -130,7 +130,7 @@
inspectionTask.setAreaId(deviceLedger.getAreaId());
inspectionTask.setInspectorId(timingTask.getInspectorIds());
inspectionTask.setInspectionLocation(timingTask.getInspectionLocation());
- inspectionTask.setRemarks("鑷姩鐢熸垚鑷畾鏃朵换鍔D: " + timingTask.getId());
+ inspectionTask.setRemarks("閼奉亜濮╅悽鐔稿灇閼奉亜鐣鹃弮鏈垫崲閸旑搹D: " + timingTask.getId());
inspectionTask.setRegistrantId(timingTask.getRegistrantId());
inspectionTask.setRegistrant(timingTask.getRegistrant());
inspectionTask.setFrequencyType(timingTask.getFrequencyType());
@@ -152,11 +152,13 @@
return calculateMonthlyNextTime(frequencyDetail, currentTime);
case "QUARTERLY":
return calculateQuarterlyNextTime(frequencyDetail, currentTime);
+ case "YEARLY":
+ return calculateYearlyNextTime(frequencyDetail, currentTime);
default:
- throw new IllegalArgumentException("涓嶆敮鎸佺殑棰戠巼绫诲瀷: " + frequencyType);
+ throw new IllegalArgumentException("娑撳秵鏁幐浣烘畱妫版垹宸肩猾璇茬��: " + frequencyType);
}
} catch (Exception e) {
- throw new RuntimeException("璁$畻涓嬫鎵ц鏃堕棿澶辫触: " + e.getMessage(), e);
+ throw new RuntimeException("鐠侊紕鐣绘稉瀣偧閹笛嗩攽閺冨爼妫挎径杈Е: " + e.getMessage(), e);
}
}
@@ -179,7 +181,7 @@
return LocalDateTime.of(nextTime.toLocalDate(), time);
}
if (nextTime.isAfter(current.plusYears(1))) {
- throw new RuntimeException("鏃犳硶鎵惧埌涓嬫鎵ц鏃堕棿");
+ throw new RuntimeException("閺冪姵纭堕幍鎯у煂娑撳顐奸幍褑顢戦弮鍫曟?");
}
}
}
@@ -217,6 +219,23 @@
);
}
+ 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("\\|");
@@ -245,7 +264,7 @@
days.add(DayOfWeek.SUNDAY);
break;
default:
- throw new IllegalArgumentException("鏃犳晥鐨勬槦鏈�: " + dayStr);
+ throw new IllegalArgumentException("閺冪姵鏅ラ惃鍕Е閺�? " + dayStr);
}
}
diff --git a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskScheduler.java b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskScheduler.java
index 125f311..5671156 100644
--- a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskScheduler.java
+++ b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskScheduler.java
@@ -1,7 +1,17 @@
package com.ruoyi.inspectiontask.service.impl;
import com.ruoyi.inspectiontask.pojo.TimingTask;
-import org.quartz.*;
+import org.quartz.CronScheduleBuilder;
+import org.quartz.CronTrigger;
+import org.quartz.JobBuilder;
+import org.quartz.JobDataMap;
+import org.quartz.JobDetail;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.Trigger;
+import org.quartz.TriggerBuilder;
+import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -18,132 +28,86 @@
@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");
}
- // 3. 鏋勫缓CronTrigger锛岀‘淇濇寔涔呭寲閰嶇疆
CronTrigger newTrigger = TriggerBuilder.newTrigger()
- .withIdentity(triggerKey) // 鍞竴鏍囪瘑锛岀敤浜庢寔涔呭寲瀛樺偍
- .withDescription(task.getTaskName() + "_TRIGGER") // 瑙﹀彂鍣ㄦ弿杩�
- .forJob(oldTrigger.getJobKey()) // 鍏宠仈瀵瑰簲鐨凧ob
- .withSchedule(CronScheduleBuilder
- .cronSchedule(convertToCronExpression(task)) // 閿欒繃鎵ц鏃剁殑绛栫暐锛堟牴鎹笟鍔¤皟鏁达級
- )
- // 4. 璁剧疆寮�濮嬫椂闂达紙鑻ヤ负null鍒欑珛鍗崇敓鏁堬級
+ .withIdentity(triggerKey)
+ .withDescription(task.getTaskName() + "_TRIGGER")
+ .forJob(oldTrigger.getJobKey())
+ .withSchedule(CronScheduleBuilder.cronSchedule(convertToCronExpression(task)))
.startAt(task.getNextExecutionTime() != null
? Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant())
: new Date())
.build();
- // 鏋勫缓鏂拌Е鍙戝櫒
-// 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);
+ scheduler.pauseJob(new JobKey("timingTask_" + taskId));
}
- /**
- * 鎭㈠浠诲姟
- */
public void resumeTimingTask(Long taskId) throws SchedulerException {
- JobKey jobKey = new JobKey("timingTask_" + taskId);
- scheduler.resumeJob(jobKey);
+ scheduler.resumeJob(new JobKey("timingTask_" + taskId));
}
- /**
- * 鍒犻櫎浠诲姟
- */
- public void unscheduleTimingTask(Long taskId){
+ public void unscheduleTimingTask(Long taskId) {
try {
- JobKey jobKey = new JobKey("timingTask_" + taskId);
- scheduler.deleteJob(jobKey);
- }catch (SchedulerException e){
+ scheduler.deleteJob(new JobKey("timingTask_" + taskId));
+ } catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
private JobDetail buildJobDetail(TimingTask task) {
- // 1. 鏋勫缓鍞竴JobKey锛堝熀浜庝换鍔D锛岀‘淇濋噸鍚悗鑳借瘑鍒級
JobKey jobKey = new JobKey("timingTask_" + task.getId());
-
- // 2. 灏佽浠诲姟鏁版嵁锛堜粎浣跨敤鍩烘湰绫诲瀷锛岀‘淇濆彲搴忓垪鍖栵級
JobDataMap jobDataMap = new JobDataMap();
- jobDataMap.put("taskId", task.getId()); // 浠诲姟ID锛圠ong锛屽彲搴忓垪鍖栵級
- jobDataMap.put("taskName", task.getTaskName()); // 浠诲姟鍚嶇О锛圫tring锛屽彲搴忓垪鍖栵級
- jobDataMap.put("taskType", task.getFrequencyType()); // 浠诲姟绫诲瀷锛圫tring锛�
- // 鎸夐渶娣诲姞鍏朵粬蹇呰鐨勫熀鏈被鍨嬪弬鏁�
+ jobDataMap.put("taskId", task.getId());
+ jobDataMap.put("taskName", task.getTaskName());
+ jobDataMap.put("taskType", task.getFrequencyType());
- // 3. 鏋勫缓JobDetail锛岃缃寔涔呭寲鐩稿叧灞炴��
return JobBuilder.newJob(TimingTaskJob.class)
- .withIdentity(jobKey) // 鍞竴鏍囪瘑锛岀敤浜庢寔涔呭寲瀛樺偍
- .withDescription(task.getTaskName()) // 浠诲姟鎻忚堪锛屽瓨鍏ユ暟鎹簱
- .usingJobData(jobDataMap) // 缁戝畾浠诲姟鏁版嵁
- .storeDurably(true) // 鍗充娇娌℃湁瑙﹀彂鍣ㄥ叧鑱斾篃鎸佷箙鍖栦繚瀛�
- .requestRecovery(true) // 褰撹皟搴﹀櫒宕╂簝鍚庢仮澶嶆椂锛岄噸鏂版墽琛屾湭瀹屾垚鐨勪换鍔�
+ .withIdentity(jobKey)
+ .withDescription(task.getTaskName())
+ .usingJobData(jobDataMap)
+ .storeDurably(true)
+ .requestRecovery(true)
.build();
}
private Trigger buildJobTrigger(TimingTask task, JobDetail jobDetail) {
- // 1. 鏋勫缓鍞竴TriggerKey锛堝熀浜庝换鍔D锛�
TriggerKey triggerKey = new TriggerKey("trigger_" + task.getId());
-
- // 2. 鐢熸垚Cron琛ㄨ揪寮忥紙鍘熼�昏緫涓嶅彉锛�
String cronExpression = convertToCronExpression(task);
- // 3. 鏋勫缓CronTrigger锛岀‘淇濇寔涔呭寲閰嶇疆
return TriggerBuilder.newTrigger()
- .withIdentity(triggerKey) // 鍞竴鏍囪瘑锛岀敤浜庢寔涔呭寲瀛樺偍
- .withDescription(task.getTaskName() + "_TRIGGER") // 瑙﹀彂鍣ㄦ弿杩�
- .forJob(jobDetail) // 鍏宠仈瀵瑰簲鐨凧ob
- .withSchedule(CronScheduleBuilder
- .cronSchedule(cronExpression)
- .withMisfireHandlingInstructionDoNothing() // 閿欒繃鎵ц鏃剁殑绛栫暐锛堟牴鎹笟鍔¤皟鏁达級
- )
- // 4. 璁剧疆寮�濮嬫椂闂达紙鑻ヤ负null鍒欑珛鍗崇敓鏁堬級
+ .withIdentity(triggerKey)
+ .withDescription(task.getTaskName() + "_TRIGGER")
+ .forJob(jobDetail)
+ .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)
+ .withMisfireHandlingInstructionDoNothing())
.startAt(task.getNextExecutionTime() != null
? Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant())
: new Date())
.build();
}
+
private String convertToCronExpression(TimingTask task) {
- // 鍙傛暟鏍¢獙
if (task == null || task.getFrequencyType() == null || task.getFrequencyDetail() == null) {
throw new IllegalArgumentException("浠诲姟鍙傛暟涓嶈兘涓虹┖");
}
- // 浣跨敤switch纭繚鏉′欢浜掓枼
- String frequencyType = task.getFrequencyType().toUpperCase(); // 缁熶竴杞负澶у啓姣旇緝
+ String frequencyType = task.getFrequencyType().toUpperCase();
switch (frequencyType) {
case "DAILY":
return convertDailyToCron(task.getFrequencyDetail());
@@ -153,18 +117,18 @@
return convertMonthlyToCron(task.getFrequencyDetail());
case "QUARTERLY":
return convertQuarterlyToCron(task.getFrequencyDetail());
+ case "YEARLY":
+ return convertYearlyToCron(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]);
@@ -172,7 +136,6 @@
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]);
@@ -180,29 +143,29 @@
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]); // 瑙f瀽鏃堕棿
+ int month = validateMonth(parts[0]);
+ int day = validateDayOfMonth(parts[1]);
+ LocalTime time = parseTime(parts[2]);
- // 璁$畻瀛e害璧峰鏈堜唤(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);
+ return String.format("0 %d %d %d %d/3 ?", time.getMinute(), time.getHour(), day, quarterStartMonth);
}
- // 鏂板楠岃瘉鏈堜唤鐨勬柟娉�(1-12)
+ private String convertYearlyToCron(String frequencyDetail) {
+ String[] parts = validateAndSplit(frequencyDetail, ",", 3);
+ int month = validateMonth(parts[0]);
+ int day = validateDayOfMonth(parts[1]);
+ LocalTime time = parseTime(parts[2]);
+ return String.format("0 %d %d %d %d ?", time.getMinute(), time.getHour(), day, month);
+ }
+
private int validateMonth(String monthStr) {
try {
int month = Integer.parseInt(monthStr);
if (month < 1 || month > 12) {
- throw new IllegalArgumentException("鏈堜唤蹇呴』鍦�1-12涔嬮棿");
+ throw new IllegalArgumentException("鏈堜唤蹇呴』鍦� 1-12 涔嬮棿");
}
return month;
} catch (NumberFormatException e) {
@@ -210,61 +173,54 @@
}
}
- // 杈呭姪鏂规硶锛氳В鏋愭椂闂�
private LocalTime parseTime(String timeStr) {
try {
return LocalTime.parse(timeStr);
} catch (DateTimeParseException e) {
- throw new IllegalArgumentException("鏃堕棿鏍煎紡蹇呴』涓篐H:mm", 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));
+ 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涔嬮棿");
+ 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("瀛e害鏈堜唤蹇呴』鏄�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);
+ 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);
}
}
-}
+}
\ No newline at end of file
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 f23a6a4..d551399 100644
--- a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
+++ b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
@@ -225,6 +225,8 @@
return calculateWeeklyFirstExecution(task.getFrequencyDetail());
} else if ("MONTHLY".equals(frequencyType)) {
return calculateMonthlyFirstExecution(task.getFrequencyDetail());
+ } else if ("YEARLY".equals(frequencyType)) {
+ return calculateYearlyFirstExecution(task.getFrequencyDetail());
} else if ("QUARTERLY".equals(frequencyType)) {
return calculateCustomFirstExecution(task.getFrequencyDetail());
} else {
@@ -315,6 +317,28 @@
return targetDateTime;
}
+ private LocalDateTime calculateYearlyFirstExecution(String frequencyDetail) {
+ String[] parts = frequencyDetail.split(",");
+ if (parts.length != 3) {
+ throw new IllegalArgumentException("鍙傛暟鏍煎紡閿欒锛屽簲涓� 03,15,17:00");
+ }
+
+ int month = Integer.parseInt(parts[0].trim());
+ int dayOfMonth = Integer.parseInt(parts[1].trim());
+ LocalTime targetTime = LocalTime.parse(parts[2].trim(), DateTimeFormatter.ofPattern("HH:mm"));
+
+ LocalDateTime now = LocalDateTime.now();
+ YearMonth currentYearMonth = YearMonth.of(now.getYear(), month);
+ int adjustedDay = Math.min(dayOfMonth, currentYearMonth.lengthOfMonth());
+ LocalDateTime targetDateTime = LocalDateTime.of(now.getYear(), month, adjustedDay, targetTime.getHour(), targetTime.getMinute());
+ if (!targetDateTime.isAfter(now)) {
+ YearMonth nextYearMonth = YearMonth.of(now.getYear() + 1, month);
+ adjustedDay = Math.min(dayOfMonth, nextYearMonth.lengthOfMonth());
+ targetDateTime = LocalDateTime.of(now.getYear() + 1, month, adjustedDay, targetTime.getHour(), targetTime.getMinute());
+ }
+ return targetDateTime;
+ }
+
private LocalDateTime calculateCustomFirstExecution(String frequencyDetail) {
return null;
}
@@ -350,6 +374,8 @@
return calculateMonthlyNextTime(frequencyDetail, currentTime);
case "QUARTERLY":
return calculateQuarterlyNextTime(frequencyDetail, currentTime);
+ case "YEARLY":
+ return calculateYearlyNextTime(frequencyDetail, currentTime);
default:
throw new IllegalArgumentException("涓嶆敮鎸佺殑棰戠巼绫诲瀷: " + frequencyType);
}
@@ -415,6 +441,23 @@
);
}
+ 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("\\|");
--
Gitblit v1.9.3