|
@@ -0,0 +1,345 @@
|
|
|
+package com.rongwei.trainingcommon.sys.service.impl;
|
|
|
+
|
|
|
+import com.aspose.words.Document;
|
|
|
+import com.aspose.words.MailMergeCleanupOptions;
|
|
|
+import com.aspose.words.net.System.Data.DataRelation;
|
|
|
+import com.aspose.words.net.System.Data.DataRow;
|
|
|
+import com.aspose.words.net.System.Data.DataSet;
|
|
|
+import com.aspose.words.net.System.Data.DataTable;
|
|
|
+import com.rongwei.rwcommon.base.exception.CustomException;
|
|
|
+import com.rongwei.rwcommon.utils.StringUtils;
|
|
|
+import com.rongwei.training.domain.TrainingDemandSurveyBackupsDo;
|
|
|
+import com.rongwei.training.vo.QuestionnaireRecordingVo;
|
|
|
+import com.rongwei.trainingcommon.sys.dao.TrainingDemandSurveyBackupsDao;
|
|
|
+import com.rongwei.trainingcommon.sys.service.ExportQuestionnaireRecordingsService;
|
|
|
+import com.rongwei.trainingcommon.sys.service.TrainingDemandSurveyBackupsService;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.core.io.ClassPathResource;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * ExportQuestionnaireRecordingsServiceImpl class
|
|
|
+ *
|
|
|
+ * @author XH
|
|
|
+ * @date 2024/06/06
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class ExportQuestionnaireRecordingsServiceImpl implements ExportQuestionnaireRecordingsService {
|
|
|
+ /**
|
|
|
+ * 模板地址
|
|
|
+ */
|
|
|
+ public static final String TEMP_PATH = "template/TrainingNeedsSurveyReport.docx";
|
|
|
+ public static final SimpleDateFormat YYYY_MM_DD = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
+ /**
|
|
|
+ * 培训模板总结
|
|
|
+ */
|
|
|
+ public static final String SUMMARY = "1、培训%s:\n" +
|
|
|
+ "培训%s方面员工希望提高自己的%s,根据调查表结果显示,培训内容方面侧重于%s。\n" +
|
|
|
+ "\n" +
|
|
|
+ "2、培训%s:\n" +
|
|
|
+ "培训%s方面以%s、%s、%s等内容为主,结合其他内容进行讲解\n" +
|
|
|
+ "\n" +
|
|
|
+ "3、%s:\n" +
|
|
|
+ "%s方面,重点收集员工能看懂,易看懂的%s,结合%s提高培训的效率。\n" +
|
|
|
+ "\n" +
|
|
|
+ "4、%s:%s以%s、%s为主,分层级进行讲授。";
|
|
|
+ public static final String FIRST_PREFIX = "为了解从业人员安全培训工作重点,本次调查针对培训基本内容和培训具体内容分别展开调查,结果如下:";
|
|
|
+ public static final String THIRD_PREFIX = "为进一步提高安全培训质量,本次调查针对培训形式和授课人员分别展开调查,结果如下:";
|
|
|
+ public static final String SECOND_SUFFIX = "调查结果显示,在%s培训方面,需求度最高的是%s方面的内容,需求度为 %s%;在%s方面,培训需求最高的是%s(%s%)、%s(%s%)、%s(%s%)等。";
|
|
|
+ public static final String FOURTH_SUFFIX = "调查结果显示,在%s方面,员工最喜闻乐见的形式是%s需求度为%s%,在%s方面,员工希望以%s为主要授课人员,需求度为%s%。";
|
|
|
+ private final Logger log = LoggerFactory.getLogger(this.getClass().getName());
|
|
|
+ @Autowired
|
|
|
+ private TrainingDemandSurveyBackupsService trainingDemandSurveyBackupsService;
|
|
|
+ @Autowired
|
|
|
+ private TrainingDemandSurveyBackupsDao trainingDemandSurveyBackupsDao;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 导出word
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void exportWord(String id, HttpServletResponse response) {
|
|
|
+ log.info("开始通过:{}导出分析报告", id);
|
|
|
+ this.getWordLicense();
|
|
|
+ // 获取培训需求调查报表
|
|
|
+ TrainingDemandSurveyBackupsDo demandSurvey = trainingDemandSurveyBackupsService.getById(id);
|
|
|
+ if (demandSurvey == null) {
|
|
|
+ log.error("无法根据ID 获取到培训需求调查信息");
|
|
|
+ throw new CustomException("无法获取到培训需求调查信息");
|
|
|
+ }
|
|
|
+ // 培训年份
|
|
|
+ String year = demandSurvey.getYear();
|
|
|
+ // 发布时间
|
|
|
+ Date releasetime = demandSurvey.getReleasetime();
|
|
|
+ // 参与培训用户(下发问卷的数量)
|
|
|
+ int copiesTotal = demandSurvey.getParticipateuserid().split(",").length;
|
|
|
+ // 已参与培训的用户(参与用户的数量)
|
|
|
+ int submitTotal = StringUtils.isBlank(demandSurvey.getParticipatinguserid()) ? 0 : demandSurvey.getParticipatinguserid().split(",").length;
|
|
|
+ // 计算回收率
|
|
|
+ BigDecimal submitRate = calculatePercentage(submitTotal, copiesTotal);
|
|
|
+ // 获取用户问卷情况
|
|
|
+ List<QuestionnaireRecordingVo> questionnaireInformation = trainingDemandSurveyBackupsDao.getQuestionnaireInformation(id);
|
|
|
+ // 对数据按照项目进行分组
|
|
|
+ LinkedHashMap<String, List<QuestionnaireRecordingVo>> collect = questionnaireInformation.stream().collect(Collectors.groupingBy(QuestionnaireRecordingVo::getTempId, LinkedHashMap::new, Collectors.toList()));
|
|
|
+
|
|
|
+ try {
|
|
|
+ ClassPathResource classPathResource = new ClassPathResource(TEMP_PATH);
|
|
|
+ Document doc = new Document(classPathResource.getInputStream());
|
|
|
+ assembleExport(year, releasetime, copiesTotal, submitTotal, submitRate, collect, doc);
|
|
|
+ response.setContentType("application/octet-stream;charset=ISO8859-1");
|
|
|
+ response.setHeader("Content-Disposition", "attachment;filename=ProblemTrackingAndResolution.docx");
|
|
|
+ doc.save(response.getOutputStream(), com.aspose.words.SaveFormat.DOCX);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ throw new CustomException("安全培训需求调查分析报告导出异常");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装填充模板的数据
|
|
|
+ *
|
|
|
+ * @param year
|
|
|
+ * @param releasetime
|
|
|
+ * @param copiesTotal
|
|
|
+ * @param submitTotal
|
|
|
+ * @param submitRate
|
|
|
+ */
|
|
|
+ public void assembleExport(String year, Date releasetime, int copiesTotal,
|
|
|
+ int submitTotal, BigDecimal submitRate,
|
|
|
+ LinkedHashMap<String, List<QuestionnaireRecordingVo>> collect,
|
|
|
+ Document doc) throws Exception {
|
|
|
+
|
|
|
+ List<List<QuestionnaireRecordingVo>> values = new ArrayList<>(collect.values());
|
|
|
+ // 非列表数据
|
|
|
+ Map<String, String> singleDataMap = new HashMap<>();
|
|
|
+ singleDataMap.put("year", year);
|
|
|
+ singleDataMap.put("releaseDate", YYYY_MM_DD.format(releasetime));
|
|
|
+ singleDataMap.put("copiesTotal", String.valueOf(copiesTotal));
|
|
|
+ singleDataMap.put("submitTotal", String.valueOf(submitTotal));
|
|
|
+ singleDataMap.put("submitRate", submitRate.toString());
|
|
|
+ singleDataMap.put("year2", year);
|
|
|
+ // 项目模板信息
|
|
|
+ DataTable projectTemp = new DataTable("list");
|
|
|
+ // 前缀
|
|
|
+ projectTemp.getColumns().add("prefix");
|
|
|
+ // 序号
|
|
|
+ projectTemp.getColumns().add("index");
|
|
|
+ // 项目名称
|
|
|
+ projectTemp.getColumns().add("name1");
|
|
|
+ projectTemp.getColumns().add("name2");
|
|
|
+ // 后缀
|
|
|
+ projectTemp.getColumns().add("suffix");
|
|
|
+
|
|
|
+ // 项目内容信息
|
|
|
+ DataTable questionInfo = new DataTable("project");
|
|
|
+ // 问题名称
|
|
|
+ questionInfo.getColumns().add("name1");
|
|
|
+ // 问题名称
|
|
|
+ questionInfo.getColumns().add("content");
|
|
|
+ // 迫切需要份数
|
|
|
+ questionInfo.getColumns().add("pqxy");
|
|
|
+ // 比较需要份数
|
|
|
+ questionInfo.getColumns().add("bjxy");
|
|
|
+ // 总份数
|
|
|
+ questionInfo.getColumns().add("zfs");
|
|
|
+ //占比
|
|
|
+ questionInfo.getColumns().add("rate");
|
|
|
+ int index = 1;
|
|
|
+ // 当前的问题信息
|
|
|
+ QuestionnaireRecordingVo recordingVo;
|
|
|
+ // 当前模板下的所有问题信息
|
|
|
+ List<QuestionnaireRecordingVo> listData;
|
|
|
+ DataRow projectRow;
|
|
|
+ for (Map.Entry<String, List<QuestionnaireRecordingVo>> entry : collect.entrySet()) {
|
|
|
+ listData = entry.getValue();
|
|
|
+ recordingVo = listData.get(0);
|
|
|
+ // 创建新的数据行
|
|
|
+ projectRow = projectTemp.newRow();
|
|
|
+ if (index == 1) {
|
|
|
+ projectRow.set("prefix", FIRST_PREFIX);
|
|
|
+ } else if (index == 3) {
|
|
|
+ projectRow.set("prefix", THIRD_PREFIX);
|
|
|
+ } else {
|
|
|
+ projectRow.set("prefix", "");
|
|
|
+ }
|
|
|
+ projectRow.set("index", index);
|
|
|
+ projectRow.set("name1", recordingVo.getTempName());
|
|
|
+ projectRow.set("name2", recordingVo.getTempName());
|
|
|
+
|
|
|
+ if (index == 2) {
|
|
|
+ projectRow.set("suffix", assembleSecondSuffix(values));
|
|
|
+ } else if (index == 4) {
|
|
|
+ projectRow.set("suffix", assembleFourthSuffix(values));
|
|
|
+ } else {
|
|
|
+ projectRow.set("suffix", "");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /************************创建内容行数据**************************/
|
|
|
+ listData.forEach(list -> {
|
|
|
+ DataRow questionRow = questionInfo.newRow();
|
|
|
+ questionRow.set("name1", list.getTempName());
|
|
|
+ questionRow.set("content", list.getQuestionName());
|
|
|
+ // 迫切需要份数
|
|
|
+ questionRow.set("pqxy", list.getPqxy());
|
|
|
+ // 比较需要份数
|
|
|
+ questionRow.set("bjxy", list.getBjxy());
|
|
|
+ // 总份数
|
|
|
+ questionRow.set("zfs", list.getTotalCount());
|
|
|
+ //占比
|
|
|
+ questionRow.set("rate", calculatePercentage(list.getPqxy() + list.getBjxy(), list.getTotalCount()));
|
|
|
+ questionInfo.getRows().add(questionRow);
|
|
|
+ });
|
|
|
+
|
|
|
+ projectTemp.getRows().add(projectRow);
|
|
|
+
|
|
|
+ index++;
|
|
|
+ }
|
|
|
+ if (values.size() >= 4) {
|
|
|
+ // 组装培训总结
|
|
|
+ singleDataMap.put("summary", assembleSummary(values));
|
|
|
+ }
|
|
|
+ doc.getMailMerge().setCleanupOptions(MailMergeCleanupOptions.REMOVE_UNUSED_FIELDS);
|
|
|
+ // 普通数据合并
|
|
|
+ doc.getMailMerge().execute(singleDataMap.keySet().toArray(new String[0]), singleDataMap.values().toArray(new String[0]));
|
|
|
+ // 项目数据合并
|
|
|
+ DataSet whySet = new DataSet();
|
|
|
+ whySet.getTables().add(projectTemp);
|
|
|
+ whySet.getTables().add(questionInfo);
|
|
|
+ String[] contCols = {"name1"};
|
|
|
+ String[] lstCols = {"name1"};
|
|
|
+ whySet.getRelations().add(new DataRelation("UserInfo", projectTemp, questionInfo, contCols, lstCols));
|
|
|
+ doc.getMailMerge().executeWithRegions(whySet);
|
|
|
+ doc.getMailMerge().setCleanupOptions(MailMergeCleanupOptions.REMOVE_EMPTY_TABLE_ROWS);
|
|
|
+ doc.getMailMerge().deleteFields();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装第二个后缀信息
|
|
|
+ * 调查结果显示,在{表1的项目名称}培训方面,需求度最高的是{表1中百分比最高的基本内容名称}方面的内容,需求度为 {该基本内容的百分比}%;
|
|
|
+ * 在{表2的项目名称}方面,培训需求最高的是{表2中百分比第一的具体内容名称}({该具体内容的百分比}%)
|
|
|
+ * 、{表2中百分比第二的具体内容名称}({该具体内容的百分比}%)、{表2中百分比第三的具体内容名称}({该具体内容的百分比}%)等。
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String assembleSecondSuffix(List<List<QuestionnaireRecordingVo>> values) {
|
|
|
+ List<QuestionnaireRecordingVo> firstList = values.get(0);
|
|
|
+ List<QuestionnaireRecordingVo> secondList = values.get(1);
|
|
|
+ // 对数据排序
|
|
|
+ firstList = firstList.stream()
|
|
|
+ .sorted(Comparator.comparingInt((QuestionnaireRecordingVo info) -> info.getPqxy() + info.getBjxy()).reversed())
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ secondList = secondList.stream()
|
|
|
+ .sorted(Comparator.comparingInt((QuestionnaireRecordingVo info) -> info.getPqxy() + info.getBjxy()).reversed())
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+
|
|
|
+ return String.format(SECOND_SUFFIX, firstList.get(0).getTempName(), firstList.get(0).getQuestionName(),
|
|
|
+ calculatePercentage(firstList.get(0).getPqxy() + firstList.get(0).getBjxy(), firstList.get(0).getTotalCount()),
|
|
|
+ secondList.get(0).getTempName(), secondList.get(0).getQuestionName(),
|
|
|
+ calculatePercentage(secondList.get(0).getPqxy() + secondList.get(0).getBjxy(), secondList.get(0).getTotalCount()),
|
|
|
+ secondList.get(2).getTempName(), secondList.get(2).getQuestionName(),
|
|
|
+ calculatePercentage(secondList.get(2).getPqxy() + secondList.get(2).getBjxy(), secondList.get(2).getTotalCount()),
|
|
|
+ secondList.get(3).getTempName(), secondList.get(3).getQuestionName(),
|
|
|
+ calculatePercentage(secondList.get(3).getPqxy() + secondList.get(3).getBjxy(), secondList.get(3).getTotalCount())
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装第四个后缀信息
|
|
|
+ * 调查结果显示,在{表3的项目名称}方面,员工最喜闻乐见的形式是{表3中百分比最高的期望培训形式名称}需求度为{该期望形式百分比}%,
|
|
|
+ * 在{表4的项目名称}方面,员工希望以{表4中百分比最高的期望授课人名称}为主要授课人员,需求度为{该期望授课人的百分比}%。
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String assembleFourthSuffix(List<List<QuestionnaireRecordingVo>> values) {
|
|
|
+
|
|
|
+ List<QuestionnaireRecordingVo> firstList = values.get(2);
|
|
|
+ List<QuestionnaireRecordingVo> secondList = values.get(3);
|
|
|
+ // 对数据排序
|
|
|
+ firstList = firstList.stream()
|
|
|
+ .sorted(Comparator.comparingInt((QuestionnaireRecordingVo info) -> info.getPqxy() + info.getBjxy()).reversed())
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ secondList = secondList.stream()
|
|
|
+ .sorted(Comparator.comparingInt((QuestionnaireRecordingVo info) -> info.getPqxy() + info.getBjxy()).reversed())
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ return String.format(FOURTH_SUFFIX, firstList.get(0).getTempName(), firstList.get(0).getQuestionName(),
|
|
|
+ calculatePercentage(firstList.get(0).getPqxy() + firstList.get(0).getBjxy(), firstList.get(0).getTotalCount()),
|
|
|
+ secondList.get(0).getTempName(), secondList.get(0).getQuestionName(),
|
|
|
+ calculatePercentage(secondList.get(0).getPqxy() + secondList.get(0).getBjxy(), secondList.get(0).getTotalCount())
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装项目总结
|
|
|
+ * 1、培训{表1的项目名称}:
|
|
|
+ * 培训{表1的项目名称}方面员工希望提高自己的{表1中百分比最高的基本内容名称},根据调查表结果显示,培训内容方面侧重于{表2中百分比第一的具体内容名称}。
|
|
|
+ * <p>
|
|
|
+ * 2、培训{表2的项目名称}:
|
|
|
+ * 培训{表2的项目名称}方面以{表2中百分比第一的具体内容名称}、{表2中百分比第二的具体内容名称}、{表2中百分比第三的具体内容名称}等内容为主,结合其他内容进行讲解
|
|
|
+ * <p>
|
|
|
+ * 3、{表3的项目名称}:
|
|
|
+ * {表3的项目名称}方面,重点收集员工能看懂,易看懂的{表3中百分比最高的期望培训形式名称},结合{表3中百分比最高的期望培训形式名称}提高培训的效率。
|
|
|
+ * <p>
|
|
|
+ * <p>
|
|
|
+ * 4、{表4的项目名称}:{表4的项目名称}以{表4中百分比第一的期望授课人名称}、{表4中百分比第二的期望授课人名称}为主,分层级进行讲授。
|
|
|
+ *
|
|
|
+ * @param values
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String assembleSummary(List<List<QuestionnaireRecordingVo>> values) {
|
|
|
+ QuestionnaireRecordingVo first = values.get(0).stream()
|
|
|
+ .sorted(Comparator.comparingInt((QuestionnaireRecordingVo info) -> info.getPqxy() + info.getBjxy()).reversed())
|
|
|
+ .collect(Collectors.toList()).get(0);
|
|
|
+ List<QuestionnaireRecordingVo> second = values.get(1).stream()
|
|
|
+ .sorted(Comparator.comparingInt((QuestionnaireRecordingVo info) -> info.getPqxy() + info.getBjxy()).reversed())
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ QuestionnaireRecordingVo third = values.get(2).stream()
|
|
|
+ .sorted(Comparator.comparingInt((QuestionnaireRecordingVo info) -> info.getPqxy() + info.getBjxy()).reversed())
|
|
|
+ .collect(Collectors.toList()).get(0);
|
|
|
+ List<QuestionnaireRecordingVo> fourth = values.get(3).stream()
|
|
|
+ .sorted(Comparator.comparingInt((QuestionnaireRecordingVo info) -> info.getPqxy() + info.getBjxy()).reversed())
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ return String.format(String.format(SUMMARY, first.getTempName(), first.getTempName(), first.getQuestionName(), second.get(0).getTempName(),
|
|
|
+ second.get(0).getTempName(),second.get(0).getTempName(), second.get(0).getQuestionName(), second.get(1).getQuestionName(), second.get(2).getQuestionName(),
|
|
|
+ third.getTempName(), third.getTempName(), third.getQuestionName(), third.getQuestionName(),
|
|
|
+ fourth.get(0).getTempName(),fourth.get(0).getTempName(), fourth.get(0).getQuestionName(), fourth.get(1).getQuestionName()));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算百分比
|
|
|
+ *
|
|
|
+ * @param divisor 除数
|
|
|
+ * @param dividend 被除数
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public BigDecimal calculatePercentage(int divisor, int dividend) {
|
|
|
+ if (divisor == 0 || dividend == 0) {
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+ return new BigDecimal(divisor)
|
|
|
+ .multiply(new BigDecimal(100))
|
|
|
+ .divide(new BigDecimal(dividend), 2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void getWordLicense() {
|
|
|
+ try {
|
|
|
+ InputStream is = this.getClass().getClassLoader().getResourceAsStream("license.xml");
|
|
|
+ com.aspose.words.License aposeLic = new com.aspose.words.License();
|
|
|
+ aposeLic.setLicense(is);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|