Browse Source

Merge remote-tracking branch 'origin/master'

master
PoffyZhang 1 year ago
parent
commit
eee8aab807
7 changed files with 202 additions and 93 deletions
  1. +22
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/common/model/FreemarkerBatchExportDTO.java
  2. +51
    -12
      pmapi/src/main/java/com/ningdatech/pmapi/common/util/FreemarkerWordUtil.java
  3. +41
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/expert/manage/ExpertReviewManage.java
  4. +1
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingExportController.java
  5. +7
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertReviewTableDTO.java
  6. +59
    -13
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/ExpertExportManage.java
  7. +21
    -66
      pmapi/src/main/resources/template/meeting/专家评审单.ftl

+ 22
- 0
pmapi/src/main/java/com/ningdatech/pmapi/common/model/FreemarkerBatchExportDTO.java View File

@@ -0,0 +1,22 @@
package com.ningdatech.pmapi.common.model;

import lombok.Data;

/**
* <p>
* FreemarkerBatchExportDTO
* </p>
*
* @author WendyYang
* @since 2023/8/1
**/
@Data
public class FreemarkerBatchExportDTO {

private String fileName;

private String template;

private Object data;

}

+ 51
- 12
pmapi/src/main/java/com/ningdatech/pmapi/common/util/FreemarkerWordUtil.java View File

@@ -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;

/**
* <p>
@@ -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<FreemarkerBatchExportDTO> 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();
}
}



+ 41
- 0
pmapi/src/main/java/com/ningdatech/pmapi/expert/manage/ExpertReviewManage.java View File

@@ -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<ExpertReview> listFinalExpertReviews(Long meetingId) {
LambdaQueryWrapper<ExpertReview> query = Wrappers.lambdaQuery(ExpertReview.class)
.eq(ExpertReview::getIsFinal, Boolean.TRUE)
.eq(ExpertReview::getMeetingId, meetingId);
return expertReviewService.list(query);
}

public Map<Long, String> buildExpertReviewToStr(Long meetingId) {
List<ExpertReview> reviews = listFinalExpertReviews(meetingId);
if (reviews.isEmpty()) {
return Collections.emptyMap();
}
List<Long> templateIds = CollUtils.fieldList(reviews, ExpertReview::getTemplateId);
List<ReviewTemplateSettings> ts = templateSettingsService.listByIds(templateIds);
Map<Long, ReviewTemplateSettings> tsMap = CollUtils.listToMap(ts, ReviewTemplateSettings::getId);
Map<Long, String> resMap = new HashMap<>(8);
for (ExpertReview review : reviews) {
ReviewTemplateSettings settings = tsMap.get(review.getTemplateId());
List<ReviewTemplateSettingsDTO> optionTemplates = JSONUtil.toList(settings.getContent(), ReviewTemplateSettingsDTO.class);
List<ReviewTemplateOptionDTO> options = JSONUtil.toList(review.getContent(), ReviewTemplateOptionDTO.class);
Map<Integer, ReviewTemplateOptionDTO> 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("<w:br/>").append(ot.getTitle()).append(":").append(optionsContent).append(";");
});
str.append("<w:br/>").append("其他意见或建议").append(":")
.append(StrUtil.blankToDefault(review.getOtherAdvice(), "--")).append(";");
str.append("<w:br/>").append("评审结果").append(":")
.append(ReviewResultEnum.getByCode(review.getReviewResult()).getValue()).append(";");
resMap.put(review.getProjectId(), str.toString());
}
return resMap;
}
}

+ 1
- 1
pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingExportController.java View File

@@ -48,7 +48,7 @@ public class MeetingExportController {
}

@GetMapping("/expertInviteTable/{meetingId}")
@ApiOperation("专家评审单导出")
@ApiOperation("专家抽取表导出")
public void exportExpertInviteTable(@PathVariable Long meetingId, HttpServletResponse response) {
expertExportManage.expertInviteTable(meetingId, response);
}


+ 7
- 1
pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertReviewTableDTO.java View File

@@ -2,6 +2,8 @@ package com.ningdatech.pmapi.meeting.entity.dto;

import lombok.Data;

import java.io.Serializable;

/**
* <p>
* 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;

}

+ 59
- 13
pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/ExpertExportManage.java View File

@@ -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;

/**
* <p>
@@ -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<String> wordName = () -> UUID.randomUUID().toString(true) + ".doc";

private List<MeetingExpert> listExpertsByAgreeOrLeave(Long meetingId) {
Page<MeetingExpert> 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<String> projectNames = new ArrayList<>();
String startTime = DateUtil.localDateTimeFormat(meeting.getStartTime(), "yyyy年M月d日");
List<FreemarkerBatchExportDTO> fbeList;
if (meeting.getIsInnerProject()) {
List<MeetingInnerProject> inners = meetingInnerProjectService.listByMeetingId(meetingId);
Map<Long, String> reviewResultMap = expertReviewManage.buildExpertReviewToStr(meetingId);
List<Long> projectIds = CollUtils.fieldList(inners, MeetingInnerProject::getProjectId);
List<Project> 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<MeetingOuterProject> 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<MeetingExpert> experts = meetingExpertService.listAgreedExperts(meetingId);
List<MeetingExpert> experts = listExpertsByAgreeOrLeave(meetingId);
List<Long> expertIds = CollUtils.fieldList(experts, MeetingExpert::getExpertId);
List<ExpertUserFullInfo> expertInfos = expertUserInfoService.listByUserId(expertIds);
Map<Long, ExpertUserFullInfo> 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<MeetingExpert> experts = meetingExpertService.listAgreedExperts(meetingId);
List<MeetingExpert> experts = listExpertsByAgreeOrLeave(meetingId);
List<Long> expertIds = CollUtils.fieldList(experts, MeetingExpert::getExpertId);
List<ExpertUserFullInfo> expertInfos = expertUserInfoService.listByUserId(expertIds);
Map<Long, ExpertUserFullInfo> 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) {


+ 21
- 66
pmapi/src/main/resources/template/meeting/专家评审单.ftl View File

@@ -553,21 +553,36 @@
<w:sz w:val="30"/>
<w:sz-cs w:val="30"/>
</w:rPr>
<w:t>${meetingTime},${holdOrg}组织专家在${meetingAddress}对${projectName}进行评审。专家组认真听取了项目业主方、建设方的情况汇报,审阅了项目材料,实地查看了设备及平台演示,专家组织质询、讨论后提出以下意见:
<w:t>${meetingTime},${holdOrg}组织专家在${meetingAddress}对${projectName}
进行评审。专家组认真听取了项目业主方、建设方的情况汇报,审阅了项目材料,实地查看了设备及平台演示,专家组织质询、讨论后提出以下意见:
</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="244" w:line-rule="auto"/>
<w:spacing w:line="257" w:line-rule="auto"/>
</w:pPr>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="244" w:line-rule="auto"/>
<w:ind w:first-line="500" w:first-line-chars="0"/>
<w:rPr>
<w:rFonts w:ascii="微软雅黑" w:h-ansi="微软雅黑" w:fareast="微软雅黑" w:cs="微软雅黑"
w:hint="fareast"/>
<w:sz w:val="30"/>
<w:sz-cs w:val="30"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:ascii="微软雅黑" w:h-ansi="微软雅黑" w:fareast="微软雅黑" w:cs="微软雅黑"
w:hint="fareast"/>
<w:sz w:val="30"/>
<w:sz-cs w:val="30"/>
</w:rPr>
<w:t>${(reviewResult)!}</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
@@ -644,73 +659,13 @@
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="245" w:line-rule="auto"/>
</w:pPr>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="245" w:line-rule="auto"/>
</w:pPr>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="245" w:line-rule="auto"/>
</w:pPr>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="245" w:line-rule="auto"/>
</w:pPr>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="245" w:line-rule="auto"/>
</w:pPr>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="245" w:line-rule="auto"/>
</w:pPr>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="245" w:line-rule="auto"/>
</w:pPr>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="245" w:line-rule="auto"/>
</w:pPr>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="245" w:line-rule="auto"/>
</w:pPr>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="245" w:line-rule="auto"/>
</w:pPr>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="245" w:line-rule="auto"/>
<w:spacing w:line="244" w:line-rule="auto"/>
</w:pPr>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="a2"/>
<w:spacing w:line="245" w:line-rule="auto"/>
<w:spacing w:line="244" w:line-rule="auto"/>
</w:pPr>
</w:p>
<w:p>


Loading…
Cancel
Save