diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/common/model/constant/ExistsSqlConst.java b/hz-pm-api/src/main/java/com/hz/pm/api/common/model/constant/ExistsSqlConst.java index 7962011..3ce4c98 100644 --- a/hz-pm-api/src/main/java/com/hz/pm/api/common/model/constant/ExistsSqlConst.java +++ b/hz-pm-api/src/main/java/com/hz/pm/api/common/model/constant/ExistsSqlConst.java @@ -27,4 +27,6 @@ public class ExistsSqlConst { public static final String USER_EXISTS_ROLE = "select 1 from nd_user_role nur where nur.user_id = nd_user_info.id "; + public static final String MEETING_INNER_PROJECT_EXISTS_MEETING = "select 1 from meeting m where meeting_inner_project.meeting_id = m.id "; + } diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/common/statemachine/action/ProjectStateChangeAction.java b/hz-pm-api/src/main/java/com/hz/pm/api/common/statemachine/action/ProjectStateChangeAction.java index be915cf..c861cba 100644 --- a/hz-pm-api/src/main/java/com/hz/pm/api/common/statemachine/action/ProjectStateChangeAction.java +++ b/hz-pm-api/src/main/java/com/hz/pm/api/common/statemachine/action/ProjectStateChangeAction.java @@ -50,9 +50,33 @@ public class ProjectStateChangeAction { project.setStatus(ProjectStatus.ON_COMPLIANCE_REVIEW.getCode()); } - @OnTransition(source = "ON_COMPLIANCE_REVIEW", target = "WITHOUT_PROJECT_REVIEW") + @OnTransition(source = "ON_COMPLIANCE_REVIEW", target = "WITHOUT_EXPERT_REVIEW") public void COMPLIANCE_REVIEW_PASS(Message message) { Project project = getProject(message); + project.setStatus(ProjectStatus.WITHOUT_EXPERT_REVIEW.getCode()); + } + + @OnTransition(source = "WITHOUT_EXPERT_REVIEW", target = "ON_EXPERT_REVIEW") + public void EXPERT_REVIEW_SUBMIT(Message message) { + Project project = getProject(message); + project.setStatus(ProjectStatus.ON_EXPERT_REVIEW.getCode()); + } + + @OnTransition(source = "EXPERT_REVIEW_FAILED", target = "ON_EXPERT_REVIEW") + public void EXPERT_REVIEW_RESUBMIT(Message message) { + Project project = getProject(message); + project.setStatus(ProjectStatus.ON_EXPERT_REVIEW.getCode()); + } + + @OnTransition(source = "ON_EXPERT_REVIEW", target = "EXPERT_REVIEW_FAILED") + public void EXPERT_REVIEW_FAILED(Message message) { + Project project = getProject(message); + project.setStatus(ProjectStatus.EXPERT_REVIEW_FAILED.getCode()); + } + + @OnTransition(source = "ON_EXPERT_REVIEW", target = "WITHOUT_PROJECT_REVIEW") + public void EXPERT_REVIEW_PASS(Message message) { + Project project = getProject(message); project.setStatus(ProjectStatus.WITHOUT_PROJECT_REVIEW.getCode()); } diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/common/statemachine/builder/impl/ProjectStateMachineBuilderImpl.java b/hz-pm-api/src/main/java/com/hz/pm/api/common/statemachine/builder/impl/ProjectStateMachineBuilderImpl.java index c4dbdd2..f030f25 100644 --- a/hz-pm-api/src/main/java/com/hz/pm/api/common/statemachine/builder/impl/ProjectStateMachineBuilderImpl.java +++ b/hz-pm-api/src/main/java/com/hz/pm/api/common/statemachine/builder/impl/ProjectStateMachineBuilderImpl.java @@ -95,8 +95,28 @@ public class ProjectStateMachineBuilderImpl implements BaseStateMachineBuilder

projects = meetingBasic.getInnerProjects().stream().map(w -> { + List projectIds = new ArrayList<>(); + List meetingInnerProjects = meetingBasic.getInnerProjects().stream().map(w -> { MeetingInnerProject project = BeanUtil.copyProperties(w, MeetingInnerProject.class); project.setMeetingId(meeting.getId()); + projectIds.add(w.getProjectId()); return project; }).collect(Collectors.toList()); - meetingInnerProjectService.saveBatch(projects); + List projects = projectService.listByIds(projectIds); + boolean allMatch = projects.stream().allMatch(w -> ProjectStatus.EXPERT_REVIEW_FAILED.eq(w.getStatus()) + || ProjectStatus.WITHOUT_EXPERT_REVIEW.eq(w.getStatus())); + if (!allMatch) { + throw ReturnException.wrap("当前关联项目包含暂不可评审项目"); + } + projects.forEach(projectStateMachineUtil::pass); + projectService.updateBatchById(projects); + meetingInnerProjectService.saveBatch(meetingInnerProjects); } // 抽取专家 inviteRule.setMeetingId(meeting.getId()); @@ -728,6 +740,14 @@ public class MeetingManage { if (!experts.isEmpty()) { meetingNotifyHelper.sendCancelMeetingMsg(experts, meeting); } + if (Boolean.TRUE.equals(meeting.getIsInnerProject())) { + // 取消项目时候重置项目状态 + List meetingInnerProjects = meetingInnerProjectService.listByMeetingId(meetingId); + List projectIds = CollUtils.fieldList(meetingInnerProjects, MeetingInnerProject::getProjectId); + List projects = projectService.listByIds(projectIds); + projects.forEach(w -> w.setStatus(ProjectStatus.WITHOUT_EXPERT_REVIEW.getCode())); + projectService.updateBatchById(projects); + } // 将取消的会议推送给MH mhApiClient.cancelMeetingToMh(meetingId); } finally { @@ -983,6 +1003,7 @@ public class MeetingManage { break; case PROJECT_REVIEW: case EXPERT_REVIEW: + query.isNotNull(Project::getConstructionPlanSealFile); buildOptionProjectQuery(query, meetingType, ProjectStatus.WITHOUT_PROJECT_REVIEW); break; default: @@ -1027,7 +1048,9 @@ public class MeetingManage { } private void buildOptionProjectQuery(LambdaQueryWrapper query, String meetingType, ProjectStatus status) { - query.eq(Project::getStatus, status.getCode()); + if (status != null) { + query.eq(Project::getStatus, status.getCode()); + } String sql = String.format("select 1 from meeting m inner join meeting_inner_project mip on" + " m.is_inner_project = 1 and m.id = mip.meeting_id and nd_project.id = mip.project_id" + " and m.type = %s and m.status != 3", meetingType); @@ -1078,22 +1101,32 @@ public class MeetingManage { public void uploadProjectReviewResult(ProjectReviewResultUploadReq req) { String key = "meeting_project_result_upload:" + req.getMeetingProjectId(); if (!distributedLock.lock(key, RETRY_TIMES)) { - throw BizException.wrap("正在上传会议结果,请勿重复操作"); + throw ReturnException.wrap("正在上传会议结果,请勿重复操作"); } try { Meeting meeting = meetingService.getById(req.getMeetingId()); if (meeting == null || MeetingStatusEnum.CANCEL.eq(meeting.getStatus())) { - throw BizException.wrap("会议不存在或已取消"); + throw ReturnException.wrap("会议不存在或已取消"); } LocalDateTime now = LocalDateTime.now(); if (meeting.getEndTime().isAfter(now)) { - throw BizException.wrap("会议未结束"); + throw ReturnException.wrap("会议未结束"); } if (!Boolean.TRUE.equals(meeting.getIsInnerProject())) { - throw BizException.wrap("此会议未关联项目"); + throw ReturnException.wrap("此会议未关联项目"); } MeetingInnerProject mip = BeanUtil.copyProperties(req, MeetingInnerProject.class); + if (mip.getReviewResult() != null) { + throw ReturnException.wrap("会议结果已上传"); + } mip.setId(req.getMeetingProjectId()); + Project project = projectService.getById(mip.getProjectId()); + if (req.getReviewResult() == 1) { + projectStateMachineUtil.pass(project); + } else { + projectStateMachineUtil.reject(project); + } + projectService.updateById(project); meetingInnerProjectService.updateById(mip); } finally { distributedLock.releaseLock(key); diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/projectdeclared/controller/ProjectReviewController.java b/hz-pm-api/src/main/java/com/hz/pm/api/projectdeclared/controller/ProjectReviewController.java index 7efd6a0..5267bd4 100644 --- a/hz-pm-api/src/main/java/com/hz/pm/api/projectdeclared/controller/ProjectReviewController.java +++ b/hz-pm-api/src/main/java/com/hz/pm/api/projectdeclared/controller/ProjectReviewController.java @@ -64,4 +64,16 @@ public class ProjectReviewController { return projectReviewManage.reviewProjectProgressStatistics(req); } + @ApiOperation("专家评审列表") + @GetMapping("/pageExpertReviewProject") + public PageVo pageExpertReviewProject(ProjectListReq req) { + return projectReviewManage.pageExpertReviewProject(req); + } + + @GetMapping("/expertReviewProgressStatistics") + @ApiOperation("专家评审项目进度统计") + public ReviewProgressStatisticsVO expertProgressStatistics(ProjectListReq req) { + return projectReviewManage.expertReviewProjectProgressStatistics(req); + } + } diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/projectdeclared/manage/ProjectReviewManage.java b/hz-pm-api/src/main/java/com/hz/pm/api/projectdeclared/manage/ProjectReviewManage.java index 2b5690e..99411cd 100644 --- a/hz-pm-api/src/main/java/com/hz/pm/api/projectdeclared/manage/ProjectReviewManage.java +++ b/hz-pm-api/src/main/java/com/hz/pm/api/projectdeclared/manage/ProjectReviewManage.java @@ -11,9 +11,12 @@ import com.hz.pm.api.common.model.constant.BizConst; import com.hz.pm.api.common.model.constant.ExistsSqlConst; import com.hz.pm.api.common.statemachine.event.ProjectStateChangeEvent; import com.hz.pm.api.common.statemachine.util.ProjectStateMachineUtil; +import com.hz.pm.api.common.util.BizUtils; import com.hz.pm.api.datascope.model.DataScopeDTO; import com.hz.pm.api.datascope.utils.DataScopeUtil; +import com.hz.pm.api.meeting.entity.domain.MeetingInnerProject; import com.hz.pm.api.meeting.entity.dto.ProjectReviewResultDTO; +import com.hz.pm.api.meeting.service.IMeetingInnerProjectService; import com.hz.pm.api.projectdeclared.model.entity.ProjectReview; import com.hz.pm.api.projectdeclared.model.req.ProjectReviewApplyReq; import com.hz.pm.api.projectdeclared.model.vo.ReviewProgressStatisticsVO; @@ -69,6 +72,7 @@ public class ProjectReviewManage { private final ProjectStateMachineUtil projectStateMachineUtil; private final MhUnitCache mhUnitCache; private final UserInfoHelper userInfoHelper; + private final IMeetingInnerProjectService meetingInnerProjectService; @Transactional(rollbackFor = Exception.class) public synchronized void projectReviewApply(ProjectReviewApplyReq req) { @@ -135,14 +139,14 @@ public class ProjectReviewManage { req.setStatus(null); ProjectManageUtil.projectQuery(query, req); query.exists(ExistsSqlConst.PROJECT_EXISTS_STATUS_CHANGE + - " and npsc.event = {0}", ProjectStateChangeEvent.COMPLIANCE_REVIEW_PASS) + " and npsc.event = {0}", ProjectStateChangeEvent.EXPERT_REVIEW_PASS) .ne(Project::getStage, ProjectStatus.STOPPED.getCode()) .eq(Project::getNewest, Boolean.TRUE) .select(Project::getStatus, Project::getId); List projects = projectService.list(query); Map countMap = CollUtils.groupCount(projects, w -> { if (!ProjectStatus.PROJECT_REVIEW_FAILED.eq(w.getStatus()) - && !ProjectStatus.COMPLIANCE_REVIEW_PASSED.eq(w.getStatus()) + && !ProjectStatus.EXPERT_REVIEW_PASSED.eq(w.getStatus()) && !ProjectStatus.WITHOUT_PROJECT_REVIEW.eq(w.getStatus()) && !ProjectStatus.ON_PROJECT_REVIEW.eq(w.getStatus()) && !ProjectStatus.ON_CHANGE_APPLY.eq(w.getStatus())) { @@ -182,7 +186,7 @@ public class ProjectReviewManage { } } else { query.exists(ExistsSqlConst.PROJECT_EXISTS_STATUS_CHANGE + - " and npsc.event = {0}", ProjectStateChangeEvent.COMPLIANCE_REVIEW_PASS); + " and npsc.event = {0}", ProjectStateChangeEvent.EXPERT_REVIEW_PASS); } ProjectManageUtil.projectQuery(query, req); query.eq(Project::getNewest, Boolean.TRUE) @@ -194,7 +198,7 @@ public class ProjectReviewManage { List records = CollUtils.convert(page.getRecords(), w -> { ProjectLibListItemVO item = BeanUtil.copyProperties(w, ProjectLibListItemVO.class); if (!ProjectStatus.PROJECT_REVIEW_FAILED.eq(w.getStatus()) - && !ProjectStatus.COMPLIANCE_REVIEW_PASSED.eq(w.getStatus()) + && !ProjectStatus.EXPERT_REVIEW_PASSED.eq(w.getStatus()) && !ProjectStatus.WITHOUT_PROJECT_REVIEW.eq(w.getStatus()) && !ProjectStatus.ON_PROJECT_REVIEW.eq(w.getStatus()) && !ProjectStatus.ON_CHANGE_APPLY.eq(w.getStatus())) { @@ -205,6 +209,100 @@ public class ProjectReviewManage { return PageVo.of(records, page.getTotal()); } + public ReviewProgressStatisticsVO expertReviewProjectProgressStatistics(ProjectListReq req) { + UserFullInfoDTO user = userInfoHelper.getUserFullInfo(LoginUserUtil.getUserId()); + LambdaQueryWrapper query = ProjectManageUtil.initQuery(); + if (!projectQueryPermission(query, user, req.getDeclaredUnitId())) { + return null; + } + req.setStatus(null); + ProjectManageUtil.projectQuery(query, req); + query.exists(ExistsSqlConst.PROJECT_EXISTS_STATUS_CHANGE + + " and npsc.event = {0}", ProjectStateChangeEvent.COMPLIANCE_REVIEW_PASS) + .ne(Project::getStage, ProjectStatus.STOPPED.getCode()) + .eq(Project::getNewest, Boolean.TRUE) + .select(Project::getStatus, Project::getId); + List projects = projectService.list(query); + Map countMap = CollUtils.groupCount(projects, w -> { + if (!ProjectStatus.EXPERT_REVIEW_FAILED.eq(w.getStatus()) + && !ProjectStatus.COMPLIANCE_REVIEW_PASSED.eq(w.getStatus()) + && !ProjectStatus.WITHOUT_EXPERT_REVIEW.eq(w.getStatus()) + && !ProjectStatus.ON_EXPERT_REVIEW.eq(w.getStatus()) + && !ProjectStatus.ON_CHANGE_APPLY.eq(w.getStatus())) { + return ProjectStatus.EXPERT_REVIEW_PASSED; + } + return ProjectStatus.getNoNull(w.getStatus()); + }); + return ReviewProgressStatisticsVO.builder() + .totalCount(projects.size()) + .todoCount(countMap.getOrDefault(ProjectStatus.WITHOUT_EXPERT_REVIEW, 0L)) + .auditCount(countMap.getOrDefault(ProjectStatus.ON_EXPERT_REVIEW, 0L)) + .passedCount(countMap.getOrDefault(ProjectStatus.EXPERT_REVIEW_PASSED, 0L)) + .failedCount(countMap.getOrDefault(ProjectStatus.EXPERT_REVIEW_FAILED, 0L)) + .build(); + } + + /** + * 项目列表 + * + * @param req \ + * @return \ + */ + public PageVo pageExpertReviewProject(ProjectListReq req) { + UserFullInfoDTO user = userInfoHelper.getUserFullInfo(LoginUserUtil.getUserId()); + LambdaQueryWrapper query = ProjectManageUtil.initQuery(); + if (!projectQueryPermission(query, user, req.getDeclaredUnitId())) { + return PageVo.empty(); + } + Integer status = req.getStatus(); + if (status != null) { + req.setStatus(null); + if (ProjectStatus.EXPERT_REVIEW_PASSED.eq(status)) { + query.exists(ExistsSqlConst.PROJECT_EXISTS_STATUS_CHANGE + + " and npsc.event = {0}", ProjectStateChangeEvent.EXPERT_REVIEW_PASS); + } else { + query.eq(Project::getStatus, status); + } + } else { + query.exists(ExistsSqlConst.PROJECT_EXISTS_STATUS_CHANGE + + " and npsc.event = {0}", ProjectStateChangeEvent.COMPLIANCE_REVIEW_PASS); + } + ProjectManageUtil.projectQuery(query, req); + query.eq(Project::getNewest, Boolean.TRUE) + .ne(Project::getStage, ProjectStatus.STOPPED.getCode()); + Page page = projectService.page(req.page(), query); + if (page.getTotal() == 0) { + return PageVo.empty(); + } + List projectIds = new ArrayList<>(); + List records = CollUtils.convert(page.getRecords(), w -> { + projectIds.add(w.getId()); + ProjectLibListItemVO item = BeanUtil.copyProperties(w, ProjectLibListItemVO.class); + if (!ProjectStatus.EXPERT_REVIEW_PASSED.eq(w.getStatus()) + && !ProjectStatus.COMPLIANCE_REVIEW_PASSED.eq(w.getStatus()) + && !ProjectStatus.WITHOUT_EXPERT_REVIEW.eq(w.getStatus()) + && !ProjectStatus.ON_EXPERT_REVIEW.eq(w.getStatus()) + && !ProjectStatus.ON_CHANGE_APPLY.eq(w.getStatus())) { + item.setStatus(ProjectStatus.EXPERT_REVIEW_PASSED.getCode()); + } + return item; + }); + Wrapper wrapper = Wrappers.lambdaQuery(MeetingInnerProject.class) + .in(MeetingInnerProject::getProjectId, projectIds) + .notExists(ExistsSqlConst.MEETING_INNER_PROJECT_EXISTS_MEETING + " and status == 3"); + List meetingInnerProjects = meetingInnerProjectService.list(wrapper); + Map lastMeetingInnerProjects = BizUtils.groupFirstMap(meetingInnerProjects, + MeetingInnerProject::getProjectId, Comparator.comparing(MeetingInnerProject::getId)); + for (ProjectLibListItemVO item : records) { + MeetingInnerProject meetingInnerProject = lastMeetingInnerProjects.get(item.getId()); + if (meetingInnerProject != null) { + item.setMeetingId(meetingInnerProject.getMeetingId()); + item.setMeetingProjectId(meetingInnerProject.getId()); + } + } + return PageVo.of(records, page.getTotal()); + } + private boolean projectQueryPermission(LambdaQueryWrapper query, UserFullInfoDTO user, Long declaredUnitId) { diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/projectlib/model/enumeration/status/ProjectStatus.java b/hz-pm-api/src/main/java/com/hz/pm/api/projectlib/model/enumeration/status/ProjectStatus.java index 94f9dc6..8501a70 100644 --- a/hz-pm-api/src/main/java/com/hz/pm/api/projectlib/model/enumeration/status/ProjectStatus.java +++ b/hz-pm-api/src/main/java/com/hz/pm/api/projectlib/model/enumeration/status/ProjectStatus.java @@ -34,12 +34,20 @@ public enum ProjectStatus implements IStatus { COMPLIANCE_REVIEW_PASSED(10032, "合规性审查通过", 10000), /** - * 项目评审 + * 专家评审 */ - WITHOUT_PROJECT_REVIEW(10040, "待项目评审", 10000), - ON_PROJECT_REVIEW(10041, "项目评审中", 10000), - PROJECT_REVIEW_FAILED(10042, "项目评审不通过", 10000), - PROJECT_REVIEW_PASSED(10043, "项目评审通过", 10000), + WITHOUT_EXPERT_REVIEW(10050, "待专家评审", 10000), + ON_EXPERT_REVIEW(10051, "专家评审中", 10000), + EXPERT_REVIEW_FAILED(10052, "专家评审不通过", 10000), + EXPERT_REVIEW_PASSED(10053, "专家评审通过", 10000), + + /** + * 项目复核 + */ + WITHOUT_PROJECT_REVIEW(10040, "待项目复核", 10000), + ON_PROJECT_REVIEW(10041, "项目复核中", 10000), + PROJECT_REVIEW_FAILED(10042, "项目复核不通过", 10000), + PROJECT_REVIEW_PASSED(10043, "项目复核通过", 10000), ON_ANNUAL_PLAN(10010, "年度计划中", 10000), diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/projectlib/model/vo/ProjectLibListItemVO.java b/hz-pm-api/src/main/java/com/hz/pm/api/projectlib/model/vo/ProjectLibListItemVO.java index 5fd3118..a2fc483 100644 --- a/hz-pm-api/src/main/java/com/hz/pm/api/projectlib/model/vo/ProjectLibListItemVO.java +++ b/hz-pm-api/src/main/java/com/hz/pm/api/projectlib/model/vo/ProjectLibListItemVO.java @@ -179,4 +179,10 @@ public class ProjectLibListItemVO { @ApiModelProperty("项目终止状态") private Integer stoppedStatus; + @ApiModelProperty("会议项目关联ID") + private Long meetingProjectId; + + @ApiModelProperty("会议ID") + private Long meetingId; + }