Browse Source

feat: 定时发送信息到信息中心

master_tdsql
hxh 7 months ago
parent
commit
e844fecff1
  1. 8
      shuili-system/pom.xml
  2. 39
      shuili-system/src/main/java/com/kms/yxgh/common/config/RedissonConfig.java
  3. 59
      shuili-system/src/main/java/com/kms/yxgh/common/domain/JobTask.java
  4. 78
      shuili-system/src/main/java/com/kms/yxgh/common/job/JobScheduled.java
  5. 33
      shuili-system/src/main/java/com/kms/yxgh/common/job/JobStatus.java
  6. 18
      shuili-system/src/main/java/com/kms/yxgh/common/job/event/StartJobEvent.java
  7. 26
      shuili-system/src/main/java/com/kms/yxgh/common/job/event/StartJobEventListener.java
  8. 159
      shuili-system/src/main/java/com/kms/yxgh/common/job/handler/AbstractSendMessageHandler.java
  9. 27
      shuili-system/src/main/java/com/kms/yxgh/common/job/handler/CycleType.java
  10. 89
      shuili-system/src/main/java/com/kms/yxgh/common/job/handler/DfAnimalPlanSendMessageHandler.java
  11. 133
      shuili-system/src/main/java/com/kms/yxgh/common/job/handler/DfCheckingPlanSendMessageHandler.java
  12. 54
      shuili-system/src/main/java/com/kms/yxgh/common/job/handler/DfYhPlanSendMessageHandler.java
  13. 10
      shuili-system/src/main/java/com/kms/yxgh/common/job/handler/JobHandler.java
  14. 12
      shuili-system/src/main/java/com/kms/yxgh/common/job/handler/SendMessageType.java
  15. 133
      shuili-system/src/main/java/com/kms/yxgh/common/job/handler/SzCheckingPlanSendMessageHandler.java
  16. 54
      shuili-system/src/main/java/com/kms/yxgh/common/job/handler/SzYhPlanSendMessageHandler.java
  17. 11
      shuili-system/src/main/java/com/kms/yxgh/common/mapper/JobTaskMapper.java
  18. 109
      shuili-system/src/main/java/com/kms/yxgh/common/service/JobTaskService.java
  19. 112
      shuili-system/src/main/java/com/kms/yxgh/df/service/DfAnimalPlanService.java
  20. 121
      shuili-system/src/main/java/com/kms/yxgh/df/service/DfPlanService.java
  21. 14
      shuili-system/src/main/java/com/kms/yxgh/df/service/DfYhPlanService.java
  22. 122
      shuili-system/src/main/java/com/kms/yxgh/sz/service/SzPlanService.java
  23. 17
      shuili-system/src/main/java/com/kms/yxgh/sz/service/SzYhPlanService.java
  24. 18
      sql/sy/v1.4.0/全量脚本/v1.4.0-all.sql
  25. 13
      sql/sy/v1.4.0/增量脚本/v1.4.0-update.sql

8
shuili-system/pom.xml

@ -28,6 +28,12 @@
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.16.4</version>
</dependency>
<!-- Mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
@ -76,7 +82,7 @@
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<artifactId>hutool-all</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.ben-manes.caffeine/caffeine -->

39
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);
}
}

59
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;
}

78
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<JobTask> 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<JobTask> getJobTaskList(int page, Date currentTime) {
IPage<JobTask> pageQuery = new Page<>(page, 100);
Wrapper<JobTask> wrapper = Wrappers.<JobTask>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");
}
}

33
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;
}
}

18
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;
}
}

26
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<StartJobEvent> {
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());
}
}

159
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<MsgVo> getMessagesAndUpdateJobTask(JobTask jobTask);
@Override
public JobTask runJob(JobTask jobTask) {
List<MsgVo> 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<MsgVo> 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;
}
}

27
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;
}
}

89
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<MsgVo> 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();
}
}

133
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<MsgVo> 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<DfCheckingPlanContentDto> 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<Integer> 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<Integer> 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();
}
}

54
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<MsgVo> 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();
}
}

10
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);
}

12
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,
}

133
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<MsgVo> 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<SzCheckingPlanContentDto> 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<Integer> 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<Integer> 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();
}
}

54
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<MsgVo> 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();
}
}

11
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<JobTask> {
}

109
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<JobTaskMapper, JobTask> {
private final RedissonClient redissonClient;
private final List<JobHandler> 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<JobTask>()
.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<JobTask>().lt("last_end_time", expireTime));
}
}

112
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<DfAnimalPlanMapper, DfAnima
private final DfAnimalOperatorMapper dfAnimalOperatorMapper;
private final DfAnimalPlanDetailMapper dfAnimalPlanDetailMapper;
private final BsSgcDfSafeJbxxMapper dfProjectMapper;
private final JobTaskService jobTaskService;
public DfAnimalPlanDto getDetailById(String id) {
DfAnimalPlan dfPlan = this.getById(id);
@ -108,7 +115,9 @@ public class DfAnimalPlanService extends BaseService<DfAnimalPlanMapper, DfAnima
if (CollectionUtil.isNotEmpty(dto.getDetails())) {
dto.getDetails().forEach(insertDetail(id));
}
return this.getDetailById(id);
DfAnimalPlanDto dfAnimalPlanDto = this.getDetailById(id);
sendMsg(dfAnimalPlanDto);
return dfAnimalPlanDto;
} else {
throw new DfException("该名称已存在");
}
@ -153,7 +162,9 @@ public class DfAnimalPlanService extends BaseService<DfAnimalPlanMapper, DfAnima
if (CollectionUtil.isNotEmpty(dto.getDetails())) {
dto.getDetails().forEach(insertDetail(id));
}
return this.getDetailById(id);
DfAnimalPlanDto dfAnimalPlanDto = this.getDetailById(id);
sendMsg(dfAnimalPlanDto);
return dfAnimalPlanDto;
} else {
throw new DfException("该名称已存在");
}
@ -163,6 +174,103 @@ public class DfAnimalPlanService extends BaseService<DfAnimalPlanMapper, DfAnima
}
private void sendMsg(DfAnimalPlanDto dto) {
if (dto == null) {
return;
}
JobTask jobTask = new JobTask();
jobTask.setBusinessId(dto.getId());
jobTask.setBusinessType(SendMessageType.DF_ANIMAL_PLAN.name());
if (dto.getIsReminder() != 1L) {
jobTaskService.updateOrInsertJobTask(jobTask, true);
return;
}
jobTask.setNextStartTime(getNextTime(dto));
jobTaskService.updateOrInsertJobTask(jobTask, false);
}
//计算下次执行时间
public Date getNextTime(DfAnimalPlanDto dto) {
CycleType cycleType = CycleType.getByCode(dto.getCycleType());
if (cycleType == null || dto.getOtherConfig() == null) {
return null;
}
switch (cycleType) {
case DAY:
return getNextDate(dto);
case WEEK:
Integer week = dto.getOtherConfig().getInteger("week");
//week指的是周几,计算下一个执行日期逻辑是:时间使用dto.getReminderTime,日期是下周几
return getNextWeekDate(dto, week);
case MONTH:
Integer day = dto.getOtherConfig().getInteger("day");
return getNextMonthDate(dto, day);
default:
return null;
}
}
private Date getNextMonthDate(DfAnimalPlanDto dto, int day) {
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.MONTH, 1);
//需要校验是否大于当前月的最大天数
int maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
if (day > 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) {

121
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<DfPlanMapper, DfPlan> {
private final DfCheckingPlanContentMapper dfCheckingPlanContentMapper;
private final SysUserService userService;
private final DfPlanOperatorService dfPlanOperatorService;
private final JobTaskService jobTaskService;
public IPage<DfPlanSimpleDto> search(SearchParam<DfPlanSearchDto> sp) {
Page<DfPlan> page = new Page<>(sp.getPageNum(), sp.getPageSize());
@ -99,7 +105,9 @@ public class DfPlanService extends BaseService<DfPlanMapper, DfPlan> {
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<DfPlanMapper, DfPlan> {
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<DfPlanMapper, DfPlan> {
}
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<Integer> 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<Integer> 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) {

14
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<DfYhPlanMapper, DfYhPlan, DfYhPlanSearchDto, DfYhPlanDetailDto> {
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<DfYhPlanMapp
return this.getBaseMapper().approvalSearchPage(page, sp.getData());
}
@Transactional(rollbackFor = Exception.class)
@Override
public void updateApprovalStatus(String formId, ApprovalStatusEnum status) {
Wrapper<DfYhPlan> wp = Wrappers.<DfYhPlan>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

122
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<SzPlanMapper, SzPlan> {
private final SzCheckingPlanContentMapper szCheckingPlanContentMapper;
private final SysUserService userService;
private final SzPlanOperatorService szPlanOperatorService;
private final JobTaskService jobTaskService;
public IPage<SzPlanSimpleDto> search(SearchParam<SzPlanSearchDto> sp) {
Page<SzPlan> page = new Page<>(sp.getPageNum(), sp.getPageSize());
@ -99,7 +106,9 @@ public class SzPlanService extends BaseService<SzPlanMapper, SzPlan> {
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<SzPlanMapper, SzPlan> {
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<SzPlanMapper, SzPlan> {
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<Integer> 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<Integer> 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<SzCheckingPlanContentDto> contents) {
if (CollectionUtils.isEmpty(contents)) {

17
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<SzYhPlanMapper, SzYhPlan, SzYhPlanSearchDto, SzYhPlanDetailDto> {
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<SzYhPlanMapp
return this.getBaseMapper().approvalSearchPage(page, sp.getData());
}
@Transactional(rollbackFor = Exception.class)
@Override
public void updateApprovalStatus(String formId, ApprovalStatusEnum status) {
Wrapper<SzYhPlan> wp = Wrappers.<SzYhPlan>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

18
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

13
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 (

Loading…
Cancel
Save