diff --git a/shuili-system/pom.xml b/shuili-system/pom.xml
index 5d4579c3..f79d2ab6 100644
--- a/shuili-system/pom.xml
+++ b/shuili-system/pom.xml
@@ -28,6 +28,12 @@
spring-boot-starter-web
+
+ org.redisson
+ redisson-spring-boot-starter
+ 3.16.4
+
+
mysql
@@ -76,7 +82,7 @@
cn.hutool
- hutool-core
+ hutool-all
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/config/RedissonConfig.java b/shuili-system/src/main/java/com/kms/yxgh/common/config/RedissonConfig.java
new file mode 100644
index 00000000..2cc4b174
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/config/RedissonConfig.java
@@ -0,0 +1,39 @@
+package com.kms.yxgh.common.config;
+
+
+import com.shuili.common.utils.StringUtils;
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class RedissonConfig {
+
+
+ @Value("${spring.redis.host}")
+ private String redisHost;
+
+ @Value("${spring.redis.port}")
+ private int redisPort;
+
+ @Value("${spring.redis.password}")
+ private String redisPassword;
+
+ @Value("${spring.redis.database:0}")
+ private int redisDatabase;
+
+ @Bean
+ public RedissonClient redissonClient() {
+ Config config = new Config();
+ config.useSingleServer()
+ .setAddress("redis://" + redisHost + ":" + redisPort)
+ .setDatabase(redisDatabase);
+ if (StringUtils.isNotBlank(redisPassword)) {
+ config.useSingleServer().setPassword(redisPassword);
+ }
+ return Redisson.create(config);
+ }
+}
\ No newline at end of file
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/domain/JobTask.java b/shuili-system/src/main/java/com/kms/yxgh/common/domain/JobTask.java
new file mode 100644
index 00000000..66039452
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/domain/JobTask.java
@@ -0,0 +1,59 @@
+package com.kms.yxgh.common.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.kms.yxgh.base.SyBaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.ToString;
+
+import java.util.Date;
+
+/**
+ * 定时任务实体类对应 bs_sgc_job_task 表
+ */
+@TableName("bs_sgc_job_task")
+@Data
+@ApiModel("定时任务")
+@ToString(callSuper = true)
+public class JobTask extends SyBaseEntity {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty("任务名称")
+ private String name;
+
+ @ApiModelProperty("业务类型")
+ private String businessType;
+
+ @ApiModelProperty("业务id")
+ private String businessId;
+
+ @ApiModelProperty("任务状态")
+ private String status;
+
+ @ApiModelProperty("任务参数")
+ @TableField(value = "params")
+ private String jobParams;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty("上次开始时间")
+ private Date lastStartTime;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty("上次结束时间")
+ private Date lastEndTime;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty("下次开始时间")
+ private Date nextStartTime;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty("任务结束时间")
+ private Date taskEndTime;
+
+ @TableField(exist = false)
+ private String remark;
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/job/JobScheduled.java b/shuili-system/src/main/java/com/kms/yxgh/common/job/JobScheduled.java
new file mode 100644
index 00000000..dc7f95b0
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/job/JobScheduled.java
@@ -0,0 +1,78 @@
+package com.kms.yxgh.common.job;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.kms.yxgh.common.domain.JobTask;
+import com.kms.yxgh.common.job.event.StartJobEvent;
+import com.kms.yxgh.common.service.JobTaskService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ApplicationContext;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.util.Calendar;
+import java.util.Date;
+
+@EnableAsync
+@EnableScheduling
+@Slf4j
+@Component
+@AllArgsConstructor
+public class JobScheduled {
+
+ public final JobTaskService jobTaskService;
+ private final ApplicationContext applicationContext;
+
+ @Scheduled(fixedRate = 1000 * 60)
+ public void run() {
+ log.info("start to run job");
+
+ Date currentTime = new Date();
+ int page = 1;
+ IPage jobTaskList = getJobTaskList(page, currentTime);
+ while (!jobTaskList.getRecords().isEmpty()) {
+ jobTaskList.getRecords().forEach(this::addTask);
+ jobTaskList = getJobTaskList(page + 1, currentTime);
+ }
+ log.info("finish run job");
+ }
+
+ private void addTask(JobTask jobTask) {
+ applicationContext.publishEvent(new StartJobEvent(this, jobTask.getId()));
+ }
+
+
+ private IPage getJobTaskList(int page, Date currentTime) {
+ IPage pageQuery = new Page<>(page, 100);
+ Wrapper wrapper = Wrappers.lambdaQuery()
+ .eq(JobTask::getStatus, JobStatus.RUNNING.getCode())
+ .le(JobTask::getNextStartTime, currentTime)
+ .gt(JobTask::getNextStartTime, getCurrentMidnight())
+ .select(JobTask::getId)
+ .orderByAsc(JobTask::getNextStartTime);
+ return jobTaskService.page(pageQuery, wrapper);
+ }
+
+ private Date getCurrentMidnight() {
+ Calendar calendar = Calendar.getInstance();
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ return calendar.getTime();
+ }
+
+ //每天凌晨1点执行,清理过期任务
+ @Scheduled(cron = "0 0 1 * * ?")
+ public void clearExpireJob() {
+ log.info("start to clear expire job");
+ jobTaskService.clearExpireJob();
+ log.info("finish clear expire job");
+ }
+
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/job/JobStatus.java b/shuili-system/src/main/java/com/kms/yxgh/common/job/JobStatus.java
new file mode 100644
index 00000000..47d56a66
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/job/JobStatus.java
@@ -0,0 +1,33 @@
+package com.kms.yxgh.common.job;
+
+import lombok.Getter;
+
+@Getter
+public enum JobStatus {
+ /**
+ * 任务状态
+ */
+ INIT("0", "初始化"),
+ RUNNING("1", "运行中"),
+ STOP("2", "停止"),
+ PAUSE("3", "暂停"),
+ FINISH("4", "完成"),
+ ERROR("5", "异常");
+
+ private final String code;
+ private final String desc;
+
+ JobStatus(String code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public static JobStatus getByCode(String code) {
+ for (JobStatus value : values()) {
+ if (value.code.equals(code)) {
+ return value;
+ }
+ }
+ return null;
+ }
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/job/event/StartJobEvent.java b/shuili-system/src/main/java/com/kms/yxgh/common/job/event/StartJobEvent.java
new file mode 100644
index 00000000..cf1aeeda
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/job/event/StartJobEvent.java
@@ -0,0 +1,18 @@
+package com.kms.yxgh.common.job.event;
+
+import lombok.Getter;
+import lombok.ToString;
+import org.springframework.context.ApplicationEvent;
+
+@Getter
+@ToString
+public class StartJobEvent extends ApplicationEvent {
+
+ private final String jobId;
+
+ public StartJobEvent(Object source, String jobId) {
+ super(source);
+ this.jobId = jobId;
+ }
+
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/job/event/StartJobEventListener.java b/shuili-system/src/main/java/com/kms/yxgh/common/job/event/StartJobEventListener.java
new file mode 100644
index 00000000..2eed9f97
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/job/event/StartJobEventListener.java
@@ -0,0 +1,26 @@
+package com.kms.yxgh.common.job.event;
+
+import com.kms.yxgh.common.service.JobTaskService;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ApplicationListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+@AllArgsConstructor
+public class StartJobEventListener implements ApplicationListener {
+
+ public final JobTaskService jobTaskService;
+
+ @Async
+ @SneakyThrows
+ @Override
+ public void onApplicationEvent(StartJobEvent event) {
+ log.info("start to run job, job id: {}", event.getJobId());
+ jobTaskService.runJob(event.getJobId());
+ log.info("finish run job, job id: {}", event.getJobId());
+ }
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/AbstractSendMessageHandler.java b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/AbstractSendMessageHandler.java
new file mode 100644
index 00000000..88b7aa31
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/AbstractSendMessageHandler.java
@@ -0,0 +1,159 @@
+package com.kms.yxgh.common.job.handler;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.kms.system.service.SysUserService;
+import com.kms.yxgh.common.domain.JobTask;
+import com.shuili.common.core.domain.entity.SysUser;
+import com.shuili.common.exception.CustomException;
+import com.shuili.common.utils.StringUtils;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+
+import java.util.Date;
+import java.util.List;
+
+@Slf4j
+public abstract class AbstractSendMessageHandler implements JobHandler {
+
+ //网关
+ @Value("${water.gateway.paasToken:}")
+ private String gatewayPaasToken;
+ @Value("${water.gateway.paasId:}")
+ private String gatewayPaasId;
+
+ //应用中台
+ @Value("${water.center.paasToken:}")
+ private String centerPaasToken;
+ @Value("${water.center.paasId:}")
+ private String centerPaasId;
+
+ @Value("${water.message.url:}")
+ private String messageUrl;
+
+ @Autowired
+ private SysUserService sysUserService;
+
+ public abstract List getMessagesAndUpdateJobTask(JobTask jobTask);
+
+ @Override
+ public JobTask runJob(JobTask jobTask) {
+ List messages = getMessagesAndUpdateJobTask(jobTask);
+ sendMessage(messages);
+ return jobTask;
+ }
+
+
+ @Data
+ public static class MsgVo {
+ private String bizType;// 业务类型(由调用方选填,可填任意字符串,仅作为查询条件使用)
+ private String content; // 消息内容
+ private String contentType; // 内容类型(由调用方选填,可填任意字符串,仅作为查询条件使用)
+ // description 粤政易消息类型为textcard时的描述,不超过512个字节,超过会自动截断
+ //msgType 粤政易消息类型:text、文本,textcard、文本卡片
+ //params 参数
+ private String receiveNo; // 接收号码:类型为短信则为手机号,粤政易则为统一身份用户id,邮箱则为邮箱号码,站内信为用户主键id
+ private String receiver; // 接收用户姓名
+ // recordId 消息记录id
+ //sendNo 发送号码:类型为短信则为手机号,粤政易则为统一身份用户id,邮箱则为邮箱号码,站内信为用户主键id
+ private String sender; // 发送用户姓名
+ //templateId 模板id//;
+ // title 粤政易消息类型为textcard时或者消息类型为email的标题,不超过128个字节,超过会自动截断
+ private String type = "inMail";// 消息类型:sms-短信,zwwx-旧粤政易,yzy-新粤政易,email-邮箱,inMail-站内信
+ //url 粤政易消息类型为textcard时点击后跳转的链接
+ //pcUrl PC端跳转URL
+ //mobileUrl 移动端跳转URL
+ // sendType 消息发送类型(关联订阅,数据字典:msg_send_type)
+ }
+
+ protected void setReceiver(MsgVo msgVo, String userId) {
+ if (StringUtils.isNotBlank(userId)) {
+ SysUser user = sysUserService.getById(userId);
+ if (user == null) {
+ log.error("用户不存在[{}]", userId);
+ return;
+ }
+ msgVo.setReceiveNo(user.getSingleUserId());
+ msgVo.setReceiver(user.getNickName());
+ }
+ }
+
+
+ private void sendMessage(List messages) {
+ if (StringUtils.isNotBlank(messageUrl)) {
+ log.warn("消息发送地址为空");
+ return;
+ }
+ if (CollectionUtil.isEmpty(messages)) {
+ log.warn("消息为空");
+ return;
+ }
+ HttpRequest httpRequest = HttpRequest.post(messageUrl).body(JSON.toJSONString(messages));
+ setHead(httpRequest);
+ try (HttpResponse response = httpRequest.execute()) {
+ if (!response.isOk()) {
+ String body = response.body();
+ WaterResult waterResult = JSONObject.parseObject(body, WaterResult.class);
+ isSuccess(waterResult);
+ } else {
+ log.error("消息发送失败");
+ }
+ } catch (Exception e) {
+ log.error("消息发送失败", e);
+ }
+ }
+
+ private void isSuccess(WaterResult waterResult) {
+ if (waterResult == null) {
+ throw new CustomException("请求异常");
+ }
+ if (waterResult.getCode() != 200 || !waterResult.getSuccess()) {
+ throw new CustomException("请求失败,原因:" + waterResult.getMessage());
+ }
+ }
+
+ private void setHead(HttpRequest httpRequest) {
+ String timestamp = String.valueOf(new Date().getTime());
+ String nonce = IdUtil.fastSimpleUUID();
+ String gatewaySignature = timestamp + gatewayPaasToken + nonce + timestamp;
+ String centerSignature = timestamp + centerPaasToken + nonce + timestamp;
+ try {
+ gatewaySignature = DigestUtils.sha256Hex(gatewaySignature).toUpperCase();
+ centerSignature = DigestUtils.sha256Hex(centerSignature).toUpperCase();
+ } catch (Exception e) {
+ log.error("签名失败", e);
+ }
+ httpRequest
+ .header("x-tif-paasid", gatewayPaasId)
+ .header("x-tif-signature", gatewaySignature)
+ .header("x-tif-timestamp", timestamp)
+ .header("x-tif-nonce", nonce)
+ .header("x-tsp-paasid", centerPaasId)
+ .header("x-tsp-signature", centerSignature)
+ .header("x-tsp-timestamp", timestamp)
+ .header("x-tsp-nonce", nonce);
+
+ }
+
+ @Data
+ @AllArgsConstructor
+ @NoArgsConstructor
+ public static class WaterResult {
+
+ private int code;
+ private String message;
+ private Boolean success;
+ private String data;
+ private String timestamp;
+ }
+
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/CycleType.java b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/CycleType.java
new file mode 100644
index 00000000..b0c9fd95
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/CycleType.java
@@ -0,0 +1,27 @@
+package com.kms.yxgh.common.job.handler;
+
+import lombok.Getter;
+
+@Getter
+public enum CycleType {
+ DAY("0", "每天"),
+ WEEK("1", "每周"),
+ MONTH("2", "每月");
+
+ private final String code;
+ private final String desc;
+
+ CycleType(String code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public static CycleType getByCode(String code) {
+ for (CycleType value : values()) {
+ if (value.code.equals(code)) {
+ return value;
+ }
+ }
+ return null;
+ }
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/DfAnimalPlanSendMessageHandler.java b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/DfAnimalPlanSendMessageHandler.java
new file mode 100644
index 00000000..61e2fad1
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/DfAnimalPlanSendMessageHandler.java
@@ -0,0 +1,89 @@
+package com.kms.yxgh.common.job.handler;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import com.kms.yxgh.common.domain.JobTask;
+import com.kms.yxgh.common.job.JobStatus;
+import com.kms.yxgh.df.dto.DfAnimalPlanDto;
+import com.kms.yxgh.df.service.DfAnimalPlanService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Component
+public class DfAnimalPlanSendMessageHandler extends AbstractSendMessageHandler {
+
+ @Autowired()
+ @Lazy
+ private DfAnimalPlanService dfAnimalPlanService;
+
+ @Override
+ public List getMessagesAndUpdateJobTask(JobTask jobTask) {
+ DfAnimalPlanDto dto = dfAnimalPlanService.getDetailById(jobTask.getBusinessId());
+ if (dto == null || dto.getIsReminder() != 1 || CollectionUtil.isEmpty(dto.getOperators())) {
+ jobTask.setTaskEndTime(new Date());
+ jobTask.setStatus(JobStatus.ERROR.getCode());
+ return Collections.emptyList();
+ }
+
+ if (isExpired(dto, new Date())) {
+ jobTask.setTaskEndTime(new Date());
+ jobTask.setStatus(JobStatus.FINISH.getCode());
+ return Collections.emptyList();
+ }
+
+ jobTask.setNextStartTime(getNextTime(dto, jobTask.getNextStartTime()));
+ boolean isFinish = isExpired(dto, jobTask.getNextStartTime());
+ if (isFinish) {
+ jobTask.setTaskEndTime(new Date());
+ jobTask.setStatus(JobStatus.FINISH.getCode());
+ }
+
+ return dto.getOperators().stream().map(operator -> {
+ MsgVo msgVo = new MsgVo();
+ msgVo.setBizType(jobTask.getBusinessType());
+ msgVo.setContent("害堤动物防治计划<<" + dto.getName() + ">>即将开始,请及时执行!");
+ msgVo.setContentType(jobTask.getBusinessId());
+ setReceiver(msgVo, operator.getUid());
+ return msgVo;
+ }).collect(Collectors.toList());
+ }
+
+ //计算下次执行时间
+ private Date getNextTime(DfAnimalPlanDto dto, Date targetTime) {
+ CycleType cycleType = CycleType.getByCode(dto.getCycleType());
+ if (cycleType == null) {
+ return targetTime;
+ }
+ switch (cycleType) {
+ case DAY:
+ return DateUtil.offsetDay(targetTime, 1);
+ case WEEK:
+ return DateUtil.offsetWeek(targetTime, 1);
+ case MONTH:
+ return DateUtil.offsetMonth(targetTime, 1);
+ default:
+ return targetTime;
+ }
+
+ }
+
+ //计划是否过期
+ private boolean isExpired(DfAnimalPlanDto dto, Date targetTime) {
+ String currentYearMonth = DateUtil.format(targetTime, "yyyy-MM");
+ String planYearMonth = DateUtil.format(dto.getPlanTime(), "yyyy-MM");
+ return !currentYearMonth.equals(planYearMonth);
+ }
+
+ @Override
+ public String type() {
+ return SendMessageType.DF_ANIMAL_PLAN.name();
+ }
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/DfCheckingPlanSendMessageHandler.java b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/DfCheckingPlanSendMessageHandler.java
new file mode 100644
index 00000000..94fe723b
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/DfCheckingPlanSendMessageHandler.java
@@ -0,0 +1,133 @@
+package com.kms.yxgh.common.job.handler;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import com.kms.yxgh.common.domain.JobTask;
+import com.kms.yxgh.common.job.JobStatus;
+import com.kms.yxgh.df.dto.DfCheckingPlanContentDto;
+import com.kms.yxgh.df.dto.DfPlanDetailDto;
+import com.kms.yxgh.df.service.DfPlanService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Component
+public class DfCheckingPlanSendMessageHandler extends AbstractSendMessageHandler {
+
+ @Autowired()
+ @Lazy
+ private DfPlanService dfPlanService;
+
+ @Override
+ public List getMessagesAndUpdateJobTask(JobTask jobTask) {
+ DfPlanDetailDto dto = dfPlanService.getDetailById(jobTask.getBusinessId());
+ if (dto == null || CollectionUtil.isEmpty(dto.getContents())) {
+ log.error("DfCheckingPlanSendMessageHandler getMessagesAndUpdateJobTask error, dto is null, jobTask:{}", jobTask);
+ jobTask.setStatus(JobStatus.ERROR.getCode());
+ return Collections.emptyList();
+ }
+ Date currentTime = new Date();
+ Optional optional = dto.getContents().stream().filter(content -> content.getStartDate().before(currentTime) && content.getEndDate().after(currentTime))
+ .findFirst();
+ if (optional.isPresent()) {
+ DfCheckingPlanContentDto content = optional.get();
+ if (CollectionUtil.isEmpty(content.getOperator())) {
+ return Collections.emptyList();
+ }
+ Date nextTime = getNextTime(dto, jobTask.getNextStartTime());
+ if (dto.getContents().stream().anyMatch(c -> c.getEndDate().after(nextTime))) {
+ jobTask.setNextStartTime(nextTime);
+ } else {
+ jobTask.setStatus(JobStatus.FINISH.getCode());
+ }
+ return content.getOperator().stream()
+ .map(operator -> {
+ MsgVo msgVo = new MsgVo();
+ msgVo.setBizType(jobTask.getBusinessType());
+ msgVo.setContent("堤防巡视检查计划<<" + content.getName() + ">>即将开始,请及时执行!\n 计划开始时间:" + content.getStartDate() + " \n计划结束时间:" + content.getEndDate());
+ msgVo.setContentType(jobTask.getBusinessId());
+ setReceiver(msgVo, operator.getUid());
+ return msgVo;
+ }).collect(Collectors.toList());
+ } else {
+ if (dto.getContents().stream().anyMatch(content -> content.getEndDate().after(currentTime))) {
+ jobTask.setStatus(JobStatus.FINISH.getCode());
+ }
+ return Collections.emptyList();
+ }
+
+ }
+
+ private Date getNextTime(DfPlanDetailDto dto, Date nextStartTime) {
+ CycleType cycleType = CycleType.getByCode(dto.getCycleType());
+ if (cycleType == null) {
+ return nextStartTime;
+ }
+ Date currentTime = new Date();
+ switch (cycleType) {
+ case DAY:
+ return DateUtil.offsetDay(nextStartTime, 1);
+ case WEEK:
+ //获取现在是周几
+ int currentWeek = DateUtil.dayOfWeek(currentTime);
+ if (dto.getOtherConfig() == null) {
+ return nextStartTime;
+ }
+ List weeks = dto.getOtherConfig().getReminderWeeks();
+ if (weeks == null) {
+ return nextStartTime;
+ }
+ weeks = weeks.stream().sorted().collect(Collectors.toList());
+ int netWeek = weeks.stream().filter(w -> w > currentWeek).findFirst().orElse(weeks.get(0));
+ if (netWeek > currentWeek) {
+ return DateUtil.offsetDay(nextStartTime, netWeek - currentWeek);
+ } else {
+ return DateUtil.offsetDay(nextStartTime, 7 - currentWeek + netWeek);
+ }
+
+ case MONTH:
+ Date currentDate = new Date();
+ int currentMonthDays = getMonthDays(currentDate);
+ int currentDay = DateUtil.dayOfMonth(currentDate);
+ if (dto.getOtherConfig() == null) {
+ return nextStartTime;
+ }
+ List days = dto.getOtherConfig().getReminderDays();
+ if (days == null) {
+ return nextStartTime;
+ }
+ days = days.stream().sorted().collect(Collectors.toList());
+ int nextDay = days.stream().filter(d -> d > currentDay && d <= currentMonthDays).findFirst().orElse(days.get(0));
+ if (nextDay > currentDay) {
+ return DateUtil.offsetDay(nextStartTime, nextDay - currentDay);
+ } else {
+ return DateUtil.offsetDay(nextStartTime, currentMonthDays - currentDay + nextDay);
+ }
+ default:
+ return nextStartTime;
+ }
+ }
+
+ //获取指定时间月份的天数
+ private int getMonthDays(Date date) {
+ //当前是否闰年
+ boolean isLeapYear = DateUtil.isLeapYear(DateUtil.year(date));
+ //获取当前月份
+ int currentMonth = DateUtil.month(date) + 1;
+ //获取当前月的天数
+ return DateUtil.lengthOfMonth(currentMonth, isLeapYear);
+ }
+
+ @Override
+ public String type() {
+ return SendMessageType.DF_CHECKING_PLAN.name();
+ }
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/DfYhPlanSendMessageHandler.java b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/DfYhPlanSendMessageHandler.java
new file mode 100644
index 00000000..5f878653
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/DfYhPlanSendMessageHandler.java
@@ -0,0 +1,54 @@
+package com.kms.yxgh.common.job.handler;
+
+import com.kms.yxgh.common.ApprovalStatusEnum;
+import com.kms.yxgh.common.domain.JobTask;
+import com.kms.yxgh.common.job.JobStatus;
+import com.kms.yxgh.df.dto.DfYhPlanDetailDto;
+import com.kms.yxgh.df.service.DfYhPlanService;
+import com.shuili.common.utils.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+@Slf4j
+@Component
+public class DfYhPlanSendMessageHandler extends AbstractSendMessageHandler {
+
+ @Autowired()
+ @Lazy
+ private DfYhPlanService dfYhPlanService;
+
+ @Override
+ public List getMessagesAndUpdateJobTask(JobTask jobTask) {
+ DfYhPlanDetailDto dto = dfYhPlanService.getDetailById(jobTask.getBusinessId());
+ jobTask.setStatus(JobStatus.FINISH.getCode());
+ jobTask.setTaskEndTime(new Date());
+ if (dto == null || dto.getResponsiblePerson() == null || StringUtils.isBlank(dto.getResponsiblePerson().getUid())) {
+ log.error("DfYhPlanSendMessageHandler getMessagesAndUpdateJobTask error, dto or responsiblePerson is null, jobTask:{}", jobTask);
+ jobTask.setStatus(JobStatus.ERROR.getCode());
+ return Collections.emptyList();
+ }
+
+ long currentTime = System.currentTimeMillis();
+ if (dto.getStartDate().getTime() > currentTime || dto.getEndDate().getTime() < currentTime || !dto.getStatus().equals(ApprovalStatusEnum.PASS.getValue())) {
+ return Collections.emptyList();
+ }
+
+ MsgVo msgVo = new MsgVo();
+ msgVo.setBizType(jobTask.getBusinessType());
+ msgVo.setContent("堤防维修养护计划<<" + dto.getName() + ">>即将开始,请及时执行!\n 计划开始时间:" + dto.getStartDate() + " \n计划结束时间:" + dto.getEndDate());
+ msgVo.setContentType(jobTask.getBusinessId());
+ setReceiver(msgVo, dto.getResponsiblePerson().getUid());
+ return Collections.singletonList(msgVo);
+ }
+
+ @Override
+ public String type() {
+ return SendMessageType.DF_YH_PLAN.name();
+ }
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/JobHandler.java b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/JobHandler.java
new file mode 100644
index 00000000..65fdbed0
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/JobHandler.java
@@ -0,0 +1,10 @@
+package com.kms.yxgh.common.job.handler;
+
+import com.kms.yxgh.common.domain.JobTask;
+
+public interface JobHandler {
+
+ String type();
+
+ JobTask runJob(JobTask jobTask);
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/SendMessageType.java b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/SendMessageType.java
new file mode 100644
index 00000000..8c84dbdc
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/SendMessageType.java
@@ -0,0 +1,12 @@
+package com.kms.yxgh.common.job.handler;
+
+import lombok.Getter;
+
+@Getter
+public enum SendMessageType {
+ DF_YH_PLAN,
+ SZ_YH_PLAN,
+ DF_ANIMAL_PLAN,
+ DF_CHECKING_PLAN,
+ SZ_CHECKING_PLAN,
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/SzCheckingPlanSendMessageHandler.java b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/SzCheckingPlanSendMessageHandler.java
new file mode 100644
index 00000000..6c58d9be
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/SzCheckingPlanSendMessageHandler.java
@@ -0,0 +1,133 @@
+package com.kms.yxgh.common.job.handler;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import com.kms.yxgh.common.domain.JobTask;
+import com.kms.yxgh.common.job.JobStatus;
+import com.kms.yxgh.sz.dto.SzCheckingPlanContentDto;
+import com.kms.yxgh.sz.dto.SzPlanDetailDto;
+import com.kms.yxgh.sz.service.SzPlanService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Component
+public class SzCheckingPlanSendMessageHandler extends AbstractSendMessageHandler {
+
+ @Autowired()
+ @Lazy
+ private SzPlanService dfPlanService;
+
+ @Override
+ public List getMessagesAndUpdateJobTask(JobTask jobTask) {
+ SzPlanDetailDto dto = dfPlanService.getDetailById(jobTask.getBusinessId());
+ if (dto == null || CollectionUtil.isEmpty(dto.getContents())) {
+ log.error("SzCheckingPlanSendMessageHandler getMessagesAndUpdateJobTask error, dto is null, jobTask:{}", jobTask);
+ jobTask.setStatus(JobStatus.ERROR.getCode());
+ return Collections.emptyList();
+ }
+ Date currentTime = new Date();
+ Optional optional = dto.getContents().stream().filter(content -> content.getStartDate().before(currentTime) && content.getEndDate().after(currentTime))
+ .findFirst();
+ if (optional.isPresent()) {
+ SzCheckingPlanContentDto content = optional.get();
+ if (CollectionUtil.isEmpty(content.getOperator())) {
+ return Collections.emptyList();
+ }
+ Date nextTime = getNextTime(dto, jobTask.getNextStartTime());
+ if (dto.getContents().stream().anyMatch(c -> c.getEndDate().after(nextTime))) {
+ jobTask.setNextStartTime(nextTime);
+ } else {
+ jobTask.setStatus(JobStatus.FINISH.getCode());
+ }
+ return content.getOperator().stream()
+ .map(operator -> {
+ MsgVo msgVo = new MsgVo();
+ msgVo.setBizType(jobTask.getBusinessType());
+ msgVo.setContent("水闸巡视检查计划<<" + content.getName() + ">>即将开始,请及时执行!\n 计划开始时间:" + content.getStartDate() + " \n计划结束时间:" + content.getEndDate());
+ msgVo.setContentType(jobTask.getBusinessId());
+ setReceiver(msgVo, operator.getUid());
+ return msgVo;
+ }).collect(Collectors.toList());
+ } else {
+ if (dto.getContents().stream().anyMatch(content -> content.getEndDate().after(currentTime))) {
+ jobTask.setStatus(JobStatus.FINISH.getCode());
+ }
+ return Collections.emptyList();
+ }
+
+ }
+
+ private Date getNextTime(SzPlanDetailDto dto, Date nextStartTime) {
+ CycleType cycleType = CycleType.getByCode(dto.getCycleType());
+ if (cycleType == null) {
+ return nextStartTime;
+ }
+ Date currentTime = new Date();
+ switch (cycleType) {
+ case DAY:
+ return DateUtil.offsetDay(nextStartTime, 1);
+ case WEEK:
+ //获取现在是周几
+ int currentWeek = DateUtil.dayOfWeek(currentTime);
+ if (dto.getOtherConfig() == null) {
+ return nextStartTime;
+ }
+ List weeks = dto.getOtherConfig().getReminderWeeks();
+ if (weeks == null) {
+ return nextStartTime;
+ }
+ weeks = weeks.stream().sorted().collect(Collectors.toList());
+ int netWeek = weeks.stream().filter(w -> w > currentWeek).findFirst().orElse(weeks.get(0));
+ if (netWeek > currentWeek) {
+ return DateUtil.offsetDay(nextStartTime, netWeek - currentWeek);
+ } else {
+ return DateUtil.offsetDay(nextStartTime, 7 - currentWeek + netWeek);
+ }
+
+ case MONTH:
+ Date currentDate = new Date();
+ int currentMonthDays = getMonthDays(currentDate);
+ int currentDay = DateUtil.dayOfMonth(currentDate);
+ if (dto.getOtherConfig() == null) {
+ return nextStartTime;
+ }
+ List days = dto.getOtherConfig().getReminderDays();
+ if (days == null) {
+ return nextStartTime;
+ }
+ days = days.stream().sorted().collect(Collectors.toList());
+ int nextDay = days.stream().filter(d -> d > currentDay && d <= currentMonthDays).findFirst().orElse(days.get(0));
+ if (nextDay > currentDay) {
+ return DateUtil.offsetDay(nextStartTime, nextDay - currentDay);
+ } else {
+ return DateUtil.offsetDay(nextStartTime, currentMonthDays - currentDay + nextDay);
+ }
+ default:
+ return nextStartTime;
+ }
+ }
+
+ //获取指定时间月份的天数
+ private int getMonthDays(Date date) {
+ //当前是否闰年
+ boolean isLeapYear = DateUtil.isLeapYear(DateUtil.year(date));
+ //获取当前月份
+ int currentMonth = DateUtil.month(date) + 1;
+ //获取当前月的天数
+ return DateUtil.lengthOfMonth(currentMonth, isLeapYear);
+ }
+
+ @Override
+ public String type() {
+ return SendMessageType.SZ_CHECKING_PLAN.name();
+ }
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/SzYhPlanSendMessageHandler.java b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/SzYhPlanSendMessageHandler.java
new file mode 100644
index 00000000..905cc8a8
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/job/handler/SzYhPlanSendMessageHandler.java
@@ -0,0 +1,54 @@
+package com.kms.yxgh.common.job.handler;
+
+import com.kms.yxgh.common.ApprovalStatusEnum;
+import com.kms.yxgh.common.domain.JobTask;
+import com.kms.yxgh.common.job.JobStatus;
+import com.kms.yxgh.sz.dto.SzYhPlanDetailDto;
+import com.kms.yxgh.sz.service.SzYhPlanService;
+import com.shuili.common.utils.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+@Slf4j
+@Component
+public class SzYhPlanSendMessageHandler extends AbstractSendMessageHandler {
+
+ @Autowired()
+ @Lazy
+ private SzYhPlanService szYhPlanService;
+
+ @Override
+ public List getMessagesAndUpdateJobTask(JobTask jobTask) {
+ SzYhPlanDetailDto dto = szYhPlanService.getDetailById(jobTask.getBusinessId());
+ jobTask.setStatus(JobStatus.FINISH.getCode());
+ jobTask.setTaskEndTime(new Date());
+ if (dto == null || dto.getResponsiblePerson() == null || StringUtils.isBlank(dto.getResponsiblePerson().getUid())) {
+ log.error("SzYhPlanSendMessageHandler getMessagesAndUpdateJobTask error, dto or responsiblePerson is null, jobTask:{}", jobTask);
+ jobTask.setStatus(JobStatus.ERROR.getCode());
+ return Collections.emptyList();
+ }
+
+ long currentTime = System.currentTimeMillis();
+ if (dto.getStartDate().getTime() > currentTime || dto.getEndDate().getTime() < currentTime || !dto.getStatus().equals(ApprovalStatusEnum.PASS.getValue())) {
+ return Collections.emptyList();
+ }
+
+ MsgVo msgVo = new MsgVo();
+ msgVo.setBizType(jobTask.getBusinessType());
+ msgVo.setContent("水闸维修养护计划<<" + dto.getName() + ">>即将开始,请及时执行!\n 计划开始时间:" + dto.getStartDate() + " \n计划结束时间:" + dto.getEndDate());
+ msgVo.setContentType(jobTask.getBusinessId());
+ setReceiver(msgVo, dto.getResponsiblePerson().getUid());
+ return Collections.singletonList(msgVo);
+ }
+
+ @Override
+ public String type() {
+ return SendMessageType.SZ_YH_PLAN.name();
+ }
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/mapper/JobTaskMapper.java b/shuili-system/src/main/java/com/kms/yxgh/common/mapper/JobTaskMapper.java
new file mode 100644
index 00000000..7c9d91df
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/mapper/JobTaskMapper.java
@@ -0,0 +1,11 @@
+package com.kms.yxgh.common.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.kms.yxgh.common.domain.JobTask;
+import org.springframework.stereotype.Repository;
+
+
+@Repository
+public interface JobTaskMapper extends BaseMapper {
+
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/common/service/JobTaskService.java b/shuili-system/src/main/java/com/kms/yxgh/common/service/JobTaskService.java
new file mode 100644
index 00000000..126ba566
--- /dev/null
+++ b/shuili-system/src/main/java/com/kms/yxgh/common/service/JobTaskService.java
@@ -0,0 +1,109 @@
+package com.kms.yxgh.common.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.kms.yxgh.common.domain.JobTask;
+import com.kms.yxgh.common.job.JobStatus;
+import com.kms.yxgh.common.job.handler.JobHandler;
+import com.kms.yxgh.common.mapper.JobTaskMapper;
+import com.shuili.common.core.service.BaseService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class JobTaskService extends BaseService {
+ private final RedissonClient redissonClient;
+ private final List handlers;
+
+ public void runJob(String jobId) {
+ JobTask jobTask = getById(jobId);
+ if (jobTask == null) {
+ return;
+ }
+ if (Objects.equals(jobTask.getStatus(), JobStatus.RUNNING.getCode())) {
+ log.info("job [{}] is in running status [{}]", jobId, JobStatus.getByCode(jobTask.getStatus()));
+ // Use Redisson to lock the job
+ RLock lock = redissonClient.getLock(jobId);
+ try {
+ // Try to acquire the lock with a wait time of 10 seconds and lease time of 60 seconds
+ if (lock.tryLock(10, 60, TimeUnit.SECONDS)) {
+ try {
+ jobTask.setLastStartTime(new Date());
+ JobHandler jobHandler = getHandler(jobTask.getBusinessType());
+ if (jobHandler != null) {
+ jobHandler.runJob(jobTask);
+ } else {
+ jobTask.setStatus(JobStatus.ERROR.getCode());
+ log.error("No job handler found for job [{},{}]", jobTask.getBusinessType(), jobId);
+ }
+ jobTask.setLastEndTime(new Date());
+ this.baseMapper.updateById(jobTask);
+ } finally {
+ lock.unlock();
+ log.info("Released lock for job [{}]", jobId);
+ }
+ } else {
+ log.info("Could not acquire lock for job [{}]", jobId);
+ }
+ } catch (InterruptedException e) {
+ log.error("Error while trying to acquire lock for job [{}]", jobId, e);
+ Thread.currentThread().interrupt();
+ }
+
+ } else {
+ log.info("job [{}] is not in running status [{}]", jobId, JobStatus.getByCode(jobTask.getStatus()));
+ }
+
+ }
+
+ @Transactional(rollbackFor = Exception.class)
+ public void updateOrInsertJobTask(JobTask jobTask, boolean isCancel) {
+ if (jobTask.getNextStartTime() == null) {
+ log.error("jobTask nextStartTime is null, jobTask:{}", jobTask);
+ }
+ JobTask old = this.baseMapper.selectOne(new QueryWrapper()
+ .eq("business_id", jobTask.getBusinessId())
+ .eq("business_type", jobTask.getBusinessType()));
+ if (old == null) {
+ if (!isCancel) {
+ jobTask.setStatus(JobStatus.RUNNING.getCode());
+ this.baseMapper.insert(jobTask);
+ }
+ } else {
+ if (isCancel) {
+ old.setStatus(JobStatus.STOP.getCode());
+ this.baseMapper.updateById(old);
+ } else {
+ old.setNextStartTime(jobTask.getNextStartTime());
+ old.setStatus(JobStatus.RUNNING.getCode());
+ this.baseMapper.updateById(old);
+ }
+ }
+
+ }
+
+ private JobHandler getHandler(String handlerType) {
+ return handlers.stream().filter(handler -> handler.type().equals(handlerType)).findFirst().orElse(null);
+ }
+
+
+ public void clearExpireJob() {
+ //删除lastEndTime是3个月前的任务
+ Calendar calendar = Calendar.getInstance();
+ calendar.add(Calendar.MONTH, -3);
+ Date expireTime = calendar.getTime();
+ this.baseMapper.delete(new QueryWrapper().lt("last_end_time", expireTime));
+
+ }
+}
diff --git a/shuili-system/src/main/java/com/kms/yxgh/df/service/DfAnimalPlanService.java b/shuili-system/src/main/java/com/kms/yxgh/df/service/DfAnimalPlanService.java
index 94fbad1b..718bffb4 100644
--- a/shuili-system/src/main/java/com/kms/yxgh/df/service/DfAnimalPlanService.java
+++ b/shuili-system/src/main/java/com/kms/yxgh/df/service/DfAnimalPlanService.java
@@ -9,7 +9,11 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kms.yg.df.domain.BsSgcDfSafeJbxx;
import com.kms.yg.df.mapper.BsSgcDfSafeJbxxMapper;
import com.kms.yxgh.base.DfException;
+import com.kms.yxgh.common.domain.JobTask;
import com.kms.yxgh.common.dto.OperatorDto;
+import com.kms.yxgh.common.job.handler.CycleType;
+import com.kms.yxgh.common.job.handler.SendMessageType;
+import com.kms.yxgh.common.service.JobTaskService;
import com.kms.yxgh.df.domain.DfAnimalOperator;
import com.kms.yxgh.df.domain.DfAnimalPlan;
import com.kms.yxgh.df.domain.DfAnimalPlanDetail;
@@ -27,6 +31,8 @@ import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import java.util.Calendar;
+import java.util.Date;
import java.util.function.Consumer;
/**
@@ -42,6 +48,7 @@ public class DfAnimalPlanService extends BaseService maxDay) {
+ day = maxDay;
+ }
+ calendar.set(Calendar.DAY_OF_MONTH, day);
+ calendar.set(Calendar.HOUR_OF_DAY, hour);
+ calendar.set(Calendar.MINUTE, minute);
+ calendar.set(Calendar.SECOND, second);
+
+ return calendar.getTime();
+ }
+
+ private Date getNextWeekDate(DfAnimalPlanDto dto, int week) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(dto.getReminderTime());
+ int hour = calendar.get(Calendar.HOUR_OF_DAY);
+ int minute = calendar.get(Calendar.MINUTE);
+ int second = calendar.get(Calendar.SECOND);
+
+ // 设置为下周几
+ calendar.setTime(new Date());
+ int currentWeek = calendar.get(Calendar.DAY_OF_WEEK);
+ int daysUntilNextWeek = (week - currentWeek + 7) % 7;
+ if (daysUntilNextWeek == 0) {
+ daysUntilNextWeek = 7;
+ }
+ calendar.add(Calendar.DAY_OF_MONTH, daysUntilNextWeek);
+ calendar.set(Calendar.HOUR_OF_DAY, hour);
+ calendar.set(Calendar.MINUTE, minute);
+ calendar.set(Calendar.SECOND, second);
+
+ return calendar.getTime();
+ }
+
+ private Date getNextDate(DfAnimalPlanDto dto) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(dto.getReminderTime());
+ int hour = calendar.get(Calendar.HOUR_OF_DAY);
+ int minute = calendar.get(Calendar.MINUTE);
+ int second = calendar.get(Calendar.SECOND);
+ // 设置为明天的日期
+ calendar.setTime(new Date());
+ calendar.add(Calendar.DAY_OF_MONTH, 1);
+ calendar.set(Calendar.HOUR_OF_DAY, hour);
+ calendar.set(Calendar.MINUTE, minute);
+ calendar.set(Calendar.SECOND, second);
+ return calendar.getTime();
+ }
+
@Transactional(rollbackFor = Exception.class)
public Boolean deleteById(String id) {
diff --git a/shuili-system/src/main/java/com/kms/yxgh/df/service/DfPlanService.java b/shuili-system/src/main/java/com/kms/yxgh/df/service/DfPlanService.java
index a3c288a1..cad9cbc9 100644
--- a/shuili-system/src/main/java/com/kms/yxgh/df/service/DfPlanService.java
+++ b/shuili-system/src/main/java/com/kms/yxgh/df/service/DfPlanService.java
@@ -1,5 +1,6 @@
package com.kms.yxgh.df.service;
+import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -8,7 +9,11 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kms.common.utils.UserUtils;
import com.kms.system.service.SysUserService;
import com.kms.yxgh.base.DfException;
+import com.kms.yxgh.common.domain.JobTask;
import com.kms.yxgh.common.dto.OperatorDto;
+import com.kms.yxgh.common.job.handler.CycleType;
+import com.kms.yxgh.common.job.handler.SendMessageType;
+import com.kms.yxgh.common.service.JobTaskService;
import com.kms.yxgh.df.domain.*;
import com.kms.yxgh.df.dto.*;
import com.kms.yxgh.df.mapper.DfCheckingPlanContentMapper;
@@ -47,6 +52,7 @@ public class DfPlanService extends BaseService {
private final DfCheckingPlanContentMapper dfCheckingPlanContentMapper;
private final SysUserService userService;
private final DfPlanOperatorService dfPlanOperatorService;
+ private final JobTaskService jobTaskService;
public IPage search(SearchParam sp) {
Page page = new Page<>(sp.getPageNum(), sp.getPageSize());
@@ -99,7 +105,9 @@ public class DfPlanService extends BaseService {
getBaseMapper().insert(dfPlan);
String id = dfPlan.getId();
saveOrUpdateContent(id, dto.getContents());
- return this.getDetailById(id);
+ DfPlanDetailDto planDetailDto = this.getDetailById(id);
+ sendMsg(planDetailDto);
+ return planDetailDto;
} else {
throw new DfException("该名称已存在");
}
@@ -120,7 +128,9 @@ public class DfPlanService extends BaseService {
getBaseMapper().updateById(dfPlan);
String id = dfPlan.getId();
saveOrUpdateContent(id, dto.getContents());
- return this.getDetailById(id);
+ DfPlanDetailDto planDetailDto = this.getDetailById(id);
+ sendMsg(planDetailDto);
+ return planDetailDto;
} else {
throw new DfException("该名称已存在");
}
@@ -130,6 +140,113 @@ public class DfPlanService extends BaseService {
}
+ private void sendMsg(DfPlanDetailDto dto) {
+ if (dto == null) {
+ return;
+ }
+ JobTask jobTask = new JobTask();
+ jobTask.setBusinessId(dto.getId());
+ jobTask.setBusinessType(SendMessageType.DF_CHECKING_PLAN.name());
+ jobTask.setNextStartTime(getNextTime(dto));
+ jobTaskService.updateOrInsertJobTask(jobTask, false);
+ }
+
+ private Date getNextTime(DfPlanDetailDto dto) {
+ CycleType cycleType = CycleType.getByCode(dto.getCycleType());
+ if (cycleType == null || dto.getOtherConfig() == null || dto.getReminderTime() == null) {
+ return null;
+ }
+ switch (cycleType) {
+ case DAY:
+ return getNextDate(dto);
+ case WEEK:
+ return getNextWeekDate(dto);
+ case MONTH:
+ return getNextMonthDate(dto);
+ default:
+ return null;
+ }
+ }
+
+ private Date getNextMonthDate(DfPlanDetailDto dto) {
+ if (dto.getOtherConfig() == null) {
+ return null;
+ }
+ List days = dto.getOtherConfig().getReminderDays();
+ if (days == null) {
+ return null;
+ }
+ Date currentTime = new Date();
+ int currentMonthDays = getMonthDays(currentTime);
+ int currentDay = DateUtil.dayOfMonth(currentTime);
+ Date nextStartTime = getCurrentDate(dto);
+ days = days.stream().sorted().collect(Collectors.toList());
+ int nextDay = days.stream().filter(w -> w > currentDay && w <= currentMonthDays).findFirst().orElse(days.get(0));
+ if (nextDay > currentDay) {
+ return DateUtil.offsetDay(nextStartTime, nextDay - currentDay);
+ } else {
+ return DateUtil.offsetDay(nextStartTime, currentMonthDays - currentDay + nextDay);
+ }
+ }
+
+ private int getMonthDays(Date date) {
+ //当前是否闰年
+ boolean isLeapYear = DateUtil.isLeapYear(DateUtil.year(date));
+ //获取当前月份
+ int currentMonth = DateUtil.month(date) + 1;
+ //获取当前月的天数
+ return DateUtil.lengthOfMonth(currentMonth, isLeapYear);
+ }
+
+ private Date getNextWeekDate(DfPlanDetailDto dto) {
+ if (dto.getOtherConfig() == null) {
+ return null;
+ }
+ List weeks = dto.getOtherConfig().getReminderWeeks();
+ if (weeks == null) {
+ return null;
+ }
+ Date currentTime = new Date();
+ int currentWeek = DateUtil.dayOfWeek(currentTime);
+ Date nextStartTime = getCurrentDate(dto);
+ weeks = weeks.stream().sorted().collect(Collectors.toList());
+ int netWeek = weeks.stream().filter(w -> w > currentWeek).findFirst().orElse(weeks.get(0));
+ if (netWeek > currentWeek) {
+ return DateUtil.offsetDay(nextStartTime, netWeek - currentWeek);
+ } else {
+ return DateUtil.offsetDay(nextStartTime, 7 - currentWeek + netWeek);
+ }
+ }
+
+ private Date getCurrentDate(DfPlanDetailDto dto) {
+ Calendar calendar = Calendar.getInstance();
+ setCalendarTime(calendar, dto.getReminderTime());
+ setCalendarToTomorrow(calendar);
+ return calendar.getTime();
+ }
+
+ private Date getNextDate(DfPlanDetailDto dto) {
+ Calendar calendar = Calendar.getInstance();
+ setCalendarTime(calendar, dto.getReminderTime());
+ setCalendarToTomorrow(calendar);
+ calendar.add(Calendar.DAY_OF_MONTH, 1);
+ return calendar.getTime();
+ }
+
+ private void setCalendarTime(Calendar calendar, Date date) {
+ calendar.setTime(date);
+ int hour = calendar.get(Calendar.HOUR_OF_DAY);
+ int minute = calendar.get(Calendar.MINUTE);
+ int second = calendar.get(Calendar.SECOND);
+ calendar.set(Calendar.HOUR_OF_DAY, hour);
+ calendar.set(Calendar.MINUTE, minute);
+ calendar.set(Calendar.SECOND, second);
+ }
+
+ private void setCalendarToTomorrow(Calendar calendar) {
+ calendar.setTime(new Date());
+ }
+
@Transactional(rollbackFor = Exception.class)
public Boolean deleteById(String[] ids) {
if (ids.length == 1) {
diff --git a/shuili-system/src/main/java/com/kms/yxgh/df/service/DfYhPlanService.java b/shuili-system/src/main/java/com/kms/yxgh/df/service/DfYhPlanService.java
index 8f917efa..6e0956cd 100644
--- a/shuili-system/src/main/java/com/kms/yxgh/df/service/DfYhPlanService.java
+++ b/shuili-system/src/main/java/com/kms/yxgh/df/service/DfYhPlanService.java
@@ -6,11 +6,13 @@ import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.kms.system.service.SysUserService;
import com.kms.yxgh.base.DfException;
import com.kms.yxgh.common.ApprovalStatusEnum;
+import com.kms.yxgh.common.domain.JobTask;
import com.kms.yxgh.common.dto.*;
+import com.kms.yxgh.common.job.handler.SendMessageType;
import com.kms.yxgh.common.service.DefaultApprovalBusinessService;
+import com.kms.yxgh.common.service.JobTaskService;
import com.kms.yxgh.df.domain.DfYhPlan;
import com.kms.yxgh.df.dto.DfYhPlanDetailDto;
import com.kms.yxgh.df.dto.DfYhPlanSearchDto;
@@ -35,7 +37,7 @@ import java.util.Optional;
@AllArgsConstructor
public class DfYhPlanService extends DefaultApprovalBusinessService {
- private final SysUserService sysUserService;
+ private final JobTaskService jobTaskService;
public DfYhPlanDetailDto getDetailById(String id) {
DfYhPlan dfPlan = this.getById(id);
@@ -130,12 +132,20 @@ public class DfYhPlanService extends DefaultApprovalBusinessService wp = Wrappers.lambdaUpdate()
.eq(DfYhPlan::getId, formId)
.set(DfYhPlan::getStatus, status.getValue());
getBaseMapper().update(null, wp);
+ DfYhPlan dfPlan = this.getBaseMapper().selectById(formId);
+
+ JobTask jobTask = new JobTask();
+ jobTask.setBusinessId(formId);
+ jobTask.setBusinessType(SendMessageType.DF_YH_PLAN.name());
+ jobTask.setNextStartTime(dfPlan.getReminderTime());
+ jobTaskService.updateOrInsertJobTask(jobTask, !ApprovalStatusEnum.PASS.equals(status));
}
@Override
diff --git a/shuili-system/src/main/java/com/kms/yxgh/sz/service/SzPlanService.java b/shuili-system/src/main/java/com/kms/yxgh/sz/service/SzPlanService.java
index 98f8ad02..ff5cf368 100644
--- a/shuili-system/src/main/java/com/kms/yxgh/sz/service/SzPlanService.java
+++ b/shuili-system/src/main/java/com/kms/yxgh/sz/service/SzPlanService.java
@@ -1,5 +1,6 @@
package com.kms.yxgh.sz.service;
+import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -8,7 +9,11 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kms.common.utils.UserUtils;
import com.kms.system.service.SysUserService;
import com.kms.yxgh.base.SzException;
+import com.kms.yxgh.common.domain.JobTask;
import com.kms.yxgh.common.dto.OperatorDto;
+import com.kms.yxgh.common.job.handler.CycleType;
+import com.kms.yxgh.common.job.handler.SendMessageType;
+import com.kms.yxgh.common.service.JobTaskService;
import com.kms.yxgh.sz.domain.*;
import com.kms.yxgh.sz.dto.*;
import com.kms.yxgh.sz.mapper.SzCheckingPlanContentMapper;
@@ -47,6 +52,8 @@ public class SzPlanService extends BaseService {
private final SzCheckingPlanContentMapper szCheckingPlanContentMapper;
private final SysUserService userService;
private final SzPlanOperatorService szPlanOperatorService;
+ private final JobTaskService jobTaskService;
+
public IPage search(SearchParam sp) {
Page page = new Page<>(sp.getPageNum(), sp.getPageSize());
@@ -99,7 +106,9 @@ public class SzPlanService extends BaseService {
getBaseMapper().insert(szPlan);
String id = szPlan.getId();
saveOrUpdateContent(id, dto.getContents());
- return this.getDetailById(id);
+ SzPlanDetailDto szPlanDetailDto = this.getDetailById(id);
+ sendMsg(szPlanDetailDto);
+ return szPlanDetailDto;
} else {
throw new SzException("该名称已存在");
}
@@ -120,7 +129,9 @@ public class SzPlanService extends BaseService {
getBaseMapper().updateById(szPlan);
String id = szPlan.getId();
saveOrUpdateContent(id, dto.getContents());
- return this.getDetailById(id);
+ SzPlanDetailDto szPlanDetailDto = this.getDetailById(id);
+ sendMsg(szPlanDetailDto);
+ return szPlanDetailDto;
} else {
throw new SzException("该名称已存在");
}
@@ -144,6 +155,113 @@ public class SzPlanService extends BaseService {
return rt;
}
+ private void sendMsg(SzPlanDetailDto dto) {
+ if (dto == null) {
+ return;
+ }
+ JobTask jobTask = new JobTask();
+ jobTask.setBusinessId(dto.getId());
+ jobTask.setBusinessType(SendMessageType.DF_CHECKING_PLAN.name());
+ jobTask.setNextStartTime(getNextTime(dto));
+ jobTaskService.updateOrInsertJobTask(jobTask, false);
+ }
+
+ private Date getNextTime(SzPlanDetailDto dto) {
+ CycleType cycleType = CycleType.getByCode(dto.getCycleType());
+ if (cycleType == null || dto.getOtherConfig() == null || dto.getReminderTime() == null) {
+ return null;
+ }
+ switch (cycleType) {
+ case DAY:
+ return getNextDate(dto);
+ case WEEK:
+ return getNextWeekDate(dto);
+ case MONTH:
+ return getNextMonthDate(dto);
+ default:
+ return null;
+ }
+ }
+
+ private Date getNextMonthDate(SzPlanDetailDto dto) {
+ if (dto.getOtherConfig() == null) {
+ return null;
+ }
+ List days = dto.getOtherConfig().getReminderDays();
+ if (days == null) {
+ return null;
+ }
+ Date currentTime = new Date();
+ int currentMonthDays = getMonthDays(currentTime);
+ int currentDay = DateUtil.dayOfMonth(currentTime);
+ Date nextStartTime = getCurrentDate(dto);
+ days = days.stream().sorted().collect(Collectors.toList());
+ int nextDay = days.stream().filter(w -> w > currentDay && w <= currentMonthDays).findFirst().orElse(days.get(0));
+ if (nextDay > currentDay) {
+ return DateUtil.offsetDay(nextStartTime, nextDay - currentDay);
+ } else {
+ return DateUtil.offsetDay(nextStartTime, currentMonthDays - currentDay + nextDay);
+ }
+ }
+
+ private int getMonthDays(Date date) {
+ //当前是否闰年
+ boolean isLeapYear = DateUtil.isLeapYear(DateUtil.year(date));
+ //获取当前月份
+ int currentMonth = DateUtil.month(date) + 1;
+ //获取当前月的天数
+ return DateUtil.lengthOfMonth(currentMonth, isLeapYear);
+ }
+
+ private Date getNextWeekDate(SzPlanDetailDto dto) {
+ if (dto.getOtherConfig() == null) {
+ return null;
+ }
+ List weeks = dto.getOtherConfig().getReminderWeeks();
+ if (weeks == null) {
+ return null;
+ }
+ Date currentTime = new Date();
+ int currentWeek = DateUtil.dayOfWeek(currentTime);
+ Date nextStartTime = getCurrentDate(dto);
+ weeks = weeks.stream().sorted().collect(Collectors.toList());
+ int netWeek = weeks.stream().filter(w -> w > currentWeek).findFirst().orElse(weeks.get(0));
+ if (netWeek > currentWeek) {
+ return DateUtil.offsetDay(nextStartTime, netWeek - currentWeek);
+ } else {
+ return DateUtil.offsetDay(nextStartTime, 7 - currentWeek + netWeek);
+ }
+ }
+
+ private Date getCurrentDate(SzPlanDetailDto dto) {
+ Calendar calendar = Calendar.getInstance();
+ setCalendarTime(calendar, dto.getReminderTime());
+ setCalendarToTomorrow(calendar);
+ return calendar.getTime();
+ }
+
+ private Date getNextDate(SzPlanDetailDto dto) {
+ Calendar calendar = Calendar.getInstance();
+ setCalendarTime(calendar, dto.getReminderTime());
+ setCalendarToTomorrow(calendar);
+ calendar.add(Calendar.DAY_OF_MONTH, 1);
+ return calendar.getTime();
+ }
+
+ private void setCalendarTime(Calendar calendar, Date date) {
+ calendar.setTime(date);
+ int hour = calendar.get(Calendar.HOUR_OF_DAY);
+ int minute = calendar.get(Calendar.MINUTE);
+ int second = calendar.get(Calendar.SECOND);
+ calendar.set(Calendar.HOUR_OF_DAY, hour);
+ calendar.set(Calendar.MINUTE, minute);
+ calendar.set(Calendar.SECOND, second);
+ }
+
+ private void setCalendarToTomorrow(Calendar calendar) {
+ calendar.setTime(new Date());
+ }
+
private void planeTime(SzPlan szPlan, List contents) {
if (CollectionUtils.isEmpty(contents)) {
diff --git a/shuili-system/src/main/java/com/kms/yxgh/sz/service/SzYhPlanService.java b/shuili-system/src/main/java/com/kms/yxgh/sz/service/SzYhPlanService.java
index ff3c6945..bbc19b97 100644
--- a/shuili-system/src/main/java/com/kms/yxgh/sz/service/SzYhPlanService.java
+++ b/shuili-system/src/main/java/com/kms/yxgh/sz/service/SzYhPlanService.java
@@ -6,13 +6,14 @@ import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.kms.system.service.SysUserService;
-import com.kms.yg.sz.service.BsSgcSzSafeJbxxService;
import com.kms.yxgh.base.DfException;
import com.kms.yxgh.base.SzException;
import com.kms.yxgh.common.ApprovalStatusEnum;
+import com.kms.yxgh.common.domain.JobTask;
import com.kms.yxgh.common.dto.*;
+import com.kms.yxgh.common.job.handler.SendMessageType;
import com.kms.yxgh.common.service.DefaultApprovalBusinessService;
+import com.kms.yxgh.common.service.JobTaskService;
import com.kms.yxgh.sz.domain.SzYhPlan;
import com.kms.yxgh.sz.dto.SzYhPlanDetailDto;
import com.kms.yxgh.sz.dto.SzYhPlanSearchDto;
@@ -35,8 +36,7 @@ import java.util.List;
@Service
@AllArgsConstructor
public class SzYhPlanService extends DefaultApprovalBusinessService {
- private final BsSgcSzSafeJbxxService bsSgcSzSafeJbxxService;
- private final SysUserService sysUserService;
+ private final JobTaskService jobTaskService;
public SzYhPlanDetailDto getDetailById(String id) {
SzYhPlan szPlan = this.getById(id);
@@ -130,12 +130,21 @@ public class SzYhPlanService extends DefaultApprovalBusinessService wp = Wrappers.lambdaUpdate()
.eq(SzYhPlan::getId, formId)
.set(SzYhPlan::getStatus, status.getValue());
getBaseMapper().update(null, wp);
+
+ SzYhPlan szPlan = this.getBaseMapper().selectById(formId);
+
+ JobTask jobTask = new JobTask();
+ jobTask.setBusinessId(formId);
+ jobTask.setBusinessType(SendMessageType.SZ_YH_PLAN.name());
+ jobTask.setNextStartTime(szPlan.getReminderTime());
+ jobTaskService.updateOrInsertJobTask(jobTask, !ApprovalStatusEnum.PASS.equals(status));
}
@Override
diff --git a/sql/sy/v1.4.0/全量脚本/v1.4.0-all.sql b/sql/sy/v1.4.0/全量脚本/v1.4.0-all.sql
index 8c8fadf7..46ece23b 100644
--- a/sql/sy/v1.4.0/全量脚本/v1.4.0-all.sql
+++ b/sql/sy/v1.4.0/全量脚本/v1.4.0-all.sql
@@ -1103,6 +1103,24 @@ CREATE TABLE `bs_sgc_sz_bxgcnrgl` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='水闸病险工程项目任务关联表';
+CREATE TABLE `bs_sgc_job_task`(
+ `ID` int NOT NULL AUTO_INCREMENT COMMENT '任务ID',
+ `NAME` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '任务名称',
+ `BUSINESS_TYPE` int NOT NULL COMMENT '业务类型',
+ `BUSINESS_Id` int NOT NULL COMMENT '业务ID',
+ `STATUS` int NOT NULL COMMENT '任务状态',
+ `PARAMS` text COLLATE utf8mb4_general_ci COMMENT '任务参数',
+ `LAST_START_TIME` datetime DEFAULT NULL COMMENT '上次开始时间',
+ `LAST_END_TIME` datetime DEFAULT NULL COMMENT '上次结束时间',
+ `NEXT_START_TIME` datetime DEFAULT NULL COMMENT '下次开始时间',
+ `TASK_END_TIME` datetime DEFAULT NULL COMMENT '任务结束时间',
+ `CREATE_UID` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
+ `CREATE_TIME` datetime DEFAULT NULL COMMENT '创建时间',
+ `UPDATE_UID` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最近修改人',
+ `UPDATE_TIME` datetime DEFAULT NULL COMMENT '最近修改时间',
+ PRIMARY KEY (`ID`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='定时任务表';
+
CREATE OR REPLACE VIEW `v_bs_sgc_dtsbr` AS
SELECT df.`ID`, df.`DIKE_CODE` AS `CODE`,gc.`DIKE_NAME` AS `NAME`,'1' AS `TYPE`,df.`STATUS` AS `STATUS`,df.`DEVICE_ID`,df.`DEVICE_NAME`,gc.`ADCD` AS ADCD, df.`WARNING_TYPE` AS `WARNING_TYPE`, df.`WARNING_LEVEL` AS `WARNING_LEVEL`, df.`WARNING_TIME` AS `WARNING_TIME`
FROM `bs_sgc_df_dtsbr` AS df
diff --git a/sql/sy/v1.4.0/增量脚本/v1.4.0-update.sql b/sql/sy/v1.4.0/增量脚本/v1.4.0-update.sql
index 84b18548..34b86bb8 100644
--- a/sql/sy/v1.4.0/增量脚本/v1.4.0-update.sql
+++ b/sql/sy/v1.4.0/增量脚本/v1.4.0-update.sql
@@ -151,17 +151,20 @@ CREATE TABLE `bs_sgc_sz_xsjhxq` (
CREATE TABLE `bs_sgc_job_task`(
`ID` int NOT NULL AUTO_INCREMENT COMMENT '任务ID',
`NAME` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '任务名称',
- `TYPE` int NOT NULL COMMENT '任务类型',
+ `BUSINESS_TYPE` int NOT NULL COMMENT '业务类型',
+ `BUSINESS_Id` int NOT NULL COMMENT '业务ID',
`STATUS` int NOT NULL COMMENT '任务状态',
- `START_DATE` datetime DEFAULT NULL COMMENT '开始时间',
- `END_DATE` datetime DEFAULT NULL COMMENT '结束时间',
- `REMINDER_TIME` datetime DEFAULT NULL COMMENT '提醒时间',
+ `PARAMS` text COLLATE utf8mb4_general_ci COMMENT '任务参数',
+ `LAST_START_TIME` datetime DEFAULT NULL COMMENT '上次开始时间',
+ `LAST_END_TIME` datetime DEFAULT NULL COMMENT '上次结束时间',
+ `NEXT_START_TIME` datetime DEFAULT NULL COMMENT '下次开始时间',
+ `TASK_END_TIME` datetime DEFAULT NULL COMMENT '任务结束时间',
`CREATE_UID` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
`CREATE_TIME` datetime DEFAULT NULL COMMENT '创建时间',
`UPDATE_UID` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最近修改人',
`UPDATE_TIME` datetime DEFAULT NULL COMMENT '最近修改时间',
PRIMARY KEY (`ID`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='任务表';
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='定时任务表';
delete from sys_menu where id in (