From dae6bdf29b59cc1436340820f44b753d772ee8ae Mon Sep 17 00:00:00 2001 From: WendyYang Date: Thu, 5 Dec 2024 19:20:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=201.=20=E5=A2=9E=E5=8A=A0=E4=BC=9A?= =?UTF-8?q?=E8=AE=AE=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE=E3=80=81=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E9=A1=B9=E7=9B=AE=E6=8E=A5=E5=8F=A3=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../action/ProjectStateChangeAction.java | 6 ++ .../impl/ProjectStateMachineBuilderImpl.java | 5 ++ .../event/ProjectStateChangeEvent.java | 5 ++ .../util/AbstractStateMachineUtil.java | 8 +- .../api/meeting/controller/MeetingController.java | 14 +++ .../entity/req/MeetingAppendProjectReq.java | 29 ++++++ .../entity/req/MeetingOptionProjectReq.java | 4 + .../hz/pm/api/meeting/manage/MeetingManage.java | 100 ++++++++++++++++++--- 8 files changed, 155 insertions(+), 16 deletions(-) create mode 100644 hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/req/MeetingAppendProjectReq.java 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 d5793ec..4350b1e 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 @@ -73,6 +73,12 @@ public class ProjectStateChangeAction { project.setStatus(ProjectStatus.WITHOUT_EXPERT_REVIEW.getCode()); } + @OnTransition(source = "ON_EXPERT_REVIEW", target = "WITHOUT_EXPERT_REVIEW") + public void EXPERT_REVIEW_WITHDRAW(Message message) { + Project project = getProject(message); + project.setStatus(ProjectStatus.WITHOUT_EXPERT_REVIEW.getCode()); + } + @OnTransition(source = "ON_EXPERT_REVIEW", target = "EXPERT_REVIEW_FAILED") public void EXPERT_REVIEW_FAILED(Message message) { Project project = getProject(message); 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 4bc6cbc..749275a 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 @@ -104,6 +104,11 @@ public class ProjectStateMachineBuilderImpl implements BaseStateMachineBuilder

& AbstractStateCh } } - //撤回 default void withDraw(O obj) { + withDraw(obj, null); + } + + //撤回 + default void withDraw(O obj, T extraArgs) { try { synchronized (getLockClass()) { - execute(obj, AbstractStateChangeEvent.getWithdrawEvent(eventClass(), statusFunction().apply(obj))); + execute(obj, AbstractStateChangeEvent.getWithdrawEvent(eventClass(), statusFunction().apply(obj)), extraArgs); } } catch (Exception e) { LOG.error("状态机撤回失败", e); diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/meeting/controller/MeetingController.java b/hz-pm-api/src/main/java/com/hz/pm/api/meeting/controller/MeetingController.java index ba97fe8..7ecab86 100644 --- a/hz-pm-api/src/main/java/com/hz/pm/api/meeting/controller/MeetingController.java +++ b/hz-pm-api/src/main/java/com/hz/pm/api/meeting/controller/MeetingController.java @@ -192,6 +192,20 @@ public class MeetingController { return meetingManage.optionProject(req); } + @PostMapping("/project/append") + @WebLog("添加项目") + @ApiOperation("添加项目") + public void appendProject(@RequestBody @Valid MeetingAppendProjectReq req) { + meetingManage.appendProject(req); + } + + @PostMapping("/project/remove") + @WebLog("移除项目") + @ApiOperation("移除项目") + public void removeProject(@RequestBody @Valid MeetingAppendProjectReq req) { + meetingManage.removeProject(req); + } + @GetMapping("/{meetingId}/projects") @ApiOperation("会议关联项目列表") public List projectsByMeetingId(@PathVariable Long meetingId) { diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/req/MeetingAppendProjectReq.java b/hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/req/MeetingAppendProjectReq.java new file mode 100644 index 0000000..42cfe91 --- /dev/null +++ b/hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/req/MeetingAppendProjectReq.java @@ -0,0 +1,29 @@ +package com.hz.pm.api.meeting.entity.req; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + *

+ * MeetingAppendProjectReq + *

+ * + * @author WendyYang + * @since 17:36 2024/12/5 + */ +@Data +public class MeetingAppendProjectReq { + + @NotNull(message = "会议ID不能为空") + @ApiModelProperty("会议ID") + private Long meetingId; + + @NotEmpty(message = "项目编码列表不能为空") + @ApiModelProperty("项目编码列表") + private List projectCodes; + +} diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/req/MeetingOptionProjectReq.java b/hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/req/MeetingOptionProjectReq.java index 37ce98a..4640631 100644 --- a/hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/req/MeetingOptionProjectReq.java +++ b/hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/req/MeetingOptionProjectReq.java @@ -1,6 +1,7 @@ package com.hz.pm.api.meeting.entity.req; import com.ningdatech.basic.model.PagePo; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; @@ -18,4 +19,7 @@ public class MeetingOptionProjectReq extends PagePo { private String meetingType; + @ApiModelProperty("会议ID") + private Long meetingId; + } diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/meeting/manage/MeetingManage.java b/hz-pm-api/src/main/java/com/hz/pm/api/meeting/manage/MeetingManage.java index d4df4dd..257a842 100644 --- a/hz-pm-api/src/main/java/com/hz/pm/api/meeting/manage/MeetingManage.java +++ b/hz-pm-api/src/main/java/com/hz/pm/api/meeting/manage/MeetingManage.java @@ -31,10 +31,7 @@ import com.hz.pm.api.meeting.builder.MeetingReviewProjectBuilder; import com.hz.pm.api.meeting.builder.ProjectReviewResultBuilder; import com.hz.pm.api.meeting.entity.domain.*; import com.hz.pm.api.meeting.entity.dto.*; -import com.hz.pm.api.meeting.entity.enumeration.ExpertAttendStatusEnum; -import com.hz.pm.api.meeting.entity.enumeration.ExpertInviteTypeEnum; -import com.hz.pm.api.meeting.entity.enumeration.MeetingReviewTypeEnum; -import com.hz.pm.api.meeting.entity.enumeration.MeetingStatusEnum; +import com.hz.pm.api.meeting.entity.enumeration.*; import com.hz.pm.api.meeting.entity.req.*; import com.hz.pm.api.meeting.entity.vo.*; import com.hz.pm.api.meeting.helper.ExpertInviteHelper; @@ -164,21 +161,19 @@ public class MeetingManage { meetingService.save(meeting); if (Boolean.TRUE.equals(meetingBasic.getIsInnerProject())) { List projectIds = new ArrayList<>(); - List meetingInnerProjects = meetingBasic.getInnerProjects().stream().map(w -> { + List mips = 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()); 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) { + if (CollUtil.anyMatch(projects, w -> !ProjectStatus.WITHOUT_EXPERT_REVIEW.eq(w.getStatus()))) { throw ReturnException.wrap("当前关联项目包含暂不可评审项目"); } projects.forEach(projectStateMachineUtil::pass); projectService.updateBatchById(projects); - meetingInnerProjectService.saveBatch(meetingInnerProjects); + meetingInnerProjectService.saveBatch(mips); } // 抽取专家 inviteRule.setMeetingId(meeting.getId()); @@ -1009,6 +1004,79 @@ public class MeetingManage { return PageVo.of(page.getRecords(), page.getTotal()); } + @Transactional(rollbackFor = Exception.class) + public synchronized void appendProject(MeetingAppendProjectReq req) { + Meeting meeting = meetingService.getById(req.getMeetingId()); + Assert.notNull(meeting, "会议不存在"); + Assert.isTrue(MeetingStatusEnum.NORMAL.eq(meeting.getStatus()), "当前会议无法添加项目"); + List projectCodes = req.getProjectCodes(); + Wrapper query = Wrappers.lambdaQuery(MeetingInnerProject.class) + .select(MeetingInnerProject::getMeetingId, MeetingInnerProject::getProjectCode, + MeetingInnerProject::getId, MeetingInnerProject::getReviewResult) + .in(MeetingInnerProject::getProjectCode, projectCodes); + Collection linkedProjList = BizUtils.groupFirst(meetingInnerProjectService.list(query), + MeetingInnerProject::getProjectId, Comparator.comparing(MeetingInnerProject::getId).reversed()); + // 移除已关联当前会议的项目 + projectCodes.removeIf(w -> CollUtil.anyMatch(linkedProjList, + x -> x.getProjectCode().equals(w) && x.getMeetingId().equals(meeting.getId()))); + if (projectCodes.isEmpty()) { + return; + } + linkedProjList.removeIf(w -> w.getMeetingId().equals(meeting.getId())); + if (CollUtil.isNotEmpty(linkedProjList)) { + Set linkedMeetingIds = CollUtils.fieldSet(linkedProjList, MeetingInnerProject::getMeetingId); + if (!linkedMeetingIds.isEmpty()) { + List meetings = meetingService.listByIds(linkedMeetingIds); + Map meetingMap = CollUtils.listToMap(meetings, Meeting::getId); + if (CollUtil.anyMatch(linkedProjList, w -> { + Meeting linkedMeeting = meetingMap.get(w.getMeetingId()); + return MeetingStatusEnum.NORMAL.eq(linkedMeeting.getStatus()) + && ExpertReviewResultEnum.PASS.eq(w.getReviewResult()); + })) { + throw ReturnException.wrap("所选项目包含已评审通过的项目"); + } + } + } + List projects = projectService.listNewestByProjectCodes(projectCodes); + if (CollUtil.anyMatch(projects, w -> !ProjectStatus.WITHOUT_EXPERT_REVIEW.eq(w.getStatus()))) { + throw ReturnException.wrap("所选项目必须为待专家评审状态"); + } + List mips = CollUtils.convert(projects, w -> { + projectStateMachineUtil.pass(w); + MeetingInnerProject mip = new MeetingInnerProject(); + mip.setProjectId(w.getId()); + mip.setMeetingId(req.getMeetingId()); + mip.setProjectCode(w.getProjectCode()); + return mip; + }); + projectService.updateBatchById(projects); + meetingInnerProjectService.saveBatch(mips); + } + + @Transactional(rollbackFor = Exception.class) + public synchronized void removeProject(MeetingAppendProjectReq req) { + Meeting meeting = meetingService.getById(req.getMeetingId()); + Assert.notNull(meeting, "会议不存在"); + Assert.isTrue(MeetingStatusEnum.NORMAL.eq(meeting.getStatus()), "当前会议无法移除项目"); + List projectCodes = req.getProjectCodes(); + Wrapper query = Wrappers.lambdaQuery(MeetingInnerProject.class) + .select(MeetingInnerProject::getId, MeetingInnerProject::getProjectCode, MeetingInnerProject::getReviewResult) + .in(MeetingInnerProject::getProjectCode, projectCodes) + .eq(MeetingInnerProject::getMeetingId, meeting.getId()); + List linkedProjList = meetingInnerProjectService.list(query); + if (projectCodes.size() != linkedProjList.size()) { + throw ReturnException.wrap("所选项目与当前会议未关联"); + } + if (CollUtil.anyMatch(linkedProjList, w -> w.getReviewResult() != null)) { + throw ReturnException.wrap("已上传评审结果的项目不能移除"); + } + Set mipIds = CollUtils.fieldSet(linkedProjList, MeetingInnerProject::getId); + meetingInnerProjectService.removeByIds(mipIds); + List projects = projectService.listNewestByProjectCodes(projectCodes); + projects.forEach(projectStateMachineUtil::withDraw); + projectService.updateBatchById(projects); + } + public PageVo optionProject(MeetingOptionProjectReq req) { String meetingType = req.getMeetingType(); LambdaQueryWrapper query = Wrappers.lambdaQuery(Project.class) @@ -1035,8 +1103,8 @@ public class MeetingManage { case PRELIMINARY_SCHEME_REVIEW: case CONSTRUCTION_SCHEME_REVIEW: case DEPT_JOIN_REVIEW: - buildOptionProjectQuery(query, meetingType, null); - buildOptionProjectQuery(query, meetingType, null); + buildOptionProjectQuery(query, meetingType); + buildOptionProjectQuery(query, meetingType); break; case ACCEPTANCE_SCHEME_REVIEW: buildOptionProjectQuery(query, meetingType, ProjectStatus.ON_FINALLY_INSPECTED); @@ -1046,11 +1114,15 @@ public class MeetingManage { case PROJECT_REVIEW: case EXPERT_REVIEW: query.isNotNull(Project::getConstructionPlanSealFile); - buildOptionProjectQuery(query, meetingType, ProjectStatus.WITHOUT_EXPERT_REVIEW, ProjectStatus.EXPERT_REVIEW_FAILED); + buildOptionProjectQuery(query, meetingType, ProjectStatus.WITHOUT_EXPERT_REVIEW); break; default: return PageVo.empty(); } + if (req.getMeetingId() != null) { + query.notExists("select 1 from meeting_inner_project mip on mip.project_code = nd_project.project_code" + + " and nd_project.newest = 1 and mip.meeting_id = {0}", req.getMeetingId()); + } ProjectManageUtil.projectBaseQuery(query); Page page = projectService.page(req.page(), query); PageVo result = PageVo.of(null, page.getTotal()); @@ -1099,9 +1171,9 @@ public class MeetingManage { query.in(Project::getStatus, statusCodeList); } 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" + + " m.is_inner_project = 1 and m.id = mip.meeting_id and nd_project.project_code = mip.project_code" + " and m.type = %s and m.status != 3", meetingType); - String sql2 = String.format("1 = (select case when review_result in (0,2) then 1 else 0 end from " + + String sql2 = String.format("1 = (select case when review_result in (2) then 1 else 0 end from " + " (select ner.review_result 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 left join nd_expert_review ner on ner.meeting_id = m.id " +