Browse Source

Merge remote-tracking branch 'origin/master'

master
niohe·erbao 1 year ago
parent
commit
823cf0cd12
84 changed files with 2015 additions and 621 deletions
  1. +5
    -0
      pmapi/pom.xml
  2. +7
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/common/constant/CommonConst.java
  3. +13
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/action/ProjectDeclareAction.java
  4. +3
    -3
      pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineBuilder.java
  5. +13
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/event/ProjectStatusChangeEvent.java
  6. +4
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/common/util/BizUtils.java
  7. +2
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/datascope/provider/DataScopeContext.java
  8. +15
    -3
      pmapi/src/main/java/com/ningdatech/pmapi/expert/controller/ExpertReviewController.java
  9. +64
    -7
      pmapi/src/main/java/com/ningdatech/pmapi/expert/manage/ExpertReviewManage.java
  10. +2
    -2
      pmapi/src/main/java/com/ningdatech/pmapi/expert/manage/ReviewTemplateSettingsManage.java
  11. +40
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/expert/model/vo/ProjectReviewDetailVO.java
  12. +2
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IExpertReviewService.java
  13. +13
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IExpertUserFullInfoService.java
  14. +2
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/expert/service/impl/ExpertReviewServiceImpl.java
  15. +5
    -8
      pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/domain/ExpertLeave.java
  16. +7
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/leave/manage/LeaveManage.java
  17. +24
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/constant/MeetingMsgTemplateConst.java
  18. +10
    -3
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingController.java
  19. +3
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/MeetingExpert.java
  20. +28
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ConfirmedRosterReq.java
  21. +5
    -4
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertRemoveReq.java
  22. +28
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertReplaceReq.java
  23. +2
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingDetailBasicVO.java
  24. +151
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/MeetingMsgHelper.java
  25. +67
    -16
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/ExpertInviteManage.java
  26. +55
    -7
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java
  27. +14
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertMapper.java
  28. +9
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertMapper.xml
  29. +3
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/IMeetingExpertService.java
  30. +9
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/IMeetingInnerProjectService.java
  31. +1
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/impl/ExpertInviteAvoidRuleServiceImpl.java
  32. +6
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/impl/MeetingExpertServiceImpl.java
  33. +10
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/impl/MeetingInnerProjectServiceImpl.java
  34. +1
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertCallResultRewriteTask.java
  35. +3
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertInviteTask.java
  36. +6
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/RandomInviteProperties.java
  37. +12
    -2
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ConstructionPlanManage.java
  38. +28
    -75
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DeclaredProjectManage.java
  39. +36
    -3
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DefaultDeclaredProjectManage.java
  40. +19
    -10
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/PrequalificationDeclaredProjectManage.java
  41. +5
    -4
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ProjectAdjustmentManage.java
  42. +9
    -5
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ReviewByDeptJointManage.java
  43. +24
    -4
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ReviewByProvincialDeptManage.java
  44. +3
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/model/entity/ProjectDraft.java
  45. +2
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/model/vo/ProjectDraftVO.java
  46. +6
    -6
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/utils/GenerateProjectCodeUtil.java
  47. +6
    -6
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/constant/ImportTemplateConstant.java
  48. +10
    -4
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/controller/AnnualPlanController.java
  49. +6
    -5
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/enumeration/ProjectLibFlagEnum.java
  50. +22
    -6
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/ConstructionPlanReviewHandle.java
  51. +5
    -2
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/DeptUnitedReviewHandle.java
  52. +25
    -4
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/PreliminaryPreviewHandle.java
  53. +29
    -5
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/UnitInnerAuditHandle.java
  54. +224
    -155
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/manage/AnnualPlanLibManage.java
  55. +209
    -6
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/manage/ProjectLibManage.java
  56. +102
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/dto/AnnualLibExportDTO.java
  57. +66
    -52
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/dto/AnnualLibImportDTO.java
  58. +3
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/dto/ProjectDTO.java
  59. +92
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/entity/AnalysisEventMonitor.java
  60. +5
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/entity/Project.java
  61. +1
    -4
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/req/ProjectListReq.java
  62. +3
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/vo/AnnualPlanListItemVO.java
  63. +6
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/vo/ProjectDetailVO.java
  64. +92
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/utils/ProjectVersionUtil.java
  65. +5
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/CheckProvincialReviewResultTask.java
  66. +0
    -10
      pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/WorkNoticeFlowTask.java
  67. +14
    -5
      pmapi/src/main/java/com/ningdatech/pmapi/staging/service/INdWorkNoticeStagingService.java
  68. +38
    -4
      pmapi/src/main/java/com/ningdatech/pmapi/staging/service/impl/NdWorkNoticeStagingServiceImpl.java
  69. +4
    -4
      pmapi/src/main/java/com/ningdatech/pmapi/staging/service/impl/ProjectStagingServiceImpl.java
  70. +0
    -22
      pmapi/src/main/java/com/ningdatech/pmapi/staging/utils/ProjectStatusFlowMapUtil.java
  71. +45
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/staging/utils/ProjectStatusFlowUtil.java
  72. +4
    -3
      pmapi/src/main/java/com/ningdatech/pmapi/staging/utils/WorkNoticeFlowMapUtil.java
  73. +152
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/sys/manage/NoticeManage.java
  74. +5
    -5
      pmapi/src/main/java/com/ningdatech/pmapi/sys/manage/NotifyManage.java
  75. +37
    -146
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/HandlerManage.java
  76. +3
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java
  77. +2
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/manage/UserInfoManage.java
  78. +3
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/model/vo/ResUserDetailVO.java
  79. +2
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/workbench/manage/WorkbenchManage.java
  80. BIN
      pmapi/src/main/resources/template/丽水市2023年数字化项目年度计划编辑表.xls
  81. +11
    -1
      pmapi/src/test/java/com/ningdatech/pmapi/statemachine/StateMachineTest.java
  82. +2
    -1
      pmapi/src/test/java/com/ningdatech/pmapi/todocenter/TodoCenterTest.java
  83. +6
    -0
      pom.xml
  84. BIN
      template/丽水市2023年数字化项目年度计划编辑表.xls

+ 5
- 0
pmapi/pom.xml View File

@@ -262,6 +262,11 @@
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
</dependency>
<!--导入导出-->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
</dependency>


</dependencies>


+ 7
- 0
pmapi/src/main/java/com/ningdatech/pmapi/common/constant/CommonConst.java View File

@@ -32,6 +32,7 @@ public interface CommonConst {
String ARCHIVED = "归档";

String FILE_NAME = "name";
String BASIS_FILE_NAME = "fileName";

String NULL = "null";

@@ -45,6 +46,12 @@ public interface CommonConst {
String NEW_CONSTRUCTION = "新建";
String CONTINUED_CONSTRUCTION = "续建";
String MONTH = "月";
String ZHI = "至";
String YEAR = "年";

Integer VERSION_ONE = 1;
Integer VERSION_SIZE = 2;
Integer VERSION_JUDGE = -1;





+ 13
- 1
pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/action/ProjectDeclareAction.java View File

@@ -44,7 +44,7 @@ public class ProjectDeclareAction {
}

@OnTransition(source = "UNDER_INTERNAL_AUDIT_NOT_PASS", target = "UNDER_INTERNAL_AUDIT")
public void UNDER_INTERNAL_RESUBMIT(Message<ProjectStatusChangeEvent> message) {
public void UNDER_INTERNAL_REJECT_RESUBMIT(Message<ProjectStatusChangeEvent> message) {
Project project = (Project) message.getHeaders().get(PROJECT_DECLARE);
project.setStatus(ProjectStatusEnum.UNDER_INTERNAL_AUDIT.getCode());
}
@@ -99,6 +99,12 @@ public class ProjectDeclareAction {
project.setStatus(ProjectStatusEnum.PREQUALIFICATION_FAILED.getCode());
}

@OnTransition(source = "PREQUALIFICATION_FAILED", target = "PENDING_PREQUALIFICATION_CHOICE")
public void PRELIMINARY_REVIEW_REJECT_RESUBMIT(Message<ProjectStatusChangeEvent> message) {
Project project = (Project) message.getHeaders().get(PROJECT_DECLARE);
project.setStatus(ProjectStatusEnum.PENDING_PREQUALIFICATION_CHOICE.getCode());
}

@OnTransition(source = "PRE_APPLYING", target = "PREQUALIFICATION_WITHDRAW_CHOICE")
public void PRE_APPLYING_WITHDRAW(Message<ProjectStatusChangeEvent> message) {
Project project = (Project) message.getHeaders().get(PROJECT_DECLARE);
@@ -174,6 +180,12 @@ public class ProjectDeclareAction {
project.setStatus(ProjectStatusEnum.SCHEME_REVIEW_FAILED.getCode());
}

@OnTransition(source = "SCHEME_REVIEW_FAILED", target = "SCHEME_UNDER_REVIEW")
public void PLAN_REVIEW_REJECT_RESUBMIT(Message<ProjectStatusChangeEvent> message) {
Project project = (Project) message.getHeaders().get(PROJECT_DECLARE);
project.setStatus(ProjectStatusEnum.SCHEME_UNDER_REVIEW.getCode());
}

@OnTransition(source = "SCHEME_UNDER_REVIEW", target = "PLAN_TO_BE_DECLARED")
public void SCHEME_UNDER_REVIEW_WITHDRAW(Message<ProjectStatusChangeEvent> message) {
Project project = (Project) message.getHeaders().get(PROJECT_DECLARE);


+ 3
- 3
pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineBuilder.java View File

@@ -86,7 +86,7 @@ public class ProjectDeclareStateMachineBuilder {
.withExternal()
.source(ProjectStatusEnum.UNDER_INTERNAL_AUDIT_NOT_PASS)
.target(ProjectStatusEnum.UNDER_INTERNAL_AUDIT)
.event(ProjectStatusChangeEvent.PROJECT_APPLICATION_SUBMIT).and()
.event(ProjectStatusChangeEvent.UNDER_INTERNAL_REJECT_RESUBMIT).and()

// 待预审预审申报,从待预审到待预审选择
.withExternal()
@@ -145,7 +145,7 @@ public class ProjectDeclareStateMachineBuilder {
.withExternal()
.source(ProjectStatusEnum.PREQUALIFICATION_FAILED)
.target(ProjectStatusEnum.PENDING_PREQUALIFICATION_CHOICE)
.event(ProjectStatusChangeEvent.PRELIMINARY_REVIEW_DECLARE).and()
.event(ProjectStatusChangeEvent.PRELIMINARY_REVIEW_REJECT_RESUBMIT).and()
// 预审不通过重新提交,从待预审选择->省级部门联审中,预审中,完成其中一种状态
.withChoice()
.source(ProjectStatusEnum.PENDING_PREQUALIFICATION_CHOICE)
@@ -200,7 +200,7 @@ public class ProjectDeclareStateMachineBuilder {
.withExternal()
.source(ProjectStatusEnum.SCHEME_REVIEW_FAILED)
.target(ProjectStatusEnum.SCHEME_UNDER_REVIEW)
.event(ProjectStatusChangeEvent.DECLARE_PLAN).and()
.event(ProjectStatusChangeEvent.PLAN_REVIEW_REJECT_RESUBMIT).and()
// 待立项批复批复,从待立项批复到待采购
.withExternal()
.source(ProjectStatusEnum.TO_BE_APPROVED)


+ 13
- 0
pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/event/ProjectStatusChangeEvent.java View File

@@ -36,6 +36,11 @@ public enum ProjectStatusChangeEvent {
*/
UNDER_INTERNAL_PASS(ProjectStatusEnum.UNDER_INTERNAL_AUDIT.getCode(), null, null),
/**
* 单位内部审核不通过重新提交(项目状态进入:单位内部审核中)
*/
UNDER_INTERNAL_REJECT_RESUBMIT(ProjectStatusEnum.UNDER_INTERNAL_AUDIT_NOT_PASS.getCode(),null,null),

/**
* 预审申报(项目状态进入:待预审选择,有判断条件:市级项目且申报金额大于1000万项目状态变为:省级部门联审中;否则项目状态变为:预审中)
*/
PRELIMINARY_REVIEW_DECLARE(ProjectStatusEnum.PENDING_PREQUALIFICATION.getCode(), null, null),
@@ -57,6 +62,10 @@ public enum ProjectStatusChangeEvent {
*/
PRELIMINARY_REVIEW_REJECT(null, ProjectStatusEnum.PRE_APPLYING.getCode(), null),
/**
* 预审不通过重新提交(项目状态变为:待预审选择)
*/
PRELIMINARY_REVIEW_REJECT_RESUBMIT(ProjectStatusEnum.PREQUALIFICATION_FAILED.getCode(),null,null),
/**
* 预审通过(项目状态变为:部门联审中)
*/
PRELIMINARY_REVIEW_PASS(ProjectStatusEnum.PRE_APPLYING.getCode(), null, null),
@@ -85,6 +94,10 @@ public enum ProjectStatusChangeEvent {
*/
PLAN_REVIEW_REJECT(null, ProjectStatusEnum.SCHEME_UNDER_REVIEW.getCode(), null),
/**
* 方案评审不通过重新提交(项目状态变为:方案评审中)
*/
PLAN_REVIEW_REJECT_RESUBMIT(ProjectStatusEnum.SCHEME_REVIEW_FAILED.getCode(),null,null),
/**
* 方案评审通过(项目状态变为:待立项批复)
*/
PLAN_REVIEW_PASS(ProjectStatusEnum.SCHEME_UNDER_REVIEW.getCode(), null, null),


+ 4
- 0
pmapi/src/main/java/com/ningdatech/pmapi/common/util/BizUtils.java View File

@@ -105,4 +105,8 @@ public class BizUtils {
})));
}

public static String inSqlJoin(List<String> strings) {
return strings.stream().map(w -> "'" + w + "'").collect(Collectors.joining(StrPool.COMMA, StrPool.LEFT_BRACKET, StrPool.RIGHT_BRACKET));
}

}

+ 2
- 1
pmapi/src/main/java/com/ningdatech/pmapi/datascope/provider/DataScopeContext.java View File

@@ -4,6 +4,7 @@ import com.ningdatech.basic.util.SpringUtils;
import com.ningdatech.pmapi.datascope.model.DataScopeDTO;
import lombok.RequiredArgsConstructor;

import java.io.Serializable;
import java.util.Map;
import java.util.Optional;

@@ -16,7 +17,7 @@ import java.util.Optional;
* @since 2022/1/9 23:28
*/
@RequiredArgsConstructor
public class DataScopeContext {
public class DataScopeContext implements Serializable {

private static final String WARN_MSG = "请先创建数据权限[%s]的实现类,使其实现 DataScopeProvider";



+ 15
- 3
pmapi/src/main/java/com/ningdatech/pmapi/expert/controller/ExpertReviewController.java View File

@@ -5,6 +5,7 @@ import com.ningdatech.log.annotation.WebLog;
import com.ningdatech.pmapi.expert.manage.ExpertReviewManage;
import com.ningdatech.pmapi.expert.model.req.ExpertReviewDetailReq;
import com.ningdatech.pmapi.expert.model.vo.ExpertReviewDetailVO;
import com.ningdatech.pmapi.expert.model.vo.ProjectReviewDetailVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
@@ -38,14 +39,16 @@ public class ExpertReviewController {
expertReviewManage.expertReview(req);
}

@GetMapping("/detail/{projectId}/{userId}")
@GetMapping("/detail/{meetingId}/{projectId}/{userId}")
@ApiOperation("获取专家评审详情")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId", value = "专家ID"),
@ApiImplicitParam(name = "projectId", value = "项目ID")
})
public ExpertReviewDetailVO getExpertReviewDetail(@PathVariable Long userId, @PathVariable Long projectId) {
return expertReviewManage.getExpertReviewDetail(userId, projectId);
public ExpertReviewDetailVO getExpertReviewDetail(@PathVariable Long userId,
@PathVariable Long projectId,
@PathVariable Long meetingId) {
return expertReviewManage.getExpertReviewDetail(userId, projectId, meetingId);
}

@GetMapping("/listForGroupLeader/{projectId}/{meetingId}")
@@ -70,4 +73,13 @@ public class ExpertReviewController {
return expertReviewManage.listReviews(projectId, meetingId, false);
}

@GetMapping("/detail/{projectId}")
@ApiImplicitParams({
@ApiImplicitParam(name = "projectId", value = "项目ID"),
})
@ApiOperation("查看项目的所有评审意见")
public ProjectReviewDetailVO projectExpertReviewDetail(@PathVariable Long projectId) {
return expertReviewManage.projectExpertReviewDetail(projectId);
}

}

+ 64
- 7
pmapi/src/main/java/com/ningdatech/pmapi/expert/manage/ExpertReviewManage.java View File

@@ -10,19 +10,25 @@ import com.ningdatech.file.entity.vo.result.AttachFileVo;
import com.ningdatech.file.service.FileService;
import com.ningdatech.pmapi.expert.model.dto.ReviewTemplateOptionDTO;
import com.ningdatech.pmapi.expert.model.entity.ExpertReview;
import com.ningdatech.pmapi.expert.model.entity.ReviewTemplateSettings;
import com.ningdatech.pmapi.expert.model.req.ExpertReviewDetailReq;
import com.ningdatech.pmapi.expert.model.vo.ExpertReviewDetailVO;
import com.ningdatech.pmapi.expert.model.vo.ProjectReviewDetailVO;
import com.ningdatech.pmapi.expert.model.vo.ReviewTemplateVO;
import com.ningdatech.pmapi.expert.service.IExpertReviewService;
import com.ningdatech.pmapi.expert.service.IReviewTemplateSettingsService;
import com.ningdatech.pmapi.meeting.entity.domain.Meeting;
import com.ningdatech.pmapi.meeting.service.IMeetingExpertService;
import com.ningdatech.pmapi.meeting.service.IMeetingInnerProjectService;
import com.ningdatech.pmapi.meeting.service.IMeetingService;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;

import static com.ningdatech.pmapi.expert.model.vo.ProjectReviewDetailVO.ReviewDetailByTypeVO;
import static com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum.AGREED;

/**
@@ -41,6 +47,9 @@ public class ExpertReviewManage {
private final DistributedLock distributedLock;
private final IMeetingExpertService meetingExpertService;
private final FileService fileService;
private final IMeetingInnerProjectService meetingInnerProjectService;
private final IMeetingService meetingService;
private final IReviewTemplateSettingsService templateSettingsService;

private static final String EXPERT_REVIEW_KEY = "expert_review:";

@@ -65,12 +74,13 @@ public class ExpertReviewManage {
public void expertReview(ExpertReviewDetailReq req) {
Long userId = LoginUserUtil.getUserId();
Long projectId = req.getProjectId();
Long meetingId = req.getMeetingId();
String expertReviewKey = buildExpertReviewKey(projectId, userId);
if (!distributedLock.lock(expertReviewKey)) {
throw BizException.wrap("保存评审意见失败,请重试");
}
try {
List<ExpertReview> reviews = expertReviewService.listByProjectIdAndExpertId(projectId, userId);
List<ExpertReview> reviews = expertReviewService.listByProjectIdAndExpertId(projectId, userId, meetingId);
if (req.getIsFinal()) {
if (reviews.isEmpty()) {
throw BizException.wrap("请先填写个人评审意见");
@@ -109,8 +119,8 @@ public class ExpertReviewManage {
}
}

public ExpertReviewDetailVO getExpertReviewDetail(Long projectId, Long userId) {
List<ExpertReview> reviews = expertReviewService.listByProjectIdAndExpertId(projectId, userId);
public ExpertReviewDetailVO getExpertReviewDetail(Long projectId, Long userId, Long meetingId) {
List<ExpertReview> reviews = expertReviewService.listByProjectIdAndExpertId(projectId, userId, meetingId);
reviews.removeIf(ExpertReview::getIsFinal);
if (reviews.isEmpty()) {
throw BizException.wrap("评审记录不存在");
@@ -141,4 +151,51 @@ public class ExpertReviewManage {
});
}

public ProjectReviewDetailVO projectExpertReviewDetail(Long projectId) {
ProjectReviewDetailVO detail = new ProjectReviewDetailVO();
List<Long> meetingIds = meetingInnerProjectService.listMeetingIdByProjectId(projectId);
if (meetingIds.isEmpty()) {
return detail;
}
List<Meeting> meetings = meetingService.listByIds(meetingIds);
Collection<Long> tmpMeetingIds = meetings.stream()
.collect(Collectors.groupingBy(Meeting::getType,
Collectors.collectingAndThen(Collectors.toList(), w -> {
w.sort(Comparator.comparing(Meeting::getCreateOn));
return w.get(w.size() - 1).getId();
}))).values();
LambdaQueryWrapper<ExpertReview> erQuery = Wrappers.lambdaQuery(ExpertReview.class)
.in(ExpertReview::getMeetingId, tmpMeetingIds)
.eq(ExpertReview::getProjectId, projectId)
.orderByDesc(ExpertReview::getCreateOn);
List<ExpertReview> expertReviews = expertReviewService.list(erQuery);
if (expertReviews.isEmpty()) {
return detail;
}
List<Long> templateIds = CollUtils.fieldList(expertReviews, ExpertReview::getTemplateId);
List<ReviewTemplateSettings> templates = templateSettingsService.listByIds(templateIds);
Map<Long, ReviewTemplateVO> templateMap = CollUtils.listToMap(templates,
ReviewTemplateSettings::getId,
ReviewTemplateSettingsManage::buildTemplateDetail);
detail.setTemplates(templateMap.values());
Map<Integer, ReviewDetailByTypeVO> map = new HashMap<>(8);
expertReviews.forEach(review -> {
ReviewTemplateVO template = templateMap.get(review.getTemplateId());
ReviewDetailByTypeVO reviewDetailByType = map.computeIfAbsent(template.getTemplateType(), k -> {
ReviewDetailByTypeVO tmpReviewDetail = new ReviewDetailByTypeVO();
tmpReviewDetail.setReviewType(k);
tmpReviewDetail.setTeamMemberReviews(new ArrayList<>());
return tmpReviewDetail;
});
ExpertReviewDetailVO tmpReview = buildExpertReviewDetail(review);
if (review.getIsFinal()) {
reviewDetailByType.setFinalReview(tmpReview);
} else {
reviewDetailByType.getTeamMemberReviews().add(tmpReview);
}
});
detail.setReviews(map.values());
return detail;
}

}

+ 2
- 2
pmapi/src/main/java/com/ningdatech/pmapi/expert/manage/ReviewTemplateSettingsManage.java View File

@@ -67,10 +67,10 @@ public class ReviewTemplateSettingsManage {

public List<ReviewTemplateVO> listReviewTemplateSettings(List<Long> templateIds) {
List<ReviewTemplateSettings> settings = reviewTemplateSettingsService.listByIds(templateIds);
return CollUtils.convert(settings, this::buildTemplateDetail);
return CollUtils.convert(settings, ReviewTemplateSettingsManage::buildTemplateDetail);
}

private ReviewTemplateVO buildTemplateDetail(ReviewTemplateSettings settings) {
protected static ReviewTemplateVO buildTemplateDetail(ReviewTemplateSettings settings) {
if (settings == null) {
throw BizException.wrap("模版不存在");
}


+ 40
- 0
pmapi/src/main/java/com/ningdatech/pmapi/expert/model/vo/ProjectReviewDetailVO.java View File

@@ -0,0 +1,40 @@
package com.ningdatech.pmapi.expert.model.vo;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.Collection;
import java.util.List;

/**
* <p>
* ProjectExpertReviewDetailVO
* </p>
*
* @author WendyYang
* @since 2023/4/19
**/
@Data
public class ProjectReviewDetailVO {

@ApiModelProperty("评审模版详情")
private Collection<ReviewTemplateVO> templates;

private Collection<ReviewDetailByTypeVO> reviews;

@Data
public static class ReviewDetailByTypeVO {

@ApiModelProperty("评审类型")
private Integer reviewType;

@ApiModelProperty("最终评审意见")
private ExpertReviewDetailVO finalReview;

@ApiModelProperty("组员评审意见")
private List<ExpertReviewDetailVO> teamMemberReviews;

}


}

+ 2
- 1
pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IExpertReviewService.java View File

@@ -21,10 +21,11 @@ public interface IExpertReviewService extends IService<ExpertReview> {
*
* @param projectId 项目ID
* @param expertId 专家ID
* @param meetingId 会议ID
* @return 评审记录
* @author WendyYang
**/
List<ExpertReview> listByProjectIdAndExpertId(Long projectId, Long expertId);
List<ExpertReview> listByProjectIdAndExpertId(Long projectId, Long expertId, Long meetingId);

/**
* 获取最终评审结果


+ 13
- 1
pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IExpertUserFullInfoService.java View File

@@ -1,8 +1,13 @@
package com.ningdatech.pmapi.expert.service;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo;

import java.util.Collection;
import java.util.List;

/**
@@ -33,7 +38,6 @@ public interface IExpertUserFullInfoService extends IService<ExpertUserFullInfo>
List<ExpertUserFullInfo> listByUserId(List<Long> userId);



/**
* 批量查询专家用户信息
*
@@ -42,4 +46,12 @@ public interface IExpertUserFullInfoService extends IService<ExpertUserFullInfo>
*/
List<ExpertUserFullInfo> listByUserIds(List<Long> userIds);

default List<String> listCompanyUniqCodeByUserIds(Collection<Long> userIds) {
LambdaQueryWrapper<ExpertUserFullInfo> query = Wrappers
.lambdaQuery(ExpertUserFullInfo.class)
.select(ExpertUserFullInfo::getCompanyUniqCode)
.in(ExpertUserFullInfo::getUserId, userIds);
return CollUtils.fieldList(list(query), ExpertUserFullInfo::getCompanyUniqCode);
}

}

+ 2
- 1
pmapi/src/main/java/com/ningdatech/pmapi/expert/service/impl/ExpertReviewServiceImpl.java View File

@@ -25,10 +25,11 @@ import java.util.Map;
public class ExpertReviewServiceImpl extends ServiceImpl<ExpertReviewMapper, ExpertReview> implements IExpertReviewService {

@Override
public List<ExpertReview> listByProjectIdAndExpertId(Long projectId, Long expertId) {
public List<ExpertReview> listByProjectIdAndExpertId(Long projectId, Long expertId, Long meetingId) {
LambdaQueryWrapper<ExpertReview> query = Wrappers.lambdaQuery(ExpertReview.class);
query.eq(ExpertReview::getProjectId, projectId);
query.eq(ExpertReview::getCreateBy, expertId);
query.eq(ExpertReview::getMeetingId, meetingId);
query.orderByAsc(ExpertReview::getCreateOn);
return list(query);
}


+ 5
- 8
pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/domain/ExpertLeave.java View File

@@ -1,8 +1,6 @@
package com.ningdatech.pmapi.leave.entity.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -48,15 +46,19 @@ public class ExpertLeave implements Serializable {
private String creator;

@ApiModelProperty("创建人")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long createBy;

@ApiModelProperty("创建时间")
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createOn;

@ApiModelProperty("修改人")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateBy;

@ApiModelProperty("修改时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateOn;

@ApiModelProperty("请假开始时间")
@@ -75,9 +77,4 @@ public class ExpertLeave implements Serializable {

private Integer status;

public void setUpdateAndCreate(Long createBy, LocalDateTime createOn) {
this.updateBy = this.createBy = createBy;
this.updateOn = this.createOn = createOn;
}

}

+ 7
- 1
pmapi/src/main/java/com/ningdatech/pmapi/leave/manage/LeaveManage.java View File

@@ -150,7 +150,7 @@ public class LeaveManage {
leave.setType(po.getType());
leave.setRemark(po.getPostscript());
leave.setLeaveUserId(leaveUserId);
leave.setUpdateAndCreate(applyUserId, now);
leave.setCreator(LoginUserUtil.getUsername());
List<KeyValDTO<LocalDateTime, LocalDateTime>> leaveDetailTimes = new ArrayList<>();
if (type.equals(LeaveTypeEnum.FIXED_TERM) || type.equals(LeaveTypeEnum.LONG_TERM)) {
boolean fixedTerm = CollUtil.isNotEmpty(po.getFixedType());
@@ -215,6 +215,12 @@ public class LeaveManage {
if (ExpertInviteTypeEnum.RANDOM.eq(meeting.getInviteType())) {
inviteTask.notifyInviteTask(meeting.getId(), Boolean.FALSE);
}
if (meeting.getConfirmedRoster()) {
LambdaUpdateWrapper<Meeting> mUpdate = Wrappers.lambdaUpdate(Meeting.class)
.set(Meeting::getConfirmedRoster, Boolean.FALSE)
.eq(Meeting::getId, meeting.getId());
meetingService.update(mUpdate);
}
// 临时请假无需审核
leave.setAuditId(0L);
leave.setStatus(LeaveStatusEnum.PASSED.getCode());


+ 24
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/constant/MeetingMsgTemplateConst.java View File

@@ -0,0 +1,24 @@
package com.ningdatech.pmapi.meeting.constant;

/**
* <p>
* MeetingMsgConst
* </p>
*
* @author WendyYang
* @since 2023/4/20
**/
public interface MeetingMsgTemplateConst {

/**
* 已结束:自动抽取结束,结束时给会议发起人发送浙政钉工作通知、短信:“注意,xxx会议自动抽取已结束,请及时确认是否召开会议”。
*/
String INVITE_END = "注意,%s会议自动抽取已结束,请及时确认是否召开会议";

/**
* 尊敬的【姓名】专家您好,您于【确认时间】接受了信息化项目评审会议邀请,会议时间:【会议时间】,会议地点:【会议地点】。请准时参加评审会议。如有疑问请联系【联系人】(【联系方式】)。
*/
String CONFIRMED_ROSTER = "尊敬的%s专家您好,您于%s接受了信息化项目评审会议邀请,会议时间:%s,会议地点:%s。请准时参加评审会议。如有疑问请联系%s(%s)。";


}

+ 10
- 3
pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingController.java View File

@@ -153,6 +153,13 @@ public class MeetingController {
meetingManage.confirmAttendByManager(req);
}

@ApiOperation("专家移除")
@PostMapping("/expertRemove")
@WebLog(value = "专家移除")
public void expertRemove(@Valid @RequestBody ExpertRemoveReq req) {
meetingManage.expertRemove(req);
}

@ApiOperation("释放专家")
@PostMapping("/expert/release")
@WebLog(value = "释放专家")
@@ -167,11 +174,11 @@ public class MeetingController {
meetingManage.setUpHeadman(req);
}

@ApiOperation("重发短信")
@ApiOperation("重发短信 | 确认名单")
@PostMapping("/confirmedRoster")
@WebLog(value = "重发短信")
public void resendSms(@RequestBody MeetingCancelReq req) {
meetingManage.confirmedRoster(req.getMeetingId());
public void resendSms(@RequestBody ConfirmedRosterReq req) {
meetingManage.confirmedRoster(req);
}

@GetMapping("/listReviewProject")


+ 3
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/MeetingExpert.java View File

@@ -56,6 +56,9 @@ public class MeetingExpert implements Serializable {
@ApiModelProperty("邀请类型")
private Integer inviteType;

@ApiModelProperty("是否已确认名单")
private Boolean confirmedRoster;

private String submitKey;

@TableField(fill = FieldFill.INSERT)


+ 28
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ConfirmedRosterReq.java View File

@@ -0,0 +1,28 @@
package com.ningdatech.pmapi.meeting.entity.req;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.NotNull;

/**
* <p>
* 会议确认名单实体
* </p>
*
* @author WendyYang
* @since 10:43 2022/8/26
*/
@Data
@ApiModel("会议确认名单实体")
public class ConfirmedRosterReq {

@NotNull(message = "会议ID不能为空")
@ApiModelProperty("会议ID")
private Long meetingId;

@ApiModelProperty
private Boolean reconfirmed;

}

+ 5
- 4
pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertRemoveReq.java View File

@@ -4,6 +4,8 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.NotNull;

/**
* <p>
* ExpertRemovePo
@@ -13,15 +15,14 @@ import lombok.Data;
* @since 08:59 2022/8/10
*/
@Data
@ApiModel("专家移除/替换)实体")
@ApiModel("专家移除实体")
public class ExpertRemoveReq {

@NotNull(message = "会议ID不能为空")
@ApiModelProperty("会议ID")
private Long meetingId;

@ApiModelProperty("专家ID")
private Long expertId;

@NotNull(message = "专家会议ID不能为空")
@ApiModelProperty("专家会议ID")
private Long expertMeetingId;



+ 28
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertReplaceReq.java View File

@@ -0,0 +1,28 @@
package com.ningdatech.pmapi.meeting.entity.req;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
* <p>
* ExpertRemovePo
* </p>
*
* @author WendyYang
* @since 08:59 2022/8/10
*/
@Data
@ApiModel("专家替换实体")
public class ExpertReplaceReq {

@ApiModelProperty("会议ID")
private Long meetingId;

@ApiModelProperty("专家ID")
private Long expertId;

@ApiModelProperty("专家会议ID")
private Long expertMeetingId;

}

+ 2
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingDetailBasicVO.java View File

@@ -36,6 +36,8 @@ public class MeetingDetailBasicVO {
@ApiModelProperty("会议类型名称")
private String typeName;

private String regionCode;

@ApiModelProperty("会议类型代码")
private String meetingType;



+ 151
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/MeetingMsgHelper.java View File

@@ -0,0 +1,151 @@
package com.ningdatech.pmapi.meeting.helper;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.pmapi.meeting.constant.MeetingMsgTemplateConst;
import com.ningdatech.pmapi.meeting.entity.domain.Meeting;
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert;
import com.ningdatech.pmapi.organization.model.entity.DingEmployeeInfo;
import com.ningdatech.pmapi.organization.model.entity.DingOrganization;
import com.ningdatech.pmapi.organization.service.IDingEmployeeInfoService;
import com.ningdatech.pmapi.organization.service.IDingOrganizationService;
import com.ningdatech.pmapi.staging.enums.MsgTypeEnum;
import com.ningdatech.pmapi.staging.service.INdWorkNoticeStagingService;
import com.ningdatech.pmapi.sys.model.entity.Notify;
import com.ningdatech.pmapi.sys.service.INotifyService;
import com.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo;
import com.ningdatech.pmapi.user.entity.UserInfo;
import com.ningdatech.pmapi.user.service.IUserInfoService;
import com.ningdatech.yxt.model.cmd.SendSmsCmd.SendSmsContext;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* <p>
* MeetingMsgHelper
* </p>
*
* @author WendyYang
* @since 2023/4/20
**/
@Component
@AllArgsConstructor
public class MeetingMsgHelper {

private final IUserInfoService userInfoService;
private final YxtCallOrSmsHelper yxtCallOrSmsHelper;
private final INdWorkNoticeStagingService workNoticeStagingService;
private final IDingEmployeeInfoService dingEmployeeInfoService;
private final IDingOrganizationService dingOrganizationService;
private final INotifyService notifyService;

private static String officialTime(LocalDateTime time) {
return time.format(DatePattern.NORM_DATETIME_MINUTE_FORMATTER);
}

private Notify getNotify(Long userId, String msg, MsgTypeEnum type, Map<String, Object> extraPara) {
Notify notify = new Notify();
notify.setUserId(userId);
notify.setContent(msg);
notify.setType(type.name());
notify.setReaded(Boolean.FALSE);
notify.setCreateTime(LocalDateTime.now());
String extraJson = JSON.toJSONString(extraPara);
notify.setExtraInfo(extraJson);
return notify;
}

private WorkNoticeInfo getSendWorkNoticeInfo(Long accountId) {
WorkNoticeInfo workNoticeInfo = new WorkNoticeInfo();
workNoticeInfo.setAccountId(accountId);
// 根据浙政钉用户ID获取部门code
DingEmployeeInfo employeeInfo = dingEmployeeInfoService.getOne(Wrappers.lambdaQuery(DingEmployeeInfo.class)
.eq(DingEmployeeInfo::getAccountId, accountId)
.eq(DingEmployeeInfo::getMainJob, String.valueOf(Boolean.TRUE))
.last("limit 1"));
String organizationCode = employeeInfo.getOrganizationCode();
workNoticeInfo.setOrganizationCode(organizationCode);
// 根据部门code获取部门名称
DingOrganization dingOrganization = dingOrganizationService.getOne(Wrappers.lambdaQuery(DingOrganization.class)
.eq(DingOrganization::getOrganizationCode, organizationCode));
String organizationName = dingOrganization.getOrganizationName();
workNoticeInfo.setOrganizationName(organizationName);
// 构建唯一的消息ID
String bizMsgId = "ZD_WORK_NOTICE_" + StrUtil.UNDERLINE + organizationCode + StrUtil.UNDERLINE
+ organizationName + accountId + StrUtil.UNDERLINE + System.currentTimeMillis();
workNoticeInfo.setBizMsgId(bizMsgId);
String receiverUserId = String.valueOf(accountId);
workNoticeInfo.setReceiverUserId(receiverUserId);
return workNoticeInfo;
}

@Transactional(rollbackFor = Exception.class)
public void sendInviteStopMsg(Long userId, Long meetingId, String meetingName) {
UserInfo info = userInfoService.getById(userId);
String msgContent = String.format(MeetingMsgTemplateConst.INVITE_END, meetingName);
// 音信通消息
SendSmsContext yxtContent = new SendSmsContext();
yxtContent.setContent(msgContent);
yxtContent.setReceiveNumber(info.getMobile());
yxtCallOrSmsHelper.sendSms(yxtContent);
// 发送工作通知
if (info.getAccountId() != null) {
WorkNoticeInfo swn = getSendWorkNoticeInfo(info.getAccountId());
swn.setMsg(msgContent);
workNoticeStagingService.addByWorkNotice(swn, MsgTypeEnum.REVIEW_MEETING);
Map<String, Object> map = new HashMap<>();
map.put("meetingId", meetingId);
Notify notify = getNotify(userId, msgContent, MsgTypeEnum.REVIEW_MEETING, map);
notifyService.save(notify);
}
}

@Transactional(rollbackFor = Exception.class)
public void sendConfirmedRosterMsg(List<MeetingExpert> experts, Meeting meeting) {
List<Long> userIds = CollUtils.fieldList(experts, MeetingExpert::getExpertId);
List<UserInfo> userInfos = userInfoService.listByIds(userIds);
Map<Long, UserInfo> userMap = CollUtils.listToMap(userInfos, UserInfo::getId);
String sTime = officialTime(meeting.getStartTime());
String eTime = officialTime(meeting.getEndTime());
String meetingTime = sTime + "至" + eTime;
List<SendSmsContext> yxtContents = new ArrayList<>();
List<Notify> notifies = new ArrayList<>();
List<WorkNoticeInfo> workingNotices = new ArrayList<>();
experts.forEach(w -> {
String msgContent = String.format(MeetingMsgTemplateConst.CONFIRMED_ROSTER,
w.getExpertName(), officialTime(w.getCreateOn()), meetingTime, meeting.getMeetingAddress(),
meeting.getConnecter(), meeting.getContact());
// 音信通消息
SendSmsContext yxtContent = new SendSmsContext();
yxtContent.setContent(msgContent);
yxtContent.setReceiveNumber(w.getMobile());
yxtContents.add(yxtContent);
UserInfo info = userMap.get(w.getExpertId());
// 发送工作通知
if (info.getAccountId() != null) {
WorkNoticeInfo swn = getSendWorkNoticeInfo(info.getAccountId());
swn.setMsg(msgContent);
workingNotices.add(swn);
Map<String, Object> map = new HashMap<>();
map.put("meetingId", meeting.getId());
Notify notify = getNotify(info.getId(), msgContent, MsgTypeEnum.EXPERT_REVIEW, map);
notifies.add(notify);
}
});
notifyService.saveBatch(notifies);
yxtCallOrSmsHelper.sendSms(yxtContents);
workNoticeStagingService.addByWorkNotice(workingNotices, MsgTypeEnum.EXPERT_REVIEW);
}


}

+ 67
- 16
pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/ExpertInviteManage.java View File

@@ -70,6 +70,9 @@ public class ExpertInviteManage {
@Value("#{randomInviteProperties.recentMeetingCount}")
private Integer recentMeetingCount;

@Value("#{randomInviteProperties.recentDays}")
private Integer recentDays;

private static final Predicate<Collection<?>> COLL_EMPTY = (coll) -> coll != null && coll.isEmpty();

private LambdaQueryWrapper<ExpertUserFullInfo> buildBaseExpertQuery() {
@@ -83,6 +86,36 @@ public class ExpertInviteManage {
.eq(ExpertUserFullInfo::getExpertAccountStatus, ExpertAccountStatusEnum.AVAILABLE.getKey());
}

private void buildAvoidCompanyAndBusinessStrip(LambdaQueryWrapper<ExpertUserFullInfo> query, List<String> units, List<String> strips) {
if (CollUtil.isNotEmpty(units)) {
String unitStr = BizUtils.inSqlJoin(units);
query.notExists("select 1 from expert_avoid_company eac where eac.user_id = nd_expert_user_full_info.user_id" +
" and company_uniq_code in " + unitStr);
}
if (CollUtil.isNotEmpty(strips)) {
String orgStr = BizUtils.inSqlJoin(strips);
query.notExists("select 1 from expert_gov_business_strip egbs where egbs.expert_user_id = nd_expert_user_full_info.user_id" +
" and business_strip_code in " + orgStr);
}
}

/**
* 获取一周内被抽中并同意参会的专家ID
*
* @param agreeCnt 一周内被抽中并同意参会次数
* @param sTime 会议开始时间
* @param days 天数
* @return java.util.List<java.lang.Long>
* @author WendyYang
**/
private List<Long> listAgreedUserIdByRecentMeetings(int agreeCnt, int days, LocalDateTime sTime) {
if (agreeCnt == 0 || days == 0) {
return Collections.emptyList();
}
LocalDateTime beginLimit = sTime.minusDays(days);
return meetingExpertService.listAgreeExpertIdByRecentDaysAndAgreeCount(agreeCnt, beginLimit, sTime);
}

/**
* 增加专家层级限制
*
@@ -249,13 +282,13 @@ public class ExpertInviteManage {
*
* @param avoidRule 回避信息
* @param randomRule 抽取规则
* @param appointExpertIds 指定抽取专家ID
* @param invitedExpertIds 指定抽取专家ID
* @return 满足抽取条件的专家
* @author WendyYang
**/
public ExpertChooseDTO expertInviteByRandomRule(AvoidRuleDTO avoidRule,
RandomInviteRuleDTO randomRule,
List<Long> appointExpertIds,
List<Long> invitedExpertIds,
LocalDateTime sTime,
LocalDateTime eTime) {
ExpertChooseDTO result = new ExpertChooseDTO(new ArrayList<>(), 0);
@@ -265,17 +298,19 @@ public class ExpertInviteManage {
}
boolean avoidExpert = CollUtil.isNotEmpty(avoidRule.getExpertIds());
boolean avoidCompany = CollUtil.isNotEmpty(avoidRule.getAvoidUnitIdList());
Set<String> tmpAvoidCompany = new HashSet<>();
Set<String> avoidCompanyUniqCodes = new HashSet<>();
if (avoidCompany) {
tmpAvoidCompany.addAll(avoidRule.getAvoidUnitIdList());
avoidCompanyUniqCodes.addAll(avoidRule.getAvoidUnitIdList());
}
if (CollUtil.isNotEmpty(invitedExpertIds)) {
List<String> tmpCompanyUniqCodes = expertUserFullInfoService.listCompanyUniqCodeByUserIds(invitedExpertIds);
avoidCompanyUniqCodes.addAll(tmpCompanyUniqCodes);
}
// 回避信息
LambdaQueryWrapper<ExpertUserFullInfo> query = buildBaseExpertQuery();
query.notIn(!tmpAvoidCompany.isEmpty(), ExpertUserFullInfo::getCompanyUniqCode, tmpAvoidCompany);
if (avoidCompany) {
query.notExists("select 1 from expert_avoid_company eac where eac.user_id = nd_expert_user_full_info.user_id" +
" and company_uniq_code in ({0})", CollUtils.joinByComma(avoidRule.getAvoidUnitIdList()));
}
query.notIn(!avoidCompanyUniqCodes.isEmpty(), ExpertUserFullInfo::getCompanyUniqCode, avoidCompanyUniqCodes);
// 处理回避单位与回避条线
buildAvoidCompanyAndBusinessStrip(query, avoidRule.getAvoidUnitIdList(), avoidRule.getAvoidOrgIdList());
Set<Long> expertIdsIn = new HashSet<>();
Set<Long> expertIdsNotIn = new HashSet<>();
if (CollUtil.isNotEmpty(merge.getExpertIdsIn())) {
@@ -283,6 +318,12 @@ public class ExpertInviteManage {
} else if (CollUtil.isNotEmpty(merge.getExpertIdsNotIn())) {
expertIdsNotIn.addAll(merge.getExpertIdsNotIn());
}
// 处理回避专家次数
if (avoidRule.getWeekInviteCount() != null) {
Integer weekInviteCount = avoidRule.getWeekInviteCount();
List<Long> tmpExpertIdsNotIn = listAgreedUserIdByRecentMeetings(weekInviteCount, recentDays, sTime);
expertIdsNotIn.addAll(tmpExpertIdsNotIn);
}
// 处理专家层级
addRegionLimit(query, randomRule);
if (!expertIdsIn.isEmpty()) {
@@ -293,8 +334,8 @@ public class ExpertInviteManage {
return result;
}
}
if (CollUtil.isNotEmpty(appointExpertIds)) {
expertIdsIn.removeIf(appointExpertIds::contains);
if (CollUtil.isNotEmpty(invitedExpertIds)) {
expertIdsIn.removeIf(invitedExpertIds::contains);
if (expertIdsIn.isEmpty()) {
return result;
}
@@ -305,8 +346,8 @@ public class ExpertInviteManage {
if (expertIdsIn.isEmpty()) {
return result;
}
} else if (avoidExpert || CollUtil.isNotEmpty(appointExpertIds)) {
Set<Long> tmpExpert = expertInviteHelper.getAvoidExpert(appointExpertIds, avoidRule, sTime, eTime);
} else if (avoidExpert || CollUtil.isNotEmpty(invitedExpertIds)) {
Set<Long> tmpExpert = expertInviteHelper.getAvoidExpert(invitedExpertIds, avoidRule, sTime, eTime);
expertIdsNotIn.addAll(tmpExpert);
} else {
Set<Long> tmpNotInUserIds = expertInviteHelper.listExpertLeaveOrInvited(sTime, eTime);
@@ -365,8 +406,14 @@ public class ExpertInviteManage {
LambdaQueryWrapper<ExpertUserFullInfo> query = buildBaseExpertQuery();
// 设置回避单位
Set<String> notInCompanyUniqCodeList = new HashSet<>(avoidRule.getAvoidUnitIdList());
query.notExists("select 1 from expert_avoid_company eac where eac.user_id = nd_expert_user_full_info.user_id" +
" and company_uniq_code in ({0})", CollUtils.joinByComma(avoidRule.getAvoidUnitIdList()));
// 处理回避单位与回避条线
buildAvoidCompanyAndBusinessStrip(query, avoidRule.getAvoidUnitIdList(), avoidRule.getAvoidOrgIdList());
// 处理回避专家次数
if (avoidRule.getWeekInviteCount() != null) {
Integer weekInviteCount = avoidRule.getWeekInviteCount();
List<Long> tmpExpertIdsNotIn = listAgreedUserIdByRecentMeetings(weekInviteCount, recentDays, msTime);
expertIdsNotIn.addAll(tmpExpertIdsNotIn);
}
// 处理专家层级
addRegionLimit(query, randomRule);

@@ -403,7 +450,11 @@ public class ExpertInviteManage {
List<String> tmpUniqCompanyCodes = CollUtils.fieldList(agreeOrNoticingUserInfos, ExpertUserFullInfo::getCompanyUniqCode);
notInCompanyUniqCodeList.addAll(tmpUniqCompanyCodes);
}

// 已请假的专家不再抽取
List<MeetingExpert> expertsOnLeave = expertGroupByStatus.get(ON_LEAVE);
if (CollUtil.isNotEmpty(expertsOnLeave)) {
expertIdsNotIn.addAll(CollUtils.fieldList(expertsOnLeave, MeetingExpert::getExpertId));
}
// 处理已拒绝专家与重复抽取
BizUtils.notEmpty(expertGroupByStatus.get(REFUSED), refuseExperts -> {
List<Long> tmpExpertIdsNotIn;


+ 55
- 7
pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java View File

@@ -36,6 +36,7 @@ import com.ningdatech.pmapi.meeting.entity.req.*;
import com.ningdatech.pmapi.meeting.entity.vo.*;
import com.ningdatech.pmapi.meeting.helper.ExpertInviteHelper;
import com.ningdatech.pmapi.meeting.helper.MeetingManageHelper;
import com.ningdatech.pmapi.meeting.helper.MeetingMsgHelper;
import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper;
import com.ningdatech.pmapi.meeting.service.*;
import com.ningdatech.pmapi.meeting.task.ExpertInviteTask;
@@ -60,6 +61,7 @@ import java.util.function.BiFunction;
import java.util.stream.Collectors;

import static com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum.*;
import static com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteTypeEnum.APPOINT;
import static com.ningdatech.pmapi.meeting.helper.ExpertInviteHelper.getExpertInviteRule;

/**
@@ -95,6 +97,7 @@ public class MeetingManage {
private final IDingOrganizationService dingOrganizationService;
private final IExpertReviewService expertReviewService;
private final ExpertInviteHelper expertInviteHelper;
private final MeetingMsgHelper meetingMsgHelper;
private static final String INVITED_RULE_CREATE = "INVITED_RULE_CREATE:";

private static final String MEETING_CREATE_KEY = "MEETING_CREATE:";
@@ -199,7 +202,7 @@ public class MeetingManage {
}
expertInviteTask.cancelByMeetingId(meetingId);
LambdaUpdateWrapper<Meeting> meetingUpdate = Wrappers.lambdaUpdate(Meeting.class)
.set(Meeting::getInviteType, ExpertInviteTypeEnum.APPOINT.getCode())
.set(Meeting::getInviteType, APPOINT.getCode())
.eq(Meeting::getId, meetingId);
meetingService.update(meetingUpdate);
saveAppointRuleByConvertFromRandomRule(meetingId);
@@ -212,7 +215,7 @@ public class MeetingManage {
AppointInviteRuleDTO rule = new AppointInviteRuleDTO();
rule.setInviteDesc("转为指定抽取");
rule.setExpertIdList(Collections.emptyList());
rule.setInviteType(ExpertInviteTypeEnum.APPOINT.getCode());
rule.setInviteType(APPOINT.getCode());
rule.setCount(0);
ExpertInviteRule inviteRule = new ExpertInviteRule();
inviteRule.setMeetingId(meetingId);
@@ -410,6 +413,7 @@ public class MeetingManage {
Assert.notNull(meeting, "会议不存在");
MeetingDetailBasicVO detail = MeetingDetailBasicVO.builder()
.meetingId(meeting.getId())
.regionCode(meeting.getRegionCode())
.meetingName(meeting.getName())
.meetingType(meeting.getType())
.meetingAddress(meeting.getMeetingAddress())
@@ -481,7 +485,7 @@ public class MeetingManage {
item.setRuleId(me.getRuleId());
item.setIsHeadman(me.getIsHeadman());
ExpertInviteRule rule = ruleMap.get(me.getRuleId());
item.setInviteType(rule == null ? ExpertInviteTypeEnum.APPOINT.getCode() : rule.getInviteType());
item.setInviteType(rule == null ? APPOINT.getCode() : rule.getInviteType());
if (NOTICING.eq(me.getStatus())) {
item.setNoticeStatus("通知中");
} else {
@@ -577,6 +581,7 @@ public class MeetingManage {
});
AvoidRuleDTO avoidInfo = inviteAvoidRuleService.getAvoidInfoDto(meetingId);
AvoidInfoVO vo = new AvoidInfoVO();
vo.setWeekInviteCount(avoidInfo.getWeekInviteCount());
vo.setAvoidOrgIds(avoidInfo.getAvoidOrgIdList());
vo.setAvoidUnitIds(avoidInfo.getAvoidUnitIdList());
if (CollUtil.isNotEmpty(vo.getAvoidOrgIds())) {
@@ -590,7 +595,7 @@ public class MeetingManage {
}
result.setAvoidInfo(vo);
} else {
List<ExpertInviteRule> appoints = groupByType.get(ExpertInviteTypeEnum.APPOINT);
List<ExpertInviteRule> appoints = groupByType.get(APPOINT);
ExpertInviteRule appoint = appoints.get(0);
AppointInviteRuleDTO appointRule = JSON.parseObject(appoint.getInviteRule(), AppointInviteRuleDTO.class);
appointRule.setId(appoint.getId());
@@ -610,7 +615,7 @@ public class MeetingManage {
}
try {
Meeting meeting = meetingService.getById(meetingId);
if (!ExpertInviteTypeEnum.APPOINT.eq(meeting.getInviteType())) {
if (!APPOINT.eq(meeting.getInviteType())) {
throw BizException.wrap("该会议不能指定邀请专家");
}
if (meeting.getConfirmedRoster()) {
@@ -713,6 +718,37 @@ public class MeetingManage {
}
}

@Transactional(rollbackFor = Exception.class)
public void expertRemove(ExpertRemoveReq req) {
String key = "EXPERT_REMOVE:" + req.getExpertMeetingId();
if (!distributedLock.lock(key, RETRY_TIMES)) {
throw BizException.wrap("删除专家失败,请重试!");
}
try {
Meeting meeting = meetingService.getById(req.getMeetingId());
if (MeetingStatusEnum.CANCELED.eq(meeting.getStatus())) {
throw BizException.wrap("会议已取消!");
}
if (LocalDateTime.now().isAfter(meeting.getStartTime())) {
throw BizException.wrap("会议已开始,不允许移除专家!");
}
MeetingExpert expert = meetingExpertService.getById(req.getExpertMeetingId());
if (!APPOINT.eq(expert.getInviteType())) {
throw BizException.wrap("随机抽取的专家不允许移除!");
}
if (!NOTICING.eq(expert.getStatus())) {
throw BizException.wrap("已确认过的专家不允许移除!");
}
LambdaUpdateWrapper<Meeting> mUpdate = Wrappers.lambdaUpdate(Meeting.class)
.set(Meeting::getConfirmedRoster, false)
.eq(Meeting::getId, req.getMeetingId());
meetingService.update(mUpdate);
meetingExpertService.removeById(req.getExpertMeetingId());
} finally {
distributedLock.releaseLock(key);
}
}

public void releaseExperts(MeetingCancelReq req) {
String key = "EXPERT_RELEASE:" + req.getMeetingId();
if (!distributedLock.lock(key, RETRY_TIMES)) {
@@ -762,7 +798,8 @@ public class MeetingManage {
}
}

public void confirmedRoster(Long meetingId) {
public void confirmedRoster(ConfirmedRosterReq req) {
Long meetingId = req.getMeetingId();
String key = "MEETING_RESEND_SMS:" + meetingId;
if (!distributedLock.lock(key, RETRY_TIMES)) {
throw BizException.wrap("请刷新后重试!");
@@ -780,7 +817,18 @@ public class MeetingManage {
meetingService.update(update);
}
List<MeetingExpert> experts = meetingExpertService.listAgreedExperts(meetingId);
// TODO 发送会议通知
List<MeetingExpert> expertNoticing = experts.stream()
.filter(w -> meeting.getConfirmedRoster() || !w.getConfirmedRoster())
.collect(Collectors.toList());
if (expertNoticing.isEmpty()) {
return;
}
List<Long> currConfirmedMeIds = CollUtils.fieldList(expertNoticing, MeetingExpert::getId);
LambdaUpdateWrapper<MeetingExpert> meUpdate = Wrappers.lambdaUpdate(MeetingExpert.class)
.in(MeetingExpert::getId, currConfirmedMeIds)
.set(MeetingExpert::getConfirmedRoster, Boolean.TRUE);
meetingExpertService.update(meUpdate);
meetingMsgHelper.sendConfirmedRosterMsg(expertNoticing, meeting);
} finally {
distributedLock.releaseLock(key);
}


+ 14
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertMapper.java View File

@@ -9,6 +9,7 @@ import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum;
import com.ningdatech.pmapi.meeting.entity.req.ReviewProjectListReq;
import org.apache.ibatis.annotations.Param;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;

@@ -62,6 +63,19 @@ public interface MeetingExpertMapper extends BaseMapper<MeetingExpert> {
@Param("meetingIds") Collection<Long> meetingIds);

/**
* 查询时间窗口之内参与会议不超过{@code agreeCount}次的专家ID
*
* @param agreeCount 参与次数(包含)
* @param startTime 开始时间
* @param endTime 结束时间
* @return 专家ID集合
* @author WendyYang
**/
List<Long> listAgreeExpertIdByRecentDaysAndAgreeCount(@Param("agreeCount") Integer agreeCount,
@Param("startTime") LocalDateTime startTime,
@Param("endTime") LocalDateTime endTime);

/**
* 根据会议ID与参与状态统计专家数量
*
* @param status 会议状态


+ 9
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertMapper.xml View File

@@ -50,6 +50,15 @@
</if>
</select>

<select id="listAgreeExpertIdByRecentDaysAndAgreeCount" resultType="long">
SELECT expert_id FROM (SELECT ROW_NUMBER() OVER ( PARTITION BY expert_id, meeting_id ORDER BY update_on DESC )
rowNumber,expert_id, status FROM meeting_expert
where meeting_id in (select id from meeting m where m.status = 1
and ((m.start_time &gt;= #{startTime} and m.start_time &lt; #{endTime})
or (m.end_time &gt;= #{startTime} and m.end_time &lt; #{endTime})) )) em
WHERE rowNumber = 1 and status = 3 group by expert_id having count(1) &gt;= #{agreeCount}
</select>

<select id="countExpertByStatusAndMeetingId"
resultType="int">
SELECT count(1) FROM (SELECT ROW_NUMBER() OVER ( PARTITION BY expert_id, meeting_id ORDER BY update_on DESC )


+ 3
- 1
pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/IMeetingExpertService.java View File

@@ -9,8 +9,8 @@ import com.ningdatech.pmapi.meeting.entity.dto.ReviewProjectDTO;
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum;
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteTypeEnum;
import com.ningdatech.pmapi.meeting.entity.req.ReviewProjectListReq;
import org.apache.ibatis.annotations.Param;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -155,4 +155,6 @@ public interface IMeetingExpertService extends IService<MeetingExpert> {
**/
Page<ReviewProjectDTO> pageReviewProjectList(ReviewProjectListReq req);

List<Long> listAgreeExpertIdByRecentDaysAndAgreeCount(int agreeCount, LocalDateTime sTime, LocalDateTime eTime);

}

+ 9
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/IMeetingInnerProjectService.java View File

@@ -24,4 +24,13 @@ public interface IMeetingInnerProjectService extends IService<MeetingInnerProjec
**/
List<MeetingInnerProject> listByMeetingId(Long meetingId);

/**
* 查询项目关联的所有会议
*
* @param projectId 会议ID
* @return 项目关联的会议ID
* @author WendyYang
**/
List<Long> listMeetingIdByProjectId(Long projectId);

}

+ 1
- 1
pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/impl/ExpertInviteAvoidRuleServiceImpl.java View File

@@ -39,7 +39,7 @@ public class ExpertInviteAvoidRuleServiceImpl extends ServiceImpl<ExpertInviteAv
avoidInfo.setAvoidOrgIdList(StrUtils.split(avoidRule.getAvoidOrgIds()));
avoidInfo.setAvoidUnitIdList(StrUtils.split(avoidRule.getAvoidUnitIds()));
avoidInfo.setExpertIds(BizUtils.splitToLong(avoidRule.getAvoidExpertIds()));
avoidInfo.setWeekInviteCount(avoidInfo.getWeekInviteCount());
avoidInfo.setWeekInviteCount(avoidRule.getWeekInviteCount());
return avoidInfo;
}



+ 6
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/impl/MeetingExpertServiceImpl.java View File

@@ -19,6 +19,7 @@ import com.ningdatech.pmapi.meeting.service.IMeetingExpertService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -134,4 +135,9 @@ public class MeetingExpertServiceImpl extends ServiceImpl<MeetingExpertMapper, M
return baseMapper.pageReviewProjectList(req.page(), req);
}

@Override
public List<Long> listAgreeExpertIdByRecentDaysAndAgreeCount(int agreeCount, LocalDateTime sTime, LocalDateTime eTime) {
return baseMapper.listAgreeExpertIdByRecentDaysAndAgreeCount(agreeCount, sTime, eTime);
}

}

+ 10
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/impl/MeetingInnerProjectServiceImpl.java View File

@@ -1,7 +1,9 @@
package com.ningdatech.pmapi.meeting.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.pmapi.meeting.entity.domain.MeetingInnerProject;
import com.ningdatech.pmapi.meeting.mapper.MeetingInnerProjectMapper;
import com.ningdatech.pmapi.meeting.service.IMeetingInnerProjectService;
@@ -26,4 +28,12 @@ public class MeetingInnerProjectServiceImpl extends ServiceImpl<MeetingInnerProj
.eq(MeetingInnerProject::getMeetingId, meetingId));
}

@Override
public List<Long> listMeetingIdByProjectId(Long projectId) {
LambdaQueryWrapper<MeetingInnerProject> query = Wrappers
.lambdaQuery(MeetingInnerProject.class)
.eq(MeetingInnerProject::getProjectId, projectId);
return CollUtils.fieldList(list(query), MeetingInnerProject::getMeetingId);
}

}

+ 1
- 1
pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertCallResultRewriteTask.java View File

@@ -207,7 +207,7 @@ public class ExpertCallResultRewriteTask {
status = REFUSED;
}
} catch (Exception e) {
log.error("获取电话回调结果异常", e);
log.error("获取电话回调结果异常{}", mrd, e);
status = UNANSWERED;
}
} else {


+ 3
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertInviteTask.java View File

@@ -16,6 +16,7 @@ import com.ningdatech.pmapi.meeting.entity.dto.ExpertChooseDTO;
import com.ningdatech.pmapi.meeting.entity.dto.InviteCacheDTO;
import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO;
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum;
import com.ningdatech.pmapi.meeting.helper.MeetingMsgHelper;
import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper;
import com.ningdatech.pmapi.meeting.manage.ExpertInviteManage;
import com.ningdatech.pmapi.meeting.service.IExpertInviteAvoidRuleService;
@@ -74,6 +75,7 @@ public class ExpertInviteTask {
private final ExpertInviteManage expertInviteManage;
private final IExpertInviteAvoidRuleService inviteAvoidRuleService;
private final YxtCallOrSmsHelper yxtCallOrSmsHelper;
private final MeetingMsgHelper meetingMsgHelper;

/**
* 用来存入线程执行句柄, 停止定时任务时使用
@@ -273,6 +275,7 @@ public class ExpertInviteTask {
if (notIgnoreCnt.get() == 0 || notIgnoreCnt.get() == notSupportCnt.get()) {
log.info("停止会议随机邀请:{} 未完成抽取规则数量 {} 无可抽取专家规则数量 {}", meetingId, notIgnoreCnt, notSupportCnt);
currProxy().cancelByMeetingId(meetingId);
meetingMsgHelper.sendInviteStopMsg(meeting.getCreateBy(), meetingId, meeting.getName());
}
}



+ 6
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/RandomInviteProperties.java View File

@@ -42,4 +42,10 @@ public class RandomInviteProperties {
* 近期会议数量(以此来降低专家抽中间隔)
*/
private Integer recentMeetingCount = 5;

/**
* 参会次数限制天数
*/
private Integer recentDays = 7;

}

+ 12
- 2
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ConstructionPlanManage.java View File

@@ -28,6 +28,9 @@ import com.ningdatech.pmapi.projectlib.model.req.ProjectListReq;
import com.ningdatech.pmapi.projectlib.model.vo.ProjectLibListItemVO;
import com.ningdatech.pmapi.projectlib.service.IProjectInstService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.staging.enums.MsgTypeEnum;
import com.ningdatech.pmapi.sys.manage.NoticeManage;
import com.ningdatech.pmapi.todocenter.constant.WorkNoticeContant;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import com.wflow.bean.entity.WflowModels;
@@ -80,6 +83,8 @@ public class ConstructionPlanManage {
private final DefaultDeclaredProjectManage declaredProjectManage;
private final DefaultDeclaredProjectManage defaultDeclaredProjectManage;

private final NoticeManage noticeManage;

/**
* 建设方案
*
@@ -133,6 +138,10 @@ public class ConstructionPlanManage {
//保存建设项目
modifyProject(projectInfo, instanceId, projectInfo.getConstructionPlanFile());

//发送给第一个审批人消息
noticeManage.sendFirtUser(projectInfo,model.getFormName(),instanceId,
WorkNoticeContant.PASS_MSG_TEMPLATE, MsgTypeEnum.PROJECT_REVIEW);

return instanceId;
}

@@ -154,8 +163,9 @@ public class ConstructionPlanManage {
VUtils.isTrue(Objects.isNull(projectInfo)).throwMessage("提交失败 此项目不存在!");
VUtils.isTrue(StringUtils.isBlank(projectDto.getConstructionPlanFile())).throwMessage("提交失败 请提交建设方案!");
//直接先到待方案审批
projectInfo.setStatus(ProjectStatusEnum.PLAN_TO_BE_DECLARED.getCode());
projectService.updateById(projectInfo);
Project project = projectLibManage.saveProjectWithVersionAndStatus(projectDto,null,
ProjectStatusEnum.PLAN_TO_BE_DECLARED.getCode());
dto.getProjectInfo().setId(project.getId());
return startTheProcess(dto);
}



+ 28
- 75
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DeclaredProjectManage.java View File

@@ -11,7 +11,7 @@ import com.ningdatech.basic.function.VUtils;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.NdDateUtils;
import com.ningdatech.pmapi.common.constant.CommonConst;
import com.ningdatech.pmapi.common.constant.BizConst;
import com.ningdatech.pmapi.common.constant.RegionConst;
import com.ningdatech.pmapi.common.enumeration.CommonEnum;
import com.ningdatech.pmapi.common.enumeration.ProjectProcessStageEnum;
@@ -19,44 +19,35 @@ import com.ningdatech.pmapi.common.helper.RegionCacheHelper;
import com.ningdatech.pmapi.common.helper.UserInfoHelper;
import com.ningdatech.pmapi.common.util.ExcelDownUtil;
import com.ningdatech.pmapi.common.util.ExcelExportStyle;
import com.ningdatech.pmapi.organization.model.entity.DingOrganization;
import com.ningdatech.pmapi.organization.service.IDingOrganizationService;
import com.ningdatech.pmapi.projectdeclared.model.dto.*;
import com.ningdatech.pmapi.projectdeclared.model.entity.ProjectDraft;
import com.ningdatech.pmapi.projectdeclared.model.vo.ProjectDraftVO;
import com.ningdatech.pmapi.projectdeclared.service.IProjectDraftService;
import com.ningdatech.pmapi.projectdeclared.utils.GenerateProjectCodeUtil;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectRenewalApprovalStatusEnum;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectTypeEnum;
import com.ningdatech.pmapi.projectlib.helper.ProjectHelper;
import com.ningdatech.pmapi.projectlib.manage.ProjectLibManage;
import com.ningdatech.pmapi.projectlib.model.dto.ProjectDTO;
import com.ningdatech.pmapi.projectlib.model.dto.ProjectRenewalExportDTO;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectApplication;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectInst;
import com.ningdatech.pmapi.projectlib.model.po.ProjectRenewalFundDeclarationPO;
import com.ningdatech.pmapi.projectlib.model.req.ProjectListReq;
import com.ningdatech.pmapi.projectlib.model.vo.ProjectLibListItemVO;
import com.ningdatech.pmapi.projectlib.service.IProjectApplicationService;
import com.ningdatech.pmapi.projectlib.service.IProjectInstService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.staging.enums.MsgTypeEnum;
import com.ningdatech.pmapi.sys.manage.NoticeManage;
import com.ningdatech.pmapi.todocenter.constant.WorkNoticeContant;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.security.auth.model.UserInfoDetails;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import com.wflow.bean.entity.WflowModels;
import com.wflow.bean.entity.WflowOrgModels;
import com.wflow.enums.OrgTypeEnum;
import com.wflow.enums.ProcessDefTypeEnum;
import com.wflow.exception.BusinessException;
import com.wflow.service.OrgProcdefService;
import com.wflow.workflow.bean.dto.OrgInfoDTO;
import com.wflow.workflow.bean.vo.ProcessStartParamsVo;
import com.wflow.workflow.service.ProcessInstanceService;
import com.wflow.workflow.service.ProcessModelService;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@@ -84,7 +75,7 @@ public class DeclaredProjectManage {

private final IProjectService projectService;

private final IProjectApplicationService projectApplicationService;
private final ProjectLibManage projectLibManage;

private final IProjectDraftService projectDraftService;

@@ -92,16 +83,13 @@ public class DeclaredProjectManage {

private final ProcessModelService processModelService;

private final IProjectInstService projectInstService;

private final DefaultDeclaredProjectManage defaultDeclaredProjectManage;

private final ProjectLibManage projectlibManager;
private final NoticeManage noticeManage;
private final UserInfoHelper userInfoHelper;

private final RegionCacheHelper regionCacheHelper;
private final GenerateProjectCodeUtil generateProjectCodeUtil;

/**
* 新项目 启动实例
@@ -142,12 +130,14 @@ public class DeclaredProjectManage {
projectInfo.setId(null);
}

// defaultDeclaredProjectManage.startProcess(projectInfo,user,ProjectProcessStageEnum.ORG_INTERNAL_APPROVAL_PROCESS.getCode());

String regionCode = user.getRegionCode();

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

if (Objects.isNull(model)) {
log.error("此 【{}】区域找不到单位流程配置", regionCode);
@@ -174,11 +164,17 @@ public class DeclaredProjectManage {
log.info("申报项目成功 【{}】", instanceId);

//如果是重新提交的话 判断下 项目是否存在
if(saveOrUpdateProject(projectInfo, instanceId,employeeCode) && Objects.nonNull(projectInfo.getDraftId())){
//保存项目相关
Project buildProject = projectLibManage.saveProjectInDeclared(projectInfo,instanceId,employeeCode);
if(Objects.nonNull(projectInfo.getDraftId())){
//如果是草稿箱提交 删除对应的草稿箱
projectDraftService.removeById(projectInfo.getDraftId());
}

//发送给第一个审批人消息
noticeManage.sendFirtUser(buildProject,model.getFormName(),instanceId,
WorkNoticeContant.PASS_MSG_TEMPLATE, MsgTypeEnum.PROJECT_REVIEW);

return instanceId;
}

@@ -206,7 +202,10 @@ public class DeclaredProjectManage {
VUtils.isTrue(Objects.isNull(projectInfo)).throwMessage("提交失败 此项目不存在!");

//项目名称去重
defaultDeclaredProjectManage.checkDuplication(projectDto);
if(StringUtils.isNotBlank(projectDto.getProjectName()) &&
!projectDto.getProjectName().equals(projectInfo.getProjectName())){
defaultDeclaredProjectManage.checkDuplication(projectDto);
}
//判断申报金额 是否等于总的 判断年度支付金额 是否等于总金额
defaultDeclaredProjectManage.checkAmount(projectDto);

@@ -240,62 +239,14 @@ public class DeclaredProjectManage {
String instanceId = processService.newStartProcess(model.getProcessDefId(),model.getFormId(), params,orgModelMap);
log.info("重新申报项目成功 【{}】", instanceId);

//保存项目
saveOrUpdateProject(projectDto,instanceId,employeeCode);
//保存项目相关
Project buildProject = projectLibManage.saveProjectInDeclared(projectDto,instanceId,employeeCode);

return instanceId;
}
//发送给第一个审批人消息
noticeManage.sendFirtUser(buildProject,model.getFormName(),instanceId,
WorkNoticeContant.PASS_MSG_TEMPLATE, MsgTypeEnum.PROJECT_REVIEW);

/**
* 申报项目 时 新增项目到项目库
*
* @param projectDto
* @param instanceId
*/
private Boolean saveOrUpdateProject(ProjectDTO projectDto, String instanceId,
String employeeCode) {
//流程启动之后 入库项目 重要业务信息 用于列表查询 展示
try {
//保存项目表信息
Project project = new Project();
BeanUtils.copyProperties(projectDto, project);
project.setCreateOn(LocalDateTime.now());
project.setUpdateOn(LocalDateTime.now());
project.setStage(ProjectStatusEnum.NOT_APPROVED.getCode());
project.setStatus(ProjectStatusEnum.UNDER_INTERNAL_AUDIT.getCode());
project.setInstCode(instanceId);
project.setSponsor(employeeCode);
String projectCode = generateProjectCodeUtil.generateProjectCode(projectDto);
project.setProjectCode(projectCode);
projectService.saveOrUpdate(project);
//保存项目应用
Boolean isApp = Objects.nonNull(projectDto.getIncludeApplication()) && 1 == projectDto.getIncludeApplication()
? Boolean.TRUE : Boolean.FALSE;
//采取批量删除 批量添加的方式
projectApplicationService.remove(Wrappers.lambdaQuery(ProjectApplication.class)
.eq(ProjectApplication::getProjectId,project.getId()));
if (isApp && CollUtil.isNotEmpty(projectDto.getApplicationList())) {
List<ProjectApplication> applications = projectDto.getApplicationList().stream().map(application -> {
ProjectApplication projectApplication = new ProjectApplication();
BeanUtils.copyProperties(application, projectApplication);
projectApplication.setProjectId(project.getId());
return projectApplication;
}).collect(Collectors.toList());
projectApplicationService.saveOrUpdateBatch(applications);
}
//保存项目和实例的关系
ProjectInst projectInst = new ProjectInst();
projectInst.setProjectId(project.getId());
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);
throw new BusinessException("项目信息入库错误 :" + e);
}
return Boolean.TRUE;
return instanceId;
}

public PageVo<ProjectDraftVO> pageDraft(DeclaredProjectListParamDTO params) {
@@ -382,6 +333,7 @@ public class DeclaredProjectManage {
LambdaQueryWrapper<Project> query = ProjectHelper.projectQuery(req);
//当非预审申报的时候 是自己单位 当是预审申报的时候 要主管单位
preQuery(query,user);
query.eq(Project::getNewest,Boolean.TRUE);
Page<Project> page = projectService.page(req.page(), query);
long total;
if ((total = page.getTotal()) == 0) {
@@ -426,6 +378,7 @@ public class DeclaredProjectManage {
LambdaQueryWrapper<Project> query = ProjectHelper.projectQuery(param);
//当非预审申报的时候 是自己单位 当是预审申报的时候 要主管单位
preQuery(query,user);
query.eq(Project::getNewest,Boolean.TRUE);
List<Project> records = projectService.list(query);

AtomicInteger serialNumber = new AtomicInteger(0);


+ 36
- 3
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DefaultDeclaredProjectManage.java View File

@@ -3,11 +3,12 @@ package com.ningdatech.pmapi.projectdeclared.manage;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Maps;
import com.ningdatech.basic.function.VUtils;
import com.ningdatech.pmapi.common.constant.BizConst;
import com.ningdatech.pmapi.common.constant.RegionConst;
import com.ningdatech.pmapi.common.enumeration.ProjectProcessStageEnum;
import com.ningdatech.pmapi.common.helper.UserInfoHelper;
import com.ningdatech.pmapi.organization.model.entity.DingOrganization;
import com.ningdatech.pmapi.organization.service.IDingOrganizationService;
import com.ningdatech.pmapi.projectdeclared.model.dto.DefaultDeclaredDTO;
import com.ningdatech.pmapi.projectdeclared.model.dto.ProjectConditionDTO;
import com.ningdatech.pmapi.projectdeclared.model.po.DeclaredProjectStatisticsPO;
@@ -17,13 +18,16 @@ import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import com.wflow.bean.entity.WflowModels;
import com.wflow.bean.entity.WflowOrgModels;
import com.wflow.enums.OrgTypeEnum;
import com.wflow.enums.ProcessDefTypeEnum;
import com.wflow.exception.BusinessException;
import com.wflow.service.OrgProcdefService;
import com.wflow.workflow.bean.dto.OrgInfoDTO;
import com.wflow.workflow.bean.dto.ProcessInstanceUserDto;
import com.wflow.workflow.bean.vo.ProcessStartParamsVo;
import com.wflow.workflow.service.ProcessModelService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
@@ -48,11 +52,40 @@ public class DefaultDeclaredProjectManage {

private final UserInfoHelper userInfoHelper;

private final IDingOrganizationService dingOrganizationService;
private final ProcessModelService processModelService;
private final OrgProcdefService orgProcdefService;

private final IDeclaredStatisticsService statisticsService;

/**
* 公共的发起流程方法
*/
public void startProcess(ProjectDTO projectDTO,UserFullInfoDTO user,Integer processType){
WflowModels model = processModelService.getOne(Wrappers.lambdaQuery(WflowModels.class)
.eq(WflowModels::getRegionCode, user.getRegionCode())
.eq(WflowModels::getProcessType, processType)
.last(BizConst.LIMIT_1));

if (Objects.isNull(model)) {
log.error("此 【{}】区域找不到对应流程配置", user.getRegionCode());
throw new BusinessException(String.format("此 【%s】区域找不到对应流程配置", user.getRegionCode()));
}

ProcessStartParamsVo params = new ProcessStartParamsVo();
params.setUser(buildUser(user.getEmployeeCode()));
params.setProcessUsers(Collections.emptyMap());
//放入条件判断的项目字段
ProjectConditionDTO conditionDto = new ProjectConditionDTO();
BeanUtils.copyProperties(projectDTO, conditionDto);
Map<String,Object> formData = Maps.newHashMap();
formData.putAll(
JSON.parseObject(JSON.toJSONString(conditionDto), new TypeReference<Map<String, Object>>() {
})
);
params.setFormData(formData);

}

//项目名称去重
public void checkDuplication(ProjectDTO project){
VUtils.isTrue(projectService.count(Wrappers.lambdaQuery(Project.class)


+ 19
- 10
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/PrequalificationDeclaredProjectManage.java View File

@@ -1,9 +1,6 @@
package com.ningdatech.pmapi.projectdeclared.manage;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -12,16 +9,14 @@ import com.ningdatech.basic.function.VUtils;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.NdDateUtils;
import com.ningdatech.pmapi.common.constant.BizConst;
import com.ningdatech.pmapi.common.enumeration.ProjectProcessStageEnum;
import com.ningdatech.pmapi.common.helper.UserInfoHelper;
import com.ningdatech.pmapi.common.statemachine.util.StateMachineUtils;
import com.ningdatech.pmapi.common.util.ExcelDownUtil;
import com.ningdatech.pmapi.common.util.ExcelExportStyle;
import com.ningdatech.pmapi.datascope.model.DataScopeDTO;
import com.ningdatech.pmapi.datascope.utils.DataScopeUtil;
import com.ningdatech.pmapi.projectdeclared.model.dto.DefaultDeclaredDTO;
import com.ningdatech.pmapi.projectdeclared.model.dto.PretrialDeclaredExportDTO;
import com.ningdatech.pmapi.projectdeclared.model.dto.ProjectConditionDTO;
import com.ningdatech.pmapi.projectdeclared.model.req.PrequalificationDeclaredListReq;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectTypeEnum;
@@ -34,8 +29,11 @@ import com.ningdatech.pmapi.projectlib.model.req.ProjectListReq;
import com.ningdatech.pmapi.projectlib.model.vo.ProjectLibListItemVO;
import com.ningdatech.pmapi.projectlib.service.IProjectInstService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.staging.enums.MsgTypeEnum;
import com.ningdatech.pmapi.staging.service.IProjectStagingService;
import com.ningdatech.pmapi.sys.manage.NoticeManage;
import com.ningdatech.pmapi.todocenter.constant.TodoCenterContant;
import com.ningdatech.pmapi.todocenter.constant.WorkNoticeContant;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import com.wflow.bean.entity.WflowModels;
@@ -69,6 +67,8 @@ public class PrequalificationDeclaredProjectManage {

private final IProjectService projectService;

private final ProjectLibManage projectLibManage;

private final StateMachineUtils stateMachineUtils;

private final IProjectStagingService projectStagingService;
@@ -83,6 +83,8 @@ public class PrequalificationDeclaredProjectManage {

private final IProjectInstService projectInstService;

private final NoticeManage noticeManage;

/**
* 提交预审
* @param dto
@@ -158,9 +160,10 @@ public class PrequalificationDeclaredProjectManage {
VUtils.isTrue(Objects.isNull(projectDto.getId())).throwMessage("提交失败 缺少项目ID!");
Project projectInfo = projectService.getById(projectDto.getId());
VUtils.isTrue(Objects.isNull(projectInfo)).throwMessage("提交失败 此项目不存在!");
//先回到 待预审状态
projectInfo.setStatus(ProjectStatusEnum.PENDING_PREQUALIFICATION.getCode());
projectService.updateById(projectInfo);
//重新提交 生成新版本号 回到 待预审状态
Project project = projectLibManage.saveProjectWithVersionAndStatus(projectDto,null,
ProjectStatusEnum.PENDING_PREQUALIFICATION.getCode());
dto.getProjectInfo().setId(project.getId());
return startTheProcess(dto);
}

@@ -181,7 +184,7 @@ public class PrequalificationDeclaredProjectManage {
WflowModels model = processModelService.getOne(Wrappers.lambdaQuery(WflowModels.class)
.eq(WflowModels::getRegionCode, regionCode)
.eq(WflowModels::getProcessType, ProjectProcessStageEnum.PROJECT_PREQUALIFICATION_APPROVAL_PROCESS.getCode())
.last("limit 1"));
.last(BizConst.LIMIT_1));

if (Objects.isNull(model)) {
log.error("此 【{}】区域找不到 预审流程配置", regionCode);
@@ -196,6 +199,10 @@ public class PrequalificationDeclaredProjectManage {
//保存预审项目
preModifyProject(projectInfo, instanceId);

//发送给第一个审批人消息
noticeManage.sendFirtUser(projectInfo,model.getFormName(),instanceId,
WorkNoticeContant.PASS_MSG_TEMPLATE, MsgTypeEnum.PROJECT_REVIEW);

return instanceId;
}

@@ -243,6 +250,7 @@ public class PrequalificationDeclaredProjectManage {
ProjectStatusEnum.JOINT_REVIEW_BY_PROVINCIAL_DEPARTMENTS_SUCCESS.getCode()));
LambdaQueryWrapper<Project> query = ProjectHelper.projectQuery(req);
buildPermission(query,user);
query.eq(Project::getNewest,Boolean.TRUE);
Page<Project> page = projectService.page(req.page(), query);
long total;
if ((total = page.getTotal()) == 0) {
@@ -304,6 +312,7 @@ public class PrequalificationDeclaredProjectManage {
LambdaQueryWrapper<Project> query = ProjectHelper.projectQuery(req);
//角色权限
buildPermission(query,user);
query.eq(Project::getNewest,Boolean.TRUE);
List<Project> records = projectService.list(query);

List<PretrialDeclaredExportDTO> collect = records.stream().map(r -> {


+ 5
- 4
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ProjectAdjustmentManage.java View File

@@ -87,7 +87,8 @@ public class ProjectAdjustmentManage {
VUtils.isTrue(Objects.isNull(projectInfo)).throwMessage("调整失败 此项目不存在!");

//项目名称去重
if(StringUtils.isNotBlank(projectDto.getProjectName())){
if(StringUtils.isNotBlank(projectDto.getProjectName()) &&
!projectDto.getProjectName().equals(projectInfo.getProjectName())){
defaultDeclaredProjectManage.checkDuplication(projectDto);
}

@@ -97,9 +98,9 @@ public class ProjectAdjustmentManage {
}

//修改项目内容
if(!modifyProject(projectDto)){
throw new BusinessException("调整项目失败!");
}
// if(!modifyProject(projectDto)){
// throw new BusinessException("调整项目失败!");
// }

//最后去重新 提交项目流程 不同的状态 提交到不同的工作流去
Function<DefaultDeclaredDTO, String> declaredFunction =


+ 9
- 5
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ReviewByDeptJointManage.java View File

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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Maps;
import com.ningdatech.basic.function.VUtils;
import com.ningdatech.pmapi.common.enumeration.ProjectProcessStageEnum;
import com.ningdatech.pmapi.projectdeclared.model.dto.ProjectConditionDTO;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
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.enums.MsgTypeEnum;
import com.ningdatech.pmapi.sys.manage.NoticeManage;
import com.ningdatech.pmapi.todocenter.constant.WorkNoticeContant;
import com.wflow.bean.entity.WflowModels;
import com.wflow.exception.BusinessException;
import com.wflow.workflow.bean.dto.OrgInfoDTO;
@@ -20,10 +20,8 @@ import com.wflow.workflow.service.ProcessInstanceService;
import com.wflow.workflow.service.ProcessModelService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Map;
@@ -50,6 +48,8 @@ public class ReviewByDeptJointManage {
private final DefaultDeclaredProjectManage declaredProjectManage;
private final DefaultDeclaredProjectManage defaultDeclaredProjectManage;

private final NoticeManage noticeManage;

/**
* 部门联审
* @param project
@@ -103,6 +103,10 @@ public class ReviewByDeptJointManage {
return Boolean.FALSE;
}

//发送给第一个审批人消息
noticeManage.sendFirtUser(projectInfo,model.getFormName(),instanceId,
WorkNoticeContant.PASS_MSG_TEMPLATE, MsgTypeEnum.PROJECT_REVIEW);

return Boolean.TRUE;
}



+ 24
- 4
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ReviewByProvincialDeptManage.java View File

@@ -6,17 +6,22 @@ import com.ningdatech.file.service.FileService;
import com.ningdatech.pmapi.projectdeclared.converter.ApplicationConverter;
import com.ningdatech.pmapi.projectdeclared.model.dto.DefaultDeclaredDTO;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.manage.ProjectLibManage;
import com.ningdatech.pmapi.projectlib.model.dto.ProjectDTO;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectApplication;
import com.ningdatech.pmapi.projectlib.service.IProjectApplicationService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.provincial.service.IJoinReviewProvincialBureauService;
import com.ningdatech.pmapi.staging.service.IProjectStagingService;
import com.ningdatech.pmapi.todocenter.constant.TodoCenterContant;
import com.wflow.exception.BusinessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

@@ -39,6 +44,10 @@ public class ReviewByProvincialDeptManage {

private final IProjectApplicationService applicationService;

private final ProjectLibManage projectLibManage;

private final IProjectStagingService projectStagingService;

/**
* 省级部门联审
* @param project
@@ -88,12 +97,23 @@ public class ReviewByProvincialDeptManage {
// 对接省级联审的接口
List<ProjectApplication> applications = applicationService.list(Wrappers.lambdaQuery(ProjectApplication.class)
.eq(ProjectApplication::getProjectId, projectInfo.getId()));

Project p = projectLibManage.saveProjectWithVersionAndStatus(project,null,
ProjectStatusEnum.JOINT_REVIEW_BY_PROVINCIAL_DEPARTMENTS.getCode());

//入库暂存表 后续处理 对接外部接口
p.setUpdateOn(LocalDateTime.now());
//保存一下 当前的主管单位发起人
p.setPreStartUserId(p.getSponsor());
//当前实例置为空
p.setInstCode(TodoCenterContant.Declared.NULL_INST_CODE);
declaringDTO.getProjectInfo().setId(p.getId());
projectService.updateById(p);
if(!joinReviewProvincialBureauService.pushImportProject(
ApplicationConverter.convertProject(projectInfo,applications,fileService))){
ApplicationConverter.convertProject(p,applications,fileService))){
throw new BusinessException("提交省级部门联审失败");
}
projectInfo.setStatus(ProjectStatusEnum.JOINT_REVIEW_BY_PROVINCIAL_DEPARTMENTS.getCode());
projectService.updateById(projectInfo);
return String.valueOf(projectInfo.getId());

return String.valueOf(p.getId());
}
}

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

@@ -299,6 +299,9 @@ public class ProjectDraft implements Serializable {
@ApiModelProperty("用户id")
private String userId;

@ApiModelProperty("项目申报书")
private String projectApplicationForm;

private Long createBy;
private Long updateBy;
}

+ 2
- 0
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/model/vo/ProjectDraftVO.java View File

@@ -303,6 +303,8 @@ public class ProjectDraftVO implements Serializable {
@ApiModelProperty("21位项目编号")
private String projectCode;

@ApiModelProperty("项目申报书")
private String projectApplicationForm;

private Long createBy;
private Long updateBy;


+ 6
- 6
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/utils/GenerateProjectCodeUtil.java View File

@@ -31,15 +31,15 @@ public class GenerateProjectCodeUtil {
@Autowired
private IProjectService projectService;

public String generateProjectCode(ProjectDTO projectInfo){
public String generateProjectCode(ProjectDTO project){
// 获取所属行政区划代码(6位)
String areaCode = projectInfo.getAreaCode();
String areaCode = project.getAreaCode();
// 获取建设年度后两位
String year = String.valueOf(projectInfo.getProjectYear() % DeclaredProjectContant.Project.YEAR_DRAW_SURPLUS);
String year = String.valueOf(project.getProjectYear() % DeclaredProjectContant.Project.YEAR_DRAW_SURPLUS);
// 9-12位固定
String fixedNumber = DeclaredProjectContant.Project.FIXED_NUMBER;
// 获取公司的财政编码
CompanyFiscalCode companyFiscalCode = companyFiscalCodeService.getByOrganizationCode(projectInfo.getBuildOrgCode());
CompanyFiscalCode companyFiscalCode = companyFiscalCodeService.getByOrganizationCode(project.getBuildOrgCode());

// 从表中查出单位配置的财政编码
if (Objects.isNull(companyFiscalCode)){
@@ -51,8 +51,8 @@ public class GenerateProjectCodeUtil {
String projectIdStr;
// 获取项目库当前最大项目序号
List<Project> projectList = projectService.list(Wrappers.lambdaQuery(Project.class).orderByDesc(Project::getId));
Project project = CollUtil.isEmpty(projectList) ? null : projectList.get(0);
Long projectId = Objects.isNull(project) ? DeclaredProjectContant.Project.MIN_PROJECT_ID : project.getId() + 1;
Project maxProject = CollUtil.isEmpty(projectList) ? null : projectList.get(0);
Long projectId = Objects.isNull(maxProject) ? DeclaredProjectContant.Project.MIN_PROJECT_ID : maxProject.getId() + 1;
if (projectId > DeclaredProjectContant.Project.MAX_PROJECT_ID){
// 超过999的项目号从1开始 1
Long newProjectId = projectId % DeclaredProjectContant.Project.MAX_PROJECT_ID;


+ 6
- 6
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/constant/ImportTemplateConstant.java View File

@@ -1,6 +1,6 @@
package com.ningdatech.pmapi.projectlib.constant;

import com.ningdatech.pmapi.projectlib.enumeration.ImportTemplateEnum;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectLibFlagEnum;

import java.util.*;

@@ -15,16 +15,16 @@ import java.util.*;
*/
public class ImportTemplateConstant {

public static final List<String> ANNUAL_PLAN_COL_LIST = Arrays.asList("序号","项目id","项目名称","建设内容","建设依据","建设性质","建设起止年限(填写到月)", "总投资", "自有资金", "政府投资-本级财政","政府投资-上级补助资金","银行贷款","其他","一季度","二季度","三季度","四季度","建设单位","项目联系人","项目分管领导","备注");
public static final List<String> ANNUAL_PLAN_COL_LIST = Arrays.asList("序号","项目id","项目名称","建设内容","建设依据","建设性质","建设起止年限(填写到月)", "总投资", "自有资金","年度投资额","政府投资-本级财政","政府投资-上级补助资金","银行贷款","其他","一季度","二季度","三季度","四季度","建设单位","项目联系人","项目分管领导","备注");

private static final Map<ImportTemplateEnum, List<String>> IMPORT_TEMPLATE_MAP;
private static final Map<ProjectLibFlagEnum, List<String>> IMPORT_TEMPLATE_MAP;

static {
IMPORT_TEMPLATE_MAP = new HashMap<>(ImportTemplateEnum.values().length);
IMPORT_TEMPLATE_MAP.put(ImportTemplateEnum.ANNUAL_PLAN, ANNUAL_PLAN_COL_LIST);
IMPORT_TEMPLATE_MAP = new HashMap<>(ProjectLibFlagEnum.values().length);
IMPORT_TEMPLATE_MAP.put(ProjectLibFlagEnum.ANNUAL_PLAN, ANNUAL_PLAN_COL_LIST);
}

public static List<String> getTemplateTitle(ImportTemplateEnum template) {
public static List<String> getTemplateTitle(ProjectLibFlagEnum template) {
return IMPORT_TEMPLATE_MAP.getOrDefault(template, Collections.emptyList());
}



+ 10
- 4
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/controller/AnnualPlanController.java View File

@@ -2,7 +2,7 @@ package com.ningdatech.pmapi.projectlib.controller;

import com.ningdatech.basic.model.PageVo;
import com.ningdatech.log.annotation.WebLog;
import com.ningdatech.pmapi.projectlib.enumeration.ImportTemplateEnum;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectLibFlagEnum;
import com.ningdatech.pmapi.projectlib.manage.AnnualPlanLibManage;
import com.ningdatech.pmapi.projectlib.model.dto.ProjectDTO;
import com.ningdatech.pmapi.projectlib.model.req.ProjectApprovedReq;
@@ -65,8 +65,8 @@ public class AnnualPlanController {
@PostMapping("/importAnnualPlan")
@ApiOperation("导入年度计划")
@WebLog("导入年度计划")
public void importAnnualPlan(@RequestParam("template") ImportTemplateEnum template, MultipartFile file) {
annualPlanLibManage.importAnnualPlan(template,file);
public void importAnnualPlan(@RequestParam("importFlag") ProjectLibFlagEnum importFlag, MultipartFile file) {
annualPlanLibManage.importAnnualPlan(importFlag,file);
}

@PostMapping("/modify")
@@ -77,9 +77,15 @@ public class AnnualPlanController {
}

@PostMapping("/exportList")
@ApiOperation("项目库列表|编辑表】导出")
@ApiOperation("项目(增补)库列表导出")
public void exportList(@Valid @RequestBody ProjectListReq param, HttpServletResponse response) {
annualPlanLibManage.exportList(param, response);
}

@PostMapping("/exportModifyList")
@ApiOperation("项目(增补)库编辑表导出")
public void exportModifyList(@Valid @RequestBody ProjectListReq param, HttpServletResponse response) {
annualPlanLibManage.exportModifyList(param, response);
}

}

pmapi/src/main/java/com/ningdatech/pmapi/projectlib/enumeration/ImportTemplateEnum.java → pmapi/src/main/java/com/ningdatech/pmapi/projectlib/enumeration/ProjectLibFlagEnum.java View File

@@ -4,24 +4,25 @@ import lombok.Getter;

/**
* <p>
* 导入模版枚举
* 项目库标志枚举
* </p>
*
* @author WendyYang
* @since 2022-11-04
*/
@Getter
public enum ImportTemplateEnum {
public enum ProjectLibFlagEnum {

/**
* 通用导入模版枚举
* 项目库标志枚举
*/

ANNUAL_PLAN("年度计划(增补)库导入");
ANNUAL_PLAN("年度计划库"),
ANNUAL_PLAN_SUPPLEMENT("年度计划增补库");

private final String value;

ImportTemplateEnum(String value) {
ProjectLibFlagEnum(String value) {
this.value = value;
}


+ 22
- 6
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/ConstructionPlanReviewHandle.java View File

@@ -6,7 +6,11 @@ import java.util.Objects;

import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Lists;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.util.NdDateUtils;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.projectlib.utils.ProjectVersionUtil;
import com.ningdatech.pmapi.todocenter.utils.BuildUserUtils;
import com.wflow.workflow.bean.process.ProgressNode;
import com.wflow.workflow.bean.vo.ProcessDetailVO;
@@ -36,32 +40,44 @@ public class ConstructionPlanReviewHandle extends AbstractProcessBusinessHandle
private final IProjectInstService projectInstService;
private final ProcessInstanceService processInstanceService;
private final BuildUserUtils buildUserUtils;
private final ProjectVersionUtil projectVersionUtil;
private final IProjectService projectService;

public ConstructionPlanReviewHandle(IProjectInstService projectInstService, ProcessInstanceService processInstanceService, BuildUserUtils buildUserUtils){
public ConstructionPlanReviewHandle(IProjectInstService projectInstService, ProcessInstanceService processInstanceService, BuildUserUtils buildUserUtils, ProjectVersionUtil projectVersionUtil, IProjectService projectService){
this.projectInstService = projectInstService;
this.processInstanceService = processInstanceService;
this.buildUserUtils = buildUserUtils;
this.projectVersionUtil = projectVersionUtil;
this.projectService = projectService;
}

@Override
void businessHandle(Long projectId, List<ProcessDetailVO> processSchedule) {
ProcessDetailVO processDetailVO = new ProcessDetailVO();
Project project = projectService.getById(projectId);
// 根据项目ID查询出建设方案评审流程的流程状态
ProjectInst projectInst = projectInstService.getOne(Wrappers.lambdaQuery(ProjectInst.class)
.eq(ProjectInst::getProjectId, projectId)
.eq(ProjectInst::getInstType, InstTypeEnum.CONSTRUCTION_PLAN_REVIEW.getCode())
.orderByDesc(ProjectInst::getCreatOn)
.last("limit 1"));

if (Objects.isNull(projectInst)){
ProcessProgressVo instanceDetail = null;
// 未找到当前版本项目的建设方案审核流程且当前项目版本号大于1(是被驳回重新申报的项目)
if (Objects.isNull(projectInst)) {
if (project.getVersion() > CommonConst.VERSION_ONE ){
// 获取上个版本的信息
instanceDetail = projectVersionUtil.getPreVerProcessInfo(projectId,InstTypeEnum.CONSTRUCTION_PLAN_REVIEW);
}
}else {
String instCode = projectInst.getInstCode();
instanceDetail = processInstanceService.getProgressInstanceDetail(null, instCode);
}
if (Objects.isNull(instanceDetail)){
processDetailVO.setStepStatus(StepStatusEnum.NOT_START);
processDetailVO.setProcessName(CommonConst.CONSTRUCTION_PLAN_REVIEW);
processSchedule.add(processDetailVO);
return;
}

String instCode = projectInst.getInstCode();
ProcessProgressVo instanceDetail = processInstanceService.getProgressInstanceDetail(null, instCode);
String status = instanceDetail.getStatus();
if (ProcessStatusEnum.UNDER_REVIEW.getDesc().equals(status)){
processDetailVO.setStepStatus(StepStatusEnum.ON_GOING);


+ 5
- 2
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/DeptUnitedReviewHandle.java View File

@@ -7,6 +7,7 @@ import java.util.Objects;
import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Lists;
import com.ningdatech.basic.util.NdDateUtils;
import com.ningdatech.pmapi.projectlib.utils.ProjectVersionUtil;
import com.ningdatech.pmapi.todocenter.utils.BuildUserUtils;
import com.wflow.workflow.bean.process.ProgressNode;
import com.wflow.workflow.bean.vo.ProcessDetailVO;
@@ -24,7 +25,7 @@ import com.wflow.workflow.enums.ProcessStatusEnum;
import com.wflow.workflow.service.ProcessInstanceService;

/**
* 单位内部审核处理
* 部门联审审核处理
*
* @author CMM
* @since 2023/02/24 14:35
@@ -36,11 +37,13 @@ public class DeptUnitedReviewHandle extends AbstractProcessBusinessHandle {
private final IProjectInstService projectInstService;
private final ProcessInstanceService processInstanceService;
private final BuildUserUtils buildUserUtils;
private final ProjectVersionUtil projectVersionUtil;

public DeptUnitedReviewHandle(IProjectInstService projectInstService, ProcessInstanceService processInstanceService, BuildUserUtils buildUserUtils){
public DeptUnitedReviewHandle(IProjectInstService projectInstService, ProcessInstanceService processInstanceService, BuildUserUtils buildUserUtils, ProjectVersionUtil projectVersionUtil){
this.projectInstService = projectInstService;
this.processInstanceService = processInstanceService;
this.buildUserUtils = buildUserUtils;
this.projectVersionUtil = projectVersionUtil;
}

@Override


+ 25
- 4
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/PreliminaryPreviewHandle.java View File

@@ -3,11 +3,15 @@ package com.ningdatech.pmapi.projectlib.handle;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.util.NdDateUtils;
import com.ningdatech.pmapi.common.constant.CommonConst;
import com.ningdatech.pmapi.projectlib.enumeration.InstTypeEnum;
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.projectlib.utils.ProjectVersionUtil;
import com.ningdatech.pmapi.todocenter.utils.BuildUserUtils;
import com.wflow.workflow.bean.process.ProgressNode;
import com.wflow.workflow.bean.vo.ProcessDetailVO;
@@ -35,30 +39,47 @@ public class PreliminaryPreviewHandle extends AbstractProcessBusinessHandle {
private final IProjectInstService projectInstService;
private final ProcessInstanceService processInstanceService;
private final BuildUserUtils buildUserUtils;
private final ProjectVersionUtil projectVersionUtil;
private final IProjectService projectService;

public PreliminaryPreviewHandle(IProjectInstService projectInstService, ProcessInstanceService processInstanceService, BuildUserUtils buildUserUtils) {
public PreliminaryPreviewHandle(IProjectInstService projectInstService, ProcessInstanceService processInstanceService, BuildUserUtils buildUserUtils, ProjectVersionUtil projectVersionUtil, IProjectService projectService) {
this.projectInstService = projectInstService;
this.processInstanceService = processInstanceService;
this.buildUserUtils = buildUserUtils;
this.projectVersionUtil = projectVersionUtil;
this.projectService = projectService;
}

@Override
void businessHandle(Long projectId, List<ProcessDetailVO> processSchedule) {
ProcessDetailVO processDetailVO = new ProcessDetailVO();
Project project = projectService.getById(projectId);
if (Objects.isNull(project)){
throw new BizException("当前项目不存在!");
}
// 根据项目ID查询项目预审流程的流程状态
ProjectInst projectInst = projectInstService.getOne(Wrappers.lambdaQuery(ProjectInst.class)
.eq(ProjectInst::getProjectId, projectId)
.eq(ProjectInst::getInstType, InstTypeEnum.PRELIMINARY_PREVIEW.getCode())
.orderByDesc(ProjectInst::getCreatOn)
.last("limit 1"));
if (Objects.isNull(projectInst)){
ProcessProgressVo instanceDetail = null;
// 未找到当前版本项目的预审审核流程且当前项目版本号大于1(是被驳回重新申报的项目)
if (Objects.isNull(projectInst)) {
if (project.getVersion() > CommonConst.VERSION_ONE){
// 获取上个版本的信息
instanceDetail = projectVersionUtil.getPreVerProcessInfo(projectId,InstTypeEnum.PRELIMINARY_PREVIEW);
}
}else {
String instCode = projectInst.getInstCode();
instanceDetail = processInstanceService.getProgressInstanceDetail(null, instCode);
}
if (Objects.isNull(instanceDetail)){
processDetailVO.setStepStatus(StepStatusEnum.NOT_START);
processDetailVO.setProcessName(CommonConst.PRELIMINARY_PREVIEW);
processSchedule.add(processDetailVO);
return;
}
String instCode = projectInst.getInstCode();
ProcessProgressVo instanceDetail = processInstanceService.getProgressInstanceDetail(null, instCode);
String status = instanceDetail.getStatus();
if (ProcessStatusEnum.UNDER_REVIEW.getDesc().equals(status)){
processDetailVO.setStepStatus(StepStatusEnum.ON_GOING);


+ 29
- 5
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/handle/UnitInnerAuditHandle.java View File

@@ -1,19 +1,24 @@
package com.ningdatech.pmapi.projectlib.handle;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.util.NdDateUtils;
import com.ningdatech.pmapi.projectlib.enumeration.InstTypeEnum;
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.common.constant.CommonConst;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.projectlib.utils.ProjectVersionUtil;
import com.ningdatech.pmapi.todocenter.utils.BuildUserUtils;
import com.wflow.workflow.bean.dto.ProcessInstanceUserDto;
import com.wflow.workflow.bean.process.ProgressNode;
@@ -39,25 +44,43 @@ public class UnitInnerAuditHandle extends AbstractProcessBusinessHandle {

private final ProcessInstanceService processInstanceService;
private final BuildUserUtils buildUserUtils;
private final ProjectVersionUtil projectVersionUtil;
private final IProjectService projectService;

public UnitInnerAuditHandle(IProjectInstService projectInstService, ProcessInstanceService processInstanceService, BuildUserUtils buildUserUtils){
public UnitInnerAuditHandle(IProjectInstService projectInstService, ProcessInstanceService processInstanceService, BuildUserUtils buildUserUtils, ProjectVersionUtil projectVersionUtil, IProjectService projectService){
this.projectInstService = projectInstService;
this.processInstanceService = processInstanceService;
this.buildUserUtils = buildUserUtils;
this.projectVersionUtil = projectVersionUtil;
this.projectService = projectService;
}

@Override
void businessHandle(Long projectId, List<ProcessDetailVO> processSchedule) {
ProcessDetailVO processDetailVO = new ProcessDetailVO();
Project project = projectService.getById(projectId);
// 根据项目ID查询出单位内部审核流程的流程状态
// 注意:已经在项目库中的项目,一定是单位内部审核已经开始的项目
ProjectInst projectInst = projectInstService.getOne(Wrappers.lambdaQuery(ProjectInst.class)
.eq(ProjectInst::getProjectId, projectId)
.eq(ProjectInst::getInstType, InstTypeEnum.UNIT_INNER_AUDIT.getCode())
.orderByDesc(ProjectInst::getCreatOn)
.last("limit 1"));
String instCode = projectInst.getInstCode();
ProcessProgressVo instanceDetail = processInstanceService.getProgressInstanceDetail(null, instCode);
ProcessProgressVo instanceDetail = null;

// 未找到当前版本项目的单位内部审核流程且当前项目版本号大于1(是被驳回重新申报的项目)
// 注意:已经在项目库中的项目,一定是单位内部审核已经开始的项目
if (Objects.isNull(projectInst)) {
if (project.getVersion() > CommonConst.VERSION_ONE){
// 获取上个版本的信息
instanceDetail = projectVersionUtil.getPreVerProcessInfo(projectId, InstTypeEnum.UNIT_INNER_AUDIT);
}
}else {
String instCode = projectInst.getInstCode();
instanceDetail = processInstanceService.getProgressInstanceDetail(null, instCode);
}
if (Objects.isNull(instanceDetail)){
throw new BizException("未获取到单位内部审核流程详情!");
}
String status = instanceDetail.getStatus();
if (ProcessStatusEnum.UNDER_REVIEW.getDesc().equals(status)){
processDetailVO.setStepStatus(StepStatusEnum.ON_GOING);
@@ -75,6 +98,7 @@ public class UnitInnerAuditHandle extends AbstractProcessBusinessHandle {
if (StepStatusEnum.contains(processDetailVO.getStepStatus(),
Lists.newArrayList(StepStatusEnum.REJECTED,
StepStatusEnum.COMPLETED))) {
// 如果是驳回,获取流程信息时可能
ProgressNode progressNode = progressInfo.get(progressInfo.size() - 1);
LocalDateTime finishTime = NdDateUtils.date2LocalDateTime(progressNode.getFinishTime());
processDetailVO.setFinishTime(finishTime);


+ 224
- 155
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/manage/AnnualPlanLibManage.java View File

@@ -1,12 +1,13 @@
package com.ningdatech.pmapi.projectlib.manage;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -14,7 +15,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.ValidUtil;
import com.ningdatech.basic.util.StrPool;
import com.ningdatech.pmapi.common.constant.CommonConst;
import com.ningdatech.pmapi.common.enumeration.CommonEnum;
import com.ningdatech.pmapi.common.helper.UserInfoHelper;
@@ -23,35 +24,44 @@ import com.ningdatech.pmapi.common.statemachine.util.StateMachineUtils;
import com.ningdatech.pmapi.common.util.ExcelDownUtil;
import com.ningdatech.pmapi.datascope.model.DataScopeDTO;
import com.ningdatech.pmapi.datascope.utils.DataScopeUtil;
import com.ningdatech.pmapi.projectlib.constant.ImportTemplateConstant;
import com.ningdatech.pmapi.projectlib.enumeration.ImportTemplateEnum;
import com.ningdatech.pmapi.expert.constant.ExpertUserInfoSensitiveFieldEnum;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectLibFlagEnum;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectRenewalApprovalStatusEnum;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.helper.ProjectHelper;
import com.ningdatech.pmapi.projectlib.model.dto.AnnualLibExportDTO;
import com.ningdatech.pmapi.projectlib.model.dto.AnnualLibImportDTO;
import com.ningdatech.pmapi.projectlib.model.dto.ProjectDTO;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectRenewalFundDeclaration;
import com.ningdatech.pmapi.projectlib.model.req.ProjectApprovedReq;
import com.ningdatech.pmapi.projectlib.model.req.ProjectIdReq;
import com.ningdatech.pmapi.projectlib.model.req.ProjectListReq;
import com.ningdatech.pmapi.projectlib.model.req.StartProjectDeclareReq;
import com.ningdatech.pmapi.projectlib.model.vo.AnnualPlanListItemVO;
import com.ningdatech.pmapi.projectlib.service.INdProjectStatusChangeService;
import com.ningdatech.pmapi.projectlib.service.IProjectRenewalFundDeclarationService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.security.auth.model.UserInfoDetails;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.ningdatech.pmapi.expert.constant.ExpertUserInfoSensitiveFieldEnum.UnitType.list;
import static com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum.*;

/**
@@ -71,27 +81,15 @@ public class AnnualPlanLibManage {
private final StateMachineUtils stateMachine;
private final INdProjectStatusChangeService statusChangeService;
private final UserInfoHelper userInfoHelper;
private final IProjectRenewalFundDeclarationService projectRenewalFundDeclarationService;

/**
* 年度计划查询状态
*/
private static final List<ProjectStatusEnum> ANNUAL_PLAN_LIST_STATUS = Arrays.asList(
IN_THE_ANNUAL_PLAN,
SCHEME_UNDER_REVIEW,
SCHEME_REVIEW_FAILED,
TO_BE_APPROVED,
TO_BE_DECLARED,
PLAN_TO_BE_DECLARED,
PENDING_PREQUALIFICATION_CHOICE,
PROJECT_APPROVED,
TO_BE_PURCHASED,
UNDER_CONSTRUCTION,
TO_BE_FINALLY_INSPECTED,
FINAL_ACCEPTANCE_IS_UNDER_REVIEW,
FINAL_ACCEPTANCE_REVIEW_FAILED,
ARCHIVED
);

private static final List<ProjectStatusEnum> ANNUAL_PLAN_LIST_STATUS =
Arrays.asList(IN_THE_ANNUAL_PLAN, SCHEME_UNDER_REVIEW, SCHEME_REVIEW_FAILED, TO_BE_APPROVED, TO_BE_DECLARED,
PLAN_TO_BE_DECLARED, PENDING_PREQUALIFICATION_CHOICE, PROJECT_APPROVED, TO_BE_PURCHASED, UNDER_CONSTRUCTION,
TO_BE_FINALLY_INSPECTED, FINAL_ACCEPTANCE_IS_UNDER_REVIEW, FINAL_ACCEPTANCE_REVIEW_FAILED, ARCHIVED);

public PageVo<AnnualPlanListItemVO> annulPlanLibList(ProjectListReq req) {
LambdaQueryWrapper<Project> query = ProjectHelper.projectQuery(req);
@@ -100,9 +98,10 @@ public class AnnualPlanLibManage {
throw new BizException("请传入是否临时增补标志!");
}
query.eq(Project::getIsTemporaryAugment, isTemporaryAugment);
query.eq(Project::getNewest, Boolean.TRUE);
query.orderByDesc(Project::getAnnualPlanAddTime);
query.in(Project::getStatus, CollUtils.fieldList(ANNUAL_PLAN_LIST_STATUS, ProjectStatusEnum::getCode));
//数据权限
// 数据权限
buildProjectLibPermission(query);
Page<Project> page = projectService.page(req.page(), query);
long total;
@@ -122,6 +121,7 @@ public class AnnualPlanLibManage {
item.setDeclaredAmount(w.getDeclareAmount());
item.setBuildOrg(w.getBuildOrgName());
item.setCreateOn(w.getCreateOn());
item.setApprovalAmount(w.getApprovalAmount());
item.setIsStartDeclaredProject(!IN_THE_ANNUAL_PLAN.eq(w.getStatus()));
result.getRecords().add(item);
});
@@ -150,15 +150,12 @@ public class AnnualPlanLibManage {
public void projectApproved(ProjectApprovedReq req) {
Project project = projectService.getById(req.getProjectId());
stateMachine.pass(project);
LambdaUpdateWrapper<Project> update = Wrappers.lambdaUpdate(Project.class)
.set(Project::getApprovalAmount, req.getApprovedAmount())
.set(Project::getApprovedFile, req.getApprovedFileId())
.set(Project::getBuildCycle, req.getBuildCycle())
LambdaUpdateWrapper<Project> update =
Wrappers.lambdaUpdate(Project.class).set(Project::getApprovalAmount, req.getApprovedAmount())
.set(Project::getApprovedFile, req.getApprovedFileId()).set(Project::getBuildCycle, req.getBuildCycle())
.set(Project::getApprovedConstructionPlanFile, req.getBuildPlanFileId())
.set(Project::getApprovalDate, req.getApprovedDate())
.set(Project::getStatus, project.getStatus())
.set(Project::getStage, project.getStage())
.eq(Project::getId, req.getProjectId());
.set(Project::getApprovalDate, req.getApprovedDate()).set(Project::getStatus, project.getStatus())
.set(Project::getStage, project.getStage()).eq(Project::getId, req.getProjectId());
projectService.update(update);
}

@@ -169,112 +166,6 @@ public class AnnualPlanLibManage {
projectService.updateById(project);
}

@Transactional(rollbackFor = Exception.class)
public void importAnnualPlan(ImportTemplateEnum template, MultipartFile file) {
String contentType = file.getContentType();
if (!contentType.equals(ExcelUtil.XLS_CONTENT_TYPE) &&
!contentType.equals(ExcelUtil.XLSX_CONTENT_TYPE)
) {
throw BizException.wrap("导入失败,不支持的文件类型,请按照提供的模板导入文件!");
}
try (InputStream inputStream = file.getInputStream();
ExcelReader reader = ExcelUtil.getReader(inputStream)) {
Map<String, String> alias;
List<String> title = ImportTemplateConstant.getTemplateTitle(template);
switch (template) {
case ANNUAL_PLAN:
alias = new HashMap<>(title.size());
alias.put(title.get(0), "id");
alias.put(title.get(1), "projectId");
alias.put(title.get(2), "projectName");
alias.put(title.get(3), "projectIntroduction");
alias.put(title.get(4), "buildBasis");
alias.put(title.get(5), "isFirst");
alias.put(title.get(6), "buildCycle");
alias.put(title.get(7), "declaredAmount");
alias.put(title.get(8), "annualPlanAmount");
alias.put(title.get(9), "declareHaveAmount");
alias.put(title.get(10), "declareGovOwnFinanceAmount");
alias.put(title.get(11), "declareGovSuperiorFinanceAmount");
alias.put(title.get(12), "declareBankLendingAmount");
alias.put(title.get(13), "declareOtherAmount");
alias.put(title.get(14), "firstQuarter");
alias.put(title.get(15), "secondQuarter");
alias.put(title.get(16), "thirdQuarter");
alias.put(title.get(17), "fourthQuarter");
alias.put(title.get(18), "buildUnitName");
alias.put(title.get(19), "contactName");
alias.put(title.get(20), "responsibleMan");
alias.put(title.get(21), "projectRemarks");
reader.setHeaderAlias(alias);
importAnnualPlanData(reader.readAll(AnnualLibImportDTO.class));
break;
default:
throw new BizException("不支持的数据导入类型");
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private void importAnnualPlanData(List<AnnualLibImportDTO> importDataList) {
if (CollectionUtils.isEmpty(importDataList)) {
return;
}
List<Project> projectList = new ArrayList<>();
List<Long> projectIds = CollUtils.fieldList(importDataList, AnnualLibImportDTO::getProjectId);
Assert.isTrue(projectIds.size() == importDataList.size(), "项目ID不可重复");
Long userId = LoginUserUtil.getUserId();
LocalDateTime now = LocalDateTime.now();
importDataList.forEach(w -> {
Project project = new Project();
project.setCreateBy(userId);
project.setCreateOn(now);
project.setUpdateBy(userId);
project.setUpdateOn(now);

project.setId(w.getProjectId());
project.setProjectName(w.getProjectName());
project.setProjectIntroduction(w.getProjectIntroduction());
// 建设依据(立项依据忽略)
if (CommonConst.NEW_CONSTRUCTION.equals(w.getIsFirst())){
project.setIsFirst(CommonEnum.YES.getCode());
}else if (CommonConst.CONTINUED_CONSTRUCTION.equals(w.getIsFirst())){
project.setIsFirst(CommonEnum.NO.getCode());
}
String buildCycle = w.getBuildCycle();
int index = buildCycle.indexOf(CommonConst.MONTH);
if (-1 == index){
throw new BizException("项目ID为:" + w.getProjectId() + "的建设起止年限格式不正确,请按照xx年xx月至xx年xx月的格式输入!");
}
String beginTime = buildCycle.substring(0, index + 1);
project.setBeginTime(beginTime);
String endTime = buildCycle.substring(index + 2);
project.setEndTime(endTime);
project.setDeclareAmount(w.getDeclaredAmount());
project.setAnnualPlanAmount(w.getAnnualPlanAmount());
project.setDeclareHaveAmount(w.getDeclareHaveAmount());
project.setDeclareGovOwnFinanceAmount(w.getDeclareGovOwnFinanceAmount());
project.setDeclareGovSuperiorFinanceAmount(w.getDeclareGovSuperiorFinanceAmount());
project.setDeclareBankLendingAmount(w.getDeclareBankLendingAmount());
project.setDeclareOtherAmount(w.getDeclareOtherAmount());
project.setEngineeringSpeedOne(w.getFirstQuarter());
project.setEngineeringSpeedTwo(w.getSecondQuarter());
project.setEngineeringSpeedThree(w.getThirdQuarter());
project.setEngineeringSpeedFour(w.getFourthQuarter());

project.setBuildOrgName(w.getBuildUnitName());
project.setContactName(w.getContactName());
project.setResponsibleMan(w.getResponsibleMan());
project.setProjectRemarks(w.getProjectRemarks());
projectList.add(project);
});
LambdaQueryWrapper<Project> delQuery = Wrappers.lambdaQuery(Project.class)
.in(Project::getId, projectIds);
projectService.remove(delQuery);
projectService.saveBatch(projectList);
}

public void updateAnnualPlan(ProjectDTO req) {
Project project = BeanUtil.copyProperties(req, Project.class);
projectService.updateById(project);
@@ -290,20 +181,16 @@ public class AnnualPlanLibManage {
param.setIsTemporaryAugment(isTemporaryAugment);
param.setStatusList(CollUtils.fieldList(ANNUAL_PLAN_LIST_STATUS, ProjectStatusEnum::getCode));
LambdaQueryWrapper<Project> query = ProjectHelper.projectQuery(param);
query.eq(Project::getNewest, Boolean.TRUE);
query.orderByDesc(Project::getAnnualPlanAddTime);
List<Project> projects = projectService.list(query);

ExcelExportWriter excelExportWriter = new ExcelExportWriter();

Integer tableFlag = param.getTableFlag();
if (Objects.isNull(tableFlag)) {
throw new BizException("请传入要导出的表格类型!");
}
String fileName = null;
if (tableFlag == 0) {
fileName = "年度计划库编辑表";
} else if (tableFlag == 1) {
if (CommonEnum.NO.getCode().equals(isTemporaryAugment)) {
fileName = "年度计划库列表";
} else if (CommonEnum.YES.getCode().equals(isTemporaryAugment)) {
fileName = "年度计划增补库列表";
}
excelExportWriter.setFileName(fileName);
List<String> sheetsNames = new ArrayList<>();
@@ -335,25 +222,207 @@ public class AnnualPlanLibManage {
}
switch (currentUserDataScope.get().getRole()) {
case NORMAL_MEMBER:
//普通用户 只能看到自己单位去申报的
// 普通用户 只能看到自己单位去申报的
query.eq(Project::getBuildOrgCode, user.getEmpPosUnitCode());
break;
case COMPANY_MANAGER:
//单位管理员 看到自己单位去申报的 + 待预审的主管单位是自己单位的项目
// 单位管理员 看到自己单位去申报的 + 待预审的主管单位是自己单位的项目
query.eq(Project::getBuildOrgCode, user.getEmpPosUnitCode());
break;
case SUPER_ADMIN:
//超级管理员 看到丽水全市的 并且也要判断他 同时是不是单位管理员
// 超级管理员 看到丽水全市的 并且也要判断他 同时是不是单位管理员
break;
case REGION_MANAGER:
//区域管理员 看到自己区域的项目
// 区域管理员 看到自己区域的项目
query.eq(Project::getAreaCode, user.getRegionCode());
break;
default:
//没有权限的话 就让它查不到
// 没有权限的话 就让它查不到
query.eq(Project::getId, "NULL");
break;
}
return user;
}

@Transactional(rollbackFor = Exception.class)
public void importAnnualPlan(ProjectLibFlagEnum importFlag, MultipartFile file) {
Long userId = LoginUserUtil.getUserId();
ImportParams params = new ImportParams();
// 标题行数
params.setTitleRows(2);
// 从第几行开始,因为第一、二个大标题被上面的参数给占了,所以不是5
params.setHeadRows(3);
// 表格数量
params.setSheetNum(2);
List<AnnualLibImportDTO> list = null;
try {
list = ExcelImportUtil.importExcel(file.getInputStream(), AnnualLibImportDTO.class, params);
} catch (Exception e) {
throw new BizException(e.getMessage());
}
// 筛选出导入的新建项目
List<AnnualLibImportDTO> newList =
list.stream().filter(d -> CommonConst.NEW_CONSTRUCTION.equals(d.getIsFirst())).collect(Collectors.toList());
List<Project> projectList = newList.stream().map(n -> {
Project project = new Project();
assemblyProjectInfo(n, project);
// 根据传入标志判断是否临时增补
if (ProjectLibFlagEnum.ANNUAL_PLAN.equals(importFlag)) {
project.setIsTemporaryAugment(CommonEnum.NO.getCode());
} else if (ProjectLibFlagEnum.ANNUAL_PLAN_SUPPLEMENT.equals(importFlag)) {
project.setIsTemporaryAugment(CommonEnum.YES.getCode());
}
project.setCreateBy(userId);
project.setUpdateBy(userId);
project.setCreateOn(LocalDateTime.now());
project.setUpdateOn(LocalDateTime.now());
return project;
}).collect(Collectors.toList());
// 保存到项目库中
projectService.saveBatch(projectList);

// 筛选出导入的续建项目
List<AnnualLibImportDTO> continuedList = list.stream()
.filter(d -> CommonConst.CONTINUED_CONSTRUCTION.equals(d.getIsFirst())).collect(Collectors.toList());
List<ProjectRenewalFundDeclaration> renewalFundDeclarationList = continuedList.stream().map(c -> {
ProjectRenewalFundDeclaration renewalFundDeclaration = new ProjectRenewalFundDeclaration();
BeanUtils.copyProperties(c, renewalFundDeclaration);
renewalFundDeclaration.setAnnualPaymentAmount(c.getAnnualPlanAmount());
renewalFundDeclaration.setOtherAmount(c.getDeclareOtherAmount());
renewalFundDeclaration.setApprovalStatus(ProjectRenewalApprovalStatusEnum.PENDING.name());
renewalFundDeclaration.setCreateOn(LocalDateTime.now());
renewalFundDeclaration.setUpdateOn(LocalDateTime.now());
return renewalFundDeclaration;
}).collect(Collectors.toList());
// 保存到续建项目资金库中
projectRenewalFundDeclarationService.saveBatch(renewalFundDeclarationList);
}

private void assemblyProjectInfo(AnnualLibImportDTO data, Project project) {
project.setId(data.getProjectId());
project.setProjectName(data.getProjectName());
project.setProjectIntroduction(data.getProjectIntroduction());
// 建设依据忽略
project.setIsFirst(CommonConst.NEW_CONSTRUCTION.equals(data.getIsFirst()) ? 1 : 0);
String[] dataArr = data.getBuildCycle().split(CommonConst.ZHI);
if (CollectionUtils.isEmpty(Arrays.asList(dataArr))) {
throw new BizException("项目ID为:" + data.getProjectId() + "的建设起止年限格式不正确,请按照xx年xx月至xx年xx月的格式输入!");
}
project.setBeginTime(dataArr[0].trim());
project.setEndTime(dataArr[1].trim());
project.setDeclareAmount(data.getDeclaredAmount());
project.setAnnualPlanAmount(data.getAnnualPlanAmount());
project.setDeclareHaveAmount(data.getDeclareHaveAmount());
project.setDeclareGovOwnFinanceAmount(data.getDeclareGovOwnFinanceAmount());
project.setDeclareGovSuperiorFinanceAmount(data.getDeclareGovSuperiorFinanceAmount());
project.setDeclareBankLendingAmount(data.getDeclareBankLendingAmount());
project.setDeclareOtherAmount(data.getDeclareOtherAmount());
project.setEngineeringSpeedOne(data.getFirstQuarter());
project.setEngineeringSpeedTwo(data.getSecondQuarter());
project.setEngineeringSpeedThree(data.getThirdQuarter());
project.setEngineeringSpeedFour(data.getFourthQuarter());
project.setBuildOrgName(data.getBuildUnitName());
project.setContactName(data.getContactName());
project.setResponsibleMan(data.getResponsibleMan());
project.setProjectRemarks(data.getProjectRemarks());
}

public void exportModifyList(ProjectListReq param, HttpServletResponse response) {
int year = LocalDateTime.now().getYear();
Integer isTemporaryAugment = param.getIsTemporaryAugment();
if (Objects.isNull(isTemporaryAugment)) {
throw new BizException("请传入是否临时增补标志!");
}
param.setIsTemporaryAugment(isTemporaryAugment);
String fileName = null;
// 设置excel的文件名称和是否增补
if (CommonEnum.NO.getCode().equals(isTemporaryAugment)) {
fileName = "丽水市" + year + "年数字化项目年度计划库编辑表";
} else if (CommonEnum.YES.getCode().equals(isTemporaryAugment)) {
fileName = "丽水市" + year + "年数字化项目年度计划增补库编辑表";
}
LambdaQueryWrapper<Project> query = ProjectHelper.projectQuery(param);
query.eq(Project::getIsTemporaryAugment, isTemporaryAugment);
query.orderByDesc(Project::getAnnualPlanAddTime);
query.in(Project::getStatus, CollUtils.fieldList(ANNUAL_PLAN_LIST_STATUS, ProjectStatusEnum::getCode));
// 数据权限
buildProjectLibPermission(query);
List<Project> projects = projectService.list(query);
List<AnnualLibExportDTO> list = projects.stream().map(p -> {
AnnualLibExportDTO dto = new AnnualLibExportDTO();
BeanUtils.copyProperties(p, dto);
String beginTime = p.getBeginTime();
String begin = beginTime.replace(StrPool.DASH, CommonConst.YEAR);
begin = begin + CommonConst.MONTH;
String endTime = p.getEndTime();
String end = endTime.replace(StrPool.DASH, CommonConst.YEAR);
end = end + CommonConst.MONTH;
String buildCycle = begin + CommonConst.ZHI + end;
dto.setBuildCycle(buildCycle);
dto.setProjectId(p.getId());
dto.setDeclaredAmount(p.getDeclareAmount());
dto.setBuildUnitName(p.getBuildOrgName());
String buildBasis = p.getBuildBasis();
List<JSONObject> fileArray = JSON.parseArray(buildBasis, JSONObject.class);
List<String> nameList = CollUtils.fieldList(fileArray, w -> w.getString(CommonConst.TITLE)
+ StrPool.LEFT_BRACKET + w.getString(CommonConst.BASIS_FILE_NAME) + StrPool.RIGHT_BRACKET);
String basis = nameList.stream().collect(Collectors.joining(StrPool.COMMA));
dto.setBuildBasis(basis);
if (CommonEnum.YES.getCode().equals(p.getIsFirst())) {
dto.setIsFirst(CommonConst.NEW_CONSTRUCTION);
} else if (CommonEnum.NO.getCode().equals(p.getIsFirst())) {
dto.setIsFirst(CommonConst.CONTINUED_CONSTRUCTION);
}
dto.setFirstQuarter(p.getEngineeringSpeedOne());
dto.setSecondQuarter(p.getEngineeringSpeedTwo());
dto.setThirdQuarter(p.getEngineeringSpeedThree());
dto.setFourthQuarter(p.getEngineeringSpeedFour());
return dto;
}).collect(Collectors.toList());

int count = 0;
for (AnnualLibExportDTO annualLibExportDTO : list) {
count++;
annualLibExportDTO.setSerialNumber(count);
}

// 获取本地目录的年度计划编辑表Excel模板
File directory = new File("");
String templateName = "丽水市" + year + "年数字化项目年度计划编辑表";
String templatePath =
directory.getAbsolutePath() + File.separator + "template" + File.separator + templateName + ".xls";
TemplateExportParams temp = new TemplateExportParams(templatePath);
temp.setSheetNum(new Integer[] {0, 1});
temp.setSheetName(new String[] {"实施类(新建)", "实施类(续建)"});
Map<String, Object> map = new HashMap<>(4);
map.put("mapList", list);
map.put("mapList1", null);
Workbook workbook = ExcelExportUtil.exportExcel(temp, map);
if (workbook == null) {
throw new BizException("读取模板失败!");
}
// 重置响应对象
response.reset();
try {
response.setHeader("Content-disposition",
"attachment;filename*=utf-8''" + URLEncoder.encode(Objects.requireNonNull(fileName), "UTF-8") + ".xls");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
response.setContentType(ExcelUtil.XLS_CONTENT_TYPE);
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
// 写出数据输出流到页面
try {
OutputStream output = response.getOutputStream();
BufferedOutputStream bufferedOutPut = new BufferedOutputStream(output);
workbook.write(bufferedOutPut);
bufferedOutPut.flush();
bufferedOutPut.close();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

+ 209
- 6
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/manage/ProjectLibManage.java View File

@@ -1,38 +1,47 @@
package com.ningdatech.pmapi.projectlib.manage;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.ningdatech.basic.function.VUtils;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.file.entity.File;
import com.ningdatech.file.service.FileService;
import com.ningdatech.pmapi.common.constant.CommonConst;
import com.ningdatech.pmapi.common.constant.RegionConst;
import com.ningdatech.pmapi.common.enumeration.CommonEnum;
import com.ningdatech.pmapi.common.enumeration.ProjectProcessStageEnum;
import com.ningdatech.pmapi.common.helper.RegionCacheHelper;
import com.ningdatech.pmapi.common.helper.UserInfoHelper;
import com.ningdatech.pmapi.common.model.entity.ExcelExportWriter;
import com.ningdatech.pmapi.common.statemachine.util.StateMachineUtils;
import com.ningdatech.pmapi.common.util.BizUtils;
import com.ningdatech.pmapi.common.util.ExcelDownUtil;
import com.ningdatech.pmapi.datascope.model.DataScopeDTO;
import com.ningdatech.pmapi.datascope.utils.DataScopeUtil;
import com.ningdatech.pmapi.projectdeclared.utils.GenerateProjectCodeUtil;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.handle.ProcessExecuteChainHandle;
import com.ningdatech.pmapi.projectlib.helper.ProjectHelper;
import com.ningdatech.pmapi.projectlib.model.dto.ProjectApplicationDTO;
import com.ningdatech.pmapi.projectlib.model.dto.ProjectDTO;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectApplication;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectInst;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectRenewalFundDeclaration;
import com.ningdatech.pmapi.projectlib.model.req.ProjectListReq;
import com.ningdatech.pmapi.projectlib.model.vo.AnnualAmountVO;
import com.ningdatech.pmapi.projectlib.model.vo.ProjectDetailVO;
import com.ningdatech.pmapi.projectlib.model.vo.ProjectLibListItemVO;
import com.ningdatech.pmapi.projectlib.service.INdProjectStatusChangeService;
import com.ningdatech.pmapi.projectlib.service.IProjectApplicationService;
import com.ningdatech.pmapi.projectlib.service.IProjectRenewalFundDeclarationService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.projectlib.service.*;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import com.wflow.exception.BusinessException;
import com.wflow.workflow.bean.vo.ProcessDetailVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -41,7 +50,9 @@ import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
* <p>
@@ -60,14 +71,18 @@ public class ProjectLibManage {
private final IProjectApplicationService applicationService;
private final IProjectRenewalFundDeclarationService renewalFundDeclarationService;
private final ProcessExecuteChainHandle processExecuteHandle;
private final INdProjectStatusChangeService projectStatusChangeService;
private final RegionCacheHelper regionCacheHelper;
private final FileService fileService;

private final UserInfoHelper userInfoHelper;
private final IProjectApplicationService projectApplicationService;
private final GenerateProjectCodeUtil generateProjectCodeUtil;
private final IProjectInstService projectInstService;

private final StateMachineUtils stateMachineUtils;

public PageVo<ProjectLibListItemVO> projectLibList(ProjectListReq req) {
LambdaQueryWrapper<Project> query = ProjectHelper.projectQuery(req);
query.eq(Project::getNewest,Boolean.TRUE);
Page<Project> page = projectService.page(req.page(), query);
long total;
if ((total = page.getTotal()) == 0) {
@@ -96,6 +111,8 @@ public class ProjectLibManage {
public PageVo<ProjectLibListItemVO> projectLibListWithPermission(ProjectListReq req) {
LambdaQueryWrapper<Project> query = ProjectHelper.projectQuery(req);
UserFullInfoDTO user = buildProjectLibPermission(query);
//项目查最新
query.eq(Project::getNewest,Boolean.TRUE);
Page<Project> page = projectService.page(req.page(), query);
long total;
if ((total = page.getTotal()) == 0) {
@@ -133,6 +150,187 @@ public class ProjectLibManage {
}

/**
* 申报新项目时 保存项目信息和其它相关联的信息
* @param projectDto
* @param instanceId
* @param employeeCode
* @return
*/
public Project saveProjectInDeclared(ProjectDTO projectDto, String instanceId,
String employeeCode) {
Project project = saveProjectNewVersion(projectDto,instanceId,employeeCode);
//保存项目和实例的关系
ProjectInst projectInst = new ProjectInst();
projectInst.setProjectId(project.getId());
projectInst.setInstCode(instanceId);
projectInst.setCreatOn(LocalDateTime.now());
projectInst.setUpdateOn(LocalDateTime.now());
projectInst.setInstType(ProjectProcessStageEnum.ORG_INTERNAL_APPROVAL_PROCESS.getCode());
projectInstService.save(projectInst);
return project;
}

/**
* 申报新项目时 保存项目信息和其它相关联的信息
* @param projectDto
* @param instanceId
* @param employeeCode
* @return
*/
public Project saveProjectNewVersion(ProjectDTO projectDto, String instanceId,
String employeeCode) {
//流程启动之后 入库项目 重要业务信息 用于列表查询 展示
try {
Project project = new Project();
//为空 代表是新申报的
if(Objects.isNull(projectDto.getId())){
BeanUtils.copyProperties(projectDto, project);
project.setCreateOn(LocalDateTime.now());
project.setUpdateOn(LocalDateTime.now());
project.setStage(ProjectStatusEnum.NOT_APPROVED.getCode());
project.setStatus(ProjectStatusEnum.UNDER_INTERNAL_AUDIT.getCode());
project.setInstCode(instanceId);
project.setSponsor(employeeCode);
String projectCode = generateProjectCodeUtil.generateProjectCode(projectDto);
project.setProjectCode(projectCode);
projectService.save(project);
}else{
//否则是重新提交的 新生成一个新版本的项目
project = newProjectWithVersion(projectDto);
project.setInstCode(instanceId);
project.setSponsor(employeeCode);
projectService.updateById(project);
}

//保存项目应用
Boolean isApp = Objects.nonNull(projectDto.getIncludeApplication()) && CommonEnum.YES.getCode().equals(projectDto.getIncludeApplication())
? Boolean.TRUE : Boolean.FALSE;
//采取批量删除 批量添加的方式
projectApplicationService.remove(Wrappers.lambdaQuery(ProjectApplication.class)
.eq(ProjectApplication::getProjectId,project.getId()));
if (isApp && CollUtil.isNotEmpty(projectDto.getApplicationList())) {
Project finalProject = project;
List<ProjectApplication> applications = projectDto.getApplicationList().stream().map(application -> {
ProjectApplication projectApplication = new ProjectApplication();
BeanUtils.copyProperties(application, projectApplication);
projectApplication.setProjectId(finalProject.getId());
return projectApplication;
}).collect(Collectors.toList());
projectApplicationService.saveOrUpdateBatch(applications);
}
return project;
} catch (Exception e) {
log.error("项目信息入库错误 " + e);
throw new BusinessException("项目信息入库错误 :" + e);
}
}

/**
* 在其它项目阶段 保存项目信息和其它相关联的信息
* @param projectDto
* @return
*/
public Project reSaveProjectNewVersion(ProjectDTO projectDto) {
//流程启动之后 入库项目 重要业务信息 用于列表查询 展示
try {
Project project = newProjectWithVersion(projectDto);

//保存项目应用
Boolean isApp = Objects.nonNull(projectDto.getIncludeApplication()) && CommonEnum.YES.getCode().equals(projectDto.getIncludeApplication())
? Boolean.TRUE : Boolean.FALSE;
//采取批量删除 批量添加的方式
projectApplicationService.remove(Wrappers.lambdaQuery(ProjectApplication.class)
.eq(ProjectApplication::getProjectId,project.getId()));
if (isApp && CollUtil.isNotEmpty(projectDto.getApplicationList())) {
Project finalProject = project;
List<ProjectApplication> applications = projectDto.getApplicationList().stream().map(application -> {
ProjectApplication projectApplication = new ProjectApplication();
BeanUtils.copyProperties(application, projectApplication);
projectApplication.setProjectId(finalProject.getId());
return projectApplication;
}).collect(Collectors.toList());
projectApplicationService.saveOrUpdateBatch(applications);
}
return project;
} catch (Exception e) {
log.error("项目信息入库错误 " + e);
throw new BusinessException("项目信息入库错误 :" + e);
}
}

/**
* 重新提交工作流时 舍弃在原有项目修改
* 新增一个新的项目 新的版本号
*/
public Project newProjectWithVersion(ProjectDTO projecDto){
Project oldProject = projectService.getById(projecDto.getId());
Project project = new Project();
VUtils.isTrue(Objects.isNull(oldProject))
.throwMessage("项目不存在!");
BeanUtil.copyProperties(oldProject,project, CopyOptions.create()
.setIgnoreError(Boolean.TRUE).setIgnoreNullValue(Boolean.TRUE));
BeanUtil.copyProperties(projecDto,project, CopyOptions.create()
.setIgnoreError(Boolean.TRUE).setIgnoreNullValue(Boolean.TRUE));
project.setVersion(oldProject.getVersion() + 1);
project.setId(null);
project.setCreateOn(LocalDateTime.now());
project.setUpdateOn(LocalDateTime.now());
stateMachineUtils.pass(project);
projectService.save(project);

projectService.update(Wrappers.lambdaUpdate(Project.class)
.set(Project::getNewest,Boolean.FALSE)
.ne(Project::getId,project.getId())
.eq(Project::getProjectCode,project.getProjectCode()));

return project;
}

public Project saveProjectWithVersionAndStatus(ProjectDTO projecDto,Integer stageCode,Integer statusCode){
Project oldProject = projectService.getById(projecDto.getId());
Project project = new Project();
VUtils.isTrue(Objects.isNull(oldProject))
.throwMessage("项目不存在!");
BeanUtil.copyProperties(oldProject,project, CopyOptions.create()
.setIgnoreError(Boolean.TRUE).setIgnoreNullValue(Boolean.TRUE));
BeanUtil.copyProperties(projecDto,project, CopyOptions.create()
.setIgnoreError(Boolean.TRUE).setIgnoreNullValue(Boolean.TRUE));
project.setVersion(oldProject.getVersion() + 1);
project.setId(null);
project.setCreateOn(LocalDateTime.now());
project.setUpdateOn(LocalDateTime.now());
if(Objects.nonNull(stageCode)){
project.setStage(stageCode);
}
if(Objects.nonNull(statusCode)){
project.setStatus(statusCode);
}

if(projectService.save(project)){
projectService.update(Wrappers.lambdaUpdate(Project.class)
.set(Project::getNewest,Boolean.FALSE)
.ne(Project::getId,project.getId())
.eq(Project::getProjectCode,project.getProjectCode()));

//app
List<ProjectApplicationDTO> applicationList = projecDto.getApplicationList();
if(CollUtil.isNotEmpty(applicationList)){
List<ProjectApplication> apps = applicationList.stream()
.map(a -> {
ProjectApplication app = BeanUtil.copyProperties(a,ProjectApplication.class);
app.setId(null);
app.setProjectId(project.getId());
return app;
})
.collect(Collectors.toList());
projectApplicationService.saveBatch(apps);
}
}

return project;
}

/**
* @param projectId 项目详情
* @return com.ningdatech.pmapi.projectlib.model.entity.vo.ProjectDetailVO
* @author ZPF
@@ -199,6 +397,7 @@ public class ProjectLibManage {
param.setPageNumber(CommonConst.EXPORT_PAGE_NUMBER);
param.setPageSize(CommonConst.EXPORT_PAGE_SIZE);
LambdaQueryWrapper<Project> query = ProjectHelper.projectQuery(param);
query.eq(Project::getNewest,Boolean.TRUE);
List<Project> projects = projectService.list(query);

ExcelExportWriter excelExportWriter = new ExcelExportWriter();
@@ -271,4 +470,8 @@ public class ProjectLibManage {
}
return user;
}

private void copyProperties(ProjectDTO projecDto, Project project) {

}
}

+ 102
- 0
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/dto/AnnualLibExportDTO.java View File

@@ -0,0 +1,102 @@
package com.ningdatech.pmapi.projectlib.model.dto;

import java.math.BigDecimal;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

import cn.afterturn.easypoi.excel.annotation.Excel;
import lombok.Data;

/**
* <p>
* AnnualLibImportDTO
* </p>
*
* @author WendyYang
* @since 13:46 2023/2/13
*/
@Data
public class AnnualLibExportDTO {

@NotNull(message = "年度投资额不能为空")
@Excel(name = "年度投资额",groupName = "2023年计划")
private BigDecimal annualPlanAmount;

@NotNull(message = "自由资金不能为空")
@Excel(name = "自有资金",groupName = "资金来源")
private BigDecimal declareHaveAmount;
@Excel(name = "政府投资-本级财政资金")
@NotNull(message = "政府投资-本级财政不能为空")
private BigDecimal declareGovOwnFinanceAmount;
@Excel(name = "政府投资-上级补助资金")
@NotNull(message = "政府投资-上级补助资金不能为空")
private BigDecimal declareGovSuperiorFinanceAmount;
@Excel(name = "银行贷款")
@NotNull(message = "银行贷款不能为空")
private BigDecimal declareBankLendingAmount;
@Excel(name = "其他")
@NotNull(message = "其他不能为空")
private BigDecimal declareOtherAmount;

@Excel(name = "一季度",groupName = "进度和支付计划")
@NotBlank(message = "一季度不能为空")
private String firstQuarter;
@Excel(name = "二季度")
@NotBlank(message = "二季度不能为空")
private String secondQuarter;
@Excel(name = "三季度")
@NotBlank(message = "三季度不能为空")
private String thirdQuarter;
@Excel(name = "四季度")
@NotBlank(message = "四季度不能为空")
private String fourthQuarter;

@NotNull(message = "序号不能为空")
@Excel(name = "序号")
private Integer serialNumber;

@Excel(name = "项目id")
@NotNull(message = "项目ID不能为空")
private Long projectId;

@Excel(name = "项目名称")
@NotBlank(message = "项目名称不能为空")
private String projectName;

@NotBlank(message = "建设内容不能为空")
@Excel(name = "建设内容")
private String projectIntroduction;

@NotBlank(message = "建设依据不能为空")
@Excel(name = "建设依据")
private String buildBasis;

@Excel(name = "建设性质")
@NotBlank(message = "建设性质不能为空")
private String isFirst;

@Excel(name = "建设起止年限(填写到月)")
@NotBlank(message = "建设起止年限不能为空")
private String buildCycle;

@NotBlank(message = "总投资不能为空")
@Excel(name = "总投资")
private BigDecimal declaredAmount;

@Excel(name = "建设单位")
@NotBlank(message = "建设单位不能为空")
private String buildUnitName;

@Excel(name = "项目联系人")
@NotBlank(message = "项目联系人不能为空")
private String contactName;

@Excel(name = "项目分管领导")
@NotBlank(message = "项目分管领导不能为空")
private String responsibleMan;

@Excel(name = "备注")
private String projectRemarks;

}

+ 66
- 52
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/dto/AnnualLibImportDTO.java View File

@@ -1,5 +1,6 @@
package com.ningdatech.pmapi.projectlib.model.dto;

import cn.afterturn.easypoi.excel.annotation.Excel;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

@@ -18,91 +19,104 @@ import java.math.BigDecimal;
@Data
public class AnnualLibImportDTO {

@ExcelProperty("序号")
@NotNull(message = "序号不能为空")
private Integer serialNumber;

@ExcelProperty("项目id")
@NotNull(message = "项目ID不能为空")
private Long projectId;

@ExcelProperty("项目名称")
@NotBlank(message = "项目名称不能为空")
private String projectName;

@NotBlank(message = "建设内容不能为空")
@ExcelProperty("建设内容")
private String projectIntroduction;

@NotBlank(message = "建设依据不能为空")
@ExcelProperty("建设依据")
private String buildBasis;

@ExcelProperty("建设性质")
@NotBlank(message = "建设性质不能为空")
private String isFirst;

@ExcelProperty("建设起止年限")
@NotBlank(message = "建设起止年限不能为空")
private String buildCycle;

@NotBlank(message = "总投资不能为空")
@ExcelProperty("总投资")
private BigDecimal declaredAmount;
@Excel(name = "项目进展",groupName = "到2022年底完成情况")
@NotNull(message = "项目进展不能为空")
private String projectProgress;
@Excel(name = "累计投资")
@NotNull(message = "累计投资不能为空")
private BigDecimal cumulativeInvest;

@NotNull(message = "年度投资额不能为空")
@ExcelProperty("年度投资额")
@Excel(name = "年度投资额",groupName = "2023年计划")
private BigDecimal annualPlanAmount;

@ExcelProperty("自有资金")
@NotNull(message = "自由资金不能为空")
@Excel(name = "自有资金",groupName = "资金来源")
private BigDecimal declareHaveAmount;

@ExcelProperty("政府投资-本级财政")
@Excel(name = "政府投资-本级财政资金")
@NotNull(message = "政府投资-本级财政不能为空")
private BigDecimal declareGovOwnFinanceAmount;

@ExcelProperty("政府投资-上级补助资金")
@Excel(name = "政府投资-上级补助资金")
@NotNull(message = "政府投资-上级补助资金不能为空")
private BigDecimal declareGovSuperiorFinanceAmount;

@ExcelProperty("银行贷款")
@Excel(name = "银行贷款")
@NotNull(message = "银行贷款不能为空")
private BigDecimal declareBankLendingAmount;

@ExcelProperty("其他")
@Excel(name = "国家、省补助",groupName = "资金来源")
@NotNull(message = "国家、省补助不能为空")
private BigDecimal govSuperiorFinanceAmount;
@Excel(name = "地方财政统筹")
@NotNull(message = "地方财政统筹不能为空")
private BigDecimal govOwnFinanceAmount;
@Excel(name = "建设单位自筹")
@NotNull(message = "建设单位自筹不能为空")
private BigDecimal haveAmount;
@Excel(name = "其他")
@NotNull(message = "其他不能为空")
private BigDecimal declareOtherAmount;

@ExcelProperty("一季度")
@Excel(name = "一季度",groupName = "进度和支付计划")
@NotBlank(message = "一季度不能为空")
private String firstQuarter;

@ExcelProperty("二季度")
@Excel(name = "二季度")
@NotBlank(message = "二季度不能为空")
private String secondQuarter;

@ExcelProperty("三季度")
@Excel(name = "三季度")
@NotBlank(message = "三季度不能为空")
private String thirdQuarter;

@ExcelProperty("四季度")
@Excel(name = "四季度")
@NotBlank(message = "四季度不能为空")
private String fourthQuarter;

@ExcelProperty("建设单位")
@NotNull(message = "序号不能为空")
@Excel(name = "序号")
private Integer serialNumber;

@Excel(name = "项目id")
@NotNull(message = "项目ID不能为空")
private Long projectId;

@Excel(name = "项目名称")
@NotBlank(message = "项目名称不能为空")
private String projectName;

@NotBlank(message = "建设内容不能为空")
@Excel(name = "建设内容")
private String projectIntroduction;

@NotBlank(message = "建设依据不能为空")
@Excel(name = "建设依据")
private String buildBasis;

@Excel(name = "建设性质")
@NotBlank(message = "建设性质不能为空")
private String isFirst;

@Excel(name = "建设周期")
@NotBlank(message = "建设周期不能为空")
private String constructionCycle;

@Excel(name = "建设起止年限(填写到月)")
@NotBlank(message = "建设起止年限不能为空")
private String buildCycle;

@NotBlank(message = "总投资不能为空")
@Excel(name = "总投资")
private BigDecimal declaredAmount;

@Excel(name = "建设单位")
@NotBlank(message = "建设单位不能为空")
private String buildUnitName;

@ExcelProperty("项目联系人")
@Excel(name = "项目联系人")
@NotBlank(message = "项目联系人不能为空")
private String contactName;

@ExcelProperty("项目分管领导")
@Excel(name = "项目分管领导")
@NotBlank(message = "项目分管领导不能为空")
private String responsibleMan;

@ExcelProperty("备注")
@Excel(name = "备注")
private String projectRemarks;

}

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

@@ -282,6 +282,9 @@ public class ProjectDTO implements Serializable {
@ApiModelProperty("项目发起人 员工code")
private String sponsor;

@ApiModelProperty("预审发起人 员工code")
private String preStartUserId;

@ApiModelProperty("上级条线单位审核意见")
private String higherLineSuperOrgReviewComments;



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

@@ -0,0 +1,92 @@
package com.ningdatech.pmapi.projectlib.model.entity;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.pmapi.common.constant.CommonConst;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;

import java.util.*;

/**
* @author CMM
* @since 2023/04/17 18:26
*/
@Data
public class AnalysisEventMonitor extends AnalysisEventListener<Map<Integer, String>> {

private final List<Project> records = new ArrayList<>();

/**
* 存储Key
*/
Map<Integer, String> key = new HashMap<>();
/**
* keyList
*/
List<String> keyList = new ArrayList<>();

@Override
public void onException(Exception exception, AnalysisContext context) throws Exception {
super.onException(exception, context);
throw BizException.wrap("导入年度计划解析失败");
}

@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
Set<Integer> integerSet = headMap.keySet();
for (Integer integer : integerSet) {
keyList.add(headMap.get(integer));
}
key.putAll(headMap);
}

@Override
public void invoke(Map<Integer, String> integerStringMap, AnalysisContext context) {
//Project project = new Project();
//project.setId(data.getProjectId());
//project.setProjectName(data.getProjectName());
//project.setProjectIntroduction(data.getProjectIntroduction());
//// 建设依据忽略
//project.setIsFirst(CommonConst.NEW_CONSTRUCTION.equals(data.getIsFirst()) ? 1 : 0);
//String[] dataArr = data.getBuildCycle().split(CommonConst.ZHI);
//project.setBeginTime(dataArr[0].trim());
//project.setEndTime(dataArr[1].trim());
//project.setDeclareAmount(data.getDeclaredAmount());
//project.setAnnualPlanAmount(data.getAnnualPlanAmount());
//project.setDeclareHaveAmount(data.getDeclareHaveAmount());
//project.setDeclareGovOwnFinanceAmount(data.getDeclareGovOwnFinanceAmount());
//project.setDeclareGovSuperiorFinanceAmount(data.getDeclareGovSuperiorFinanceAmount());
//project.setDeclareBankLendingAmount(data.getDeclareBankLendingAmount());
//project.setDeclareOtherAmount(data.getDeclareOtherAmount());
//project.setEngineeringSpeedOne(data.getFirstQuarter());
//project.setEngineeringSpeedTwo(data.getSecondQuarter());
//project.setEngineeringSpeedThree(data.getThirdQuarter());
//project.setEngineeringSpeedFour(data.getFourthQuarter());
//project.setBuildOrgName(data.getBuildUnitName());
//project.setContactName(data.getContactName());
//project.setResponsibleMan(data.getResponsibleMan());
//project.setProjectRemarks(data.getProjectRemarks());
//records.add(project);
}

@Override
public void doAfterAllAnalysed(AnalysisContext context) {
//if (records.isEmpty()) {
// throw BizException.wrap("导入年度计划为空");
//}
//List<Long> projectIds = CollUtils.fieldList(records, Project::getId);
//long count = projectService.count(Wrappers.lambdaQuery(Project.class)
// .in(Project::getId, projectIds));
//if (count != records.size()) {
// throw BizException.wrap("请确保所有项目都存在");
//}
//projectService.updateBatchById(records);
}
}

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

@@ -324,4 +324,9 @@ public class Project implements Serializable {
@ApiModelProperty("省级联审 审批结果")
private String sjlsResult;

@ApiModelProperty("版本号")
private Integer version;

@ApiModelProperty("是否是最新版本")
private Boolean newest;
}

+ 1
- 4
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/req/ProjectListReq.java View File

@@ -2,12 +2,12 @@ package com.ningdatech.pmapi.projectlib.model.req;

import com.ningdatech.basic.model.PagePo;
import com.ningdatech.pmapi.common.enumeration.ExportOptionEnum;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectLibFlagEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@@ -91,7 +91,4 @@ public class ProjectListReq extends PagePo {

@ApiModelProperty("导出选项")
private List<ExportOptionEnum> exportOptionList;

@ApiModelProperty(value = "表格类型",allowableValues = "0,1")
private Integer tableFlag;
}

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

@@ -29,6 +29,9 @@ public class AnnualPlanListItemVO {
@ApiModelProperty("申报金额")
private BigDecimal declaredAmount;

@ApiModelProperty("立项批复金额")
private BigDecimal approvalAmount;

@ApiModelProperty("预算年度")
private Integer projectYear;



+ 6
- 0
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/model/vo/ProjectDetailVO.java View File

@@ -322,6 +322,12 @@ public class ProjectDetailVO {
@ApiModelProperty("省级联审 审批结果")
private String sjlsResult;

@ApiModelProperty("版本号")
private Integer version;

@ApiModelProperty("是否是最新版本")
private Boolean newest;

private LocalDateTime createOn;
private LocalDateTime updateOn;



+ 92
- 0
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/utils/ProjectVersionUtil.java View File

@@ -0,0 +1,92 @@
package com.ningdatech.pmapi.projectlib.utils;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.pmapi.common.constant.CommonConst;
import com.ningdatech.pmapi.projectlib.enumeration.InstTypeEnum;
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.wflow.workflow.bean.vo.ProcessProgressVo;
import com.wflow.workflow.enums.ProcessHandlerEnum;
import com.wflow.workflow.enums.ProcessStatusEnum;
import com.wflow.workflow.service.ProcessInstanceService;
import liquibase.pro.packaged.I;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
* 根据项目版本获取流程详情工具类
*
* @author CMM
* @since 2023/04/20 09:57
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class ProjectVersionUtil {

private final IProjectService projectService;
private final ProcessInstanceService processInstanceService;
private final IProjectInstService projectInstService;

/**
* 根据最新的项目ID获取临近项目版本的审核记录信息
* @param projectId
* @return
*/
public ProcessProgressVo getPreVerProcessInfo(Long projectId, InstTypeEnum instTypeEnum){
Project project = projectService.getById(projectId);
if (Objects.isNull(project)){
throw new BizException("当前项目不存在!");
}
String projectCode = project.getProjectCode();
if (StringUtils.isEmpty(projectCode)){
throw new BizException("当前项目编号为空!");
}
// 获取相同项目编号的项目
List<Project> projectList = projectService.list(Wrappers.lambdaQuery(Project.class)
.eq(Project::getProjectCode, projectCode));
if (projectList.size() < CommonConst.VERSION_SIZE){
throw new BizException("未发现该项目的历史版本!");
}

// 获取之前版本的项目
int index = projectList.size() - 1;
ProcessProgressVo instanceDetail = null;
while (index > 0){
index = index - 1;
Project preProject = projectList.get(index);
// 从项目流程实例关联表中查出实例详情
List<ProjectInst> projectInstList = projectInstService.list(Wrappers.lambdaQuery(ProjectInst.class)
.eq(ProjectInst::getProjectId, preProject.getId())
.eq(ProjectInst::getInstType,instTypeEnum.getCode()));
if (CollUtil.isNotEmpty(projectInstList)) {
List<ProcessProgressVo> processProgressVoList = projectInstList.stream()
.map(p -> processInstanceService.getProgressInstanceDetail(null, p.getInstCode()))
.collect(Collectors.toList());
// 筛选出上个版本该类型审核流程通过的流程详情
List<ProcessProgressVo> instanceDetailList = processProgressVoList.stream()
.filter(p -> ProcessStatusEnum.APPROVED.getDesc().equals(p.getStatus()))
.collect(Collectors.toList());
if (CollUtil.isEmpty(instanceDetailList)){
continue;
}
// 获取最后一个流程详情
return instanceDetailList.get(instanceDetailList.size() - 1);
}
}
return null;
}
}

+ 5
- 0
pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/CheckProvincialReviewResultTask.java View File

@@ -75,6 +75,11 @@ public class CheckProvincialReviewResultTask {
log.info("此项目 【{}】 还未审核",projectRes.getProjectId());
} else if(ProjectProvincialAuditStatusEnum.AUDITING.getCode().equals(projectRes.getProjectStatus())){
log.info("此项目 【{}】 还在审核中",projectRes.getProjectId());
project.setUpdateOn(LocalDateTime.now());
//保存审核结果
project.setSjlsResult(CollUtil.isNotEmpty(projectRes.getProcessComment())
? JSON.toJSONString(projectRes.getProcessComment()) : StringUtils.EMPTY);
projectService.updateById(project);
}else if(ProjectProvincialAuditStatusEnum.SUCCESS.getCode().equals(projectRes.getProjectStatus())){
log.info("此项目 【{}】 审核通过",projectRes.getProjectId());
stateMachineUtils.pass(project);


+ 0
- 10
pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/WorkNoticeFlowTask.java View File

@@ -4,14 +4,9 @@ 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;

import com.ningdatech.basic.model.GenericResult;
import com.ningdatech.pmapi.staging.model.entity.WorkNoticeStaging;
import com.ningdatech.pmapi.staging.service.INdWorkNoticeStagingService;
import com.ningdatech.pmapi.staging.utils.WorkNoticeFlowMapUtil;
import com.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo;
import com.ningdatech.zwdd.client.ZwddClient;
import org.springframework.beans.BeanUtils;
@@ -20,13 +15,8 @@ import org.springframework.stereotype.Component;

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.service.IProjectStagingService;
import com.ningdatech.pmapi.staging.utils.ProjectStatusFlowMapUtil;

import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;


+ 14
- 5
pmapi/src/main/java/com/ningdatech/pmapi/staging/service/INdWorkNoticeStagingService.java View File

@@ -1,15 +1,15 @@
package com.ningdatech.pmapi.staging.service;

import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ningdatech.pmapi.staging.enums.MsgTypeEnum;
import com.ningdatech.pmapi.staging.model.entity.ProjectStaging;
import com.ningdatech.pmapi.staging.model.entity.WorkNoticeStaging;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo;

import java.util.List;

/**
* <p>
* 服务类
* 服务类
* </p>
*
* @author CMM
@@ -19,5 +19,14 @@ public interface INdWorkNoticeStagingService extends IService<WorkNoticeStaging>

Boolean addRetryTimes(WorkNoticeStaging workNoticeStaging);

public Boolean addByWorkNotice(WorkNoticeInfo workNoticeInfo, MsgTypeEnum msgType) ;
Boolean addByWorkNotice(WorkNoticeInfo workNoticeInfo, MsgTypeEnum msgType);

/**
* 批量保存工作通知
*
* @param workNoticeInfos 工作通知内容
* @param msgType 通知类型
*/
void addByWorkNotice(List<WorkNoticeInfo> workNoticeInfos, MsgTypeEnum msgType);

}

+ 38
- 4
pmapi/src/main/java/com/ningdatech/pmapi/staging/service/impl/NdWorkNoticeStagingServiceImpl.java View File

@@ -13,10 +13,12 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
* <p>
* 服务实现类
* 服务实现类
* </p>
*
* @author CMM
@@ -33,6 +35,7 @@ public class NdWorkNoticeStagingServiceImpl extends ServiceImpl<NdWorkNoticeStag

/**
* 增加 重试次数 和下次扫描时间
*
* @param workNoticeStaging
* @return java.lang.Boolean
* @author CMM
@@ -41,22 +44,23 @@ public class NdWorkNoticeStagingServiceImpl extends ServiceImpl<NdWorkNoticeStag
@Override
public Boolean addRetryTimes(WorkNoticeStaging workNoticeStaging) {
Integer retryTimes = workNoticeStaging.getRetryTimes() + 1;
if(!workNoticeFlowMapUtil.intervalTimeMap.containsKey(retryTimes)){
if (!workNoticeFlowMapUtil.intervalTimeMap.containsKey(retryTimes)) {
log.info("没有对应重试间隔时间 添加重试信息失败");
return Boolean.FALSE;
}
Integer addSeconds = workNoticeFlowMapUtil.intervalTimeMap.get(retryTimes);
Boolean dead = Boolean.FALSE;
//超过重试最大次数 dead置为 true
if(retryTimes.compareTo(StagingContant.Retry.MAX_RETRY_TIMES) > 0){
if (retryTimes.compareTo(StagingContant.Retry.MAX_RETRY_TIMES) > 0) {
dead = Boolean.TRUE;
}
LocalDateTime nextRetryTime = LocalDateTime.now().plusSeconds(addSeconds);
return mapper.addRetryTimes(workNoticeStaging.getId(),retryTimes,nextRetryTime,dead);
return mapper.addRetryTimes(workNoticeStaging.getId(), retryTimes, nextRetryTime, dead);
}

/**
* 在对应的流程处理后,增加一个工作通知到暂存表中
*
* @param workNoticeInfo
* @param msgType
* @return java.lang.Boolean
@@ -80,4 +84,34 @@ public class NdWorkNoticeStagingServiceImpl extends ServiceImpl<NdWorkNoticeStag
.build();
return this.save(workNoticeStaging);
}

/**
* 在对应的流程处理后,增加一个工作通知到暂存表中
*
* @param workNoticeInfo
* @param msgType
* @return java.lang.Boolean
* @author CMM
* @since 2023/02/28 20:02
*/
@Override
public void addByWorkNotice(List<WorkNoticeInfo> workNoticeInfos, MsgTypeEnum msgType) {
LocalDateTime now = LocalDateTime.now();
List<WorkNoticeStaging> workNoticeInfoList = workNoticeInfos.stream()
.map(workNoticeInfo -> WorkNoticeStaging.builder()
.accountId(workNoticeInfo.getAccountId())
.msg(workNoticeInfo.getMsg())
.bizMsgId(workNoticeInfo.getBizMsgId())
.organizationCode(workNoticeInfo.getOrganizationCode())
.organizationName(workNoticeInfo.getOrganizationName())
.receiverUserId(workNoticeInfo.getReceiverUserId())
.msgType(msgType)
.createOn(now)
.updateOn(now)
.nextTime(now)
.retryTimes(0)
.build()).collect(Collectors.toList());
saveBatch(workNoticeInfoList);
}

}

+ 4
- 4
pmapi/src/main/java/com/ningdatech/pmapi/staging/service/impl/ProjectStagingServiceImpl.java View File

@@ -6,7 +6,7 @@ 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.service.IProjectStagingService;
import com.ningdatech.pmapi.staging.utils.ProjectStatusFlowMapUtil;
import com.ningdatech.pmapi.staging.utils.ProjectStatusFlowUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -28,7 +28,7 @@ public class ProjectStagingServiceImpl extends ServiceImpl<ProjectStagingMapper,

private final ProjectStagingMapper mapper;

private final ProjectStatusFlowMapUtil projectStatusFlowMapUtil;
private final ProjectStatusFlowUtil projectStatusFlowUtil;

/**
* 在某些状态节点 增加一个项目到状态暂存库
@@ -61,11 +61,11 @@ public class ProjectStagingServiceImpl extends ServiceImpl<ProjectStagingMapper,
@Override
public Boolean addRetryTimes(ProjectStaging projectStaging) {
Integer retryTimes = projectStaging.getRetryTimes() + 1;
if(!projectStatusFlowMapUtil.intervalTimeMap.containsKey(retryTimes)){
if(!projectStatusFlowUtil.intervalTimeMap.containsKey(retryTimes)){
log.info("没有对应重试间隔时间 添加重试信息失败");
return Boolean.FALSE;
}
Integer addSeconds = projectStatusFlowMapUtil.intervalTimeMap.get(retryTimes);
Integer addSeconds = projectStatusFlowUtil.intervalTimeMap.get(retryTimes);
Boolean dead = Boolean.FALSE;
//超过重试最大次数 dead置为 true
if(retryTimes.compareTo(StagingContant.Retry.MAX_RETRY_TIMES) > 0){


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

@@ -29,10 +29,6 @@ public class ProjectStatusFlowMapUtil {
private ReviewByDeptJointManage reviewByDeptJointManage;

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

/**
* 初始化业务分派逻辑,代替了if-else部分
@@ -47,22 +43,4 @@ public class ProjectStatusFlowMapUtil {
statusFlowFunctionMap.put(ProjectStatusEnum.DEPARTMENT_JOINT_REVIEW.getCode(),
project->reviewByDeptJointManage.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);
}
}

+ 45
- 0
pmapi/src/main/java/com/ningdatech/pmapi/staging/utils/ProjectStatusFlowUtil.java View File

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

import com.google.common.collect.Maps;
import com.ningdatech.pmapi.projectdeclared.manage.ReviewByDeptJointManage;
import com.ningdatech.pmapi.projectdeclared.manage.ReviewByProvincialDeptManage;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import org.springframework.beans.factory.annotation.Autowired;
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
public class ProjectStatusFlowUtil {
/**
* key 重试的次数 , value 是增加是描述
*/
public Map<Integer, Integer> intervalTimeMap = Maps.newHashMap();

/**
* 初始化业务分派逻辑,代替了if-else部分
* key: 枚举 状态值
* value: lambda表达式,最终会获取发起实例的函数
*/
public ProjectStatusFlowUtil(){
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);
}
}

+ 4
- 3
pmapi/src/main/java/com/ningdatech/pmapi/staging/utils/WorkNoticeFlowMapUtil.java View File

@@ -2,6 +2,8 @@ package com.ningdatech.pmapi.staging.utils;

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

import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
@@ -13,7 +15,7 @@ import lombok.RequiredArgsConstructor;
* @since 2023/02/28 17:03
*/
@Component
@RequiredArgsConstructor
@AllArgsConstructor
public class WorkNoticeFlowMapUtil {
/**
* key 重试的次数 , value 是增加是描述
@@ -23,8 +25,7 @@ public class WorkNoticeFlowMapUtil {
/**
* 扫描的间隔越来越长 秒数
*/
@PostConstruct
public void intervalTimeMapInit(){
public WorkNoticeFlowMapUtil(){
intervalTimeMap.put(1,60 * 2);
intervalTimeMap.put(2,60 * 6);
intervalTimeMap.put(3,60 * 15);


+ 152
- 0
pmapi/src/main/java/com/ningdatech/pmapi/sys/manage/NoticeManage.java View File

@@ -2,32 +2,56 @@ package com.ningdatech.pmapi.sys.manage;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.model.IdVo;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.file.entity.vo.result.AttachFileVo;
import com.ningdatech.file.service.FileService;
import com.ningdatech.pmapi.common.helper.UserInfoHelper;
import com.ningdatech.pmapi.common.util.BizUtils;
import com.ningdatech.pmapi.organization.model.entity.DingEmployeeInfo;
import com.ningdatech.pmapi.organization.model.entity.DingOrganization;
import com.ningdatech.pmapi.organization.service.IDingEmployeeInfoService;
import com.ningdatech.pmapi.organization.service.IDingOrganizationService;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.staging.enums.MsgTypeEnum;
import com.ningdatech.pmapi.staging.service.INdWorkNoticeStagingService;
import com.ningdatech.pmapi.sys.enumeration.NoticeTypeEnum;
import com.ningdatech.pmapi.sys.model.entity.Notice;
import com.ningdatech.pmapi.sys.model.entity.Notify;
import com.ningdatech.pmapi.sys.model.req.NoticeListReq;
import com.ningdatech.pmapi.sys.model.req.NoticeSaveReq;
import com.ningdatech.pmapi.sys.model.req.NoticeStatusModifyReq;
import com.ningdatech.pmapi.sys.model.vo.NoticeDetailVO;
import com.ningdatech.pmapi.sys.model.vo.NoticeListItemVO;
import com.ningdatech.pmapi.sys.service.INoticeService;
import com.ningdatech.pmapi.sys.service.INotifyService;
import com.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo;
import com.ningdatech.pmapi.todocenter.model.dto.ProjectAuditMsgExtraDTO;
import com.ningdatech.pmapi.user.entity.UserInfo;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.service.IUserInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.runtime.ActivityInstance;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.ningdatech.pmapi.todocenter.constant.WorkNoticeContant.AUDIT_WORK_TITLE;

/**
* <p>
* MsgManage
@@ -38,11 +62,26 @@ import java.util.stream.Collectors;
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class NoticeManage {

private final INoticeService noticeService;
private final FileService fileService;

private final IUserInfoService userInfoService;

private final IDingEmployeeInfoService dingEmployeeInfoService;

private final IDingOrganizationService dingOrganizationService;

private final INotifyService notifyService;

private final INdWorkNoticeStagingService workNoticeStagingService;

private final RuntimeService runtimeService;

private final UserInfoHelper userInfoHelper;

@Transactional(rollbackFor = Exception.class)
public IdVo<Long> saveOrModify(NoticeSaveReq req) {
Notice notice = BeanUtil.copyProperties(req, Notice.class);
@@ -128,4 +167,117 @@ public class NoticeManage {
noticeService.removeById(id);
}


/**
* 发送消息
* @param employeeCode 员工号
* @param userId 用户ID
* @param project 项目
* @param procDefinitionName 流程定义名
* @param template 消息模板内容
* @param msgTypeEnum 枚举
*/
public void sendNotice(String employeeCode, Long userId, Project project, String procDefinitionName,
String template, MsgTypeEnum msgTypeEnum){
// 获取发送浙政钉工作通知必要信息
WorkNoticeInfo passWorkNoticeInfo = getSendWorkNoticeInfo(employeeCode);
String passMsg = String.format(template, project.getProjectName(), procDefinitionName);
passWorkNoticeInfo.setMsg(passMsg);
// 放入系统通知表中,保存记录
Notify notify = assemblyAuditNotify(userId, project, passMsg);
notify.setType(msgTypeEnum.name());
notifyService.save(notify);
// 放入工作通知暂存表中,通过扫表异步发送
workNoticeStagingService.addByWorkNotice(passWorkNoticeInfo, msgTypeEnum);
}

/**
* 获取发送浙政钉工作通知的信息
*
* @param currentEmployeeCode
* @return com.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo
* @author CMM
* @since 2023/02/15 14:04
*/
public WorkNoticeInfo getSendWorkNoticeInfo(String currentEmployeeCode) {
UserInfo auditUserInfo = userInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class).eq(UserInfo::getEmployeeCode,currentEmployeeCode).last("limit 1"));
if (Objects.isNull(auditUserInfo)) {
throw new BizException("该用户不存在!");
}
WorkNoticeInfo workNoticeInfo = new WorkNoticeInfo();
Long accountId = auditUserInfo.getAccountId();
if (Objects.isNull(accountId)) {
throw new BizException("该用户没有录入浙政钉信息!");
}
workNoticeInfo.setAccountId(accountId);
// 根据浙政钉用户ID获取部门code
DingEmployeeInfo employeeInfo = dingEmployeeInfoService.getOne(Wrappers.lambdaQuery(DingEmployeeInfo.class)
.eq(DingEmployeeInfo::getAccountId, accountId)
.eq(DingEmployeeInfo::getMainJob,String.valueOf(Boolean.TRUE))
.last("limit 1"));
String organizationCode = employeeInfo.getOrganizationCode();
workNoticeInfo.setOrganizationCode(organizationCode);
// 根据部门code获取部门名称
DingOrganization dingOrganization = dingOrganizationService.getOne(Wrappers.lambdaQuery(DingOrganization.class)
.eq(DingOrganization::getOrganizationCode, organizationCode));
String organizationName = dingOrganization.getOrganizationName();
workNoticeInfo.setOrganizationName(organizationName);
// 构建唯一的消息ID
String bizMsgId = "ZD_WORK_NOTICE_" + StrUtil.UNDERLINE + organizationCode + StrUtil.UNDERLINE
+ organizationName + accountId + StrUtil.UNDERLINE + System.currentTimeMillis();
workNoticeInfo.setBizMsgId(bizMsgId);
String receiverUserId = String.valueOf(accountId);
workNoticeInfo.setReceiverUserId(receiverUserId);
return workNoticeInfo;
}

/**
* 装配项目审核工作通知
* @param userId
* @param project
* @param msg
*/
private Notify assemblyAuditNotify(Long userId, Project project, String msg) {
Notify notify = new Notify();
notify.setTitle(AUDIT_WORK_TITLE);
notify.setUserId(userId);
notify.setContent(msg);
notify.setReaded(Boolean.FALSE);
notify.setCreateTime(LocalDateTime.now());
ProjectAuditMsgExtraDTO msgExtraDto = new ProjectAuditMsgExtraDTO();
msgExtraDto.setProjectId(project.getId());
msgExtraDto.setInstanceId(project.getInstCode());
String extraJson = JSON.toJSONString(msgExtraDto);
notify.setExtraInfo(extraJson);
return notify;
}

/**
* 找寻第一个审核人 去发消息
* @param project
* @param formName
* @param template
* @param msgTypeEnum
*/
public void sendFirtUser(Project project, String formName,String instanceId, String template, MsgTypeEnum msgTypeEnum) {
try {
List<ActivityInstance> activityInstances = runtimeService.createActivityInstanceQuery()
.processInstanceId(instanceId)
.activityType("userTask")
.orderByActivityInstanceStartTime()
.asc()
.list();

for (ActivityInstance activityInstance : activityInstances) {
if(StringUtils.isNotBlank(activityInstance.getAssignee())){
UserFullInfoDTO user = userInfoHelper.getUserFullInfoByEmployeeCode(activityInstance.getAssignee());
sendNotice(activityInstance.getAssignee(), user.getUserId(), project, formName,
template, msgTypeEnum);
}
}
}catch (Exception e){
log.error("发送消息失败 :" + e);
}

}
}

+ 5
- 5
pmapi/src/main/java/com/ningdatech/pmapi/sys/manage/NotifyManage.java View File

@@ -45,14 +45,14 @@ public class NotifyManage {
.like(Objects.nonNull(notifyListReq.getTitle()), Notify::getTitle, notifyListReq.getTitle())
.eq(Objects.nonNull(notifyListReq.getType()), Notify::getType, notifyListReq.getType())
.orderByDesc(Notify::getCreateTime);
notifyService.page(page,wrapper);
if(page.getTotal() == 0L){
notifyService.page(page, wrapper);
if (page.getTotal() == 0L) {
return PageVo.empty();
}
List<NotifyVO> list = page.getRecords().stream()
.map(n -> {
NotifyVO notifyVo = new NotifyVO();
BeanUtil.copyProperties(n,notifyVo);
BeanUtil.copyProperties(n, notifyVo);
String extraInfo = n.getExtraInfo();
if (StringUtils.isNotBlank(extraInfo)) {
JSONObject jsonObject = JSON.parseObject(extraInfo);
@@ -66,12 +66,12 @@ public class NotifyManage {
return notifyVo;
})
.collect(Collectors.toList());
return PageVo.of(list,page.getTotal());
return PageVo.of(list, page.getTotal());
}

public NotifyVO detail(Long id) {
Notify one = notifyService.getById(id);
return BeanUtil.copyProperties(one,NotifyVO.class);
return BeanUtil.copyProperties(one, NotifyVO.class);
}

public Boolean read(Long id) {


+ 37
- 146
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/HandlerManage.java View File

@@ -1,22 +1,32 @@
package com.ningdatech.pmapi.todocenter.manage;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import static com.ningdatech.pmapi.todocenter.constant.WorkNoticeContant.*;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.file.service.FileService;
import com.ningdatech.pmapi.common.helper.UserInfoHelper;
import com.ningdatech.pmapi.common.statemachine.util.StateMachineUtils;
import com.ningdatech.pmapi.organization.model.entity.DingEmployeeInfo;
import com.ningdatech.pmapi.organization.model.entity.DingOrganization;
import com.ningdatech.pmapi.organization.service.IDingEmployeeInfoService;
import com.ningdatech.pmapi.organization.service.IDingOrganizationService;
import com.ningdatech.pmapi.projectdeclared.manage.DeclaredProjectManage;
import com.ningdatech.pmapi.projectdeclared.manage.DefaultDeclaredProjectManage;
import com.ningdatech.pmapi.projectdeclared.model.dto.ProjectDraftSaveDTO;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.manage.ProjectLibManage;
import com.ningdatech.pmapi.projectlib.model.dto.ProjectApplicationDTO;
import com.ningdatech.pmapi.projectlib.model.dto.ProjectDTO;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
@@ -25,47 +35,21 @@ import com.ningdatech.pmapi.projectlib.model.entity.ProjectInst;
import com.ningdatech.pmapi.projectlib.service.IProjectApplicationService;
import com.ningdatech.pmapi.projectlib.service.IProjectInstService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.signature.service.ICompanySignatureService;
import com.ningdatech.pmapi.staging.enums.MsgTypeEnum;
import com.ningdatech.pmapi.staging.service.INdWorkNoticeStagingService;
import com.ningdatech.pmapi.staging.service.IProjectStagingService;
import com.ningdatech.pmapi.sys.model.entity.Notify;
import com.ningdatech.pmapi.sys.service.INotifyService;
import com.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo;
import com.ningdatech.pmapi.sys.manage.NoticeManage;
import com.ningdatech.pmapi.todocenter.constant.TodoCenterContant;
import com.ningdatech.pmapi.todocenter.model.dto.ProjectAuditMsgExtraDTO;
import com.ningdatech.pmapi.todocenter.service.StatisticsService;
import com.ningdatech.pmapi.todocenter.utils.BuildUserUtils;
import com.ningdatech.pmapi.todocenter.utils.PdfUtils;
import com.ningdatech.pmapi.user.entity.UserInfo;
import com.ningdatech.pmapi.user.service.IUserInfoService;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import com.wflow.contants.HisProInsEndActId;
import com.wflow.contants.WflowContant;
import com.wflow.workflow.bean.process.ProgressNode;
import com.wflow.workflow.bean.process.enums.NodeTypeEnum;
import com.wflow.workflow.bean.vo.ProcessProgressVo;
import com.wflow.workflow.enums.ProcessHandlerEnum;
import com.wflow.workflow.service.ProcessInstanceService;
import com.wflow.workflow.service.ProcessTaskService;

import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.ningdatech.pmapi.todocenter.constant.WorkNoticeContant.*;

/**
* @Classname HandlerManage
@@ -82,17 +66,13 @@ public class HandlerManage {

private final TaskService taskService;
private final HistoryService historyService;
private final IUserInfoService userInfoService;
private final IProjectService projectService;
private final StateMachineUtils stateMachineUtils;
private final IDingEmployeeInfoService dingEmployeeInfoService;
private final IDingOrganizationService dingOrganizationService;
private final ProcessInstanceService processInstanceService;
private final INdWorkNoticeStagingService workNoticeStagingService;
private final IProjectApplicationService projectApplicationService;
private final IProjectStagingService projectStagingService;
private final IProjectInstService projectInstService;
private final INotifyService notifyService;
private final NoticeManage noticeManage;
private final DeclaredProjectManage declaredProjectManage;

/**
@@ -147,16 +127,9 @@ public class HandlerManage {
default:
throw new IllegalStateException("Unexpected value: " + declaredProject.getStatus());
}
// 获取发送浙政钉工作通知必要信息
WorkNoticeInfo passWorkNoticeInfo2 = getSendWorkNoticeInfo(currentEmployeeCode);
String passMsg2 = String.format(PASS_MSG_TEMPLATE2, declaredProject.getProjectName(), instance.getProcessDefinitionName());
passWorkNoticeInfo2.setMsg(passMsg2);
// 放入系统通知表中,保存记录
Notify notify = assemblyAuditNotify(userId, declaredProject, passMsg2);
notify.setType(MsgTypeEnum.PROJECT_REVIEW_PASS.name());
notifyService.save(notify);
// 放入工作通知暂存表中,通过扫表异步发送
workNoticeStagingService.addByWorkNotice(passWorkNoticeInfo2, MsgTypeEnum.PROJECT_REVIEW_PASS);
//发送消息
noticeManage.sendNotice(instance.getStartUserId(),userId,declaredProject,instance.getProcessDefinitionName(),
PASS_MSG_TEMPLATE2,MsgTypeEnum.PROJECT_REVIEW_PASS);
} else {
// 若有下一个审核人(当前节点的用户),
// 向其发送浙政钉工作通知:标题:审核任务 内容:【单位名称】的【项目名称】需要您审核。
@@ -164,18 +137,13 @@ public class HandlerManage {
if (Objects.isNull(currentEmployeeCode)) {
throw new BizException("审核人信息不存在!");
}
WorkNoticeInfo sendWorkNoticeInfo = getSendWorkNoticeInfo(currentEmployeeCode);
String msg = String.format(PASS_MSG_TEMPLATE, sendWorkNoticeInfo.getOrganizationName(), declaredProject.getProjectName());
sendWorkNoticeInfo.setMsg(msg);
// 放入系统通知表中,保存记录
Notify notify = assemblyAuditNotify(userId, declaredProject, msg);
notify.setType(MsgTypeEnum.PROJECT_REVIEW.name());
notifyService.save(notify);
// 放入工作通知暂存表中,通过扫表异步发送
workNoticeStagingService.addByWorkNotice(sendWorkNoticeInfo, MsgTypeEnum.PROJECT_REVIEW);
//发送消息
noticeManage.sendNotice(currentEmployeeCode,userId,declaredProject,instance.getProcessDefinitionName(),
PASS_MSG_TEMPLATE,MsgTypeEnum.PROJECT_REVIEW);
}
}


/**
* 驳回后 所处理的逻辑
* @param declaredProject
@@ -185,17 +153,9 @@ public class HandlerManage {
Long userId = LoginUserUtil.getUserId();
// 更新项目状态和流程状态
updateRejectProjectStatus(userId, declaredProject);
// 获取发送浙政钉工作通知必要信息
WorkNoticeInfo rejectWorkNoticeInfo = getSendWorkNoticeInfo(instance.getStartUserId());
String rejectMsg = String.format(REJECT_MSG_TEMPLATE, declaredProject.getProjectName(),
instance.getProcessDefinitionName());
rejectWorkNoticeInfo.setMsg(rejectMsg);
// 放入系统通知表中,保存记录
Notify notify = assemblyAuditNotify(userId, declaredProject, rejectMsg);
notify.setType(MsgTypeEnum.PROJECT_REVIEW_REJECT.name());
notifyService.save(notify);
// 放入工作通知暂存表中,通过扫表异步发送
workNoticeStagingService.addByWorkNotice(rejectWorkNoticeInfo, MsgTypeEnum.PROJECT_REVIEW_REJECT);
//发送消息
noticeManage.sendNotice(instance.getStartUserId(),userId,declaredProject,instance.getProcessDefinitionName(),
REJECT_MSG_TEMPLATE,MsgTypeEnum.PROJECT_REVIEW_REJECT);
}

/**
@@ -269,17 +229,9 @@ public class HandlerManage {
public void afterBackTodo(Project declaredProject, HistoricProcessInstance instance) {
Long userId = LoginUserUtil.getUserId();
// 给项目创建人、流程发起人发送浙政钉工作通知:【项目名称】的【流程名称】被退回,请及时处理。
// 获取发送浙政钉工作通知必要信息
WorkNoticeInfo backWorkNoticeInfo = getSendWorkNoticeInfo(instance.getStartUserId());
String backMsg = String.format(BACK_MSG_TEMPLATE, declaredProject.getProjectName(),
instance.getProcessDefinitionName());
backWorkNoticeInfo.setMsg(backMsg);
// 放入系统通知表中,保存记录
Notify notify = assemblyAuditNotify(userId, declaredProject, backMsg);
notify.setType(MsgTypeEnum.PROJECT_REVIEW_BACK.name());
notifyService.save(notify);
// 放入工作通知暂存表中,通过扫表异步发送
workNoticeStagingService.addByWorkNotice(backWorkNoticeInfo, MsgTypeEnum.PROJECT_REVIEW_BACK);
//发送消息
noticeManage.sendNotice(instance.getStartUserId(),userId,declaredProject,instance.getProcessDefinitionName(),
BACK_MSG_TEMPLATE,MsgTypeEnum.PROJECT_REVIEW_BACK);
}


@@ -345,67 +297,6 @@ public class HandlerManage {
projectService.updateById(declaredProject);
}

/**
* 装配项目审核工作通知
* @param userId
* @param project
* @param msg
*/
private Notify assemblyAuditNotify(Long userId, Project project, String msg) {
Notify notify = new Notify();
notify.setTitle(AUDIT_WORK_TITLE);
notify.setUserId(userId);
notify.setContent(msg);
notify.setReaded(Boolean.FALSE);
notify.setCreateTime(LocalDateTime.now());
ProjectAuditMsgExtraDTO msgExtraDto = new ProjectAuditMsgExtraDTO();
msgExtraDto.setProjectId(project.getId());
msgExtraDto.setInstanceId(project.getInstCode());
String extraJson = JSON.toJSONString(msgExtraDto);
notify.setExtraInfo(extraJson);
return notify;
}

/**
* 获取发送浙政钉工作通知的信息
*
* @param currentEmployeeCode
* @return com.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo
* @author CMM
* @since 2023/02/15 14:04
*/
public WorkNoticeInfo getSendWorkNoticeInfo(String currentEmployeeCode) {
UserInfo auditUserInfo = userInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class).eq(UserInfo::getEmployeeCode,currentEmployeeCode).last("limit 1"));
if (Objects.isNull(auditUserInfo)) {
throw new BizException("该用户不存在!");
}
WorkNoticeInfo workNoticeInfo = new WorkNoticeInfo();
Long accountId = auditUserInfo.getAccountId();
if (Objects.isNull(accountId)) {
throw new BizException("该用户没有录入浙政钉信息!");
}
workNoticeInfo.setAccountId(accountId);
// 根据浙政钉用户ID获取部门code
DingEmployeeInfo employeeInfo = dingEmployeeInfoService.getOne(Wrappers.lambdaQuery(DingEmployeeInfo.class)
.eq(DingEmployeeInfo::getAccountId, accountId)
.eq(DingEmployeeInfo::getMainJob,String.valueOf(Boolean.TRUE))
.last("limit 1"));
String organizationCode = employeeInfo.getOrganizationCode();
workNoticeInfo.setOrganizationCode(organizationCode);
// 根据部门code获取部门名称
DingOrganization dingOrganization = dingOrganizationService.getOne(Wrappers.lambdaQuery(DingOrganization.class)
.eq(DingOrganization::getOrganizationCode, organizationCode));
String organizationName = dingOrganization.getOrganizationName();
workNoticeInfo.setOrganizationName(organizationName);
// 构建唯一的消息ID
String bizMsgId = "ZD_WORK_NOTICE_" + StrUtil.UNDERLINE + organizationCode + StrUtil.UNDERLINE
+ organizationName + accountId + StrUtil.UNDERLINE + System.currentTimeMillis();
workNoticeInfo.setBizMsgId(bizMsgId);
String receiverUserId = String.valueOf(accountId);
workNoticeInfo.setReceiverUserId(receiverUserId);
return workNoticeInfo;
}

public void deleteBackComments(List<HistoricVariableInstance> approves) {
if(CollUtil.isNotEmpty(approves)){
for(HistoricVariableInstance approve : approves){


+ 3
- 0
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java View File

@@ -209,6 +209,7 @@ public class TodoCenterManage {
Project projectInfo = projectInfoMap.get(d.getInstanceId());
ResToBeProcessedVO res = new ResToBeProcessedVO();
BeanUtils.copyProperties(projectInfo, res);
res.setInstCode(d.getInstanceId());
res.setProjectId(projectInfo.getId());
res.setBuildOrg(projectInfo.getBuildOrgName());
res.setDeclaredAmount(projectInfo.getDeclareAmount());
@@ -524,6 +525,7 @@ public class TodoCenterManage {
ResToBeProcessedVO res = new ResToBeProcessedVO();
Project projectInfo = projectInfoMap.get(d.getInstanceId());
BeanUtils.copyProperties(projectInfo, res);
res.setInstCode(d.getInstanceId());
res.setBuildOrg(projectInfo.getBuildOrgName());
res.setDeclaredAmount(projectInfo.getDeclareAmount());
res.setProjectId(projectInfo.getId());
@@ -802,6 +804,7 @@ public class TodoCenterManage {
ResToBeProcessedVO res = new ResToBeProcessedVO();
Project project = projectInfoMap.get(d.getInstanceId());
BeanUtils.copyProperties(project, res);
res.setInstCode(d.getInstanceId());
res.setNodeId(d.getNodeId());
res.setProjectId(project.getId());
res.setBuildOrg(project.getBuildOrgName());


+ 2
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/manage/UserInfoManage.java View File

@@ -416,6 +416,8 @@ public class UserInfoManage {
resUserDetailVO.setOrgCode(userFullInfo.getOrganizationCode());
resUserDetailVO.setOrgName(userFullInfo.getOrganizationName());
resUserDetailVO.setRegionCode(userFullInfo.getRegionCode());
resUserDetailVO.setRegionName(regionCacheHelper.getRegionName(userFullInfo.getRegionCode()
,RegionConst.RL_COUNTY));
resUserDetailVO.setEmpPosUnitCode(userFullInfo.getEmpPosUnitCode());
resUserDetailVO.setEmpPosUnitName(userFullInfo.getEmpPosUnitName());
}


+ 3
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/model/vo/ResUserDetailVO.java View File

@@ -4,9 +4,11 @@ import com.ningdatech.pmapi.common.constant.RegionConst;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

/**
* @author liuxinxin
@@ -40,6 +42,7 @@ public class ResUserDetailVO {
@ApiModelProperty("所属区域")
private Long regionId;
private String regionCode;
private String regionName;

@ApiModelProperty("用户任职所在单位code")
private String empPosUnitCode;


+ 2
- 0
pmapi/src/main/java/com/ningdatech/pmapi/workbench/manage/WorkbenchManage.java View File

@@ -51,6 +51,7 @@ public class WorkbenchManage {

public WorkbenchVO getWorkbenchData(Integer year){
WorkbenchVO res = new WorkbenchVO();
UserInfoDetails user = LoginUserUtil.loginUserDetail();

//1.待办中心数据
TodoCenterStatisticsVO statisticsVO = todoCenterManage.todoCenterStatistics();
@@ -70,6 +71,7 @@ public class WorkbenchManage {
projectListReq.setPageNumber(1);
projectListReq.setPageSize(5);
projectListReq.setProjectYear(year);
projectListReq.setBuildOrgCode(user.getEmpPosUnitCode());
res.setProjects(projectLibManage.projectLibListWithPermission(projectListReq).getRecords().stream().collect(Collectors.toList()));

//3.所有公告按类型分


BIN
pmapi/src/main/resources/template/丽水市2023年数字化项目年度计划编辑表.xls View File


+ 11
- 1
pmapi/src/test/java/com/ningdatech/pmapi/statemachine/StateMachineTest.java View File

@@ -1,9 +1,9 @@
package com.ningdatech.pmapi.statemachine;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.pmapi.AppTests;
import com.ningdatech.pmapi.common.statemachine.util.StateMachineUtils;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import org.junit.jupiter.api.Test;
@@ -32,4 +32,14 @@ public class StateMachineTest extends AppTests {
System.out.println(String.format("project:%s", JSON.toJSONString(project)));
projectService.updateById(project);
}

@Test
public void yyyyyy(){
Project project = projectService.getById(400);
projectService.update(Wrappers.lambdaUpdate(Project.class)
.set(Project::getNewest,Boolean.FALSE)
.ne(Project::getId,project.getId())
.eq(Project::getProjectCode,project.getProjectCode()));
System.out.println(project);
}
}

+ 2
- 1
pmapi/src/test/java/com/ningdatech/pmapi/todocenter/TodoCenterTest.java View File

@@ -13,6 +13,7 @@ import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.model.vo.ProjectDetailVO;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.staging.service.INdWorkNoticeStagingService;
import com.ningdatech.pmapi.sys.manage.NoticeManage;
import com.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo;
import com.ningdatech.pmapi.todocenter.manage.HandlerManage;
import com.ningdatech.pmapi.todocenter.manage.TodoCenterManage;
@@ -72,7 +73,7 @@ public class TodoCenterTest extends AppTests {
private HistoryService historyService;

@Autowired
private HandlerManage handlerManage;
private NoticeManage handlerManage;

@Test
public void sendWorkNoticeTest() throws ExecutionException, InterruptedException {


+ 6
- 0
pom.xml View File

@@ -175,6 +175,12 @@
<artifactId>html2pdf</artifactId>
<version>2.0.2</version>
</dependency>
<!--导入导出-->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.2.0</version>
</dependency>

</dependencies>
</dependencyManagement>


BIN
template/丽水市2023年数字化项目年度计划编辑表.xls View File


Loading…
Cancel
Save