Commit 4fa315d7 by xieshaohua

[新增]超时通知

parent 188cb5db
...@@ -117,7 +117,7 @@ public class WorkOrderInfoVO { ...@@ -117,7 +117,7 @@ public class WorkOrderInfoVO {
* 结束时间毫秒 * 结束时间毫秒
*/ */
@Schema(description = "结束时间毫秒") @Schema(description = "结束时间毫秒")
private String endTimeMill; private long endTimeMill;
/** /**
* 期望完成日期 * 期望完成日期
*/ */
......
...@@ -53,7 +53,11 @@ ...@@ -53,7 +53,11 @@
<artifactId>spring-cloud-starter-openfeign</artifactId> <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.keymobile.notice</groupId>
<artifactId>common</artifactId>
<version>${notice.version}</version>
</dependency>
</dependencies> </dependencies>
......
...@@ -87,35 +87,41 @@ public class WorkOrderApi { ...@@ -87,35 +87,41 @@ public class WorkOrderApi {
@RequestMapping(value = "/getProcesses", method = {RequestMethod.GET}) @RequestMapping(value = "/getProcesses", method = {RequestMethod.GET})
@Operation(summary = "根据工单id获取审批记录", description = "") @Operation(summary = "根据工单id获取审批记录", description = "")
public List<WorkOrderProcessVO> getProcesses(@RequestParam String workOrderId) { public List<WorkOrderProcessVO> getProcesses(@RequestParam String workOrderId) {
return workOrderService.getProcesses(workOrderId); return workOrderService.getProcesses(workOrderId);
} }
@RequestMapping(value = "/getById", method = {RequestMethod.GET}) @RequestMapping(value = "/getById", method = {RequestMethod.GET})
@Operation(summary = "根据工单id获取详情信息", description = "") @Operation(summary = "根据工单id获取详情信息", description = "")
public WorkOrderInfoVO getById(@RequestParam String workOrderId) { public WorkOrderInfoVO getById(@RequestParam String workOrderId) {
return workOrderService.getById(workOrderId); return workOrderService.getById(workOrderId);
} }
@RequestMapping(value = "/checkCreate", method = {RequestMethod.GET}) @RequestMapping(value = "/checkCreate", method = {RequestMethod.GET})
@Operation(summary = "校验是否具有创建工单的权限", description = "") @Operation(summary = "校验是否具有创建工单的权限", description = "")
public boolean checkCreatePermission(@RequestParam(required = false) String userName) { public boolean checkCreatePermission(@RequestParam(required = false) String userName) {
return workOrderService.checkCreatePermission(userName); return workOrderService.checkCreatePermission(userName);
} }
@GetMapping(value = "/users/find") @GetMapping(value = "/users/find")
@Operation(summary = "人员接口", description = "") @Operation(summary = "人员接口", description = "")
List<User> findUser(@RequestParam(value = "types", required = false) String[] types, public List<User> findUser(@RequestParam(value = "types", required = false) String[] types,
@RequestParam(value = "dataRoleIds", required = false) Long[] dataRoleIds, @RequestParam(value = "dataRoleIds", required = false) Long[] dataRoleIds,
@RequestParam(value = "match", required = false) String match, @RequestParam(value = "match", required = false) String match,
@RequestParam(value = "userGroupIds", required = false) Long[] userGroupIds){ @RequestParam(value = "userGroupIds", required = false) Long[] userGroupIds) {
return workOrderService.findUser(types, dataRoleIds, match, userGroupIds); return workOrderService.findUser(types, dataRoleIds, match, userGroupIds);
} }
@GetMapping(value = "/stages") @GetMapping(value = "/stages")
@Operation(summary = "流程流转", description = "") @Operation(summary = "流程流转", description = "")
List<WorkOrderStageVO> stages(@RequestParam String workOrderId){ public List<WorkOrderStageVO> stages(@RequestParam String workOrderId) {
return workOrderService.stages(workOrderId); return workOrderService.stages(workOrderId);
} }
@GetMapping(value = "/timeoutNotice")
@Operation(summary = "超时通知", description = "")
public void timeoutNotice() {
workOrderService.timeoutNotice();
}
} }
...@@ -100,7 +100,7 @@ public class WorkOrderInfo { ...@@ -100,7 +100,7 @@ public class WorkOrderInfo {
/** /**
* 结束时间毫秒 * 结束时间毫秒
*/ */
private String endTimeMill; private long endTimeMill;
/** /**
* 期望完成日期 * 期望完成日期
*/ */
......
package com.keymobile.governworkorder.core.persistence.model;
import jakarta.persistence.Id;
import jakarta.persistence.Transient;
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.List;
/**
* @author xiesh
* @version 1.0.0
* @date 2025/8/12
* @desc 工单通知信息
*/
@Data
@Document(collection = "g_work_order_notice")
public class WorkOrderNotice {
/**
* id
*/
@Id
private String id;
/**
* 通知用户
*/
private List<String> users;
/**
* 通知内容
*/
private String content;
}
...@@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.PathVariable; ...@@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import java.util.List; import java.util.List;
import java.util.Map;
@FeignClient(name = "AuthService") @FeignClient(name = "AuthService")
public interface AuthService { public interface AuthService {
...@@ -26,4 +27,7 @@ public interface AuthService { ...@@ -26,4 +27,7 @@ public interface AuthService {
@RequestParam(value = "dataRoleIds", required = false) Long[] dataRoleIds, @RequestParam(value = "dataRoleIds", required = false) Long[] dataRoleIds,
@RequestParam(value = "match", required = false) String match, @RequestParam(value = "match", required = false) String match,
@RequestParam(value = "userGroupIds", required = false) Long[] userGroupIds); @RequestParam(value = "userGroupIds", required = false) Long[] userGroupIds);
@GetMapping(value = "/users/exactFindByName")
Map<String, Object> exactFindByName(@RequestParam(value = "name") String name);
} }
package com.keymobile.governworkorder.core.service;
import java.util.List;
public interface NoticeService {
void send(String content, String url, List<String> userIds);
}
...@@ -44,4 +44,5 @@ public interface WorkOrderService { ...@@ -44,4 +44,5 @@ public interface WorkOrderService {
List<WorkOrderStageVO> stages(String workOrderId); List<WorkOrderStageVO> stages(String workOrderId);
void timeoutNotice();
} }
package com.keymobile.governworkorder.core.service.impl;
import com.keymobile.governworkorder.core.remote.AuthService;
import com.keymobile.governworkorder.core.service.NoticeService;
import com.keymobile.governworkorder.core.util.ObjectUtil;
import com.keymobile.notice.common.NoticeInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static com.keymobile.notice.common.mq.NoticeMQConstant.NOTICE_EXCHANGE;
import static com.keymobile.notice.common.mq.NoticeMQConstant.NOTICE_ROUTING_KEY;
@Service
public class NoticeServiceImpl implements NoticeService {
private static final Logger log = LoggerFactory.getLogger(NoticeServiceImpl.class);
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private AuthService authService;
@Override
public void send(String content, String url, List<String> userNames) {
try {
log.info("发送通知,内容 :{},用户:{}", content, userNames);
List<String> userIds = getUserIds(userNames);
if(CollectionUtils.isEmpty(userIds)){
return;
}
NoticeInfo notice = convert(content, url, userIds);
log.info("发送通知,exchange :{},ROUTINGKEY:{},notice:{}", NOTICE_EXCHANGE, NOTICE_ROUTING_KEY, ObjectUtil.toJson(notice));
rabbitTemplate.convertAndSend(NOTICE_EXCHANGE, NOTICE_ROUTING_KEY, notice);
} catch (Exception e) {
log.error("发送通知失败", e);
}
}
private NoticeInfo convert(String content, String url, List<String> userIds) {
return new NoticeInfo() {
@Override
public String getAppType() {
return "index";
}
@Override
public String getContent() {
return content;
}
@Override
public String getUrl() {
return url;
}
@Override
public Long getNoticeMillisecondTimestamp() {
return System.currentTimeMillis();
}
@Override
public List<String> getUserIdList() {
return userIds;
}
};
}
private List<String> getUserIds(List<String> userNames) {
if (CollectionUtils.isEmpty(userNames)) {
return Collections.emptyList();
}
return userNames.stream().map(o -> {
Map<String, Object> user = authService.exactFindByName(o);
if (user == null) {
return null;
} else {
return ObjectUtil.toString(user.get("id"));
}
}).filter(Objects::nonNull).collect(Collectors.toList());
}
}
...@@ -8,6 +8,7 @@ import com.keymobile.governworkorder.common.type.*; ...@@ -8,6 +8,7 @@ import com.keymobile.governworkorder.common.type.*;
import com.keymobile.governworkorder.core.dto.WorkOrdeQueryDto; import com.keymobile.governworkorder.core.dto.WorkOrdeQueryDto;
import com.keymobile.governworkorder.core.dto.WorkOrderConfirmDataDto; import com.keymobile.governworkorder.core.dto.WorkOrderConfirmDataDto;
import com.keymobile.governworkorder.core.messaging.WorkOrderMessageService; import com.keymobile.governworkorder.core.messaging.WorkOrderMessageService;
import com.keymobile.governworkorder.core.persistence.model.WorkOrderNotice;
import com.keymobile.governworkorder.core.persistence.model.WorkOrderProcess; import com.keymobile.governworkorder.core.persistence.model.WorkOrderProcess;
import com.keymobile.governworkorder.core.persistence.model.WorkOrderData; import com.keymobile.governworkorder.core.persistence.model.WorkOrderData;
import com.keymobile.governworkorder.core.persistence.model.WorkOrderInfo; import com.keymobile.governworkorder.core.persistence.model.WorkOrderInfo;
...@@ -15,11 +16,11 @@ import com.keymobile.governworkorder.core.remote.AuthService; ...@@ -15,11 +16,11 @@ import com.keymobile.governworkorder.core.remote.AuthService;
import com.keymobile.governworkorder.core.remote.user.User; import com.keymobile.governworkorder.core.remote.user.User;
import com.keymobile.governworkorder.core.remote.user.UserGroup; import com.keymobile.governworkorder.core.remote.user.UserGroup;
import com.keymobile.governworkorder.core.service.FileService; import com.keymobile.governworkorder.core.service.FileService;
import com.keymobile.governworkorder.core.service.NoticeService;
import com.keymobile.governworkorder.core.service.WorkOrderService; import com.keymobile.governworkorder.core.service.WorkOrderService;
import com.keymobile.governworkorder.core.util.*; import com.keymobile.governworkorder.core.util.*;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
...@@ -30,12 +31,15 @@ import org.springframework.data.mongodb.core.MongoTemplate; ...@@ -30,12 +31,15 @@ import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.support.PageableExecutionUtils; import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.*; import java.util.*;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -58,6 +62,8 @@ public class WorkOrderServiceImpl implements WorkOrderService { ...@@ -58,6 +62,8 @@ public class WorkOrderServiceImpl implements WorkOrderService {
private FileService fileService; private FileService fileService;
@Autowired @Autowired
private AuthService authService; private AuthService authService;
@Autowired
private NoticeService noticeService;
@Value("${process.createGroup:治理工单创建组}") @Value("${process.createGroup:治理工单创建组}")
private String createGroup; private String createGroup;
@Value("${process.approvalGroup:治理工单审批组}") @Value("${process.approvalGroup:治理工单审批组}")
...@@ -408,6 +414,8 @@ public class WorkOrderServiceImpl implements WorkOrderService { ...@@ -408,6 +414,8 @@ public class WorkOrderServiceImpl implements WorkOrderService {
workOrder.setNextUserDname(null); workOrder.setNextUserDname(null);
workOrder.setStage(OrderProcessStageTypeEnum.PROCESS_DONE.getName()); workOrder.setStage(OrderProcessStageTypeEnum.PROCESS_DONE.getName());
workOrder.setStatus(OrderStatusTypeEnum.STATUS_INVALIDATE.getName()); workOrder.setStatus(OrderStatusTypeEnum.STATUS_INVALIDATE.getName());
workOrder.setEndTime(DateUtil.getDate());
workOrder.setEndTimeMill(System.currentTimeMillis());
mongoTemplate.save(process); mongoTemplate.save(process);
mongoTemplate.save(workOrder); mongoTemplate.save(workOrder);
WorkOrderInfoVO messageVO = convertMessage(workOrder); WorkOrderInfoVO messageVO = convertMessage(workOrder);
...@@ -425,6 +433,9 @@ public class WorkOrderServiceImpl implements WorkOrderService { ...@@ -425,6 +433,9 @@ public class WorkOrderServiceImpl implements WorkOrderService {
workOrder.setNextUserDname(null); workOrder.setNextUserDname(null);
workOrder.setStage(OrderProcessStageTypeEnum.PROCESS_DONE.getName()); workOrder.setStage(OrderProcessStageTypeEnum.PROCESS_DONE.getName());
workOrder.setStatus(OrderStatusTypeEnum.STATUS_DONE.getName()); workOrder.setStatus(OrderStatusTypeEnum.STATUS_DONE.getName());
workOrder.setEndTime(DateUtil.getDate());
workOrder.setEndTimeMill(System.currentTimeMillis());
mongoTemplate.save(process); mongoTemplate.save(process);
mongoTemplate.save(workOrder); mongoTemplate.save(workOrder);
...@@ -497,6 +508,48 @@ public class WorkOrderServiceImpl implements WorkOrderService { ...@@ -497,6 +508,48 @@ public class WorkOrderServiceImpl implements WorkOrderService {
} }
@Scheduled(cron = "0 0 6 * * ?")
public void timeoutNotice() {
log.info("超时通知同步开始");
long now = LocalDate.now(ZoneId.of("+8"))
.atStartOfDay()
.toInstant(ZoneOffset.of("+8")).toEpochMilli();
Query query = Query.query(Criteria.where("status").is(OrderStatusTypeEnum.STATUS_PROCESSING.getName())
.and("expectedEndTime").lt(String.valueOf(now)));
List<WorkOrderInfo> workOrderList = mongoTemplate.find(query, WorkOrderInfo.class);
for (WorkOrderInfo workOrder : workOrderList) {
String userNames = workOrder.getNextUserName();
if (StringUtils.isNotBlank(userNames)) {
WorkOrderNotice notice = mongoTemplate.findById(workOrder.getId(), WorkOrderNotice.class);
String[] userNameArgs = StringUtils.split(userNames, ",");
List<String> noticeUsers = notice == null ? new ArrayList<>() : notice.getUsers();
List<String> newNoticeUsers = new ArrayList<>();
String content = String.format("工单:%s,工单id:%s,已经超时,请您尽快处理。", workOrder.getTitle(), workOrder.getId());
boolean noticeFlag = false;
for (String userName : userNameArgs) {
if (!noticeUsers.contains(userName)) {
noticeUsers.add(userName);
newNoticeUsers.add(userName);
noticeFlag = true;
}
}
if (noticeFlag) {
noticeService.send(content, null, newNoticeUsers);
notice = new WorkOrderNotice();
notice.setId(workOrder.getId());
notice.setUsers(noticeUsers);
notice.setContent(content);
mongoTemplate.save(notice);
}
}
}
log.info("超时通知同步结束");
}
private void validateAndFillWorkOrder(WorkOrderInfo workOrder) { private void validateAndFillWorkOrder(WorkOrderInfo workOrder) {
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
<akka.version>2.6.0</akka.version> <akka.version>2.6.0</akka.version>
<poi.version>4.1.1</poi.version> <poi.version>4.1.1</poi.version>
<easyExcel.version>3.3.4</easyExcel.version> <easyExcel.version>3.3.4</easyExcel.version>
<notice.version>mcd-1.0.1</notice.version>
</properties> </properties>
<dependencies> <dependencies>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment