浏览代码

Merge remote-tracking branch 'origin/master' into mode-min-unit

fangpy 1 年之前
父节点
当前提交
4bf31d66e7
共有 18 个文件被更改,包括 579 次插入51 次删除
  1. 3 0
      cx-aps/cx-aps-common/src/main/java/com/rongwei/bscommon/sys/service/ApsProductDetailService.java
  2. 17 10
      cx-aps/cx-aps-common/src/main/java/com/rongwei/bscommon/sys/service/impl/ApsBlankOrderServiceImpl.java
  3. 3 0
      cx-aps/cx-aps-common/src/main/java/com/rongwei/bscommon/sys/service/impl/ApsProcessOperationServiceImpl.java
  4. 19 0
      cx-aps/cx-aps-common/src/main/java/com/rongwei/bscommon/sys/service/impl/ApsProductDetailServiceImpl.java
  5. 6 6
      cx-aps/cx-aps-common/src/main/java/com/rongwei/bscommon/sys/service/impl/ApsProductionOrderServiceImpl.java
  6. 1 1
      cx-aps/cx-aps-common/src/main/resources/mybatis/ApsBlankOrderDao.xml
  7. 3 2
      cx-aps/cx-aps-common/src/main/resources/mybatis/ApsProcessOperationProcessEquBackupDao.xml
  8. 17 31
      cx-aps/cx-aps-entity/src/main/java/com/rongwei/bsentity/domain/ApsProcessOperationProcessEquBackupDo.java
  9. 16 0
      cx-aps/cx-aps-server/src/main/java/com/rongwei/bsserver/controller/ApsProductDetailController.java
  10. 1 1
      cx-knowledge-base/cx-knowledge-base-common/src/main/java/com/rongwei/bscommon/sys/service/impl/KnowledgeBaseServiceImpl.java
  11. 3 0
      rw-training/training-common/src/main/java/com/rongwei/trainingcommon/sys/dao/TrainingDemandSurveyBackupsDao.java
  12. 14 0
      rw-training/training-common/src/main/java/com/rongwei/trainingcommon/sys/service/ExportQuestionnaireRecordingsService.java
  13. 345 0
      rw-training/training-common/src/main/java/com/rongwei/trainingcommon/sys/service/impl/ExportQuestionnaireRecordingsServiceImpl.java
  14. 45 0
      rw-training/training-common/src/main/resources/mybatis/TrainingDemandSurveyBackupsDao.xml
  15. 43 0
      rw-training/training-entity/src/main/java/com/rongwei/training/vo/QuestionnaireRecordingVo.java
  16. 30 0
      rw-training/training-server/src/main/java/com/rongwei/training/controller/ExportQuestionnaireRecordingsController.java
  17. 13 0
      rw-training/training-server/src/main/resources/license.xml
  18. 二进制
      rw-training/training-server/src/main/resources/template/TrainingNeedsSurveyReport.docx

+ 3 - 0
cx-aps/cx-aps-common/src/main/java/com/rongwei/bscommon/sys/service/ApsProductDetailService.java

@@ -5,6 +5,7 @@ import com.rongwei.bsentity.domain.ApsProductDetailDo;
 import com.rongwei.rwcommon.base.R;
 import org.springframework.web.bind.annotation.RequestBody;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -22,4 +23,6 @@ public interface ApsProductDetailService extends IService<ApsProductDetailDo> {
     R updateCustomOrder(Map<String, Object> params);
 
     R updateMergeCustomOrder(@RequestBody Map<String, Object> params);
+
+    R updateOrSaveProductDetails(List<ApsProductDetailDo> req);
 }

+ 17 - 10
cx-aps/cx-aps-common/src/main/java/com/rongwei/bscommon/sys/service/impl/ApsBlankOrderServiceImpl.java

@@ -71,6 +71,8 @@ public class ApsBlankOrderServiceImpl extends ServiceImpl<ApsBlankOrderDao, ApsB
     @Autowired
     private ApsBlankOrderDao apsBlankOrderDao;
     @Autowired
+    private ApsBlankOrderService apsBlankOrderService;
+    @Autowired
     private ApsProcessOperationProcessEquServiceImpl processOperationProcessEquService;
     @Autowired
     private ApsScheduleConfigService apsScheduleConfigService;
@@ -412,11 +414,16 @@ public class ApsBlankOrderServiceImpl extends ServiceImpl<ApsBlankOrderDao, ApsB
         processOperationProcessEquService.update(new LambdaUpdateWrapper<ApsProcessOperationProcessEquDo>()
                 .set(ApsProcessOperationProcessEquDo::getLockmark, lockMark)
                 .in(ApsProcessOperationProcessEquDo::getBlankid, blackOrderId));
+        // 解锁
         if (LOCKMARK_N.equals(lockMark)) {
             // 更新坯料计划对应工序作业的生产状态为待发布
             apsProcessOperationService.update(new LambdaUpdateWrapper<ApsProcessOperationDo>()
                     .in(ApsProcessOperationDo::getBlankid, blackOrderId)
-                    .set(ApsProcessOperationDo::getProcessstatus, "20"));
+                    .set(ApsProcessOperationDo::getProcessstatus, "20")
+            );
+            apsBlankOrderService.update(new LambdaUpdateWrapper<ApsBlankOrderDo>()
+                    .in(ApsBlankOrderDo::getId,blackOrderId)
+                    .set(ApsBlankOrderDo::getSchedulingstatus,"20"));
         }
         // 回传坯料计划ID 用于前段更新锁定状态
         return R.ok(blackOrderId);
@@ -1495,10 +1502,10 @@ public class ApsBlankOrderServiceImpl extends ServiceImpl<ApsBlankOrderDao, ApsB
                 //判断是否存在对应的产品明细
                 if (apsProcessOutputProductDo.getProductid().equals(apsProductDetailDo.getId())) {
                     haveProductDetail = true;
-                    //计划输出订单重量 > 对应订单产品订单总数量;错误提示:输出成品 {订单产品} 计划输出订单重量 不能大于 订单总数量
-                    if (apsProcessOutputProductDo.getPlanoutputonerollweight().compareTo(apsProductDetailDo.getTotalordercount()) > 0) {
-                        return R.error("输出成品:" + apsProcessOutputProductDo.getProductname() + " 计划输出订单重量 不能大于 订单总数量");
-                    }
+//                    //计划输出订单重量 > 对应订单产品订单总数量;错误提示:输出成品 {订单产品} 计划输出订单重量 不能大于 订单总数量
+//                    if (apsProcessOutputProductDo.getPlanoutputonerollweight().compareTo(apsProductDetailDo.getTotalordercount()) > 0) {
+//                        return R.error("输出成品:" + apsProcessOutputProductDo.getProductname() + " 计划输出订单重量 不能大于 订单总数量");
+//                    }
                 }
             }
             if (!haveProductDetail && apsProcessOutputProductDo.getPlanoutputonerollweight().compareTo(new BigDecimal(0)) > 0) {
@@ -1523,7 +1530,7 @@ public class ApsBlankOrderServiceImpl extends ServiceImpl<ApsBlankOrderDao, ApsB
         //============校验工艺路线=============
         //如果坯料需求的坯料输出成品字段值不等于坯料需求的工艺输出成品字段值,错误提示:工艺路线输出成品与坯料输出成品不一致
         if (!apsBlankOrderDo.getOutputfinishproduct().equals(apsBlankOrderDo.getOutputmaterial())) {
-            return R.error("工艺路线输出成品与坯料输出成品不一致");
+            return R.error("工艺路线输出成品" + apsBlankOrderDo.getOutputmaterial() + "与坯料输出成品" + apsBlankOrderDo.getOutputfinishproduct() + "不一致");
         }
         //如果坯料需求的是否备料=是,并且首道工序作业的是否坯料工序=是,错误提示:工艺路线错误,首道工序作业是坯料工序,备料不能作为输入物料
         //是否备料
@@ -1722,9 +1729,9 @@ public class ApsBlankOrderServiceImpl extends ServiceImpl<ApsBlankOrderDao, ApsB
                 if (apsProcessOutputProductDo.getProductid().equals(apsProductDetailDo.getId())) {
                     haveProductDetail = true;
                     //计划输出订单重量 > 对应订单产品订单总数量;错误提示:输出成品 {订单产品} 计划输出订单重量 不能大于 订单总数量
-                    if (apsProcessOutputProductDo.getPlanoutputonerollweight().compareTo(apsProductDetailDo.getTotalordercount()) > 0) {
-                        return R.error("第" + j + "个坯料计划 输出成品:" + apsProcessOutputProductDo.getProductname() + " 计划输出订单重量 不能大于 订单总数量");
-                    }
+//                    if (apsProcessOutputProductDo.getPlanoutputonerollweight().compareTo(apsProductDetailDo.getTotalordercount()) > 0) {
+//                        return R.error("第" + j + "个坯料计划 输出成品:" + apsProcessOutputProductDo.getProductname() + " 计划输出订单重量 不能大于 订单总数量");
+//                    }
                 }
             }
             if (!haveProductDetail && apsProcessOutputProductDo.getPlanoutputonerollweight().compareTo(new BigDecimal(0)) > 0) {
@@ -1736,7 +1743,7 @@ public class ApsBlankOrderServiceImpl extends ServiceImpl<ApsBlankOrderDao, ApsB
         //============校验工艺路线=============
         //如果坯料需求的坯料输出成品字段值不等于坯料需求的工艺输出成品字段值,错误提示:工艺路线输出成品与坯料输出成品不一致
         if (!apsBlankOrderDo.getOutputfinishproduct().equals(apsBlankOrderDo.getOutputmaterial())) {
-            return R.error("第" + j + "个坯料计划 工艺路线输出成品与坯料输出成品不一致");
+            return R.error("第" + j + "个坯料计划 工艺路线输出成品" + apsBlankOrderDo.getOutputmaterial() + "与坯料输出成品" + apsBlankOrderDo.getOutputfinishproduct() + "不一致");
         }
         //如果坯料需求的是否备料=是,并且首道工序作业的是否坯料工序=是,错误提示:工艺路线错误,首道工序作业是坯料工序,备料不能作为输入物料
         //是否备料

+ 3 - 0
cx-aps/cx-aps-common/src/main/java/com/rongwei/bscommon/sys/service/impl/ApsProcessOperationServiceImpl.java

@@ -735,6 +735,9 @@ public class ApsProcessOperationServiceImpl extends ServiceImpl<ApsProcessOperat
                     //校验车间代号
                     if (ObjectUtil.isNotEmpty(equDo.getProcessworkshopid())) {
                         if (workShopMap.containsKey(equDo.getProcessworkshopid())) {
+                            if(ObjectUtil.isEmpty(workShopMap.get(equDo.getProcessworkshopid()))){
+                                return R.error("加工车间" + equDo.getProcessworkshop() + "代号不能为空");
+                            }
                             String workShopCode = workShopMap.get(equDo.getProcessworkshopid()).toString();
                             if (ObjectUtil.isEmpty(workShopCode) || workShopCode.length() != 1) {
                                 return R.error("加工车间" + equDo.getProcessworkshop() + "代号不能为空");

+ 19 - 0
cx-aps/cx-aps-common/src/main/java/com/rongwei/bscommon/sys/service/impl/ApsProductDetailServiceImpl.java

@@ -1,6 +1,7 @@
 package com.rongwei.bscommon.sys.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.rongwei.bscommon.sys.dao.ApsProductDetailDao;
 import com.rongwei.bscommon.sys.service.ApsProductDetailService;
@@ -8,11 +9,14 @@ import com.rongwei.bscommon.sys.service.ApsProductionMergeOrderService;
 import com.rongwei.bscommon.sys.service.ApsProductionOrderService;
 import com.rongwei.bscommon.sys.service.SlaveSourceService;
 import com.rongwei.bsentity.domain.*;
+import com.rongwei.rwadmincommon.system.vo.SysUserVo;
 import com.rongwei.rwcommon.base.R;
 import com.rongwei.rwcommon.utils.SecurityUtil;
 import com.rongwei.rwcommon.utils.StringUtils;
+import com.rongwei.safecommon.utils.CXCommonUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.RequestBody;
 
 import java.util.ArrayList;
@@ -445,4 +449,19 @@ public class ApsProductDetailServiceImpl extends ServiceImpl<ApsProductDetailDao
             return R.error("获取客户订单系统订单失败,请联系管理员");
         }
     }
+
+    @Override
+    @Transactional
+    public R updateOrSaveProductDetails(List<ApsProductDetailDo> req) {
+        // 当前等路人所属工厂
+        SysUserVo currentUser = CXCommonUtils.getCurrentUser();
+        String tenantId = currentUser.getOrganizationDoList().get(0).getFullpid().split(",")[1];
+        if (ObjectUtil.isNotEmpty(req) && req.size() > 0) {
+            for (ApsProductDetailDo apsProductDetailDo : req) {
+                apsProductDetailDo.setTenantid(tenantId);
+            }
+            this.saveOrUpdateBatch(req);
+        }
+        return R.ok();
+    }
 }

+ 6 - 6
cx-aps/cx-aps-common/src/main/java/com/rongwei/bscommon/sys/service/impl/ApsProductionOrderServiceImpl.java

@@ -144,7 +144,7 @@ public class ApsProductionOrderServiceImpl extends ServiceImpl<ApsProductionOrde
         //产品明细信息
         List<ApsProductDetailVo> apsProductDetailVoList = req.getApsProductDetailVoList();
         //坯料计划信息(坯料计划是一保存的状态,校验直接通过数据库查询)
-        List<ApsBlankOrderDo> apsBlankOrderDoList = apsBlankOrderDao.selectList(new QueryWrapper<ApsBlankOrderDo>().lambda().eq(ApsBlankOrderDo::getProductionorderid, apsProductionOrderDo.getId()));
+        List<ApsBlankOrderDo> apsBlankOrderDoList = apsBlankOrderDao.selectList(new QueryWrapper<ApsBlankOrderDo>().lambda().eq(ApsBlankOrderDo::getProductionorderid, apsProductionOrderDo.getId()).orderByDesc(ApsBlankOrderDo::getModifydate));
         //是否需要检验坯料计划是否已排程
         Boolean checkSchedule = req.getCheckSchedule();
 
@@ -192,11 +192,11 @@ public class ApsProductionOrderServiceImpl extends ServiceImpl<ApsProductionOrde
         if (ObjectUtil.isEmpty(apsProductDetailVoList) || apsProductDetailVoList.size() <= 0) {
             return R.error("产品明细至少有一个");
         }
-        for (ApsProductDetailVo apsProductDetailVo : apsProductDetailVoList) {
-            if (ObjectUtil.isEmpty(apsProductDetailVo.getTotalordercount()) || ObjectUtil.isEmpty(apsProductDetailVo.getPlanout()) || apsProductDetailVo.getTotalordercount().compareTo(apsProductDetailVo.getPlanout()) != 0) {
-                return R.error("订单产品 " + apsProductDetailVo.getInputmaterialdescription() + " 订单总数量与坯料计划输出总重量不一致");
-            }
-        }
+//        for (ApsProductDetailVo apsProductDetailVo : apsProductDetailVoList) {
+//            if (ObjectUtil.isEmpty(apsProductDetailVo.getTotalordercount()) || ObjectUtil.isEmpty(apsProductDetailVo.getPlanout()) || apsProductDetailVo.getTotalordercount().compareTo(apsProductDetailVo.getPlanout()) != 0) {
+//                return R.error("订单产品 " + apsProductDetailVo.getInputmaterialdescription() + " 订单总数量与坯料计划输出总重量不一致");
+//            }
+//        }
 
         //查询此订单所有产品明细对应的输出成品的卷数和
 //        List<ProductDetailIdAndPlanOutPutRollCountAllVo> planOutPutRollCountAllVos = this.baseMapper.getProductDetailIdAndPlanOutPutRollCountAll(apsProductDetailVoList.get(0).getMainid());

+ 1 - 1
cx-aps/cx-aps-common/src/main/resources/mybatis/ApsBlankOrderDao.xml

@@ -155,7 +155,7 @@
         left join aps_process_operation_process_equ apope on apope.PROCESSID=apo.ID and apope.DELETED='0'
         <where>
             abo.DELETED ='0'
-            <if test="lockTime=='n'">
+            <if test='lockMark=="n"'>
                 AND abo.PRODUCTSTATUS !='40'
                 and abo.PRODUCTSTATUS !='50'
             </if>

+ 3 - 2
cx-aps/cx-aps-common/src/main/resources/mybatis/ApsProcessOperationProcessEquBackupDao.xml

@@ -54,7 +54,7 @@
         REPORTROLL,CHECKOUTROLL,UNFINISHROLL,
         WORKSTATUS,BACHMATERIALPROCESS,WAITREPORTID,
         LOCKMARK,BLANKID,BACKUPUSER,
-        BACKUPUSERID,BACKUPDATE
+        BACKUPUSERID,BACKUPDATE,HASCONFLICT,CONFLICTDES,SOFTCONFLICTDES
     </sql>
     <insert id="processOperationEquBackup">
         <if test="equDos != null and equDos.size() >0">
@@ -70,7 +70,8 @@
                 #{data.closestatus},#{data.planprocessrall},#{data.startingroll},
                 #{data.reportroll},#{data.checkoutroll},#{data.unfinishroll},
                 #{data.workstatus},#{data.bachmaterialprocess},#{data.waitreportid},
-                #{data.lockmark},#{data.blankid},#{userName} ,#{userId} ,NOW())
+                #{data.lockmark},#{data.blankid},#{userName} ,#{userId} ,NOW(),
+                #{data.hasconflict},#{data.conflictdes},#{data.softconflictdes})
                 ON DUPLICATE KEY UPDATE DELETED='0'
             </foreach>
         </if>

+ 17 - 31
cx-aps/cx-aps-entity/src/main/java/com/rongwei/bsentity/domain/ApsProcessOperationProcessEquBackupDo.java

@@ -11,147 +11,133 @@ import java.util.Date;
 
 /**
  * 生产订单-坯料计划-工序作业加工设备
+ *
  * @TableName aps_process_operation_process_equ_backup
  */
-@TableName(value ="aps_process_operation_process_equ_backup")
+@TableName(value = "aps_process_operation_process_equ_backup")
 @Data
 public class ApsProcessOperationProcessEquBackupDo extends BaseDo implements Serializable {
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
     /**
      * 主键ID
      */
     @TableId
     private String id;
-
     /**
-     * 
+     *
      */
     private String tenantid;
-
     /**
      * 扩展json格式配置
      */
     private String roption;
-
     /**
      * 所属工厂
      */
     private String ownedfactory;
-
     /**
      * 工序作业ID
      */
     private String processid;
-
     /**
      * 加工车间ID
      */
     private String processworkshopid;
-
     /**
      * 加工车间
      */
     private String processworkshop;
-
     /**
      * 加工设备ID
      */
     private String processdeviceid;
-
     /**
      * 加工设备
      */
     private String processdevice;
-
     /**
      * 计划开工时间
      */
     private Date planstartdate;
-
     /**
      * 实际开工时间
      */
     private Date actualstartdate;
-
     /**
      * 计划完工时间
      */
     private Date planenddate;
-
     /**
      * 实际完工时间
      */
     private Date actualfinishdate;
-
     /**
      * 完工状态
      */
     private String closestatus;
-
     /**
      * 计划加工卷数
      */
     private Integer planprocessrall;
-
     /**
      * 已开工卷数
      */
     private Integer startingroll;
-
     /**
      * 已报工卷数
      */
     private Integer reportroll;
-
     /**
      * 已检验卷数
      */
     private Integer checkoutroll;
-
     /**
      * 未完工卷数
      */
     private Integer unfinishroll;
-
     /**
      * 作业状态
      */
     private String workstatus;
-
     /**
      * 待加工料卷批次号
      */
     private String bachmaterialprocess;
-
     /**
      * 待报工记录ID
      */
     private String waitreportid;
-
     /**
      * 是否锁定 y:锁定,n:未锁定
      */
     private String lockmark;
-
     /**
      * 坯料计划ID
      */
     private String blankid;
-
     /**
      * 备份人姓名
      */
     private String backupuser;
-
     /**
      * 备份人姓名ID
      */
     private String backupuserid;
-
     /**
      * 备份日期
      */
     private Date backupdate;
-
-    @TableField(exist = false)
-    private static final long serialVersionUID = 1L;
+    /**
+     * 是否冲突(y:是,n:否)
+     */
+    private String hasconflict;
+    /**
+     * 强制冲突描述
+     */
+    private String conflictdes;
+    /**
+     * 非强制冲突描述(警告)
+     */
+    private String softconflictdes;
 }

+ 16 - 0
cx-aps/cx-aps-server/src/main/java/com/rongwei/bsserver/controller/ApsProductDetailController.java

@@ -2,6 +2,7 @@ package com.rongwei.bsserver.controller;
 
 
 import com.rongwei.bscommon.sys.service.ApsProductDetailService;
+import com.rongwei.bsentity.domain.ApsProductDetailDo;
 import com.rongwei.rwcommon.base.R;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -10,6 +11,7 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -68,5 +70,19 @@ public class ApsProductDetailController {
             return R.error("获取客户订单系统订单失败,请联系管理员");
         }
     }
+
+    /**
+     * 更新或保存产品明细
+     */
+    @PostMapping("/updateOrSaveProductDetails")
+    public R updateOrSaveProductDetails(@RequestBody List<ApsProductDetailDo> req) {
+        try {
+            log.info("更新或保存产品明细;参数为:{}", req);
+            return apsProductDetailService.updateOrSaveProductDetails(req);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return R.error("更新或保存产品明细失败,请联系管理员");
+        }
+    }
 }
 

+ 1 - 1
cx-knowledge-base/cx-knowledge-base-common/src/main/java/com/rongwei/bscommon/sys/service/impl/KnowledgeBaseServiceImpl.java

@@ -76,7 +76,7 @@ public class KnowledgeBaseServiceImpl implements KnowledgeBaseService {
                     List<KBDictDataVo> kbDictDataVoList = collect.stream().filter(dictData -> dictData.getLabel().contains(searchContent)).collect(Collectors.toList());
                     String searchValue = kbDictDataVoList.stream().map(KBDictDataVo::getValue).collect(Collectors.joining(","));
                     info.setSearchValue(StringUtils.isBlank(searchValue) ? "" : searchValue);
-                    info.setDictData(collect.stream().collect(Collectors.toMap(KBDictDataVo::getValue, KBDictDataVo::getLabel)));
+                    info.setDictData(collect.stream().collect(Collectors.toMap(KBDictDataVo::getValue, KBDictDataVo::getLabel,(existingValue, newValue) -> existingValue)));
                 } else {
                     info.setSearchValue(searchContent);
                 }

+ 3 - 0
rw-training/training-common/src/main/java/com/rongwei/trainingcommon/sys/dao/TrainingDemandSurveyBackupsDao.java

@@ -2,6 +2,7 @@ package com.rongwei.trainingcommon.sys.dao;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.rongwei.training.domain.TrainingDemandSurveyBackupsDo;
+import com.rongwei.training.vo.QuestionnaireRecordingVo;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
@@ -32,6 +33,8 @@ public interface TrainingDemandSurveyBackupsDao extends BaseMapper<TrainingDeman
             "where ID=#{surveyId}")
     void updateParticipant(@Param("userId")String userId,@Param("userName")String userName,@Param("surveyId")String surveyId);
 
+
+    List<QuestionnaireRecordingVo> getQuestionnaireInformation(@Param("id")String id);
 }
 
 

+ 14 - 0
rw-training/training-common/src/main/java/com/rongwei/trainingcommon/sys/service/ExportQuestionnaireRecordingsService.java

@@ -0,0 +1,14 @@
+package com.rongwei.trainingcommon.sys.service;
+
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * ExportQuestionnaireRecordingsService class
+ *
+ * @author XH
+ * @date 2024/06/06
+ */
+public interface ExportQuestionnaireRecordingsService {
+
+    void exportWord(String id, HttpServletResponse response);
+}

+ 345 - 0
rw-training/training-common/src/main/java/com/rongwei/trainingcommon/sys/service/impl/ExportQuestionnaireRecordingsServiceImpl.java

@@ -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();
+        }
+    }
+}

+ 45 - 0
rw-training/training-common/src/main/resources/mybatis/TrainingDemandSurveyBackupsDao.xml

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.rongwei.trainingcommon.sys.dao.TrainingDemandSurveyBackupsDao">
+
+
+    <select id="getQuestionnaireInformation" resultType="com.rongwei.training.vo.QuestionnaireRecordingVo">
+        SELECT
+        dsc.TEMPID as tempId,
+        dsc.TEMPNAME as tempName,
+        dsc.NUM,
+        dsc.QUESTIONNAME as questionName,
+        SUM(IF(dsua.ANSWER REGEXP '(^|-;-)迫切需要(-;|$)',1,0)) AS pqxy,
+        SUM(IF(dsua.ANSWER REGEXP '(^|-;-)比较需要(-;|$)',1,0)) AS bjxy,
+        SUM(IF(dsua.ANSWER REGEXP '(^|-;-)一般需要(-;|$)',1,0)) AS ybxy,
+        SUM(IF(dsua.ANSWER REGEXP '(^|-;-)不需要(-;|$)',1,0)) AS bxy,
+        count(dsua.ID) AS totalCount,
+        tdsb.ID
+        FROM demand_survey_content dsc
+        LEFT JOIN training_demand_survey_backups tdsb ON dsc.SURVERID = tdsb.ID
+        LEFT JOIN training_demand_survey tds ON tds.ID = tdsb.OLDSURVEYID
+        LEFT JOIN demand_survey_user_answer dsua ON tdsb.ID = dsua.SURVERID AND dsua.SURVERCONTENTID = dsc.ID
+        <where>
+            FIND_IN_SET(dsc.QUESTIONTYPE, '1,2')
+            AND dsc.`OPTIONS` LIKE '%一般需要%'
+            AND dsc.`OPTIONS` LIKE '%不需要%'
+            AND dsc.`OPTIONS` LIKE '%迫切需要%'
+            AND dsc.`OPTIONS` LIKE '%比较需要%'
+            -- AND dsua.ID IS NOT NULL
+            and tdsb.ID= #{id}
+        </where>
+        GROUP BY
+        dsc.QUESTIONID,
+        dsc.QUESTIONNAME,
+        dsc.TEMPNAME,
+        dsc.TEMPID
+        ORDER BY CASE dsc.TEMPNAME
+        WHEN '培训内容' THEN 1
+        WHEN '期望培训形式' THEN 2
+        WHEN '期望授课人' THEN 3
+        WHEN '影响培训开展得因素' THEN 4
+        ELSE 5
+        END,
+        dsc.NUM asc
+    </select>
+</mapper>

+ 43 - 0
rw-training/training-entity/src/main/java/com/rongwei/training/vo/QuestionnaireRecordingVo.java

@@ -0,0 +1,43 @@
+package com.rongwei.training.vo;
+
+import lombok.Data;
+
+/**
+ * QuestionnaireRecordingVo class
+ *
+ * @author XH
+ * @date 2024/06/06
+ */
+@Data
+public class QuestionnaireRecordingVo {
+    /**
+     * 培训项目ID
+     */
+    private String tempId;
+    /**
+     * 培训项目名称
+     */
+    private String tempName;
+    /**
+     * 问题名称
+     */
+    private String questionName;
+    /**
+     * 迫切需要数量
+     */
+    private int pqxy=0;
+    /**
+     * 比较需要数量
+     */
+    private int bjxy=0;
+    /**
+     * 一般需要数量
+     */
+    private int ybxy=0;
+    /**
+     * 不需要数量
+     */
+    private int bxy=0;
+
+    private int totalCount=0;
+}

+ 30 - 0
rw-training/training-server/src/main/java/com/rongwei/training/controller/ExportQuestionnaireRecordingsController.java

@@ -0,0 +1,30 @@
+package com.rongwei.training.controller;
+
+import com.rongwei.rwcommon.base.R;
+
+import com.rongwei.trainingcommon.sys.service.ExportQuestionnaireRecordingsService;
+import org.checkerframework.checker.units.qual.A;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+/**
+ * ExportQuestionnaireRecordingsController class
+ * 导出问卷培训记录信息
+ * @author XH
+ * @date 2024/06/06
+ */
+@RestController
+@RequestMapping("/export")
+public class ExportQuestionnaireRecordingsController {
+    @Autowired
+    private ExportQuestionnaireRecordingsService exportQuestionnaireRecordingsService;
+
+    @PostMapping("/questionnaire/recording/{id}")
+    public void export(@PathVariable("id") String id, HttpServletResponse response){
+     exportQuestionnaireRecordingsService.exportWord(id,response);
+    }
+}

+ 13 - 0
rw-training/training-server/src/main/resources/license.xml

@@ -0,0 +1,13 @@
+<License>
+    <Data>
+        <Products>
+            <Product>Aspose.Total for Java</Product>
+            <Product>Aspose.Words for Java</Product>
+        </Products>
+        <EditionType>Enterprise</EditionType>
+        <SubscriptionExpiry>20991231</SubscriptionExpiry>
+        <LicenseExpiry>20991231</LicenseExpiry>
+        <SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>
+    </Data>
+    <Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature>
+</License>

二进制
rw-training/training-server/src/main/resources/template/TrainingNeedsSurveyReport.docx