diff --git a/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/web/institution/EvalTechReviewController.java b/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/web/institution/EvalTechReviewController.java index 0935bc8..93b1442 100644 --- a/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/web/institution/EvalTechReviewController.java +++ b/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/web/institution/EvalTechReviewController.java @@ -5,7 +5,9 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.qinan.safetyeval.client.api.institution.EvalTechReviewApi; import org.qinan.safetyeval.client.co.institution.EvalTechReviewCO; +import org.qinan.safetyeval.client.co.institution.EvalTechReviewDetailCO; import org.qinan.safetyeval.client.dto.SingleResponse; +import org.qinan.safetyeval.client.dto.institution.EvalTechReviewConfirmCmd; import org.qinan.safetyeval.client.dto.institution.EvalTechReviewSaveCmd; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -31,4 +33,16 @@ public class EvalTechReviewController { public SingleResponse get(@ApiParam("项目ID") @RequestParam String projectId) { return evalTechReviewApi.getByProject(projectId); } */ + + @ApiOperation("技审确认") + @PostMapping("/confirm") + public SingleResponse confirm(@Validated @RequestBody EvalTechReviewConfirmCmd cmd) { + return evalTechReviewApi.confirm(cmd); + } + + @ApiOperation("按项目查询详情(技审人成员+审核项)") + @GetMapping("/detail") + public SingleResponse detail(@ApiParam("项目ID") @RequestParam Long projectId) { + return evalTechReviewApi.getDetailByProject(projectId); + } } diff --git a/safety-eval-app/src/main/java/org/qinan/safetyeval/app/executor/institution/EvalTechReviewExecutor.java b/safety-eval-app/src/main/java/org/qinan/safetyeval/app/executor/institution/EvalTechReviewExecutor.java index bad8e99..b36c6d5 100644 --- a/safety-eval-app/src/main/java/org/qinan/safetyeval/app/executor/institution/EvalTechReviewExecutor.java +++ b/safety-eval-app/src/main/java/org/qinan/safetyeval/app/executor/institution/EvalTechReviewExecutor.java @@ -1,21 +1,46 @@ package org.qinan.safetyeval.app.executor.institution; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.commons.lang3.StringUtils; import org.qinan.safetyeval.app.executor.institution.support.EvalCmdCopy; import org.qinan.safetyeval.app.executor.institution.support.EvalNodeCoConverter; import org.qinan.safetyeval.app.executor.institution.support.EvalProjectNodeSupport; +import org.qinan.safetyeval.app.item.convertor.EvalReviewItemCmdConvertor; import org.qinan.safetyeval.client.api.institution.EvalTechReviewApi; import org.qinan.safetyeval.client.co.institution.EvalTechReviewCO; +import org.qinan.safetyeval.client.co.institution.EvalTechReviewDetailCO; import org.qinan.safetyeval.client.dto.SingleResponse; +import org.qinan.safetyeval.client.dto.institution.EvalTechReviewConfirmCmd; import org.qinan.safetyeval.client.dto.institution.EvalTechReviewSaveCmd; +import org.qinan.safetyeval.client.item.request.EvalReviewItemAddCmd; +import org.qinan.safetyeval.client.item.response.EvalReviewItemCo; +import org.qinan.safetyeval.domain.constant.ProjectStageEnum; +import org.qinan.safetyeval.domain.constant.ReviewDimensionEnum; import org.qinan.safetyeval.domain.entity.EvalProjectEntity; +import org.qinan.safetyeval.domain.entity.EvalProjectMemberEntity; import org.qinan.safetyeval.domain.entity.EvalTechReviewEntity; import org.qinan.safetyeval.domain.exception.BizException; import org.qinan.safetyeval.domain.exception.ErrorCode; +import org.qinan.safetyeval.domain.gateway.EvalProjectMemberGateway; import org.qinan.safetyeval.domain.gateway.EvalTechReviewGateway; +import org.qinan.safetyeval.domain.item.gateway.EvalReviewItemGateway; +import org.qinan.safetyeval.domain.item.model.EvalReviewItemE; +import org.qinan.safetyeval.domain.service.ProjectStageSyncService; import org.qinan.safetyeval.domain.support.EvalNodeCodes; +import org.qinan.safetyeval.infrastructure.convertor.EvalTechReviewConvertor; +import org.qinan.safetyeval.infrastructure.dataobject.EvalTechReviewDO; +import org.qinan.safetyeval.infrastructure.mapper.EvalTechReviewMapper; +import org.qinan.safetyeval.infrastructure.persistence.queryservice.EvalReviewItemQueryService; +import org.qinan.safetyeval.infrastructure.support.NodeWriteAuthority; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + +import static org.qinan.safetyeval.domain.exception.ErrorCode.ASSIGN_SIGN_TASK; +import static org.qinan.safetyeval.domain.exception.ErrorCode.SIGN_TASK_NOT_COMPLETE; @Service public class EvalTechReviewExecutor implements EvalTechReviewApi { @@ -24,6 +49,20 @@ public class EvalTechReviewExecutor implements EvalTechReviewApi { private EvalTechReviewGateway evalTechReviewGateway; @Resource private EvalProjectNodeSupport evalProjectNodeSupport; + @Resource + private EvalProjectMemberGateway evalProjectMemberGateway; + @Resource + private EvalReviewItemQueryService evalReviewItemQueryService; + @Resource + private EvalTechReviewConvertor evalTechReviewConvertor; + @Resource + private EvalReviewItemGateway evalReviewItemGateway; + @Resource + private EvalReviewItemCmdConvertor evalReviewItemCmdConvertor; + @Resource + private ProjectStageSyncService projectStageSyncService; + @Resource + private EvalTechReviewMapper evalTechReviewMapper; @Override public SingleResponse getOrSave(EvalTechReviewSaveCmd cmd) { @@ -57,4 +96,88 @@ public class EvalTechReviewExecutor implements EvalTechReviewApi { } return SingleResponse.success(EvalNodeCoConverter.toTechCO(entity)); } + + @Override + @Transactional(rollbackFor = Exception.class) + public SingleResponse confirm(EvalTechReviewConfirmCmd cmd) { + Long projectId = cmd.getProjectId(); + EvalProjectEntity project = evalProjectNodeSupport.requireProject(projectId); + // 判断项目是否归档 + if (project.getArchiveFlag() != null && project.getArchiveFlag() == 1) { + throw new BizException(ErrorCode.EVAL_PROJECT_ARCHIVED); + } + + EvalTechReviewEntity entity = evalTechReviewConvertor.applyConfirmCmd(cmd); + EvalTechReviewDO evalTechReviewDO = null; + if (cmd.getId() != null) { + evalTechReviewDO = evalTechReviewMapper.selectOne(new LambdaQueryWrapper() + .eq(EvalTechReviewDO::getId, cmd.getId()) + .select(EvalTechReviewDO::getId, EvalTechReviewDO::getReviewerSignatureUrl)); + if (evalTechReviewDO == null) { + throw new BizException(ErrorCode.EVAL_TECH_REVIEW_NOT_FOUND); + } + } + + // 审核结果编码:1通过 2退回修改 + if (cmd.getResultCode() != null && cmd.getResultCode() == 1) { + if (evalTechReviewDO == null) { + throw new BizException(ASSIGN_SIGN_TASK); + } + if (StringUtils.isBlank(evalTechReviewDO.getReviewerSignatureUrl())) { + throw new BizException(SIGN_TASK_NOT_COMPLETE); + } + projectStageSyncService.onNodeCompleted(projectId, ProjectStageEnum.TECHNICAL_REVIEW.getNode()); + } + + if (cmd.getId() != null) { + entity = evalTechReviewGateway.modify(entity); + } else { + // id为空,新增数据 + entity.setOrgId(project.getOrgId()); + entity = evalTechReviewGateway.save(entity); + } + + // 审核项:根据bizId和bizType先删后增 + String bizType = ReviewDimensionEnum.TypeEnum.EVAL_TECH_REVIEW.getCode(); + evalReviewItemGateway.deletedEvalReviewItemByBizIdAndBizType(entity.getId(), bizType); + for (EvalReviewItemAddCmd itemCmd : cmd.getReviewItems()) { + EvalReviewItemE itemE = evalReviewItemCmdConvertor.convertCmdToE(itemCmd); + itemE.setBizId(entity.getId()); + itemE.setBizType(bizType); + evalReviewItemGateway.add(itemE); + } + return SingleResponse.success(); + } + + @Override + public SingleResponse getDetailByProject(Long projectId) { + // 1. 查询项目成员中的技审人信息 + List members = evalProjectMemberGateway + .listByProjectIdAndRoleCode(projectId, NodeWriteAuthority.ROLE_TECH_REVIEWER); + + // 2. 查询技审记录,未查询到则技审记录字段为空 + EvalTechReviewEntity entity = evalTechReviewGateway.getByProjectId(projectId, null); + EvalTechReviewDetailCO detailCO = new EvalTechReviewDetailCO(); + detailCO.setReviewers(evalTechReviewConvertor.toMemberCOs(members)); + if (entity != null) { + detailCO.setTechReview(evalTechReviewConvertor.toTechCO(entity)); + // 3. 通过技审记录id查询审核项列表 + detailCO.setReviewItems(evalReviewItemQueryService.listByBizIdAndBizType( + entity.getId(), ReviewDimensionEnum.TypeEnum.EVAL_TECH_REVIEW.getCode())); + } else { + // 未查询到技审记录,按审核维度枚举构建默认审核项 + detailCO.setReviewItems(ReviewDimensionEnum.getListByType(ReviewDimensionEnum.TypeEnum.EVAL_TECH_REVIEW) + .stream() + .map(dimension -> { + EvalReviewItemCo item = new EvalReviewItemCo(); + item.setBizType(ReviewDimensionEnum.TypeEnum.EVAL_TECH_REVIEW.getCode()); + item.setReviewDimensionCode(dimension.getCode()); + item.setReviewDimensionName(dimension.getLabel()); + item.setReviewFocus(dimension.getReviewFocus()); + return item; + }) + .collect(Collectors.toList())); + } + return SingleResponse.success(detailCO); + } } diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/api/institution/EvalTechReviewApi.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/api/institution/EvalTechReviewApi.java index b4428b0..f3ef6ba 100644 --- a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/api/institution/EvalTechReviewApi.java +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/api/institution/EvalTechReviewApi.java @@ -1,10 +1,14 @@ package org.qinan.safetyeval.client.api.institution; import org.qinan.safetyeval.client.co.institution.EvalTechReviewCO; +import org.qinan.safetyeval.client.co.institution.EvalTechReviewDetailCO; import org.qinan.safetyeval.client.dto.SingleResponse; +import org.qinan.safetyeval.client.dto.institution.EvalTechReviewConfirmCmd; import org.qinan.safetyeval.client.dto.institution.EvalTechReviewSaveCmd; public interface EvalTechReviewApi { SingleResponse getOrSave(EvalTechReviewSaveCmd cmd); SingleResponse getByProject(String projectId); + SingleResponse confirm(EvalTechReviewConfirmCmd cmd); + SingleResponse getDetailByProject(Long projectId); } diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/institution/EvalTechReviewDetailCO.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/institution/EvalTechReviewDetailCO.java new file mode 100644 index 0000000..f03d68a --- /dev/null +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/institution/EvalTechReviewDetailCO.java @@ -0,0 +1,23 @@ +package org.qinan.safetyeval.client.co.institution; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.qinan.safetyeval.client.item.response.EvalReviewItemCo; + +import java.util.List; + +/** + * 技审详情CO,聚合技审记录、技审人成员信息与审核项列表。 + */ +@Data +public class EvalTechReviewDetailCO { + + @ApiModelProperty("技审记录信息") + private EvalTechReviewCO techReview; + + @ApiModelProperty("技审人成员信息") + private List reviewers; + + @ApiModelProperty("审核项列表") + private List reviewItems; +} diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/dto/institution/EvalTechReviewConfirmCmd.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/dto/institution/EvalTechReviewConfirmCmd.java new file mode 100644 index 0000000..a37e606 --- /dev/null +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/dto/institution/EvalTechReviewConfirmCmd.java @@ -0,0 +1,49 @@ +package org.qinan.safetyeval.client.dto.institution; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.qinan.safetyeval.client.item.request.EvalReviewItemAddCmd; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; +import java.util.List; + +@Data +public class EvalTechReviewConfirmCmd { + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("项目id") + private Long projectId; + + @ApiModelProperty(value = "节点状态编码:1未开始 2进行中 3已完成 4退回", example = "2") + private Integer statusCode; + + @ApiModelProperty(value = "技审人人员id") + private Long reviewerPersonnelId; + + @ApiModelProperty(value = "技审人姓名", example = "2") + private String reviewerName; + + @ApiModelProperty(value = "审核签字任务状态 dispatched 下发,non_dispatched 未下发", example = "non_dispatched") + private String reviewerSignatureTaskStatus; + + @ApiModelProperty(value = "审核结果编码:1通过 2退回修改", example = "1") + private Integer resultCode; + + @ApiModelProperty(value = "总体审核意见") + @Size(max = 2000) + private String opinionContent; + + @ApiModelProperty(value = "审核时间", hidden = true) + private LocalDateTime reviewTime; + + @ApiModelProperty("审核项列表") + @NotNull + @Size(min = 1, max = 16) + @Valid + private List reviewItems; +} diff --git a/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/convertor/EvalTechReviewConvertor.java b/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/convertor/EvalTechReviewConvertor.java new file mode 100644 index 0000000..bb32ce7 --- /dev/null +++ b/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/convertor/EvalTechReviewConvertor.java @@ -0,0 +1,28 @@ +package org.qinan.safetyeval.infrastructure.convertor; + +import org.mapstruct.Mapper; +import org.qinan.safetyeval.client.co.institution.EvalProjectMemberCO; +import org.qinan.safetyeval.client.co.institution.EvalTechReviewCO; +import org.qinan.safetyeval.client.dto.institution.EvalTechReviewConfirmCmd; +import org.qinan.safetyeval.domain.entity.EvalProjectMemberEntity; +import org.qinan.safetyeval.domain.entity.EvalTechReviewEntity; + +import java.util.List; + +/** + * 技审相关对象转换器。 + */ +@Mapper(componentModel = "spring") +public interface EvalTechReviewConvertor { + + EvalTechReviewCO toTechCO(EvalTechReviewEntity entity); + + EvalProjectMemberCO toMemberCO(EvalProjectMemberEntity entity); + + List toMemberCOs(List entities); + + /** + * 将 ConfirmCmd 转换为新的 entity。 + */ + EvalTechReviewEntity applyConfirmCmd(EvalTechReviewConfirmCmd cmd); +}