|
@@ -1,8 +1,11 @@
|
|
|
package cn.sciento.farm.automationv2.domain.entity;
|
|
package cn.sciento.farm.automationv2.domain.entity;
|
|
|
|
|
|
|
|
|
|
+import cn.sciento.core.exception.CommonException;
|
|
|
import cn.sciento.farm.automationv2.domain.enums.ScheduleType;
|
|
import cn.sciento.farm.automationv2.domain.enums.ScheduleType;
|
|
|
import cn.sciento.farm.automationv2.domain.enums.TaskScheduleRuleStatus;
|
|
import cn.sciento.farm.automationv2.domain.enums.TaskScheduleRuleStatus;
|
|
|
|
|
+import cn.sciento.farm.automationv2.infra.constant.BaseConstant;
|
|
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
|
|
|
+import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
|
import io.choerodon.mybatis.domain.AuditDomain;
|
|
import io.choerodon.mybatis.domain.AuditDomain;
|
|
|
import io.swagger.annotations.ApiModel;
|
|
import io.swagger.annotations.ApiModel;
|
|
|
import lombok.AllArgsConstructor;
|
|
import lombok.AllArgsConstructor;
|
|
@@ -60,13 +63,36 @@ public class TaskScheduleRule extends AuditDomain {
|
|
|
*/
|
|
*/
|
|
|
private String cronExpression;
|
|
private String cronExpression;
|
|
|
|
|
|
|
|
- // ================== SIMPLE 模式字段 ==================
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 执行时间(schedule_type=CRON和SIMPLE 共用)
|
|
|
|
|
+ * 格式:"HH:mm:ss",例如:"02:00:00"
|
|
|
|
|
+ * 用于前端展示和生成 cronExpression
|
|
|
|
|
+ */
|
|
|
|
|
+ private String executeTime;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 重复周期 - 星期几(schedule_type=CRON时必填)
|
|
|
|
|
+ * 存储格式:"1,3,5" 表示周一、周三、周五
|
|
|
|
|
+ * 1=周一, 2=周二, 3=周三, 4=周四, 5=周五, 6=周六, 7=周日
|
|
|
|
|
+ * 用于前端展示和生成 cronExpression
|
|
|
|
|
+ */
|
|
|
|
|
+ private String repeatWeekdays;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 起始时间(schedule_type=SIMPLE时必填)
|
|
|
|
|
|
|
+ * 有效开始日期(schedule_type=CRON时可选)
|
|
|
|
|
+ * 在此日期之前不会触发任务
|
|
|
*/
|
|
*/
|
|
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
|
|
- private LocalDateTime startTime;
|
|
|
|
|
|
|
+ private LocalDateTime validStartDate;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 有效结束日期(schedule_type=CRON时可选)
|
|
|
|
|
+ * 在此日期之后不再触发任务
|
|
|
|
|
+ */
|
|
|
|
|
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
|
|
|
|
+ private LocalDateTime validEndDate;
|
|
|
|
|
+
|
|
|
|
|
+ // ================== SIMPLE 模式字段 ==================
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 执行间隔天数(schedule_type=SIMPLE时必填)
|
|
* 执行间隔天数(schedule_type=SIMPLE时必填)
|
|
@@ -86,11 +112,6 @@ public class TaskScheduleRule extends AuditDomain {
|
|
|
// ================== 状态控制 ==================
|
|
// ================== 状态控制 ==================
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 是否启用:true启用 false禁用
|
|
|
|
|
- */
|
|
|
|
|
- private Boolean enabled;
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
* 规则状态:ACTIVE活跃 / COMPLETED已完成 / DISABLED已禁用
|
|
* 规则状态:ACTIVE活跃 / COMPLETED已完成 / DISABLED已禁用
|
|
|
* ACTIVE: 规则正在生效
|
|
* ACTIVE: 规则正在生效
|
|
|
* COMPLETED: SIMPLE模式下已达到执行次数上限,自动停用
|
|
* COMPLETED: SIMPLE模式下已达到执行次数上限,自动停用
|
|
@@ -130,6 +151,7 @@ public class TaskScheduleRule extends AuditDomain {
|
|
|
/**
|
|
/**
|
|
|
* 是否为 CRON 模式
|
|
* 是否为 CRON 模式
|
|
|
*/
|
|
*/
|
|
|
|
|
+ @JsonIgnore
|
|
|
public boolean isCronMode() {
|
|
public boolean isCronMode() {
|
|
|
return ScheduleType.CRON.equals(scheduleType);
|
|
return ScheduleType.CRON.equals(scheduleType);
|
|
|
}
|
|
}
|
|
@@ -137,6 +159,7 @@ public class TaskScheduleRule extends AuditDomain {
|
|
|
/**
|
|
/**
|
|
|
* 是否为 SIMPLE 模式
|
|
* 是否为 SIMPLE 模式
|
|
|
*/
|
|
*/
|
|
|
|
|
+ @JsonIgnore
|
|
|
public boolean isSimpleMode() {
|
|
public boolean isSimpleMode() {
|
|
|
return ScheduleType.SIMPLE.equals(scheduleType);
|
|
return ScheduleType.SIMPLE.equals(scheduleType);
|
|
|
}
|
|
}
|
|
@@ -144,6 +167,7 @@ public class TaskScheduleRule extends AuditDomain {
|
|
|
/**
|
|
/**
|
|
|
* SIMPLE 模式是否已达到执行次数上限
|
|
* SIMPLE 模式是否已达到执行次数上限
|
|
|
*/
|
|
*/
|
|
|
|
|
+ @JsonIgnore
|
|
|
public boolean reachedExecutionLimit() {
|
|
public boolean reachedExecutionLimit() {
|
|
|
return isSimpleMode()
|
|
return isSimpleMode()
|
|
|
&& executedCount != null
|
|
&& executedCount != null
|
|
@@ -154,6 +178,7 @@ public class TaskScheduleRule extends AuditDomain {
|
|
|
/**
|
|
/**
|
|
|
* 增加已执行次数
|
|
* 增加已执行次数
|
|
|
*/
|
|
*/
|
|
|
|
|
+ @JsonIgnore
|
|
|
public void incrementExecutedCount() {
|
|
public void incrementExecutedCount() {
|
|
|
if (executedCount == null) {
|
|
if (executedCount == null) {
|
|
|
executedCount = 0;
|
|
executedCount = 0;
|
|
@@ -164,13 +189,15 @@ public class TaskScheduleRule extends AuditDomain {
|
|
|
/**
|
|
/**
|
|
|
* 是否有效(启用且未完成)
|
|
* 是否有效(启用且未完成)
|
|
|
*/
|
|
*/
|
|
|
|
|
+ @JsonIgnore
|
|
|
public boolean isActive() {
|
|
public boolean isActive() {
|
|
|
- return Boolean.TRUE.equals(enabled) && TaskScheduleRuleStatus.ACTIVE.getCode().equals(status);
|
|
|
|
|
|
|
+ return BaseConstant.ENABLE.equals(enabledFlag) && TaskScheduleRuleStatus.ACTIVE.getCode().equals(status);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 生成 Quartz Job 名称
|
|
* 生成 Quartz Job 名称
|
|
|
*/
|
|
*/
|
|
|
|
|
+ @JsonIgnore
|
|
|
public static String generateJobName(Long taskId, Long ruleId) {
|
|
public static String generateJobName(Long taskId, Long ruleId) {
|
|
|
return String.format("TASK_%d_RULE_%d", taskId, ruleId);
|
|
return String.format("TASK_%d_RULE_%d", taskId, ruleId);
|
|
|
}
|
|
}
|
|
@@ -178,6 +205,7 @@ public class TaskScheduleRule extends AuditDomain {
|
|
|
/**
|
|
/**
|
|
|
* 生成 Quartz Trigger 名称
|
|
* 生成 Quartz Trigger 名称
|
|
|
*/
|
|
*/
|
|
|
|
|
+ @JsonIgnore
|
|
|
public static String generateTriggerName(Long taskId, Long ruleId) {
|
|
public static String generateTriggerName(Long taskId, Long ruleId) {
|
|
|
return String.format("TRIGGER_%d_RULE_%d", taskId, ruleId);
|
|
return String.format("TRIGGER_%d_RULE_%d", taskId, ruleId);
|
|
|
}
|
|
}
|
|
@@ -185,10 +213,101 @@ public class TaskScheduleRule extends AuditDomain {
|
|
|
/**
|
|
/**
|
|
|
* 填充Quartz相关字段
|
|
* 填充Quartz相关字段
|
|
|
*/
|
|
*/
|
|
|
|
|
+ @JsonIgnore
|
|
|
public void fillQuartzNames() {
|
|
public void fillQuartzNames() {
|
|
|
if (this.taskId != null && this.id != null) {
|
|
if (this.taskId != null && this.id != null) {
|
|
|
this.quartzJobName = generateJobName(this.taskId, this.id);
|
|
this.quartzJobName = generateJobName(this.taskId, this.id);
|
|
|
this.quartzTriggerName = generateTriggerName(this.taskId, this.id);
|
|
this.quartzTriggerName = generateTriggerName(this.taskId, this.id);
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 根据 executeTime 和 repeatWeekdays 生成 CRON 表达式
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return Cron 表达式,例如:"0 0 2 ? * MON,WED,FRI"
|
|
|
|
|
+ * @throws IllegalArgumentException 如果参数格式不正确
|
|
|
|
|
+ */
|
|
|
|
|
+ @JsonIgnore
|
|
|
|
|
+ public String generateCronExpression() {
|
|
|
|
|
+ if (!isCronMode()) {
|
|
|
|
|
+ throw new CommonException("wfautoV2.task.schedule.typeError");
|
|
|
|
|
+ }
|
|
|
|
|
+ // 预留字段,如果存在则直接试用
|
|
|
|
|
+ if (cronExpression != null && !cronExpression.equals("")){
|
|
|
|
|
+ return cronExpression;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (executeTime == null || executeTime.isEmpty()) {
|
|
|
|
|
+ throw new CommonException("wfautoV2.parameter.incomplete");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (repeatWeekdays == null || repeatWeekdays.isEmpty()) {
|
|
|
|
|
+ throw new CommonException("wfautoV2.parameter.incomplete");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 解析执行时间 "HH:mm:ss"
|
|
|
|
|
+ String[] timeParts = executeTime.split(":");
|
|
|
|
|
+ if (timeParts.length != 3) {
|
|
|
|
|
+ throw new CommonException("wfautoV2.parameter.error");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String hour = timeParts[0];
|
|
|
|
|
+ String minute = timeParts[1];
|
|
|
|
|
+ String second = timeParts[2];
|
|
|
|
|
+
|
|
|
|
|
+ // 转换星期数字为 Cron 格式
|
|
|
|
|
+ // 输入:"1,3,5" -> 输出:"MON,WED,FRI"
|
|
|
|
|
+ String[] weekdayNumbers = repeatWeekdays.split(",");
|
|
|
|
|
+ StringBuilder cronWeekdays = new StringBuilder();
|
|
|
|
|
+
|
|
|
|
|
+ for (int i = 0; i < weekdayNumbers.length; i++) {
|
|
|
|
|
+ if (i > 0) {
|
|
|
|
|
+ cronWeekdays.append(",");
|
|
|
|
|
+ }
|
|
|
|
|
+ cronWeekdays.append(numberToWeekday(weekdayNumbers[i].trim()));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 构造 Cron 表达式:秒 分 时 日 月 周
|
|
|
|
|
+ return String.format("%s %s %s ? * %s", second, minute, hour, cronWeekdays.toString());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 数字转换为 Cron 星期格式
|
|
|
|
|
+ * 1=MON, 2=TUE, 3=WED, 4=THU, 5=FRI, 6=SAT, 7=SUN
|
|
|
|
|
+ */
|
|
|
|
|
+ @JsonIgnore
|
|
|
|
|
+ private String numberToWeekday(String number) {
|
|
|
|
|
+ switch (number) {
|
|
|
|
|
+ case "1": return "MON";
|
|
|
|
|
+ case "2": return "TUE";
|
|
|
|
|
+ case "3": return "WED";
|
|
|
|
|
+ case "4": return "THU";
|
|
|
|
|
+ case "5": return "FRI";
|
|
|
|
|
+ case "6": return "SAT";
|
|
|
|
|
+ case "7": return "SUN";
|
|
|
|
|
+ default: throw new IllegalArgumentException("无效的星期数字: " + number);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 检查当前时间是否在有效日期范围内
|
|
|
|
|
+ */
|
|
|
|
|
+ @JsonIgnore
|
|
|
|
|
+ public boolean isWithinValidPeriod() {
|
|
|
|
|
+ if (!isCronMode()) {
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
+
|
|
|
|
|
+ if (validStartDate != null && now.isBefore(validStartDate)) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (validEndDate != null && now.isAfter(validEndDate)) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|