Browse Source

项目状态暂存库

tags/24080901
PoffyZhang 1 year ago
parent
commit
8753ea6ba0
21 changed files with 536 additions and 203 deletions
  1. +0
    -4
      pmapi/pom.xml
  2. +1
    -2
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/controller/PrequalificationDeclaredController.java
  3. +0
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ConstructionPlanManage.java
  4. +18
    -4
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DeclaredProjectManage.java
  5. +14
    -6
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/PrequalificationDeclaredProjectManage.java
  6. +87
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ReviewByDeptJointManage.java
  7. +50
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ReviewByProvincialDeptManage.java
  8. +3
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/entity/ProjectInst.java
  9. +0
    -64
      pmapi/src/main/java/com/ningdatech/pmapi/rabbitmq/config/DirectRabbitConfig.java
  10. +0
    -47
      pmapi/src/main/java/com/ningdatech/pmapi/rabbitmq/config/RabbitConfig.java
  11. +0
    -59
      pmapi/src/main/java/com/ningdatech/pmapi/rabbitmq/controller/TestController.java
  12. +93
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/ProjectStatusFlowTask.java
  13. +12
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/staging/contants/StagingContant.java
  14. +13
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/staging/mapper/ProjectStagingMapper.java
  15. +12
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/staging/mapper/ProjectStagingMapper.xml
  16. +69
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/staging/model/entity/ProjectStaging.java
  17. +18
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/staging/serivice/IProjectStagingService.java
  18. +77
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/staging/serivice/impl/ProjectStagingServiceImpl.java
  19. +69
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/staging/utils/ProjectStatusFlowMapUtil.java
  20. +0
    -11
      pmapi/src/test/resources/application-dev.yml
  21. +0
    -5
      pom.xml

+ 0
- 4
pmapi/pom.xml View File

@@ -264,10 +264,6 @@
<systemPath>${basedir}/src/lib/zwdd-sdk-java-1.2.0.jar</systemPath>
</dependency>
<dependency>
<groupId>com.ningdatech</groupId>
<artifactId>nd-rabbitmq-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>


+ 1
- 2
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/controller/PrequalificationDeclaredController.java View File

@@ -49,7 +49,6 @@ public class PrequalificationDeclaredController {
@ApiOperation(value = "申报预审", notes = "申报预审")
@PostMapping("/start")
public String startTheProcess(@Validated @RequestBody DefaultDeclaredDTO dto) {
String instanceId = prequalificationDeclaredProjectManage.startTheProcess(dto);
return "提交预审 【" + instanceId + "】 成功";
return prequalificationDeclaredProjectManage.startTheProcess(dto);
}
}

+ 0
- 1
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ConstructionPlanManage.java View File

@@ -82,7 +82,6 @@ public class ConstructionPlanManage {
VUtils.isTrue(!ProjectStatusEnum.PLAN_TO_BE_DECLARED.getCode().equals(projectInfo.getStatus()) ||
!ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage()))
.throwMessage("提交失败 该项目不是 方案待申报状态或者未立项阶段");
// TODO 再判断 该项目是否 真实走完 预审审批

ProcessStartParamsVo params = new ProcessStartParamsVo();
params.setUser(dto.getUser());


+ 18
- 4
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DeclaredProjectManage.java View File

@@ -114,6 +114,14 @@ public class DeclaredProjectManage {
@Transactional(rollbackFor = Exception.class)
public String startTheProcess(DefaultDeclaredDTO dto) {
ProjectDTO projectInfo = dto.getProjectInfo();

//如果是重新提交的话 判断下 项目是否存在
if(Objects.nonNull(projectInfo.getId())){
Project oldProject = projectService.getById(projectInfo.getId());
VUtils.isTrue(Objects.isNull(oldProject))
.throwMessage(String.format("重新提交失败 该项目【%s】不存在",projectInfo.getId()));
}

String regionCode = projectInfo.getAreaCode();

WflowModels model = processModelService.getOne(Wrappers.lambdaQuery(WflowModels.class)
@@ -144,8 +152,8 @@ public class DeclaredProjectManage {
String instanceId = processService.startProcess(model.getProcessDefId(), params);
log.info("申报项目成功 【{}】", instanceId);

//保存项目
saveProject(dto.getProjectInfo(), instanceId, regionCode);
//如果是重新提交的话 判断下 项目是否存在
saveOrUpdateProject(dto.getProjectInfo(), instanceId, regionCode);

return instanceId;
}
@@ -174,6 +182,11 @@ public class DeclaredProjectManage {
throw new BusinessException(String.format("此 【%s】区域找不到单位流程配置", regionCode));
}

//首先要判断 项目当前状态 是不是 单位内部拒绝
VUtils.isTrue(!ProjectStatusEnum.UNDER_INTERNAL_AUDIT_NOT_PASS.getCode().equals(projectInfo.getStatus()) ||
!ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage()))
.throwMessage("提交失败 该项目不是 单位内部拒绝审核状态或者未立项阶段");

ProcessStartParamsVo params = new ProcessStartParamsVo();
params.setUser(dto.getUser());
params.setProcessUsers(Collections.emptyMap());
@@ -221,7 +234,7 @@ public class DeclaredProjectManage {
* @param projectDto
* @param instanceId
*/
private void saveProject(ProjectDTO projectDto, String instanceId, String regionCode) {
private void saveOrUpdateProject(ProjectDTO projectDto, String instanceId, String regionCode) {
//流程启动之后 入库项目 重要业务信息 用于列表查询 展示
try {
//保存项目表信息
@@ -233,7 +246,7 @@ public class DeclaredProjectManage {
project.setStage(ProjectStatusEnum.NOT_APPROVED.getCode());
project.setStatus(ProjectStatusEnum.UNDER_INTERNAL_AUDIT.getCode());
project.setInstCode(instanceId);
projectService.save(project);
projectService.saveOrUpdate(project);
//保存项目应用
if (CollUtil.isNotEmpty(projectDto.getApplicationList())) {
List<ProjectApplication> applications = projectDto.getApplicationList().stream().map(application -> {
@@ -250,6 +263,7 @@ public class DeclaredProjectManage {
projectInst.setInstCode(instanceId);
projectInst.setCreatOn(LocalDateTime.now());
projectInst.setUpdateOn(LocalDateTime.now());
projectInst.setInstType(ProjectProcessStageEnum.ORG_INTERNAL_APPROVAL_PROCESS.getCode());
projectInstService.save(projectInst);
} catch (Exception e) {
log.error("项目信息入库错误 ", e);


+ 14
- 6
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/PrequalificationDeclaredProjectManage.java View File

@@ -15,6 +15,7 @@ import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectInst;
import com.ningdatech.pmapi.projectlib.service.IProjectInstService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.staging.serivice.IProjectStagingService;
import com.wflow.bean.entity.WflowModels;
import com.wflow.exception.BusinessException;
import com.wflow.workflow.bean.vo.ProcessStartParamsVo;
@@ -52,6 +53,8 @@ public class PrequalificationDeclaredProjectManage {

private final IProjectInstService projectInstService;

private final IProjectStagingService projectStagingService;

/**
* 提交预审
*
@@ -95,8 +98,13 @@ public class PrequalificationDeclaredProjectManage {
//如果是省级部门 需要联审的(申报金额大于1000万 并且是市级项目)
if(ProjectStatusEnum.JOINT_REVIEW_BY_PROVINCIAL_DEPARTMENTS
.getCode().equals(projectInfo.getStatus())){
//TODO 对接外部 省级
instanceId = DeclaredProjectContant.Instance.PROVINCE_INSTANCE_ID;
//入库暂存表 后续处理 对接外部接口
projectInfo.setUpdateOn(LocalDateTime.now());
if(projectStagingService.addByProject(projectInfo,"省级部门联审")
&& projectService.updateById(projectInfo)){
return "提交省级部门联审成功";
}
return "提交省级部门联审失败";
}else if(ProjectStatusEnum.PRE_APPLYING
.getCode().equals(projectInfo.getStatus())){
//如果是非省级联审的项目 直接提交 预审
@@ -115,14 +123,13 @@ public class PrequalificationDeclaredProjectManage {
log.info("提交预审项目成功 【{}】", instanceId);

//保存预审项目
if(Objects.nonNull(instanceId)){
modifyProject(projectInfo, instanceId);
}
modifyProject(projectInfo, instanceId);

}else{
throw new BusinessException("项目状态 错误 project :" + JSON.toJSONString(projectInfo));
}

return instanceId;
return "提交预审成功【" + instanceId + "】";
}

/**
@@ -146,6 +153,7 @@ public class PrequalificationDeclaredProjectManage {
projectInst.setInstCode(instanceId);
projectInst.setCreatOn(LocalDateTime.now());
projectInst.setUpdateOn(LocalDateTime.now());
projectInst.setInstType(ProjectProcessStageEnum.PROJECT_PREQUALIFICATION_APPROVAL_PROCESS.getCode());
projectInstService.save(projectInst);
} catch (Exception e) {
log.error("提交预审 项目信息修改 错误 ", e);


+ 87
- 0
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ReviewByDeptJointManage.java View File

@@ -0,0 +1,87 @@
package com.ningdatech.pmapi.projectdeclared.manage;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.basic.function.VUtils;
import com.ningdatech.pmapi.common.enumeration.ProjectProcessStageEnum;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.service.IProjectInstService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.wflow.bean.entity.WflowModels;
import com.wflow.exception.BusinessException;
import com.wflow.workflow.service.ProcessInstanceService;
import com.wflow.workflow.service.ProcessModelService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Objects;

/**
* @Classname ReviewByDeptJointManage
* @Description 部门联审
* @Date 2023/2/17 14:48
* @Author PoffyZhang
*/
@Component
@Slf4j
@RequiredArgsConstructor
public class ReviewByDeptJointManage {

private final IProjectService projectService;

private final ProcessModelService processModelService;

private final ProcessInstanceService processService;

private final IProjectInstService projectInstService;

/**
* 省级部门联审
* @param project
* @return
*/
@Transactional(rollbackFor = Exception.class)
public Boolean startTheProcess(Project project) {
VUtils.isTrue(Objects.isNull(project.getId())).throwMessage("提交失败 缺少项目ID!");
Project projectInfo = projectService.getById(project.getId());
VUtils.isTrue(Objects.isNull(projectInfo)).throwMessage("提交失败 此项目不存在!");
String regionCode = projectInfo.getAreaCode();

WflowModels model = processModelService.getOne(Wrappers.lambdaQuery(WflowModels.class)
.eq(WflowModels::getRegionCode, regionCode)
.eq(WflowModels::getProcessType, ProjectProcessStageEnum.DEPARTMENT_JOINT_APPROVAL_PROCESS.getCode())
.last("limit 1"));

if (Objects.isNull(model)) {
log.error("此 【{}】区域找不到 部门联审申报流程配置", regionCode);
throw new BusinessException(String.format("此 【%s】区域找不到 部门联审申报流程配置", regionCode));
}
//要判断 项目当前状态 是不是 部门联审
VUtils.isTrue(!ProjectStatusEnum.DEPARTMENT_JOINT_REVIEW.getCode().equals(projectInfo.getStatus()) ||
!ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage()))
.throwMessage("提交失败 该项目不是 省级部门联审状态状态或者未立项阶段");

// 再判断 该项目是否 真实走完 预审审批 并且提取出 提交人
// projectInstService.
//
// ProcessStartParamsVo params = new ProcessStartParamsVo();
// params.setUser(dto.getUser());
// params.setProcessUsers(Collections.emptyMap());
// //放入条件判断的项目字段
// ProjectConditionDTO conditionDto = new ProjectConditionDTO();
// BeanUtils.copyProperties(projectInfo, conditionDto);
// dto.getFormData().putAll(
// JSON.parseObject(JSON.toJSONString(conditionDto), new TypeReference<Map<String, Object>>() {
// })
// );
// params.setFormData(dto.getFormData());
// String instanceId = processService.startProcess(model.getProcessDefId(), params);
// log.info("建设方案项目申报成功 【{}】", instanceId);
//
// //保存建设项目
// modifyProject(projectInfo, instanceId, projectInfo.getConstructionPlanFile());

return null;
}
}

+ 50
- 0
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ReviewByProvincialDeptManage.java View File

@@ -0,0 +1,50 @@
package com.ningdatech.pmapi.projectdeclared.manage;

import com.ningdatech.basic.function.VUtils;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Objects;

/**
* @Classname ReviewByProvincialDeptManage
* @Description 省级部门联审
* @Date 2023/2/17 14:48
* @Author PoffyZhang
*/
@Component
@Slf4j
@RequiredArgsConstructor
public class ReviewByProvincialDeptManage {

private final IProjectService projectService;

/**
* 省级部门联审
* @param project
* @return
*/
@Transactional(rollbackFor = Exception.class)
public Boolean startTheProcess(Project project) {
VUtils.isTrue(Objects.isNull(project.getId())).throwMessage("提交失败 缺少项目ID!");
Project projectInfo = projectService.getById(project.getId());
VUtils.isTrue(Objects.isNull(projectInfo)).throwMessage("提交失败 此项目不存在!");
String regionCode = projectInfo.getAreaCode();

//首先要判断 项目当前状态 是不是 省级部门联审
VUtils.isTrue(!ProjectStatusEnum.JOINT_REVIEW_BY_PROVINCIAL_DEPARTMENTS.getCode().equals(projectInfo.getStatus()) ||
!ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage()))
.throwMessage("提交失败 该项目不是 省级部门联审状态状态或者未立项阶段");
// TODO 对接省级联审的接口
Boolean sucessProvince = Boolean.FALSE;
if(sucessProvince){
//成功了后
}

return Boolean.FALSE;
}
}

+ 3
- 0
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/entity/ProjectInst.java View File

@@ -34,6 +34,9 @@ public class ProjectInst implements Serializable {
@ApiModelProperty("实例ID")
private String instCode;

@ApiModelProperty("实例类型 1单位内部审批流程 2项目预审审批流程 3部门联合审批流程 4建设方案审批流程 5验收申报审批流程")
private Integer instType;

@ApiModelProperty("创建时间")
private LocalDateTime creatOn;



+ 0
- 64
pmapi/src/main/java/com/ningdatech/pmapi/rabbitmq/config/DirectRabbitConfig.java View File

@@ -1,64 +0,0 @@
package com.ningdatech.pmapi.rabbitmq.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* @author zpf
* @version 1.0.0
* @Description 创建direct类型的交换机
* @createTime 2023年02月17日
*/
@Slf4j
@Configuration
public class DirectRabbitConfig {


private static final String QUEUE = "TestDirectQueue";
private static final String EXCHANGE = "TestDirectExchange";
private static final String ROUTING_KEY = "TestDirectRouting";

/**
* 创建一个名为TestDirectQueue的队列
*
* @return
*/
@Bean
public Queue testDirectQueue() {
// durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
// exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
// autoDelete:是否自动删除,有消息者订阅本队列,然后所有消费者都解除订阅此队列,会自动删除。
// arguments:队列携带的参数,比如设置队列的死信队列,消息的过期时间等等。
return new Queue(QUEUE, true);
}

/**
* 创建一个名为TestDirectExchange的Direct类型的交换机
*
* @return
*/
@Bean
public DirectExchange testDirectExchange() {
// durable:是否持久化,默认是false,持久化交换机。
// autoDelete:是否自动删除,交换机先有队列或者其他交换机绑定的时候,然后当该交换机没有队列或其他交换机绑定的时候,会自动删除。
// arguments:交换机设置的参数,比如设置交换机的备用交换机(Alternate Exchange),当消息不能被路由到该交换机绑定的队列上时,会自动路由到备用交换机
return new DirectExchange(EXCHANGE, true, false);
}

/**
* 绑定交换机和队列
*
* @return
*/
@Bean
public Binding bindingDirect() {
//bind队列to交换机中with路由key(routing key)
return BindingBuilder.bind(testDirectQueue()).to(testDirectExchange()).with(ROUTING_KEY);
}
}


+ 0
- 47
pmapi/src/main/java/com/ningdatech/pmapi/rabbitmq/config/RabbitConfig.java View File

@@ -1,47 +0,0 @@
package com.ningdatech.pmapi.rabbitmq.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Configuration
public class RabbitConfig {

@Bean
public RabbitTemplate createRabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate();
rabbitTemplate.setConnectionFactory(connectionFactory);

//设置消息投递失败的策略,有两种策略:自动删除或返回到客户端。
//我们既然要做可靠性,当然是设置为返回到客户端(true是返回客户端,false是自动删除)
rabbitTemplate.setMandatory(true);

rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (ack) {
log.info("ConfirmCallback 关联数据:{},投递成功,确认情况:{}", correlationData, ack);
} else {
log.info("ConfirmCallback 关联数据:{},投递失败,确认情况:{},原因:{}", correlationData, ack, cause);
}
}
});

rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
@Override
public void returnedMessage(ReturnedMessage returnedMessage) {
log.info("ReturnsCallback 消息:{},回应码:{},回应信息:{},交换机:{},路由键:{}"
, returnedMessage.getMessage(), returnedMessage.getReplyCode()
, returnedMessage.getReplyText(), returnedMessage.getExchange()
, returnedMessage.getRoutingKey());
}
});

return rabbitTemplate;
}
}

+ 0
- 59
pmapi/src/main/java/com/ningdatech/pmapi/rabbitmq/controller/TestController.java View File

@@ -1,59 +0,0 @@
package com.ningdatech.pmapi.rabbitmq.controller;

import com.alibaba.fastjson.JSON;
import com.ningdatech.pmapi.user.entity.UserInfo;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

/**
* @author zpf
* @version 1.0.0
* @Description
* @createTime 2023年02月17日
*/
@RestController
public class TestController {

@Autowired
RabbitTemplate rabbitTemplate;


@GetMapping("/test")
public String test() {
return "producer ok";
}

@GetMapping("/push")
public String push() {
for (int i = 1; i <= 5; i++) {
//这个参数是用来做消息的唯一标识
//发布消息时使用,存储在消息的headers中
UserInfo user = new UserInfo();
user.setId(1L);
user.setRealName("汪涵");
// 关联的数据,可以用在消息投递失败的时候,作为一个线索,比如我把当前用户的id放进去,如果user消息投递失败
// 我后面可以根据id再找到user,再次投递数据
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString().concat("-") + i);
if (i == 2) {
//故意把交换机写错,演示 confirmCallback
rabbitTemplate.convertAndSend("TestDirectExchange_111", "TestDirectRouting",
JSON.toJSONString(user), correlationData);
} else if (i == 3) {
//故意把路由键写错,演示 returnCallback
rabbitTemplate.convertAndSend("TestDirectExchange", "TestDirectRouting_111",
JSON.toJSONString(user), correlationData);
} else {
//正常发送
rabbitTemplate.convertAndSend("TestDirectExchange", "TestDirectRouting",
JSON.toJSONString(user), correlationData);
}
}
return "producer push ok";
}
}


+ 93
- 0
pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/ProjectStatusFlowTask.java View File

@@ -0,0 +1,93 @@
package com.ningdatech.pmapi.scheduler.task;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.scheduler.contants.TaskContant;
import com.ningdatech.pmapi.staging.contants.StagingContant;
import com.ningdatech.pmapi.staging.model.entity.ProjectStaging;
import com.ningdatech.pmapi.staging.serivice.IProjectStagingService;
import com.ningdatech.pmapi.staging.utils.ProjectStatusFlowMapUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;

/**
* @Classname ProjectStatusFlowTask
* @Description
* @Date 2023/2/20 10:12
* @Author PoffyZhang
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class ProjectStatusFlowTask {

private final IProjectStagingService projectStagingService;

private final IProjectService projectService;

private final ProjectStatusFlowMapUtil projectStatusFlowMapUtil;

@Scheduled(cron = "0 */1 * * * ?")
public void statusFlow() throws UnknownHostException {
//测试暂时用自己电脑HOST
if (TaskContant.Host.HOST_ZPF.equals(InetAddress.getLocalHost().getHostName())) {
//1. 定时取 项目暂存表的数据 去进行状态继续流转
List<ProjectStaging> stagingList = projectStagingService.list(Wrappers.lambdaQuery(ProjectStaging.class)
.eq(ProjectStaging::getDead,Boolean.FALSE)
.ge(ProjectStaging::getNextTime, LocalDateTime.now())
.le(ProjectStaging::getRetryTimes, StagingContant.Retry.MAX_RETRY_TIMES)
.orderByAsc(ProjectStaging::getProjectId));

log.info("需要状态流转的项目 size:{} :{}",stagingList.size(), JSON.toJSONString(stagingList));
if(CollUtil.isEmpty(stagingList)){
log.info("没有需要状态流转的项目!");
return;
}

//遍历
for(ProjectStaging projectStaging : stagingList){
try{
Project project = projectService.getById(projectStaging.getProjectId());
if(Objects.isNull(project)){
log.info("此项目 【{}】 不存在",projectStaging.getProjectId());
continue;
}

//2. 用函数map 定位到 状态流转的函数
Map<Integer, Function<Project, Boolean>> reStartProcessMap =
projectStatusFlowMapUtil.statusFlowFunctionMap;

if(!reStartProcessMap.containsKey(project.getStatus())){
log.info("此项目 【{}】 当前状态 【{}】,没有对应流转函数",projectStaging.getProjectId(),project.getStatus());
continue;
}

Function<Project, Boolean> functionMap = reStartProcessMap.get(project.getStatus());
//执行对应的函数
if(functionMap.apply(project)){
//执行成功了 删除暂存的数据
projectStagingService.removeById(projectStaging);
}
}catch (Exception e){
log.error("项目流转 异常 projectId:【" + projectStaging.getProjectId() + "】 异常内容:" + e);
}finally {
//增加重试的次数 和下次扫描时间
projectStagingService.addRetryTimes(projectStaging);
}
}
}
}
}

+ 12
- 0
pmapi/src/main/java/com/ningdatech/pmapi/staging/contants/StagingContant.java View File

@@ -0,0 +1,12 @@
package com.ningdatech.pmapi.staging.contants;

/**
* 项目暂存 静态配置
*/
public interface StagingContant {

class Retry {
public static final Integer MAX_RETRY_TIMES = 10;
}

}

+ 13
- 0
pmapi/src/main/java/com/ningdatech/pmapi/staging/mapper/ProjectStagingMapper.java View File

@@ -0,0 +1,13 @@
package com.ningdatech.pmapi.staging.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ningdatech.pmapi.staging.model.entity.ProjectStaging;
import org.apache.ibatis.annotations.Param;

import java.time.LocalDateTime;

public interface ProjectStagingMapper extends BaseMapper<ProjectStaging> {

Boolean addRetryTimes(@Param("id") Long id, @Param("retryTimes") Integer retryTimes,
@Param("nextRetryTime") LocalDateTime nextRetryTime,@Param("dead") Boolean dead);
}

+ 12
- 0
pmapi/src/main/java/com/ningdatech/pmapi/staging/mapper/ProjectStagingMapper.xml View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ningdatech.pmapi.staging.mapper.ProjectStagingMapper">

<update id="addRetryTimes" >
update nd_project_staging
set retry_times = #{retryTimes},
next_time = #{nextRetryTime},
dead = #{dead}
where id = #{id} and retry_times = #{retryTimes - 1}
</update>
</mapper>

+ 69
- 0
pmapi/src/main/java/com/ningdatech/pmapi/staging/model/entity/ProjectStaging.java View File

@@ -0,0 +1,69 @@
package com.ningdatech.pmapi.staging.model.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
* @Classname ProjectStaging
* @Description
* @Date 2023/2/20 9:40
* @Author PoffyZhang
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName("nd_project_staging")
@ApiModel(value = "ProjectStaging", description = "项目暂存表 扫描进行 状态继续流转 做解耦用")
public class ProjectStaging implements Serializable {

@ApiModelProperty("主键")
@TableId(type = IdType.AUTO)
private Long id;

@ApiModelProperty("项目ID")
private Long projectId;

@ApiModelProperty("项目名称")
private String projectName;

@ApiModelProperty("实例code")
private String instCode;

@ApiModelProperty("流程状态")
private Integer processStatus;

@ApiModelProperty("项目阶段")
private Integer stage;

@ApiModelProperty("项目状态")
private Integer status;

@ApiModelProperty("备注")
private String remark;

@ApiModelProperty("重试次数")
private Integer retryTimes;

@ApiModelProperty("是否死信")
private Boolean dead;

@ApiModelProperty("下次扫描时间")
private LocalDateTime nextTime;

@ApiModelProperty("创建时间")
private LocalDateTime createOn;

@ApiModelProperty("修改时间")
private LocalDateTime updateOn;
}

+ 18
- 0
pmapi/src/main/java/com/ningdatech/pmapi/staging/serivice/IProjectStagingService.java View File

@@ -0,0 +1,18 @@
package com.ningdatech.pmapi.staging.serivice;

import com.baomidou.mybatisplus.extension.service.IService;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.staging.model.entity.ProjectStaging;

/**
* @Classname IProjectStagingService
* @Description
* @Date 2023/2/20 10:08
* @Author PoffyZhang
*/
public interface IProjectStagingService extends IService<ProjectStaging> {

Boolean addRetryTimes(ProjectStaging projectStaging);

public Boolean addByProject(Project project,String remark) ;
}

+ 77
- 0
pmapi/src/main/java/com/ningdatech/pmapi/staging/serivice/impl/ProjectStagingServiceImpl.java View File

@@ -0,0 +1,77 @@
package com.ningdatech.pmapi.staging.serivice.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.staging.contants.StagingContant;
import com.ningdatech.pmapi.staging.mapper.ProjectStagingMapper;
import com.ningdatech.pmapi.staging.model.entity.ProjectStaging;
import com.ningdatech.pmapi.staging.serivice.IProjectStagingService;
import com.ningdatech.pmapi.staging.utils.ProjectStatusFlowMapUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

/**
* <p>
* 服务实现类
* </p>
*
* @author zpf
* @since 2023-02-18
*/
@Service
@Slf4j
@RequiredArgsConstructor
public class ProjectStagingServiceImpl extends ServiceImpl<ProjectStagingMapper, ProjectStaging> implements IProjectStagingService {

private final ProjectStagingMapper mapper;

private final ProjectStatusFlowMapUtil projectStatusFlowMapUtil;

/**
* 在某些状态节点 增加一个项目到状态暂存库
* @param project
* @return
*/
@Override
public Boolean addByProject(Project project,String remark) {
ProjectStaging projectStaging = ProjectStaging.builder()
.projectId(project.getId())
.projectName(project.getProjectName())
.stage(project.getStage())
.status(project.getStatus())
.createOn(LocalDateTime.now())
.updateOn(LocalDateTime.now())
.instCode(project.getInstCode())
.processStatus(project.getProcessStatus())
.nextTime(LocalDateTime.now())
.retryTimes(0)
.remark(remark)
.build();
return this.save(projectStaging);
}

/**
* 增加 重试次数 和下次扫描时间
* @param projectStaging
* @return
*/
@Override
public Boolean addRetryTimes(ProjectStaging projectStaging) {
Integer retryTimes = projectStaging.getRetryTimes() + 1;
if(!projectStatusFlowMapUtil.intervalTimeMap.containsKey(retryTimes)){
log.info("没有对应重试间隔时间 添加重试信息失败");
return Boolean.FALSE;
}
Integer addSeconds = projectStatusFlowMapUtil.intervalTimeMap.get(retryTimes);
Boolean dead = Boolean.FALSE;
//超过重试最大次数 dead置为 true
if(retryTimes.compareTo(StagingContant.Retry.MAX_RETRY_TIMES) > 0){
dead = Boolean.TRUE;
}
LocalDateTime nextRetryTime = LocalDateTime.now().plusSeconds(addSeconds);
return mapper.addRetryTimes(projectStaging.getId(),retryTimes,nextRetryTime,dead);
}
}

+ 69
- 0
pmapi/src/main/java/com/ningdatech/pmapi/staging/utils/ProjectStatusFlowMapUtil.java View File

@@ -0,0 +1,69 @@
package com.ningdatech.pmapi.staging.utils;

import com.google.common.collect.Maps;
import com.ningdatech.pmapi.projectdeclared.manage.ConstructionPlanManage;
import com.ningdatech.pmapi.projectdeclared.manage.DeclaredProjectManage;
import com.ningdatech.pmapi.projectdeclared.manage.PrequalificationDeclaredProjectManage;
import com.ningdatech.pmapi.projectdeclared.manage.ReviewByProvincialDeptManage;
import com.ningdatech.pmapi.projectdeclared.model.dto.DefaultDeclaredDTO;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.staging.model.entity.ProjectStaging;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.function.Function;

/**
* @Classname ProjectStatusFlowMapUtil
* @Description 状态流转 事件函数MAP
* @Date 2023/2/15 11:19
* @Author PoffyZhang
*/
@Component
@RequiredArgsConstructor
public class ProjectStatusFlowMapUtil {
private final ReviewByProvincialDeptManage provincialDeptManage;

private final ReviewByProvincialDeptManage provincialDeptManage;

public Map<Integer, Function<Project,Boolean>> statusFlowFunctionMap = Maps.newHashMap();
/**
* key 重试的次数 , value 是增加是描述
*/
public Map<Integer, Integer> intervalTimeMap = Maps.newHashMap();

/**
* 初始化业务分派逻辑,代替了if-else部分
* key: 枚举 状态值
* value: lambda表达式,最终会获取发起实例的函数
*/
@PostConstruct
public void statusFlowFunctionInit(){
//省级部门联审
statusFlowFunctionMap.put(ProjectStatusEnum.JOINT_REVIEW_BY_PROVINCIAL_DEPARTMENTS.getCode(),
project->provincialDeptManage.startTheProcess(project));
//部门联审
statusFlowFunctionMap.put(ProjectStatusEnum.DEPARTMENT_JOINT_REVIEW.getCode(),
project->provincialDeptManage.startTheProcess(project));
}

/**
* 扫描的间隔越来越长 秒数
*/
@PostConstruct
public void intervalTimeMapInit(){
intervalTimeMap.put(1,60 * 2);
intervalTimeMap.put(2,60 * 6);
intervalTimeMap.put(3,60 * 15);
intervalTimeMap.put(4,60 * 30);
intervalTimeMap.put(5,60 * 60);
intervalTimeMap.put(6,60 * 60 * 2);
intervalTimeMap.put(7,60 * 60 * 5);
intervalTimeMap.put(8,60 * 60 * 12);
intervalTimeMap.put(9,60 * 60 * 24);
intervalTimeMap.put(10,60 * 60 * 72);
}
}

+ 0
- 11
pmapi/src/test/resources/application-dev.yml View File

@@ -87,17 +87,6 @@ spring:
wall:
config:
multi-statement-allow: true
# rabbitmq 配置信息
rabbitmq:
host: 110.40.194.60
port: 5672
username: admin
password: admin
#1、确保消息从发送端到服务端投递可靠(分为以下两个步骤)
#1.1、确认消息已发送到交换机(Exchange) 可以把publisher-confirms: true 替换为 publisher-confirm-type: correlate
publisher-confirm-type: correlated
#1.2、确认消息从交换机中到队列中
publisher-returns: true

mybatis-plus:
configuration:


+ 0
- 5
pom.xml View File

@@ -150,11 +150,6 @@
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.ningdatech</groupId>
<artifactId>nd-rabbitmq-starter</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.6</version>


Loading…
Cancel
Save