diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/model/FreemarkerBatchExportDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/model/FreemarkerBatchExportDTO.java new file mode 100644 index 0000000..7221f81 --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/model/FreemarkerBatchExportDTO.java @@ -0,0 +1,22 @@ +package com.ningdatech.pmapi.common.model; + +import lombok.Data; + +/** + *

+ * FreemarkerBatchExportDTO + *

+ * + * @author WendyYang + * @since 2023/8/1 + **/ +@Data +public class FreemarkerBatchExportDTO { + + private String fileName; + + private String template; + + private Object data; + +} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/action/ProjectDeclareYHAction.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/action/ProjectDeclareYHAction.java index 9fe7b1b..1498589 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/action/ProjectDeclareYHAction.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/action/ProjectDeclareYHAction.java @@ -210,6 +210,7 @@ public class ProjectDeclareYHAction { Project project = (Project) message.getHeaders().get(PROJECT_DECLARE); project.setStatus(ProjectStatusEnum.OPERATION.getCode()); } + @OnTransition(source = "OPERATION", target = "UNDER_CONSTRUCTION") public void START_TO_WORK(Message message) { Project project = (Project) message.getHeaders().get(PROJECT_DECLARE); diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineJNBuilder.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineJNBuilder.java index 6699f8a..48195f1 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineJNBuilder.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineJNBuilder.java @@ -211,12 +211,11 @@ public class ProjectDeclareStateMachineJNBuilder implements ProjectDeclareStateM .source(ProjectStatusEnum.TO_BE_APPROVED) .target(ProjectStatusEnum.TO_BE_PURCHASED) .event(ProjectStatusChangeEvent.PROJECT_APPROVAL).and() - // 待采购采购备案,从待采购到实施中 + // 待采购采购备案,从待采购到建设中 .withExternal() .source(ProjectStatusEnum.TO_BE_PURCHASED) .target(ProjectStatusEnum.OPERATION) .event(ProjectStatusChangeEvent.PURCHASE_PUT_ON_RECORD).and() - // 待开工 实施,从实施到建设中 .withExternal() .source(ProjectStatusEnum.OPERATION) diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineJYBuilder.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineJYBuilder.java index 0e1e70b..c805486 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineJYBuilder.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineJYBuilder.java @@ -211,7 +211,7 @@ public class ProjectDeclareStateMachineJYBuilder implements ProjectDeclareStateM .source(ProjectStatusEnum.TO_BE_APPROVED) .target(ProjectStatusEnum.TO_BE_PURCHASED) .event(ProjectStatusChangeEvent.PROJECT_APPROVAL).and() - // 待采购采购备案,从待采购到实施中 + // 待采购采购备案,从待采购到建设中 .withExternal() .source(ProjectStatusEnum.TO_BE_PURCHASED) .target(ProjectStatusEnum.OPERATION) diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineKFQBuilder.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineKFQBuilder.java index a9c54d0..df9064c 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineKFQBuilder.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineKFQBuilder.java @@ -211,7 +211,7 @@ public class ProjectDeclareStateMachineKFQBuilder implements ProjectDeclareState .source(ProjectStatusEnum.TO_BE_APPROVED) .target(ProjectStatusEnum.TO_BE_PURCHASED) .event(ProjectStatusChangeEvent.PROJECT_APPROVAL).and() - // 待采购采购备案,从待采购到实施中 + // 待采购采购备案,从待采购到建设中 .withExternal() .source(ProjectStatusEnum.TO_BE_PURCHASED) .target(ProjectStatusEnum.OPERATION) diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineLDBuilder.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineLDBuilder.java index 575ff1a..d762eca 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineLDBuilder.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineLDBuilder.java @@ -211,7 +211,7 @@ public class ProjectDeclareStateMachineLDBuilder implements ProjectDeclareStateM .source(ProjectStatusEnum.TO_BE_APPROVED) .target(ProjectStatusEnum.TO_BE_PURCHASED) .event(ProjectStatusChangeEvent.PROJECT_APPROVAL).and() - // 待采购采购备案,从待采购到实施中 + // 待采购采购备案,从待采购到建设中 .withExternal() .source(ProjectStatusEnum.TO_BE_PURCHASED) .target(ProjectStatusEnum.OPERATION) @@ -221,7 +221,7 @@ public class ProjectDeclareStateMachineLDBuilder implements ProjectDeclareStateM .withExternal() .source(ProjectStatusEnum.OPERATION) .target(ProjectStatusEnum.UNDER_CONSTRUCTION) - .event(ProjectStatusChangeEvent.START_TO_WORK).and() + .event(ProjectStatusChangeEvent.PURCHASE_PUT_ON_RECORD).and() // 建设中初验备案,从建设中到待终验 .withExternal() .source(ProjectStatusEnum.UNDER_CONSTRUCTION) diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineLQBuilder.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineLQBuilder.java index 737d7f5..acb3467 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineLQBuilder.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineLQBuilder.java @@ -212,7 +212,7 @@ public class ProjectDeclareStateMachineLQBuilder implements ProjectDeclareStateM .source(ProjectStatusEnum.TO_BE_APPROVED) .target(ProjectStatusEnum.TO_BE_PURCHASED) .event(ProjectStatusChangeEvent.PROJECT_APPROVAL).and() - // 待采购采购备案,从待采购到实施中 + // 待采购采购备案,从待采购到建设中 .withExternal() .source(ProjectStatusEnum.TO_BE_PURCHASED) .target(ProjectStatusEnum.OPERATION) @@ -222,7 +222,7 @@ public class ProjectDeclareStateMachineLQBuilder implements ProjectDeclareStateM .withExternal() .source(ProjectStatusEnum.OPERATION) .target(ProjectStatusEnum.UNDER_CONSTRUCTION) - .event(ProjectStatusChangeEvent.START_TO_WORK).and() + .event(ProjectStatusChangeEvent.PURCHASE_PUT_ON_RECORD).and() // 建设中初验备案,从建设中到待终验 .withExternal() .source(ProjectStatusEnum.UNDER_CONSTRUCTION) diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineQTBuilder.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineQTBuilder.java index 43dae81..ce31064 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineQTBuilder.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineQTBuilder.java @@ -211,7 +211,7 @@ public class ProjectDeclareStateMachineQTBuilder implements ProjectDeclareStateM .source(ProjectStatusEnum.TO_BE_APPROVED) .target(ProjectStatusEnum.TO_BE_PURCHASED) .event(ProjectStatusChangeEvent.PROJECT_APPROVAL).and() - // 待采购采购备案,从待采购到实施中 + // 待采购采购备案,从待采购到建设中 .withExternal() .source(ProjectStatusEnum.TO_BE_PURCHASED) .target(ProjectStatusEnum.OPERATION) @@ -221,7 +221,7 @@ public class ProjectDeclareStateMachineQTBuilder implements ProjectDeclareStateM .withExternal() .source(ProjectStatusEnum.OPERATION) .target(ProjectStatusEnum.UNDER_CONSTRUCTION) - .event(ProjectStatusChangeEvent.START_TO_WORK).and() + .event(ProjectStatusChangeEvent.PURCHASE_PUT_ON_RECORD).and() // 建设中初验备案,从建设中到待终验 .withExternal() .source(ProjectStatusEnum.UNDER_CONSTRUCTION) diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineQYBuilder.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineQYBuilder.java index 617c7d7..c34160a 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineQYBuilder.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineQYBuilder.java @@ -211,7 +211,7 @@ public class ProjectDeclareStateMachineQYBuilder implements ProjectDeclareStateM .source(ProjectStatusEnum.TO_BE_APPROVED) .target(ProjectStatusEnum.TO_BE_PURCHASED) .event(ProjectStatusChangeEvent.PROJECT_APPROVAL).and() - // 待采购采购备案,从待采购到实施中 + // 待采购采购备案,从待采购到建设中 .withExternal() .source(ProjectStatusEnum.TO_BE_PURCHASED) .target(ProjectStatusEnum.OPERATION) @@ -221,7 +221,7 @@ public class ProjectDeclareStateMachineQYBuilder implements ProjectDeclareStateM .withExternal() .source(ProjectStatusEnum.OPERATION) .target(ProjectStatusEnum.UNDER_CONSTRUCTION) - .event(ProjectStatusChangeEvent.START_TO_WORK).and() + .event(ProjectStatusChangeEvent.PURCHASE_PUT_ON_RECORD).and() // 建设中初验备案,从建设中到待终验 .withExternal() .source(ProjectStatusEnum.UNDER_CONSTRUCTION) diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineSBJBuilder.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineSBJBuilder.java index c321412..5b96623 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineSBJBuilder.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineSBJBuilder.java @@ -212,7 +212,7 @@ public class ProjectDeclareStateMachineSBJBuilder implements ProjectDeclareState .source(ProjectStatusEnum.TO_BE_APPROVED) .target(ProjectStatusEnum.TO_BE_PURCHASED) .event(ProjectStatusChangeEvent.PROJECT_APPROVAL).and() - // 待采购采购备案,从待采购到实施中 + // 待采购采购备案,从待采购到建设中 .withExternal() .source(ProjectStatusEnum.TO_BE_PURCHASED) .target(ProjectStatusEnum.OPERATION) @@ -222,7 +222,7 @@ public class ProjectDeclareStateMachineSBJBuilder implements ProjectDeclareState .withExternal() .source(ProjectStatusEnum.OPERATION) .target(ProjectStatusEnum.UNDER_CONSTRUCTION) - .event(ProjectStatusChangeEvent.START_TO_WORK).and() + .event(ProjectStatusChangeEvent.PURCHASE_PUT_ON_RECORD).and() // 建设中初验备案,从建设中到待终验 .withExternal() .source(ProjectStatusEnum.UNDER_CONSTRUCTION) diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineSCBuilder.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineSCBuilder.java index eddf681..7c38c88 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineSCBuilder.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineSCBuilder.java @@ -221,7 +221,7 @@ public class ProjectDeclareStateMachineSCBuilder implements ProjectDeclareStateM .source(ProjectStatusEnum.TO_BE_APP_REGISTER) .target(ProjectStatusEnum.TO_BE_PURCHASED) .event(ProjectStatusChangeEvent.REGISTER_APP).and() - // 待采购采购备案,从待采购到实施中 + // 待采购采购备案,从待采购到建设中 .withExternal() .source(ProjectStatusEnum.TO_BE_PURCHASED) .target(ProjectStatusEnum.OPERATION) @@ -231,7 +231,7 @@ public class ProjectDeclareStateMachineSCBuilder implements ProjectDeclareStateM .withExternal() .source(ProjectStatusEnum.OPERATION) .target(ProjectStatusEnum.UNDER_CONSTRUCTION) - .event(ProjectStatusChangeEvent.START_TO_WORK).and() + .event(ProjectStatusChangeEvent.PURCHASE_PUT_ON_RECORD).and() // 建设中初验备案,从建设中到待终验 .withExternal() .source(ProjectStatusEnum.UNDER_CONSTRUCTION) diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineSYBuilder.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineSYBuilder.java index 048aac5..44b90cc 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineSYBuilder.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineSYBuilder.java @@ -211,7 +211,7 @@ public class ProjectDeclareStateMachineSYBuilder implements ProjectDeclareStateM .source(ProjectStatusEnum.TO_BE_APPROVED) .target(ProjectStatusEnum.TO_BE_PURCHASED) .event(ProjectStatusChangeEvent.PROJECT_APPROVAL).and() - // 待采购采购备案,从待采购到实施中 + // 待采购采购备案,从待采购到建设中 .withExternal() .source(ProjectStatusEnum.TO_BE_PURCHASED) .target(ProjectStatusEnum.OPERATION) @@ -221,7 +221,7 @@ public class ProjectDeclareStateMachineSYBuilder implements ProjectDeclareStateM .withExternal() .source(ProjectStatusEnum.OPERATION) .target(ProjectStatusEnum.UNDER_CONSTRUCTION) - .event(ProjectStatusChangeEvent.START_TO_WORK).and() + .event(ProjectStatusChangeEvent.PURCHASE_PUT_ON_RECORD).and() // 建设中初验备案,从建设中到待终验 .withExternal() .source(ProjectStatusEnum.UNDER_CONSTRUCTION) diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineYHBuilder.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineYHBuilder.java index e7bbd74..5d00597 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineYHBuilder.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/builder/ProjectDeclareStateMachineYHBuilder.java @@ -211,7 +211,7 @@ public class ProjectDeclareStateMachineYHBuilder implements ProjectDeclareStateM .source(ProjectStatusEnum.TO_BE_APPROVED) .target(ProjectStatusEnum.TO_BE_PURCHASED) .event(ProjectStatusChangeEvent.PROJECT_APPROVAL).and() - // 待采购采购备案,从待采购到实施中 + // 待采购采购备案,从待采购到建设中 .withExternal() .source(ProjectStatusEnum.TO_BE_PURCHASED) .target(ProjectStatusEnum.OPERATION) @@ -221,7 +221,7 @@ public class ProjectDeclareStateMachineYHBuilder implements ProjectDeclareStateM .withExternal() .source(ProjectStatusEnum.OPERATION) .target(ProjectStatusEnum.UNDER_CONSTRUCTION) - .event(ProjectStatusChangeEvent.START_TO_WORK).and() + .event(ProjectStatusChangeEvent.PURCHASE_PUT_ON_RECORD).and() // 建设中初验备案,从建设中到待终验 .withExternal() .source(ProjectStatusEnum.UNDER_CONSTRUCTION) diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/util/FreemarkerWordUtil.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/util/FreemarkerWordUtil.java index 8fa62f0..cc5b787 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/common/util/FreemarkerWordUtil.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/util/FreemarkerWordUtil.java @@ -2,6 +2,7 @@ package com.ningdatech.pmapi.common.util; import cn.hutool.core.io.IoUtil; import com.ningdatech.basic.exception.BizException; +import com.ningdatech.pmapi.common.model.FreemarkerBatchExportDTO; import com.ningdatech.pmapi.meeting.entity.dto.ExpertFeeExportDTO; import com.ningdatech.pmapi.meeting.entity.dto.ExpertInfoDTO; import freemarker.template.Configuration; @@ -19,6 +20,9 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; /** *

@@ -31,6 +35,16 @@ import java.util.ArrayList; @Slf4j public class FreemarkerWordUtil { + private static void setDownFileName(HttpServletResponse response, String fileName) { + String fileNameEncoded; + try { + fileNameEncoded = URLEncoder.encode(fileName, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("文件名编码异常"); + } + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileNameEncoded); + } + private static final Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_31); static { @@ -69,21 +83,46 @@ public class FreemarkerWordUtil { public static void export(String fileName, Object data, HttpServletResponse response, String templateName) throws TemplateException, IOException { Template template = CONFIGURATION.getTemplate(templateName); - StringWriter out = new StringWriter(); - Writer writer = new BufferedWriter(out, 4096); - template.process(data, writer); response.setCharacterEncoding(StandardCharsets.UTF_8.displayName()); response.setContentType(ContentType.APPLICATION_JSON.getMimeType()); - response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + URLEncoder.encode(fileName, "UTF-8")); - try (InputStream is = new ByteArrayResource(out.toString().getBytes(StandardCharsets.UTF_8)).getInputStream(); - ServletOutputStream outputStream = response.getOutputStream()) { - // 缓冲区 - byte[] buffer = new byte[1024]; - int bytesToRead; - // 通过循环将读入的Word文件的内容输出到浏览器中 - while ((bytesToRead = is.read(buffer)) != -1) { - outputStream.write(buffer, 0, bytesToRead); + setDownFileName(response, fileName); + try (StringWriter out = new StringWriter(); + Writer writer = new BufferedWriter(out, 4096)) { + template.process(data, writer); + try (InputStream is = new ByteArrayResource(out.toString().getBytes(StandardCharsets.UTF_8)).getInputStream(); + ServletOutputStream outputStream = response.getOutputStream()) { + // 缓冲区 + byte[] buffer = new byte[1024]; + int bytesToRead; + // 通过循环将读入的Word文件的内容输出到浏览器中 + while ((bytesToRead = is.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesToRead); + } + } + } + + + } + + public static void exportBatch(HttpServletResponse response, List fbeList, String fileName) throws IOException, TemplateException { + response.setCharacterEncoding(StandardCharsets.UTF_8.displayName()); + response.setContentType("application/zip"); + setDownFileName(response, fileName); + try (ServletOutputStream os = response.getOutputStream(); + ZipOutputStream zos = new ZipOutputStream(os)) { + for (FreemarkerBatchExportDTO param : fbeList) { + Template template = CONFIGURATION.getTemplate(param.getTemplate()); + StringWriter out = new StringWriter(); + try (Writer writer = new BufferedWriter(out, 4096)) { + template.process(param.getData(), writer); + } + ZipEntry zipEntry = new ZipEntry(param.getFileName()); + zos.putNextEntry(zipEntry); + zos.write(out.toString().getBytes(StandardCharsets.UTF_8)); + zos.closeEntry(); } + } finally { + response.flushBuffer(); } } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/expert/manage/ExpertReviewManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/expert/manage/ExpertReviewManage.java index d77a4e8..e7772d5 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/expert/manage/ExpertReviewManage.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/expert/manage/ExpertReviewManage.java @@ -1,5 +1,6 @@ package com.ningdatech.pmapi.expert.manage; +import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; @@ -8,7 +9,9 @@ import com.ningdatech.basic.util.CollUtils; import com.ningdatech.cache.lock.DistributedLock; import com.ningdatech.file.entity.vo.result.AttachFileVo; import com.ningdatech.file.service.FileService; +import com.ningdatech.pmapi.expert.constant.ReviewResultEnum; import com.ningdatech.pmapi.expert.model.dto.ReviewTemplateOptionDTO; +import com.ningdatech.pmapi.expert.model.dto.ReviewTemplateSettingsDTO; import com.ningdatech.pmapi.expert.model.entity.ExpertReview; import com.ningdatech.pmapi.expert.model.entity.ReviewTemplateSettings; import com.ningdatech.pmapi.expert.model.req.ExpertReviewDetailReq; @@ -199,4 +202,42 @@ public class ExpertReviewManage { return detail; } + public List listFinalExpertReviews(Long meetingId) { + LambdaQueryWrapper query = Wrappers.lambdaQuery(ExpertReview.class) + .eq(ExpertReview::getIsFinal, Boolean.TRUE) + .eq(ExpertReview::getMeetingId, meetingId); + return expertReviewService.list(query); + } + + public Map buildExpertReviewToStr(Long meetingId) { + List reviews = listFinalExpertReviews(meetingId); + if (reviews.isEmpty()) { + return Collections.emptyMap(); + } + List templateIds = CollUtils.fieldList(reviews, ExpertReview::getTemplateId); + List ts = templateSettingsService.listByIds(templateIds); + Map tsMap = CollUtils.listToMap(ts, ReviewTemplateSettings::getId); + Map resMap = new HashMap<>(8); + for (ExpertReview review : reviews) { + ReviewTemplateSettings settings = tsMap.get(review.getTemplateId()); + List optionTemplates = JSONUtil.toList(settings.getContent(), ReviewTemplateSettingsDTO.class); + List options = JSONUtil.toList(review.getContent(), ReviewTemplateOptionDTO.class); + Map optionsMap = CollUtils.listToMap(options, ReviewTemplateOptionDTO::getQuestionSerialNo); + StringBuilder str = new StringBuilder(); + optionTemplates.forEach(ot -> { + ReviewTemplateOptionDTO rto = optionsMap.get(ot.getSerialNo()); + String optionsContent = ot.getOptions().stream() + .filter(w -> rto.getOptionSerialNo().contains(w.getSerialNo())) + .map(ReviewTemplateSettingsDTO.OptionDTO::getOption) + .collect(Collectors.joining("、")); + str.append("").append(ot.getTitle()).append(":").append(optionsContent).append(";"); + }); + str.append("").append("其他意见或建议").append(":") + .append(StrUtil.blankToDefault(review.getOtherAdvice(), "--")).append(";"); + str.append("").append("评审结果").append(":") + .append(ReviewResultEnum.getByCode(review.getReviewResult()).getValue()).append(";"); + resMap.put(review.getProjectId(), str.toString()); + } + return resMap; + } } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/irs/controller/ApplicationController.java b/pmapi/src/main/java/com/ningdatech/pmapi/irs/controller/ApplicationController.java index 2fc2ab3..40289c2 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/irs/controller/ApplicationController.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/irs/controller/ApplicationController.java @@ -1,19 +1,17 @@ package com.ningdatech.pmapi.irs.controller; -import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.ningdatech.log.annotation.WebLog; import com.ningdatech.pmapi.irs.manage.AppIrsManage; import com.ningdatech.pmapi.irs.model.dto.ApiApplyDTO; -import com.ningdatech.pmapi.irs.model.dto.ApiApplySearchResult; import com.ningdatech.pmapi.irs.model.dto.PushProjectAppToIrsDTO; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; + import javax.validation.Valid; import java.security.NoSuchAlgorithmException; -import java.util.List; /** * @Classname ApplicationController @@ -45,4 +43,10 @@ public class ApplicationController { public JSONArray searchApps(ApiApplyDTO apply) throws NoSuchAlgorithmException { return appIrsManage.searchApps(apply); } + + @GetMapping("/digitalResourcesIndicators/{appCode}/{pageSize}") + public JSONObject getDigitalResourcesIndicators(@PathVariable String appCode,@PathVariable Integer pageSize) { + return appIrsManage.getDigitalResourceIndicatorsByAppCode(appCode, pageSize); + } + } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/irs/controller/IrsController.java b/pmapi/src/main/java/com/ningdatech/pmapi/irs/controller/IrsController.java index 02856c4..6b92eed 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/irs/controller/IrsController.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/irs/controller/IrsController.java @@ -1,9 +1,6 @@ package com.ningdatech.pmapi.irs.controller; import com.ningdatech.log.annotation.WebLog; -import com.ningdatech.pmapi.common.util.CryptUtils; -import com.ningdatech.pmapi.common.util.HttpUtil; -import com.ningdatech.pmapi.irs.utils.RefreshTokenUtil; import com.ningdatech.pmapi.projectdeclared.manage.IrsManage; import com.ningdatech.pmapi.projectdeclared.model.vo.IrsApplicationVO; import com.ningdatech.pmapi.projectdeclared.model.vo.PiotTasksVO; @@ -11,10 +8,11 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/irs/manage/AppIrsManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/irs/manage/AppIrsManage.java index 82d43f2..6120d4c 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/irs/manage/AppIrsManage.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/irs/manage/AppIrsManage.java @@ -9,12 +9,13 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.ningdatech.basic.function.VUtils; import com.ningdatech.irs.service.IRefreshTokenService; import com.ningdatech.pmapi.common.enumeration.CommonEnum; -import com.ningdatech.pmapi.common.statemachine.contants.RegionContant; import com.ningdatech.pmapi.common.statemachine.util.StateMachineUtils; import com.ningdatech.pmapi.common.util.CryptUtils; import com.ningdatech.pmapi.common.util.HttpUtil; import com.ningdatech.pmapi.common.util.RefreshKeyUtil; -import com.ningdatech.pmapi.irs.model.dto.*; +import com.ningdatech.pmapi.irs.model.dto.ApiApplyDTO; +import com.ningdatech.pmapi.irs.model.dto.ApiApplySearchResult; +import com.ningdatech.pmapi.irs.model.dto.PushProjectAppToIrsDTO; import com.ningdatech.pmapi.irs.model.res.ApiResponse; import com.ningdatech.pmapi.projectlib.model.dto.ProjectDTO; import com.ningdatech.pmapi.projectlib.model.entity.Project; @@ -34,7 +35,6 @@ import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import java.security.NoSuchAlgorithmException; import java.time.LocalDateTime; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -93,8 +93,23 @@ public class AppIrsManage { @Value("${irs.push-project-detail.appSecret}") private String pushProjectAppSecret; + //=============数字资源指标获取======================================================================================== + + @Value("${irs.digital-resource-indicators.app-key}") + private String driAppKey; + + @Value("${irs.digital-resource-indicators.app-secret}") + private String driAppSecret; + + @Value("${irs.digital-resource-indicators.interface-name}") + private String driInterfaceName; + + @Value("${irs.digital-resource-indicators.url}") + private String driUrl; + /** * 推送 项目和应用关系 + * * @param dto * @return * @throws NoSuchAlgorithmException @@ -112,14 +127,14 @@ public class AppIrsManage { ApiApplyDTO apiApply = new ApiApplyDTO(); apiApply.setAppId(appCode); JSONObject jsonObject = this.searchApp(apiApply); - ApiApplySearchResult apiApplySearchResult = JSON.parseObject(JSON.toJSONString(jsonObject),ApiApplySearchResult.class); + ApiApplySearchResult apiApplySearchResult = JSON.parseObject(JSON.toJSONString(jsonObject), ApiApplySearchResult.class); VUtils.isTrue(Objects.isNull(apiApplySearchResult)).throwMessage("应用在IRS不存在!"); long timestamp = System.currentTimeMillis(); String areaCode = project.getAreaCode(); String projectName = project.getProjectName(); String requestSecret = RefreshKeyUtil.getRequestSecret(pushAppKey, pushAppScret); - String capCode = CryptUtils.encryptHMAC(timestamp + areaCode,"bcb4fc0f517fc168ee543fcf4d231f3b"); + String capCode = CryptUtils.encryptHMAC(timestamp + areaCode, "bcb4fc0f517fc168ee543fcf4d231f3b"); String capTime = String.valueOf(timestamp); String sign = CryptUtils.MD5Encode(pushAppKey + requestSecret + timestamp); String url = pushUrl + "?requestTime=" + timestamp + @@ -134,14 +149,14 @@ public class AppIrsManage { ApiResponse body = forEntity.getBody(); - if(Objects.isNull(body) || Objects.isNull(body.getCode()) - || 0 != body.getCode()){ + if (Objects.isNull(body) || Objects.isNull(body.getCode()) + || 0 != body.getCode()) { return Boolean.FALSE; } //保存关系 app.setAppCode(appCode); - if(applicationService.updateById(app)){ + if (applicationService.updateById(app)) { /** * 判断下 如果成功的话 那么判断下 这个项目的初次创建的app 是否都已经被注册 * 如果都已经注册 要调用状态机 进入下一个状态 @@ -150,8 +165,8 @@ public class AppIrsManage { .eq(ProjectApplication::getProjectId, project.getId())); //筛选出 初次新建的app 但是没有appCode的 apps = apps.stream().filter(a -> { - if(CommonEnum.YES.getCode().equals(a.getIsFirst()) && - StringUtils.isBlank(app.getAppCode())){ + if (CommonEnum.YES.getCode().equals(a.getIsFirst()) && + StringUtils.isBlank(app.getAppCode())) { return Boolean.TRUE; } return Boolean.FALSE; @@ -159,7 +174,7 @@ public class AppIrsManage { .collect(Collectors.toList()); //如果筛选出来的 为空的话 就调用状态机 - if(CollUtil.isEmpty(apps)){ + if (CollUtil.isEmpty(apps)) { stateMachineUtils.pass(project); project.setUpdateOn(LocalDateTime.now()); projectService.updateById(project); @@ -171,6 +186,7 @@ public class AppIrsManage { /** * 查询app + * * @param apply * @return * @throws NoSuchAlgorithmException @@ -184,27 +200,27 @@ public class AppIrsManage { "&appKey=" + searchAppKey + "&" + "pageSize=10&pageNum=1&appCode=" + appCode + "&areaCode=&deptCode=&name="; - log.info("url : {}",url); + log.info("url : {}", url); RestTemplate restTemplate = new RestTemplate(); ResponseEntity forEntity = restTemplate.getForEntity(url, String.class); - log.info("查询应用目录 : {}",JSON.toJSONString(forEntity)); + log.info("查询应用目录 : {}", JSON.toJSONString(forEntity)); - if(Objects.nonNull(forEntity.getBody()) && Objects.nonNull(forEntity.getBody())){ + if (Objects.nonNull(forEntity.getBody()) && Objects.nonNull(forEntity.getBody())) { JSONObject body = JSON.parseObject(forEntity.getBody()); - if(Objects.isNull(body)){ + if (Objects.isNull(body)) { return null; } JSONObject datas = body.getJSONObject("datas"); - if(Objects.isNull(datas)){ + if (Objects.isNull(datas)) { return null; } JSONObject data = datas.getJSONObject("data"); - if(Objects.isNull(data)){ + if (Objects.isNull(data)) { return null; } JSONArray apiApplySearchResult = data.getJSONArray("apiApplySearchResult"); - if(CollUtil.isEmpty(apiApplySearchResult)){ + if (CollUtil.isEmpty(apiApplySearchResult)) { return null; } return apiApplySearchResult.getJSONObject(0); @@ -225,19 +241,19 @@ public class AppIrsManage { RestTemplate restTemplate = new RestTemplate(); ResponseEntity forEntity = restTemplate.getForEntity(url, String.class); - log.info("查询应用目录 : {}",JSON.toJSONString(forEntity)); + log.info("查询应用目录 : {}", JSON.toJSONString(forEntity)); - if(Objects.nonNull(forEntity.getBody())){ + if (Objects.nonNull(forEntity.getBody())) { JSONObject body = JSON.parseObject(forEntity.getBody()); - if(Objects.isNull(body)){ + if (Objects.isNull(body)) { return null; } JSONObject datas = body.getJSONObject("datas"); - if(Objects.isNull(datas)){ + if (Objects.isNull(datas)) { return null; } JSONObject data = datas.getJSONObject("data"); - if(Objects.isNull(data)){ + if (Objects.isNull(data)) { return null; } JSONArray apiApplySearchResult = data.getJSONArray("apiApplySearchResult"); @@ -252,14 +268,14 @@ public class AppIrsManage { String appKey = "A331101453557202109017383"; String method = "POST"; String interfaceName = "5crv7i4727abLCv0"; - String secret = refreshTokenService.refreshToken(appKey,appSecret,govRequestTokenUrl,govRefreshTokenUrl,interfaceName,method); - log.info("secret :{}",secret); + String secret = refreshTokenService.refreshToken(appKey, appSecret, govRequestTokenUrl, govRefreshTokenUrl, interfaceName, method); + log.info("secret :{}", secret); String sign = MD5.create().digestHex(appKey + secret + timestamp); HttpComponentsClientHttpRequestFactory factory = HttpUtil.generateHttpRequestFactory(); RestTemplate restTemplate; - if(Objects.nonNull(factory)){ + if (Objects.nonNull(factory)) { restTemplate = new RestTemplate(factory); - }else{ + } else { restTemplate = new RestTemplate(); } String appId = "A330000100000202105005790"; @@ -269,7 +285,7 @@ public class AppIrsManage { "&sign=" + sign + "&appKey=" + appKey + "&capCode=" + capCode + "&capTime=" + timestamp + "&appId=" + appId; - log.info("url :{}",url); + log.info("url :{}", url); ResponseEntity forEntity = restTemplate.getForEntity(url, String.class); log.info(forEntity.getBody()); return forEntity.getBody(); @@ -277,6 +293,7 @@ public class AppIrsManage { /** * 推送项目详情 + * * @return */ public String pushProjectDetail(ProjectDTO projectDto) { @@ -285,14 +302,14 @@ public class AppIrsManage { String appKey = pushProjectAppKey; String method = HttpMethod.POST.name(); String interfaceName = pushProjectInterfaceName; - String secret = refreshTokenService.refreshToken(appKey,appSecret,govRequestTokenUrl,govRefreshTokenUrl,interfaceName,method); - log.info("secret :{}",secret); + String secret = refreshTokenService.refreshToken(appKey, appSecret, govRequestTokenUrl, govRefreshTokenUrl, interfaceName, method); + log.info("secret :{}", secret); String sign = MD5.create().digestHex(appKey + secret + timestamp); HttpComponentsClientHttpRequestFactory factory = HttpUtil.generateHttpRequestFactory(); RestTemplate restTemplate; - if(Objects.nonNull(factory)){ + if (Objects.nonNull(factory)) { restTemplate = new RestTemplate(factory); - }else{ + } else { restTemplate = new RestTemplate(); } String baseProjPrincipal = projectDto.getResponsibleMan();//"蒋国海" @@ -318,13 +335,13 @@ public class AppIrsManage { String baseProvManDeprtDing = projectDto.getHigherSuperOrgCode();//"GO_6c383c049d95461f9a0df780140ceb32"; String baseBasisEstablish = projectDto.getBuildBasis();//"中共遂昌县委办公室关于研究开发“天工”智能化管理平台(三期)的函"; String capCode = null; - try{ + try { capCode = CryptUtils.encryptHMAC(timestamp + areaCode, "bcb4fc0f517fc168ee543fcf4d231f3b"); - }catch (Exception e){ + } catch (Exception e) { log.error(e.getMessage()); } - String url = pushProjectUrl+ "?" + + String url = pushProjectUrl + "?" + "requestTime=" + timestamp + "&sign=" + sign + "&appKey=" + appKey + "&baseProjPrincipal=" + baseProjPrincipal + "" + "&baseProjSetYear=" + baseProjSetYear + "&baseProjId=" + baseProjId + @@ -337,9 +354,36 @@ public class AppIrsManage { "&baseProjConsClass=" + baseProjConsClass + "&capCode=" + capCode + "&baseManDeprtDing=" + baseManDeprtDing + "&baseProvManDeprtDing=" + baseProvManDeprtDing + "&baseBasisEstablish=" + baseBasisEstablish + "&baseAreaCode=" + areaCode + "&capTime=" + timestamp + "&baseAreaName=" + baseAreaName; - log.info("url :{}",url); + log.info("url :{}", url); ResponseEntity forEntity = restTemplate.getForEntity(url, String.class); log.info(forEntity.getBody()); return forEntity.getBody(); } + + public JSONObject getDigitalResourceIndicatorsByAppCode(String appCode, Integer pageSize) { + long timestamp = System.currentTimeMillis(); + String appSecret = driAppSecret; + String appKey = driAppKey; + String method = HttpMethod.POST.name(); + String interfaceName = driInterfaceName; + String secret = refreshTokenService.refreshToken(appKey, appSecret, govRequestTokenUrl, govRefreshTokenUrl, interfaceName, method); + log.info("secret : {}", secret); + String sign = MD5.create().digestHex(appKey + secret + timestamp); + HttpComponentsClientHttpRequestFactory factory = HttpUtil.generateHttpRequestFactory(); + RestTemplate restTemplate; + if (Objects.nonNull(factory)) { + restTemplate = new RestTemplate(factory); + } else { + restTemplate = new RestTemplate(); + } + + String url = driUrl + "?" + + "requestTime=" + timestamp + "&sign=" + sign + + "&appKey=" + appKey + "&appCode=" + appCode + "&pageIndex=1&pageSize=" + pageSize; + log.info("url :{}", url); + ResponseEntity forEntity = restTemplate.getForEntity(url, JSONObject.class); + log.info(Objects.requireNonNull(forEntity.getBody()).toJSONString()); + return forEntity.getBody(); + } + } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingExpertJudgeController.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingExpertJudgeController.java new file mode 100644 index 0000000..2398c1f --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingExpertJudgeController.java @@ -0,0 +1,43 @@ +package com.ningdatech.pmapi.meeting.controller; + + +import com.ningdatech.pmapi.meeting.entity.req.MeetingExpertJudgeReq; +import com.ningdatech.pmapi.meeting.entity.req.MeetingExpertJudgeReq.Basic; +import com.ningdatech.pmapi.meeting.manage.MeetingExpertJudgeManage; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + *

+ * 前端控制器 + *

+ * + * @author WendyYang + * @since 2023-07-31 + */ +@Api(tags = "履职评价管理") +@AllArgsConstructor +@RestController +@RequestMapping("/api/v1/meeting/expert-judge") +public class MeetingExpertJudgeController { + + private final MeetingExpertJudgeManage expertJudgeManage; + + @ApiOperation("保存履职评价") + @PostMapping("/submit") + public void saveExpertJudge(@Validated(Basic.class) @RequestBody MeetingExpertJudgeReq req) { + expertJudgeManage.saveExpertJudge(req); + } + + @ApiOperation("查看履职评价") + @GetMapping("/detail/{meetingExpertId}") + public MeetingExpertJudgeReq expertJudgeDetail(@PathVariable Long meetingExpertId) { + return expertJudgeManage.expertJudgeDetail(meetingExpertId); + } + +} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingExportController.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingExportController.java index b742e40..9829397 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingExportController.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingExportController.java @@ -48,7 +48,7 @@ public class MeetingExportController { } @GetMapping("/expertInviteTable/{meetingId}") - @ApiOperation("专家评审单导出") + @ApiOperation("专家抽取表导出") public void exportExpertInviteTable(@PathVariable Long meetingId, HttpServletResponse response) { expertExportManage.expertInviteTable(meetingId, response); } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/MeetingExpertJudge.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/MeetingExpertJudge.java new file mode 100644 index 0000000..73de8bc --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/MeetingExpertJudge.java @@ -0,0 +1,65 @@ +package com.ningdatech.pmapi.meeting.entity.domain; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 会议专家履职评价表 + *

+ * + * @author WendyYang + * @since 2023-07-31 + */ +@Data +@TableName("meeting_expert_judge") +@ApiModel(value = "MeetingExpertJudge对象") +public class MeetingExpertJudge implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.AUTO) + private Long id; + + @ApiModelProperty("会议ID") + private Long meetingId; + + private Long expertId; + + @ApiModelProperty("会议专家ID") + private Long meetingExpertId; + + @ApiModelProperty("评分(1~10)") + private Integer score; + + @ApiModelProperty("是否参加:1 准时、2 迟到、3 缺席") + private Integer attended; + + @ApiModelProperty("参与程度:1 积极、2 消极") + private Integer performance; + + @ApiModelProperty("是否提出建议:true 是、false 否") + private Boolean advised; + + @ApiModelProperty("是否早退:true 早退、false 未早退") + private Boolean leaveEarly; + + @ApiModelProperty("是否违规:true 是、false 否") + private Boolean brokeRule; + + @ApiModelProperty("违规内容") + private String brokeRuleContent; + + @TableField(fill = FieldFill.INSERT) + private Long createBy; + + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createOn; + +} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertReviewTableDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertReviewTableDTO.java index e5c10d7..b74b69b 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertReviewTableDTO.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertReviewTableDTO.java @@ -2,6 +2,8 @@ package com.ningdatech.pmapi.meeting.entity.dto; import lombok.Data; +import java.io.Serializable; + /** *

* ExpertReviewTableDTO @@ -11,7 +13,9 @@ import lombok.Data; * @since 2023/7/24 **/ @Data -public class ExpertReviewTableDTO { +public class ExpertReviewTableDTO implements Serializable { + + private static final long serialVersionUID = 3383159744182234397L; private String projectName; @@ -21,4 +25,6 @@ public class ExpertReviewTableDTO { private String holdOrg; + private String reviewResult; + } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingAndAttendStatusDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingAndAttendStatusDTO.java index 9991234..bf2fca7 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingAndAttendStatusDTO.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingAndAttendStatusDTO.java @@ -15,6 +15,10 @@ public class MeetingAndAttendStatusDTO { private Long meetingId; + private Long meetingExpertId; + + private Long expertId; + private Integer status; private Boolean attended; diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertJudgeEnum.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertJudgeEnum.java new file mode 100644 index 0000000..cfea76b --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertJudgeEnum.java @@ -0,0 +1,49 @@ +package com.ningdatech.pmapi.meeting.entity.enumeration; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + *

+ * ExpertJudgeEnum + *

+ * + * @author WendyYang + * @since 2023/8/3 + **/ +public class ExpertJudgeEnum { + + private ExpertJudgeEnum() { + } + + @Getter + @AllArgsConstructor + public enum AttendStatus { + ON_TIME(1, "准时"), + BE_LATE(2, "迟到"), + ABSENT(3, "缺席"); + + private final Integer code; + private final String value; + + public boolean eq(Integer code) { + return this.code.equals(code); + } + } + + @Getter + @AllArgsConstructor + public enum Performance { + + POSITIVE(1, "积极"), + NEGATIVE(2, "消极"); + + private final Integer code; + private final String value; + + public boolean eq(Integer code) { + return this.code.equals(code); + } + } + +} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingExpertJudgeReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingExpertJudgeReq.java new file mode 100644 index 0000000..841c551 --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingExpertJudgeReq.java @@ -0,0 +1,77 @@ +package com.ningdatech.pmapi.meeting.entity.req; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertJudgeEnum; +import org.hibernate.validator.constraints.Range; + +/** + *

+ * MeetingExpertJudgeReq + *

+ * + * @author WendyYang + * @since 2023/7/31 + **/ +@Data +public class MeetingExpertJudgeReq { + + private Long id; + + @NotNull(message = "会议ID不能为空", groups = Basic.class) + private Long meetingId; + + @NotNull(message = "会议专家ID不能为空", groups = Basic.class) + private Long meetingExpertId; + + @ApiModelProperty("评分(1~10)") + @NotNull(message = "评分不能为空", groups = Basic.class) + @Range(min = 1, max = 10, message = "评分范围为:1~10") + private Integer score; + + /** + * @see ExpertJudgeEnum.AttendStatus + */ + @ApiModelProperty("是否参加:1 准时、2 迟到、3 缺席") + @NotNull(message = "是否参加不能为空", groups = Basic.class) + private Integer attended; + + /** + * @see ExpertJudgeEnum.Performance + */ + @ApiModelProperty("参与程度:1 积极、2 消极") + @NotNull(message = "参与度不能为空", groups = Attend.class) + private Integer performance; + + @ApiModelProperty("是否提出建议:true 是、false 否") + @NotNull(message = "是否提出建议不能为空", groups = Attend.class) + private Boolean advised; + + @ApiModelProperty("是否早退:true 早退、false 未早退") + @NotNull(message = "是否早退不能为空", groups = Attend.class) + private Boolean leaveEarly; + + @ApiModelProperty("是否违规:true 是、false 否") + @NotNull(message = "是否违规不能为空", groups = Attend.class) + private Boolean brokeRule; + + @ApiModelProperty("违规内容") + private String brokeRuleContent; + + @JSONField(format = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createOn; + + //================================================================================================================== + + public interface Attend { + } + + public interface Basic { + } + +} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingByManagerVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingByManagerVO.java index 5c6e43a..c502c6e 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingByManagerVO.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingByManagerVO.java @@ -29,6 +29,9 @@ public class MeetingByManagerVO { @ApiModelProperty("会议ID") private Long meetingId; + @ApiModelProperty("会议专家ID") + private Long meetingExpertId; + @ApiModelProperty("会议开始时间") @JSONField(format = "yyyy-MM-dd HH:mm") private LocalDateTime startTime; @@ -70,4 +73,7 @@ public class MeetingByManagerVO { @ApiModelProperty("联系方式") private String contact; + @ApiModelProperty("是否评价") + private Boolean hasJudge; + } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/ExpertExportManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/ExpertExportManage.java index 8455cfe..8b2c3cf 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/ExpertExportManage.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/ExpertExportManage.java @@ -3,16 +3,20 @@ package com.ningdatech.pmapi.meeting.manage; import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.UUID; import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ningdatech.basic.exception.BizException; import com.ningdatech.basic.util.CollUtils; +import com.ningdatech.pmapi.common.model.FreemarkerBatchExportDTO; import com.ningdatech.pmapi.common.util.FreemarkerWordUtil; import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo; +import com.ningdatech.pmapi.expert.manage.ExpertReviewManage; import com.ningdatech.pmapi.expert.service.IExpertUserFullInfoService; import com.ningdatech.pmapi.meeting.entity.domain.Meeting; import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; import com.ningdatech.pmapi.meeting.entity.domain.MeetingInnerProject; import com.ningdatech.pmapi.meeting.entity.domain.MeetingOuterProject; import com.ningdatech.pmapi.meeting.entity.dto.*; +import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum; import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; import com.ningdatech.pmapi.meeting.service.IMeetingInnerProjectService; import com.ningdatech.pmapi.meeting.service.IMeetingOuterProjectService; @@ -29,11 +33,13 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Collectors; /** *

@@ -54,6 +60,7 @@ public class ExpertExportManage { private final IMeetingOuterProjectService meetingOuterProjectService; private final IExpertUserFullInfoService expertUserInfoService; private final IProjectService projectService; + private final ExpertReviewManage expertReviewManage; //================================================================================================================== @@ -78,6 +85,16 @@ public class ExpertExportManage { static Supplier wordName = () -> UUID.randomUUID().toString(true) + ".doc"; + private List listExpertsByAgreeOrLeave(Long meetingId) { + Page page = Page.of(1, 20); + meetingExpertService.pageExpertByStatusAndMeetingId(page, meetingId, null, null); + if (page.getTotal() == 0) { + return Collections.emptyList(); + } + page.getRecords().removeIf(w -> !(ExpertAttendStatusEnum.AGREED.eq(w.getStatus()) || ExpertAttendStatusEnum.ON_LEAVE.eq(w.getStatus()))); + return page.getRecords(); + } + //================================================================================================================== public void exportFeeForExpert(Long meetingId, HttpServletResponse response) { @@ -130,22 +147,43 @@ public class ExpertExportManage { public void expertReviewTable(Long meetingId, HttpServletResponse response) { try { Meeting meeting = meetingService.getById(meetingId); - ExpertReviewTableDTO data = new ExpertReviewTableDTO(); - data.setMeetingTime(DateUtil.localDateTimeFormat(meeting.getStartTime(), "yyyy年M月d日")); - data.setMeetingAddress(meeting.getMeetingAddress()); - data.setHoldOrg(meeting.getHoldOrg()); - List projectNames = new ArrayList<>(); + String startTime = DateUtil.localDateTimeFormat(meeting.getStartTime(), "yyyy年M月d日"); + List fbeList; if (meeting.getIsInnerProject()) { List inners = meetingInnerProjectService.listByMeetingId(meetingId); + Map reviewResultMap = expertReviewManage.buildExpertReviewToStr(meetingId); List projectIds = CollUtils.fieldList(inners, MeetingInnerProject::getProjectId); List projects = projectService.listByIds(projectIds); - projects.forEach(w -> projectNames.add(w.getProjectName())); + fbeList = projects.stream().map(w -> { + FreemarkerBatchExportDTO fbe = new FreemarkerBatchExportDTO(); + ExpertReviewTableDTO currData = new ExpertReviewTableDTO(); + currData.setHoldOrg(meeting.getHoldOrg()); + currData.setMeetingTime(startTime); + currData.setMeetingAddress(meeting.getMeetingAddress()); + currData.setProjectName(w.getProjectName()); + currData.setReviewResult(reviewResultMap.get(w.getId())); + fbe.setData(currData); + fbe.setTemplate(EXPERT_REVIEW); + fbe.setFileName(w.getProjectName() + ".doc"); + return fbe; + }).collect(Collectors.toList()); } else { List inners = meetingOuterProjectService.listByMeetingId(meetingId); - inners.forEach(w -> projectNames.add(w.getProjectName())); + fbeList = inners.stream().map(w -> { + FreemarkerBatchExportDTO fbe = new FreemarkerBatchExportDTO(); + ExpertReviewTableDTO currData = new ExpertReviewTableDTO(); + currData.setHoldOrg(meeting.getHoldOrg()); + currData.setMeetingTime(startTime); + currData.setMeetingAddress(meeting.getMeetingAddress()); + currData.setProjectName(w.getProjectName()); + fbe.setData(currData); + fbe.setTemplate(EXPERT_REVIEW); + fbe.setFileName(w.getProjectName() + ".doc"); + return fbe; + }).collect(Collectors.toList()); } - data.setProjectName(StrUtil.join("、", projectNames)); - FreemarkerWordUtil.export(wordName.get(), data, response, EXPERT_REVIEW); + String exportFileName = meeting.getName() + "专家评审表.zip"; + FreemarkerWordUtil.exportBatch(response, fbeList, exportFileName); } catch (TemplateException | IOException e) { log.error("专家评审单导出异常:{}", meetingId, e); throw BizException.wrap("专家评审单导出失败"); @@ -171,13 +209,17 @@ public class ExpertExportManage { data.setProjectName(StrUtil.join("、", projectNames)); data.setExperts(new ArrayList<>()); // 设置专家信息 - List experts = meetingExpertService.listAgreedExperts(meetingId); + List experts = listExpertsByAgreeOrLeave(meetingId); List expertIds = CollUtils.fieldList(experts, MeetingExpert::getExpertId); List expertInfos = expertUserInfoService.listByUserId(expertIds); Map expertMap = CollUtils.listToMap(expertInfos, ExpertUserFullInfo::getUserId); experts.forEach(w -> { ExpertInfoDTO expert = new ExpertInfoDTO(); - expert.setName(w.getExpertName()); + if (ExpertAttendStatusEnum.ON_LEAVE.eq(w.getStatus())) { + expert.setBank(w.getExpertName() + "(请假)"); + } else { + expert.setName(w.getExpertName()); + } ExpertUserFullInfo expertUser = expertMap.get(w.getExpertId()); if (expertUser != null) { expert.setCompany(expertUser.getCompany()); @@ -217,7 +259,7 @@ public class ExpertExportManage { } data.setExperts(new ArrayList<>()); // 设置专家信息 - List experts = meetingExpertService.listAgreedExperts(meetingId); + List experts = listExpertsByAgreeOrLeave(meetingId); List expertIds = CollUtils.fieldList(experts, MeetingExpert::getExpertId); List expertInfos = expertUserInfoService.listByUserId(expertIds); Map expertMap = CollUtils.listToMap(expertInfos, ExpertUserFullInfo::getUserId); @@ -225,7 +267,11 @@ public class ExpertExportManage { experts.forEach(w -> { ExpertInfoDTO expert = new ExpertInfoDTO(); expert.setNo(integer.incrementAndGet()); - expert.setName(w.getExpertName()); + if (ExpertAttendStatusEnum.ON_LEAVE.eq(w.getStatus())) { + expert.setBank(w.getExpertName() + "(请假)"); + } else { + expert.setName(w.getExpertName()); + } expert.setMobile(w.getMobile()); ExpertUserFullInfo expertUser = expertMap.get(w.getExpertId()); if (expertUser != null) { diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingExpertJudgeManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingExpertJudgeManage.java new file mode 100644 index 0000000..f16ff12 --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingExpertJudgeManage.java @@ -0,0 +1,94 @@ +package com.ningdatech.pmapi.meeting.manage; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.ningdatech.basic.exception.BizException; +import com.ningdatech.basic.util.CollUtils; +import com.ningdatech.basic.util.ValidUtil; +import com.ningdatech.cache.lock.DistributedLock; +import com.ningdatech.pmapi.meeting.entity.domain.Meeting; +import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; +import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpertJudge; +import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum; +import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertJudgeEnum; +import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatusEnum; +import com.ningdatech.pmapi.meeting.entity.req.MeetingExpertJudgeReq; +import com.ningdatech.pmapi.meeting.entity.req.MeetingExpertJudgeReq.Attend; +import com.ningdatech.pmapi.meeting.service.IMeetingExpertJudgeService; +import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; +import com.ningdatech.pmapi.meeting.service.IMeetingService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + *

+ * MeetingExpertJudgeManage + *

+ * + * @author WendyYang + * @since 2023/7/31 + **/ +@Component +@AllArgsConstructor +public class MeetingExpertJudgeManage { + + private final IMeetingExpertJudgeService expertJudgeService; + private final IMeetingExpertService meetingExpertService; + private final IMeetingService meetingService; + private final DistributedLock distributedLock; + + private MeetingExpertJudge getMeetingExpertJudge(Long meetingExpertId) { + LambdaQueryWrapper query = Wrappers.lambdaQuery(MeetingExpertJudge.class) + .eq(MeetingExpertJudge::getMeetingExpertId, meetingExpertId); + return expertJudgeService.getOne(query); + } + + public void saveExpertJudge(MeetingExpertJudgeReq req) { + String key = "lock_expert_judge:" + req.getMeetingExpertId(); + if (!distributedLock.lock(key, 3)) { + throw BizException.wrap("履职评价失败,请重试"); + } + try { + if (!ExpertJudgeEnum.AttendStatus.ABSENT.eq(req.getAttended())) { + Map validMap = ValidUtil.valid(req, Attend.class); + if (!validMap.isEmpty()) { + String errMsg = CollUtils.joinByComma(validMap.values()); + throw BizException.wrap(errMsg); + } + } + // 会议状态校验 + Meeting meeting = meetingService.getById(req.getMeetingId()); + if (meeting == null || MeetingStatusEnum.CANCELED.eq(meeting.getStatus())) { + throw BizException.wrap("会议不存在或已取消"); + } + // 专家抽取状态校验 + MeetingExpert expert = meetingExpertService.getById(req.getMeetingExpertId()); + if (expert == null || (ExpertAttendStatusEnum.AGREED.eq(expert.getStatus()) + && ExpertAttendStatusEnum.ON_LEAVE.eq(expert.getStatus()))) { + throw BizException.wrap("未被抽中专家无法进行履职评价"); + } + // 智能履职评价一次 + MeetingExpertJudge judge = getMeetingExpertJudge(req.getMeetingExpertId()); + if (judge != null) { + throw BizException.wrap("履职评价已提交"); + } + MeetingExpertJudge entity = BeanUtil.copyProperties(req, MeetingExpertJudge.class); + entity.setExpertId(expert.getExpertId()); + expertJudgeService.save(entity); + } finally { + distributedLock.releaseLock(key); + } + } + + public MeetingExpertJudgeReq expertJudgeDetail(Long meetingExpertId) { + MeetingExpertJudge judge = getMeetingExpertJudge(meetingExpertId); + if (judge == null) { + throw BizException.wrap("履职评价未提交"); + } + return BeanUtil.copyProperties(judge, MeetingExpertJudgeReq.class); + } + +} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java index 96e61d9..f55c4e3 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java @@ -97,6 +97,7 @@ public class MeetingManage { private final ExpertInviteHelper expertInviteHelper; private final MeetingCallOrMsgHelper meetingCallOrMsgHelper; private final MeetingDataScopeHelper meetingDataScopeHelper; + private final IMeetingExpertJudgeService expertJudgeService; private static final String INVITED_RULE_CREATE = "INVITED_RULE_CREATE:"; private static final String MEETING_CREATE_KEY = "MEETING_CREATE:"; @@ -324,7 +325,11 @@ public class MeetingManage { return PageVo.empty(); } Map mapByMeetingId = new HashMap<>(16); - meetings.forEach(w -> mapByMeetingId.put(w.getMeetingId(), w)); + List meetingExpertIds = new ArrayList<>(); + meetings.forEach(w -> { + mapByMeetingId.put(w.getMeetingId(), w); + meetingExpertIds.add(w.getMeetingExpertId()); + }); LambdaQueryWrapper query = new LambdaQueryWrapper() .orderByDesc(Meeting::getCreateOn) .in(Meeting::getId, mapByMeetingId.keySet()) @@ -337,11 +342,14 @@ public class MeetingManage { if (page.getTotal() == 0) { return PageVo.empty(); } + List existsMeIds = expertJudgeService.listExistsMeetingExpertIds(meetingExpertIds); PageVo result = new PageVo<>(new ArrayList<>(), page.getTotal()); page.getRecords().forEach(meeting -> { MeetingByManagerVO item = meetingManageHelper.buildByMeeting(meeting); MeetingAndAttendStatusDTO info = mapByMeetingId.get(meeting.getId()); + item.setMeetingExpertId(info.getMeetingExpertId()); item.setExpertStatus(info.getStatus()); + item.setHasJudge(existsMeIds.contains(info.getMeetingExpertId())); result.getRecords().add(item); }); return result; diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertJudgeMapper.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertJudgeMapper.java new file mode 100644 index 0000000..d178d32 --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertJudgeMapper.java @@ -0,0 +1,16 @@ +package com.ningdatech.pmapi.meeting.mapper; + +import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpertJudge; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author CMM + * @since 2023-07-31 + */ +public interface MeetingExpertJudgeMapper extends BaseMapper { + +} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertJudgeMapper.xml b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertJudgeMapper.xml new file mode 100644 index 0000000..25776c8 --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertJudgeMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertMapper.xml b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertMapper.xml index f83ff1d..619829d 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertMapper.xml +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertMapper.xml @@ -4,7 +4,7 @@