Эх сурвалжийг харах

Merge branch 'master' of http://47.114.101.16:7070/ssy/newcpms

dengliying 1 жил өмнө
parent
commit
5b03ab6866
69 өөрчлөгдсөн 9205 нэмэгдсэн , 321 устгасан
  1. 2 2
      master/pom.xml
  2. 4 0
      master/src/main/java/com/ruoyi/framework/web/controller/BaseController.java
  3. 6 6
      master/src/main/java/com/ruoyi/project/training/bccnew/controller/TTsFirstplanController.java
  4. 3 3
      master/src/main/java/com/ruoyi/project/training/bccnew/controller/TTsFirstplanTmplController.java
  5. 51 41
      master/src/main/java/com/ruoyi/project/training/bccnew/controller/TTsNewController.java
  6. 8 8
      master/src/main/java/com/ruoyi/project/training/bccnew/controller/TTsYsplanTmplController.java
  7. 10 0
      master/src/main/java/com/ruoyi/project/training/bccnew/domain/TTsNew.java
  8. 0 1
      master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsFirstplanMapper.java
  9. 0 1
      master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsFirstplanTmplMapper.java
  10. 0 1
      master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsFlplanMapper.java
  11. 0 1
      master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsFlplanTmplMapper.java
  12. 0 1
      master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsFtplanMapper.java
  13. 0 1
      master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsFtplanTmplMapper.java
  14. 0 1
      master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsLjplanMapper.java
  15. 0 1
      master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsLjplanTmplMapper.java
  16. 0 1
      master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsNewMapper.java
  17. 0 1
      master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsYsplanMapper.java
  18. 0 1
      master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsYsplanTmplMapper.java
  19. 162 0
      master/src/main/java/com/ruoyi/project/training/controller/TTrainingbccController.java
  20. 112 0
      master/src/main/java/com/ruoyi/project/training/controller/TTrainingbccDeviceController.java
  21. 524 0
      master/src/main/java/com/ruoyi/project/training/domain/TTrainingbcc.java
  22. 278 0
      master/src/main/java/com/ruoyi/project/training/domain/TTrainingbccDevice.java
  23. 1 1
      master/src/main/java/com/ruoyi/project/training/elearn/controller/TElLearnController.java
  24. 13 0
      master/src/main/java/com/ruoyi/project/training/elearn/controller/TElResourceController.java
  25. 3 0
      master/src/main/java/com/ruoyi/project/training/elearn/domain/TElExam.java
  26. 11 0
      master/src/main/java/com/ruoyi/project/training/elearn/domain/TElResource.java
  27. 67 0
      master/src/main/java/com/ruoyi/project/training/mapper/TTrainingbccDeviceMapper.java
  28. 63 0
      master/src/main/java/com/ruoyi/project/training/mapper/TTrainingbccMapper.java
  29. 61 0
      master/src/main/java/com/ruoyi/project/training/service/ITTrainingbccDeviceService.java
  30. 63 0
      master/src/main/java/com/ruoyi/project/training/service/ITTrainingbccService.java
  31. 93 0
      master/src/main/java/com/ruoyi/project/training/service/impl/TTrainingbccDeviceServiceImpl.java
  32. 168 0
      master/src/main/java/com/ruoyi/project/training/service/impl/TTrainingbccServiceImpl.java
  33. 1 1
      master/src/main/resources/application.yml
  34. 3 0
      master/src/main/resources/mybatis/document/TPlantproglistMapper.xml
  35. 148 0
      master/src/main/resources/mybatis/training/TTrainingbccDeviceMapper.xml
  36. 192 0
      master/src/main/resources/mybatis/training/TTrainingbccMapper.xml
  37. 1 1
      master/src/main/resources/mybatis/training/bccnew/TTsNewMapper.xml
  38. 7 1
      master/src/main/resources/mybatis/training/elearn/TElExamMapper.xml
  39. 2 2
      master/src/main/resources/mybatis/training/elearn/TElLearnMapper.xml
  40. BIN
      master/src/main/resources/static/word/training/appraisalForm.docx
  41. BIN
      master/src/main/resources/static/word/training/targetPlan.docx
  42. 53 0
      ui/src/api/training/bccdevice.js
  43. 13 13
      ui/src/api/training/bccnew/ysPlan.js
  44. 72 0
      ui/src/api/training/trainingbcc.js
  45. 19 1
      ui/src/router/index.js
  46. 2 0
      ui/src/views/components/PlantProgList/index.vue
  47. 2 2
      ui/src/views/login.vue
  48. 439 0
      ui/src/views/training/bccdevice/index.vue
  49. 75 62
      ui/src/views/training/bccnew/firstPlanTmpl/index.vue
  50. 2 117
      ui/src/views/training/bccnew/firstplan/index.vue
  51. 534 0
      ui/src/views/training/bccnew/firstplan/index_student.vue
  52. 192 3
      ui/src/views/training/bccnew/flPlan/index.vue
  53. 191 3
      ui/src/views/training/bccnew/ftPlan/index.vue
  54. 191 3
      ui/src/views/training/bccnew/ljPlan/index.vue
  55. 7 6
      ui/src/views/training/bccnew/tsnew/index.vue
  56. 754 0
      ui/src/views/training/bccnew/tsnew/index_s.vue
  57. 4 4
      ui/src/views/training/bccnew/tsnew/score.vue
  58. 496 0
      ui/src/views/training/bccnew/tsnew/score_student.vue
  59. 5 5
      ui/src/views/training/bccnew/tsnew/trainingPlan.vue
  60. 120 0
      ui/src/views/training/bccnew/tsnew/trainingPlan_student.vue
  61. 209 21
      ui/src/views/training/bccnew/ysPlan/index.vue
  62. 13 4
      ui/src/views/training/elearn/learn/index.vue
  63. 2 0
      ui/src/views/training/elearn/paper/list.vue
  64. 9 0
      ui/src/views/training/elearn/resource/index.vue
  65. 437 0
      ui/src/views/training/trainingbcc/deviceList.vue
  66. 1280 0
      ui/src/views/training/trainingbcc/index.vue
  67. 1502 0
      ui/src/views/training/trainingbcc/indexbak.vue
  68. 261 0
      ui/src/views/training/trainingbcc/trainingNew.vue
  69. 264 0
      ui/src/views/training/trainingbcc/trainingNon.vue

+ 2 - 2
master/pom.xml

@@ -119,8 +119,8 @@
             <version>${pagehelper.spring.boot.starter.version}</version>
         </dependency>
 
-        <!--阿里数据库连接池 -->
-        <dependency>
+        <dependency>        <!--阿里数据库连接池 -->
+
             <groupId>com.alibaba</groupId>
             <artifactId>druid-spring-boot-starter</artifactId>
             <version>${druid.version}</version>

+ 4 - 0
master/src/main/java/com/ruoyi/framework/web/controller/BaseController.java

@@ -125,4 +125,8 @@ public class BaseController
         LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
         return loginUser.getUser().getNickName();
     }
+    protected String getBaseStaffId () {
+        LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
+        return loginUser.getUser().getStaffId();
+    }
 }

+ 6 - 6
master/src/main/java/com/ruoyi/project/training/bccnew/controller/TTsFirstplanController.java

@@ -38,7 +38,7 @@ public class TTsFirstplanController extends BaseController {
     /**
      * 查询进组培训列表
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:firstplan:list')")
+//    @PreAuthorize("@ss.hasPermi('bccnew:firstplan:list')")
     @GetMapping("/list")
     public TableDataInfo list(TTsFirstplan tTsFirstplan) {
         startPage();
@@ -49,7 +49,7 @@ public class TTsFirstplanController extends BaseController {
     /**
      * 导出进组培训列表
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:firstplan:export')")
+//    @PreAuthorize("@ss.hasPermi('bccnew:firstplan:export')")
     @Log(title = "进组培训", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     public AjaxResult export(TTsFirstplan tTsFirstplan) {
@@ -61,7 +61,7 @@ public class TTsFirstplanController extends BaseController {
     /**
      * 获取进组培训详细信息
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:firstplan:query')")
+//    @PreAuthorize("@ss.hasPermi('bccnew:firstplan:query')")
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id) {
         return AjaxResult.success(tTsFirstplanService.selectTTsFirstplanById(id));
@@ -70,7 +70,7 @@ public class TTsFirstplanController extends BaseController {
     /**
      * 新增进组培训
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:firstplan:add')")
+//    @PreAuthorize("@ss.hasPermi('bccnew:firstplan:add')")
     @Log(title = "进组培训", businessType = BusinessType.INSERT)
     @PostMapping
     public AjaxResult add(@RequestBody TTsFirstplan tTsFirstplan) {
@@ -104,7 +104,7 @@ public class TTsFirstplanController extends BaseController {
     /**
      * 修改进组培训
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:firstplan:edit')")
+//    @PreAuthorize("@ss.hasPermi('bccnew:firstplan:edit')")
     @Log(title = "进组培训", businessType = BusinessType.UPDATE)
     @PutMapping
     public AjaxResult edit(@RequestBody TTsFirstplan tTsFirstplan) {
@@ -114,7 +114,7 @@ public class TTsFirstplanController extends BaseController {
     /**
      * 删除进组培训
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:firstplan:remove')")
+//    @PreAuthorize("@ss.hasPermi('bccnew:firstplan:remove')")
     @Log(title = "进组培训", businessType = BusinessType.DELETE)
     @DeleteMapping("/{ids}")
     public AjaxResult remove(@PathVariable Long[] ids) {

+ 3 - 3
master/src/main/java/com/ruoyi/project/training/bccnew/controller/TTsFirstplanTmplController.java

@@ -94,15 +94,15 @@ public class TTsFirstplanTmplController extends BaseController {
     }
 
     @Log(title = "附件上传", businessType = BusinessType.UPDATE)
-    @PostMapping("/uploadFile")
-    public AjaxResult uploadFile(@RequestParam("file") MultipartFile file, Long id) throws IOException {
+    @PostMapping("/uploadFile/{id}")
+    public AjaxResult uploadFile(@RequestParam("file") MultipartFile file, @PathVariable Long id) throws IOException {
         if (!file.isEmpty()) {
             String url = FileUploadUtils.upload(RuoYiConfig.getFilePath("/bccnew"), file);
             TTsFirstplanTmpl entity = tTsFirstplanTmplService.selectTTsFirstplanTmplById(id);
             entity.setFileUrl(url);
             entity.setFileName(file.getOriginalFilename());
             tTsFirstplanTmplService.updateTTsFirstplanTmpl(entity);
-            return AjaxResult.success();
+            return AjaxResult.success(id);
         }
         return AjaxResult.error("上传失败,请联系管理员");
     }

+ 51 - 41
master/src/main/java/com/ruoyi/project/training/bccnew/controller/TTsNewController.java

@@ -2,7 +2,6 @@ package com.ruoyi.project.training.bccnew.controller;
 
 import com.deepoove.poi.XWPFTemplate;
 import com.deepoove.poi.data.*;
-import com.deepoove.poi.data.style.BorderStyle;
 import com.ruoyi.common.utils.file.FileUploadUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
@@ -26,7 +25,10 @@ import java.io.InputStream;
 import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.*;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -91,10 +93,13 @@ public class TTsNewController extends BaseController {
     /**
      * 查询导师带徒列表
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:tsnew:list')")
+//    @PreAuthorize("@ss.hasPermi('bccnew:tsnew:list')")
     @GetMapping("/list")
     public TableDataInfo list(TTsNew tTsNew) {
         startPage();
+        if ("1".equals(tTsNew.getIsStudent())) {
+                tTsNew.setStaffId(getBaseStaffId());
+        }
         List<TTsNew> list = tTsNewService.selectTTsNewList(tTsNew);
         //线程池
         ExecutorService executorService = Executors.newFixedThreadPool(10);
@@ -128,7 +133,7 @@ public class TTsNewController extends BaseController {
                         List<TTsYsplan> ysPlansNow = tTsYsplanService.selectTTsYsplanListByNewId(tTsYsplan);
                         secAll = ysPlansAll.size();
                         secNow = ysPlansNow.size();
-                    }else if (t.getPlanType() == 3) {
+                    } else if (t.getPlanType() == 3) {
                         TTsFlplan tTsFlplan = new TTsFlplan();
                         tTsFlplan.setNewId(t.getNewId());
                         List<TTsFlplan> flPlansAll = tTsFlplanService.selectTTsFlplanListByNewId(tTsFlplan);
@@ -136,7 +141,7 @@ public class TTsNewController extends BaseController {
                         List<TTsFlplan> flPlansNow = tTsFlplanService.selectTTsFlplanListByNewId(tTsFlplan);
                         secAll = flPlansAll.size();
                         secNow = flPlansNow.size();
-                    }else if (t.getPlanType() == 4) {
+                    } else if (t.getPlanType() == 4) {
                         TTsFtplan tTsFtplan = new TTsFtplan();
                         tTsFtplan.setNewId(t.getNewId());
                         List<TTsFtplan> ftPlansAll = tTsFtplanService.selectTTsFtplanListByNewId(tTsFtplan);
@@ -171,7 +176,7 @@ public class TTsNewController extends BaseController {
     /**
      * 导出导师带徒列表
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:tsnew:export')")
+//    @PreAuthorize("@ss.hasPermi('bccnew:tsnew:export')")
     @Log(title = "导师带徒", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     public AjaxResult export(TTsNew tTsNew) {
@@ -183,7 +188,7 @@ public class TTsNewController extends BaseController {
     /**
      * 获取导师带徒详细信息
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:tsnew:query')")
+//    @PreAuthorize("@ss.hasPermi('bccnew:tsnew:query')")
     @GetMapping(value = "/{newId}")
     public AjaxResult getInfo(@PathVariable("newId") Long newId) {
         return AjaxResult.success(tTsNewService.selectTTsNewById(newId));
@@ -192,7 +197,7 @@ public class TTsNewController extends BaseController {
     /**
      * 新增导师带徒
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:tsnew:add')")
+//    @PreAuthorize("@ss.hasPermi('bccnew:tsnew:add')")
     @Log(title = "导师带徒", businessType = BusinessType.INSERT)
     @PostMapping
     public AjaxResult add(@RequestBody TTsNew tTsNew) throws IOException {
@@ -316,7 +321,7 @@ public class TTsNewController extends BaseController {
         params.put("traineeSignature", Pictures.ofLocal(fileName(apprentice.getSignUrl())).size(100, 40).create());
         params.put("tutor", Texts.of(mentor.getNickName()).create());
         params.put("trainee", Texts.of(apprentice.getNickName()).create());
-        String[][] planList = null;
+        RowRenderData[] planList = null;
         String post = "";
         Long planType = tTsNew.getPlanType();
         Long newId = tTsNew.getNewId();
@@ -325,48 +330,48 @@ public class TTsNewController extends BaseController {
             TTsLjplan ljplan = new TTsLjplan();
             ljplan.setNewId(newId);
             List<TTsLjplan> tTsLjplans = tTsLjplanService.selectTTsLjplanListByNewId(ljplan);
-            planList = new String[tTsLjplans.size()+1][];
-            planList[0] = new String[] { "Training Plan 详细计划", "Planned Training Date 计划培训日期", "Training Topics 培训主题", "Expected Training Requirement 培训预期达到的要求" };
+            planList = new RowRenderData[tTsLjplans.size() + 1];
+            planList[0] = Rows.create("Training Plan 详细计划", "Planned Training Date 计划培训日期", "Training Topics 培训主题", "Expected Training Requirement 培训预期达到的要求");
             int i = 0;
             for (TTsLjplan plan : tTsLjplans) {
                 i++;
-                planList[i] = new String[] { plan.getDetailPlan(), "", plan.getTopic(), "学习结束考核,且考试成绩达到80分以上" };
+                planList[i] = Rows.create(plan.getDetailPlan(), "", plan.getTopic(), "学习结束考核,且考试成绩达到80分以上");
             }
         } else if (planType == 2L) {
             post = "压缩";
             TTsYsplan ysplan = new TTsYsplan();
             ysplan.setNewId(newId);
             List<TTsYsplan> tTsYsplans = tTsYsplanService.selectTTsYsplanListByNewId(ysplan);
-            planList = new String[tTsYsplans.size()+1][];
-            planList[0] = new String[] { "Training Plan 详细计划", "Planned Training Date 计划培训日期", "Training Topics 培训主题", "Expected Training Requirement 培训预期达到的要求" };
+            planList = new RowRenderData[tTsYsplans.size() + 1];
+            planList[0] = Rows.create("Training Plan 详细计划", "Planned Training Date 计划培训日期", "Training Topics 培训主题", "Expected Training Requirement 培训预期达到的要求");
             int i = 0;
             for (TTsYsplan plan : tTsYsplans) {
                 i++;
-                planList[i] = new String[] { plan.getDetailPlan(), "", plan.getTopic(), "学习结束考核,且考试成绩达到80分以上" };
+                planList[i] = Rows.create(plan.getDetailPlan(), "", plan.getTopic(), "学习结束考核,且考试成绩达到80分以上");
             }
         } else if (planType == 3L) {
             post = "分离";
             TTsFlplan flplan = new TTsFlplan();
             flplan.setNewId(newId);
             List<TTsFlplan> tTsFlplans = tTsFlplanService.selectTTsFlplanListByNewId(flplan);
-            planList = new String[tTsFlplans.size()+1][];
-            planList[0] = new String[] { "Training Plan 详细计划", "Planned Training Date 计划培训日期", "Training Topics 培训主题", "Expected Training Requirement 培训预期达到的要求" };
+            planList = new RowRenderData[tTsFlplans.size() + 1];
+            planList[0] = Rows.create("Training Plan 详细计划", "Planned Training Date 计划培训日期", "Training Topics 培训主题", "Expected Training Requirement 培训预期达到的要求");
             int i = 0;
             for (TTsFlplan plan : tTsFlplans) {
                 i++;
-                planList[i] = new String[] { plan.getDetailPlan(), "", plan.getTopic(), "学习结束考核,且考试成绩达到80分以上" };
+                planList[i] = Rows.create(plan.getDetailPlan(), "", plan.getTopic(), "学习结束考核,且考试成绩达到80分以上");
             }
         } else if (planType == 4L) {
             post = "芳烃";
             TTsFtplan ftplan = new TTsFtplan();
             ftplan.setNewId(newId);
             List<TTsFtplan> tTsFtplans = tTsFtplanService.selectTTsFtplanListByNewId(ftplan);
-            planList = new String[tTsFtplans.size()+1][];
-            planList[0] = new String[] { "Training Plan 详细计划", "Planned Training Date 计划培训日期", "Training Topics 培训主题", "Expected Training Requirement 培训预期达到的要求" };
+            planList = new RowRenderData[tTsFtplans.size() + 1];
+            planList[0] = Rows.create("Training Plan 详细计划", "Planned Training Date 计划培训日期", "Training Topics 培训主题", "Expected Training Requirement 培训预期达到的要求");
             int i = 0;
             for (TTsFtplan plan : tTsFtplans) {
                 i++;
-                planList[i] = new String[] { plan.getDetailPlan(), "", plan.getTopic(), "学习结束考核,且考试成绩达到80分以上" };
+                planList[i] = Rows.create(plan.getDetailPlan(), "", plan.getTopic(), "学习结束考核,且考试成绩达到80分以上");
             }
         }
         params.put("tutorPost", Texts.of(post).create());
@@ -396,7 +401,7 @@ public class TTsNewController extends BaseController {
         params.put("traineeSignature", Pictures.ofLocal(fileName(apprentice.getSignUrl())).size(100, 40).create());
         params.put("tutor", Texts.of(mentor.getNickName()).create());
         params.put("trainee", Texts.of(apprentice.getNickName()).create());
-        String[][] planList = null;
+        RowRenderData[] planList = null;
         String post = "";
         Long planType = tTsNew.getPlanType();
         Long newId = tTsNew.getNewId();
@@ -405,57 +410,62 @@ public class TTsNewController extends BaseController {
             TTsLjplan ljplan = new TTsLjplan();
             ljplan.setNewId(newId);
             List<TTsLjplan> tTsLjplans = tTsLjplanService.selectTTsLjplanListByNewId(ljplan);
-            planList = new String[tTsLjplans.size()+2][];
-            planList[0] = new String[] { "", "Training Topics 培训主题", "Training Date 培训日期", "Training Effectiveness Evaluation* 培训效果评价*", "Training Effectiveness Acknowledgement 培训效果确认", "", "Mentor comment 导师意见" };
-            planList[1] = new String[] { "", "", "", "", "Trainee 学徒", "Tutor 导师", "Proceed to next topic or not 是否转至下一主题" };
+            planList = new RowRenderData[tTsLjplans.size() + 2];
+            planList[0] = Rows.create("Training Topics 培训主题", "", "Training Date 培训日期", "Training Effectiveness Evaluation* 培训效果评价*", "Training Effectiveness Acknowledgement 培训效果确认", "", "Mentor comment 导师意见");
+            planList[1] = Rows.create("", "", "", "", "Trainee 学徒", "Tutor 导师", "Proceed to next topic or not 是否转至下一主题");
             int i = 1;
             for (TTsLjplan plan : tTsLjplans) {
                 i++;
-                planList[i] = new String[] { plan.getDetailPlan(), plan.getTopic(), "", "", "", "", "" };
+                planList[i] = Rows.create(plan.getDetailPlan(), plan.getTopic(), "", "", "", "", "");
             }
         } else if (planType == 2L) {
             post = "压缩";
             TTsYsplan ysplan = new TTsYsplan();
             ysplan.setNewId(newId);
             List<TTsYsplan> tTsYsplans = tTsYsplanService.selectTTsYsplanListByNewId(ysplan);
-            planList = new String[tTsYsplans.size()+2][];
-            planList[0] = new String[] { "", "Training Topics 培训主题", "Training Date 培训日期", "Training Effectiveness Evaluation* 培训效果评价*", "Training Effectiveness Acknowledgement 培训效果确认", "", "Mentor comment 导师意见" };
-            planList[1] = new String[] { "", "", "", "", "Trainee 学徒", "Tutor 导师", "Proceed to next topic or not 是否转至下一主题" };
+            planList = new RowRenderData[tTsYsplans.size() + 2];
+            planList[0] = Rows.create("Training Topics 培训主题", "", "Training Date 培训日期", "Training Effectiveness Evaluation* 培训效果评价*", "Training Effectiveness Acknowledgement 培训效果确认", "", "Mentor comment 导师意见");
+            planList[1] = Rows.create("", "", "", "", "Trainee 学徒", "Tutor 导师", "Proceed to next topic or not 是否转至下一主题");
             int i = 1;
             for (TTsYsplan plan : tTsYsplans) {
                 i++;
-                planList[i] = new String[] { plan.getDetailPlan(), plan.getTopic(), "", "", "", "", "" };
+                planList[i] = Rows.create(plan.getDetailPlan(), plan.getTopic(), "", "", "", "", "");
             }
         } else if (planType == 3L) {
             post = "分离";
             TTsFlplan flplan = new TTsFlplan();
             flplan.setNewId(newId);
             List<TTsFlplan> tTsFlplans = tTsFlplanService.selectTTsFlplanListByNewId(flplan);
-            planList = new String[tTsFlplans.size()+2][];
-            planList[0] = new String[] { "", "Training Topics 培训主题", "Training Date 培训日期", "Training Effectiveness Evaluation* 培训效果评价*", "Training Effectiveness Acknowledgement 培训效果确认", "", "Mentor comment 导师意见" };
-            planList[1] = new String[] { "", "", "", "", "Trainee 学徒", "Tutor 导师", "Proceed to next topic or not 是否转至下一主题" };
+            planList = new RowRenderData[tTsFlplans.size() + 2];
+            planList[0] = Rows.create("Training Topics 培训主题", "", "Training Date 培训日期", "Training Effectiveness Evaluation* 培训效果评价*", "Training Effectiveness Acknowledgement 培训效果确认", "", "Mentor comment 导师意见");
+            planList[1] = Rows.create("", "", "", "", "Trainee 学徒", "Tutor 导师", "Proceed to next topic or not 是否转至下一主题");
             int i = 1;
             for (TTsFlplan plan : tTsFlplans) {
                 i++;
-                planList[i] = new String[] { plan.getDetailPlan(), plan.getTopic(), "", "", "", "", "" };
+                planList[i] = Rows.create(plan.getDetailPlan(), plan.getTopic(), "", "", "", "", "");
             }
         } else if (planType == 4L) {
             post = "芳烃";
             TTsFtplan ftplan = new TTsFtplan();
             ftplan.setNewId(newId);
             List<TTsFtplan> tTsFtplans = tTsFtplanService.selectTTsFtplanListByNewId(ftplan);
-            planList = new String[tTsFtplans.size()+2][];
-            planList[0] = new String[] { "", "Training Topics 培训主题", "Training Date 培训日期", "Training Effectiveness Evaluation* 培训效果评价*", "Training Effectiveness Acknowledgement 培训效果确认", "", "Mentor comment 导师意见" };
-            planList[1] = new String[] { "", "", "", "", "Trainee 学徒", "Tutor 导师", "Proceed to next topic or not 是否转至下一主题" };
+            planList = new RowRenderData[tTsFtplans.size() + 2];
+            planList[0] = Rows.create("Training Topics 培训主题", "", "Training Date 培训日期", "Training Effectiveness Evaluation* 培训效果评价*", "Training Effectiveness Acknowledgement 培训效果确认", "", "Mentor comment 导师意见");
+            planList[1] = Rows.create("", "", "", "", "Trainee 学徒", "Tutor 导师", "Proceed to next topic or not 是否转至下一主题");
             int i = 1;
             for (TTsFtplan plan : tTsFtplans) {
                 i++;
-                planList[i] = new String[] { plan.getDetailPlan(), plan.getTopic(), "", "", "", "", "" };
+                planList[i] = Rows.create(plan.getDetailPlan(), plan.getTopic(), "", "", "", "", "");
             }
         }
         params.put("tutorPost", Texts.of(post).create());
         params.put("traineePost", Texts.of(post).create());
-        params.put("planList", Tables.of(planList).create());
+        MergeCellRule rule = MergeCellRule.builder()
+                .map(MergeCellRule.Grid.of(0, 0), MergeCellRule.Grid.of(1, 1))
+                .map(MergeCellRule.Grid.of(0, 2), MergeCellRule.Grid.of(1, 2))
+                .map(MergeCellRule.Grid.of(0, 4), MergeCellRule.Grid.of(0, 5))
+                .map(MergeCellRule.Grid.of(0, 3), MergeCellRule.Grid.of(1, 3)).build();
+        params.put("planList", Tables.of(planList).mergeRule(rule).create());
         // 渲染文本
         return params;
     }
@@ -511,7 +521,7 @@ public class TTsNewController extends BaseController {
     /**
      * 修改导师带徒
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:tsnew:edit')")
+//    @PreAuthorize("@ss.hasPermi('bccnew:tsnew:edit')")
     @Log(title = "导师带徒", businessType = BusinessType.UPDATE)
     @PutMapping
     public AjaxResult edit(@RequestBody TTsNew tTsNew) {
@@ -521,7 +531,7 @@ public class TTsNewController extends BaseController {
     /**
      * 删除导师带徒
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:tsnew:remove')")
+//    @PreAuthorize("@ss.hasPermi('bccnew:tsnew:remove')")
     @Log(title = "导师带徒", businessType = BusinessType.DELETE)
     @DeleteMapping("/{newIds}")
     public AjaxResult remove(@PathVariable Long[] newIds) {

+ 8 - 8
master/src/main/java/com/ruoyi/project/training/bccnew/controller/TTsYsplanTmplController.java

@@ -26,7 +26,7 @@ import org.springframework.web.multipart.MultipartFile;
  * @date 2024-06-13
  */
 @RestController
-@RequestMapping("/bccnew/yaPlan")
+@RequestMapping("/bccnew/ysPlan")
 public class TTsYsplanTmplController extends BaseController
 {
     @Autowired
@@ -35,7 +35,7 @@ public class TTsYsplanTmplController extends BaseController
     /**
      * 查询压缩培训模版列表
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:yaPlan:list')")
+    @PreAuthorize("@ss.hasPermi('bccnew:ysPlan:list')")
     @GetMapping("/list")
     public TableDataInfo list(TTsYsplanTmpl tTsYsplanTmpl)
     {
@@ -47,20 +47,20 @@ public class TTsYsplanTmplController extends BaseController
     /**
      * 导出压缩培训模版列表
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:yaPlan:export')")
+    @PreAuthorize("@ss.hasPermi('bccnew:ysPlan:export')")
     @Log(title = "压缩培训模版", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     public AjaxResult export(TTsYsplanTmpl tTsYsplanTmpl)
     {
         List<TTsYsplanTmpl> list = tTsYsplanTmplService.selectTTsYsplanTmplList(tTsYsplanTmpl);
         ExcelUtil<TTsYsplanTmpl> util = new ExcelUtil<TTsYsplanTmpl>(TTsYsplanTmpl.class);
-        return util.exportExcel(list, "yaPlan");
+        return util.exportExcel(list, "ysPlan");
     }
 
     /**
      * 获取压缩培训模版详细信息
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:yaPlan:query')")
+    @PreAuthorize("@ss.hasPermi('bccnew:ysPlan:query')")
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id)
     {
@@ -70,7 +70,7 @@ public class TTsYsplanTmplController extends BaseController
     /**
      * 新增压缩培训模版
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:yaPlan:add')")
+    @PreAuthorize("@ss.hasPermi('bccnew:ysPlan:add')")
     @Log(title = "压缩培训模版", businessType = BusinessType.INSERT)
     @PostMapping
     public AjaxResult add(@RequestBody TTsYsplanTmpl tTsYsplanTmpl)
@@ -81,7 +81,7 @@ public class TTsYsplanTmplController extends BaseController
     /**
      * 修改压缩培训模版
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:yaPlan:edit')")
+    @PreAuthorize("@ss.hasPermi('bccnew:ysPlan:edit')")
     @Log(title = "压缩培训模版", businessType = BusinessType.UPDATE)
     @PutMapping
     public AjaxResult edit(@RequestBody TTsYsplanTmpl tTsYsplanTmpl)
@@ -92,7 +92,7 @@ public class TTsYsplanTmplController extends BaseController
     /**
      * 删除压缩培训模版
      */
-    @PreAuthorize("@ss.hasPermi('bccnew:yaPlan:remove')")
+    @PreAuthorize("@ss.hasPermi('bccnew:ysPlan:remove')")
     @Log(title = "压缩培训模版", businessType = BusinessType.DELETE)
 	@DeleteMapping("/{ids}")
     public AjaxResult remove(@PathVariable Long[] ids)

+ 10 - 0
master/src/main/java/com/ruoyi/project/training/bccnew/domain/TTsNew.java

@@ -17,6 +17,8 @@ public class TTsNew extends BaseEntity
 {
     private static final long serialVersionUID = 1L;
 
+    private String isStudent;
+
     /** 唯一标识ID */
     private Long newId;
 
@@ -104,6 +106,14 @@ public class TTsNew extends BaseEntity
     /** 导师带徒考评表word地址 */
     private String appraisalFormWordPath;
 
+    public String getIsStudent() {
+        return isStudent;
+    }
+
+    public void setIsStudent(String isStudent) {
+        this.isStudent = isStudent;
+    }
+
     public String getMentorAgreementWordPath() {
         return mentorAgreementWordPath;
     }

+ 0 - 1
master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsFirstplanMapper.java

@@ -27,7 +27,6 @@ public interface TTsFirstplanMapper
      * @param tTsFirstplan 进组培训
      * @return 进组培训集合
      */
-    @DataScope(deptAlias = "d")
     public List<TTsFirstplan> selectTTsFirstplanList(TTsFirstplan tTsFirstplan);
 
     /**

+ 0 - 1
master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsFirstplanTmplMapper.java

@@ -26,7 +26,6 @@ public interface TTsFirstplanTmplMapper
      * @param tTsFirstplanTmpl 进组培训模版
      * @return 进组培训模版集合
      */
-    @DataScope(deptAlias = "d")
     public List<TTsFirstplanTmpl> selectTTsFirstplanTmplList(TTsFirstplanTmpl tTsFirstplanTmpl);
 
     /**

+ 0 - 1
master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsFlplanMapper.java

@@ -26,7 +26,6 @@ public interface TTsFlplanMapper
      * @param tTsFlplan 分离培训
      * @return 分离培训集合
      */
-    @DataScope(deptAlias = "d")
     public List<TTsFlplan> selectTTsFlplanList(TTsFlplan tTsFlplan);
 
     public List<TTsFlplan> selectTTsFlplanListByNewId(TTsFlplan tTsFlplan);

+ 0 - 1
master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsFlplanTmplMapper.java

@@ -26,7 +26,6 @@ public interface TTsFlplanTmplMapper
      * @param tTsFlplanTmpl 分离培训模版
      * @return 分离培训模版集合
      */
-    @DataScope(deptAlias = "d")
     public List<TTsFlplanTmpl> selectTTsFlplanTmplList(TTsFlplanTmpl tTsFlplanTmpl);
 
     /**

+ 0 - 1
master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsFtplanMapper.java

@@ -26,7 +26,6 @@ public interface TTsFtplanMapper
      * @param tTsFtplan 芳烃培训
      * @return 芳烃培训集合
      */
-    @DataScope(deptAlias = "d")
     public List<TTsFtplan> selectTTsFtplanList(TTsFtplan tTsFtplan);
     public List<TTsFtplan> selectTTsFtplanListByNewId(TTsFtplan tTsFtplan);
 

+ 0 - 1
master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsFtplanTmplMapper.java

@@ -26,7 +26,6 @@ public interface TTsFtplanTmplMapper
      * @param tTsFtplanTmpl 芳烃培训模版
      * @return 芳烃培训模版集合
      */
-    @DataScope(deptAlias = "d")
     public List<TTsFtplanTmpl> selectTTsFtplanTmplList(TTsFtplanTmpl tTsFtplanTmpl);
 
     /**

+ 0 - 1
master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsLjplanMapper.java

@@ -26,7 +26,6 @@ public interface TTsLjplanMapper
      * @param tTsLjplan 裂解培训
      * @return 裂解培训集合
      */
-    @DataScope(deptAlias = "d")
     public List<TTsLjplan> selectTTsLjplanList(TTsLjplan tTsLjplan);
     public List<TTsLjplan> selectTTsLjplanListByNewId(TTsLjplan tTsLjplan);
 

+ 0 - 1
master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsLjplanTmplMapper.java

@@ -26,7 +26,6 @@ public interface TTsLjplanTmplMapper
      * @param tTsLjplanTmpl 裂解培训模版
      * @return 裂解培训模版集合
      */
-    @DataScope(deptAlias = "d")
     public List<TTsLjplanTmpl> selectTTsLjplanTmplList(TTsLjplanTmpl tTsLjplanTmpl);
 
     /**

+ 0 - 1
master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsNewMapper.java

@@ -26,7 +26,6 @@ public interface TTsNewMapper
      * @param tTsNew 导师带徒
      * @return 导师带徒集合
      */
-    @DataScope(deptAlias = "d")
     public List<TTsNew> selectTTsNewList(TTsNew tTsNew);
 
     /**

+ 0 - 1
master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsYsplanMapper.java

@@ -26,7 +26,6 @@ public interface TTsYsplanMapper
      * @param tTsYsplan 转岗培训
      * @return 转岗培训集合
      */
-    @DataScope(deptAlias = "d")
     public List<TTsYsplan> selectTTsYsplanList(TTsYsplan tTsYsplan);
     public List<TTsYsplan> selectTTsYsplanListByNewId(TTsYsplan tTsYsplan);
 

+ 0 - 1
master/src/main/java/com/ruoyi/project/training/bccnew/mapper/TTsYsplanTmplMapper.java

@@ -26,7 +26,6 @@ public interface TTsYsplanTmplMapper
      * @param tTsYsplanTmpl 压缩培训模版
      * @return 压缩培训模版集合
      */
-    @DataScope(deptAlias = "d")
     public List<TTsYsplanTmpl> selectTTsYsplanTmplList(TTsYsplanTmpl tTsYsplanTmpl);
 
     /**

+ 162 - 0
master/src/main/java/com/ruoyi/project/training/controller/TTrainingbccController.java

@@ -0,0 +1,162 @@
+package com.ruoyi.project.training.controller;
+
+import java.util.List;
+
+import com.ruoyi.project.training.domain.TTrainingbccDevice;
+import com.ruoyi.project.training.mapper.TTrainingbccDeviceMapper;
+import com.ruoyi.project.training.mapper.TTrainingbccMapper;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.project.training.domain.TTrainingbcc;
+import com.ruoyi.project.training.service.ITTrainingbccService;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.framework.web.page.TableDataInfo;
+
+import javax.annotation.Resource;
+
+/**
+ * 装置培训跟踪bController
+ *
+ * @author ssy
+ * @date 2024-06-19
+ */
+@RestController
+@RequestMapping("/training/trainingbcc")
+public class TTrainingbccController extends BaseController
+{
+    @Autowired
+    private ITTrainingbccService tTrainingbccService;
+    @Resource
+    private TTrainingbccDeviceMapper tTrainingbccDeviceMapper;
+    @Resource
+    private TTrainingbccMapper tTrainingbccMapper;
+    /**
+     * 查询装置培训跟踪b列表
+     */
+    @PreAuthorize("@ss.hasPermi('training:trainingbcc:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(TTrainingbcc tTrainingbcc)
+    {
+        startPage();
+        List<TTrainingbcc> list = tTrainingbccService.selectTTrainingbccList(tTrainingbcc);
+        for (TTrainingbcc t: list
+             ) {
+            TTrainingbccDevice device = new TTrainingbccDevice();
+            device.setRegularId(t.getId());
+            int all = tTrainingbccDeviceMapper.countTraining(device);
+
+            device.setExamState(1l);
+            int finish = tTrainingbccDeviceMapper.countTraining(device);
+            t.setHaveTraining(finish);
+            t.setMustTraining(all);
+            if (all != 0) {
+                String per = String.valueOf(finish* 100 / all);
+                t.setTrainingPercent(per);
+            }else {
+                t.setTrainingPercent("0");
+            }
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出装置培训跟踪b列表
+     */
+    @PreAuthorize("@ss.hasPermi('training:trainingbcc:export')")
+    @Log(title = "装置培训跟踪b", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(TTrainingbcc tTrainingbcc)
+    {
+        List<TTrainingbcc> list = tTrainingbccService.selectTTrainingbccList(tTrainingbcc);
+        ExcelUtil<TTrainingbcc> util = new ExcelUtil<TTrainingbcc>(TTrainingbcc.class);
+        return util.exportExcel(list, "trainingbcc");
+    }
+
+    /**
+     * 获取装置培训跟踪b详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('training:trainingbcc:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(tTrainingbccService.selectTTrainingbccById(id));
+    }
+
+    /**
+     * 获取装置培训跟踪b详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('training:trainingbcc:query')")
+    @GetMapping(value = "/staffIds/{id}")
+    public AjaxResult getStaffIds(@PathVariable("id") Long id)
+    {
+        TTrainingbcc tTrainingbcc = tTrainingbccService.selectTTrainingbccById(id);
+        TTrainingbccDevice param = new TTrainingbccDevice();
+        param.setRegularId(id);
+        List<TTrainingbccDevice> list = tTrainingbccDeviceMapper.selectTTrainingbccDeviceList(param);
+        String staffIds = "";
+        for (TTrainingbccDevice t : list
+             ) {
+            staffIds = staffIds + "," + t.getStaffId();
+        }
+        tTrainingbcc.setStaffIds(staffIds);
+        return AjaxResult.success(tTrainingbcc);
+    }
+
+
+    /**
+     * 新增装置培训跟踪b
+     */
+    @PreAuthorize("@ss.hasPermi('training:trainingbcc:add')")
+    @Log(title = "装置培训跟踪b", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody TTrainingbcc tTrainingbcc)
+    {
+        return toAjax(tTrainingbccService.insertTTrainingbcc(tTrainingbcc));
+    }
+
+    /**
+     * 修改装置培训跟踪b
+     */
+    @PreAuthorize("@ss.hasPermi('training:trainingbcc:edit')")
+    @Log(title = "装置培训跟踪b", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody TTrainingbcc tTrainingbcc)
+    {
+        return toAjax(tTrainingbccService.updateTTrainingbcc(tTrainingbcc));
+    }
+
+    /**
+     * 修改装置培训跟踪b
+     */
+    @PreAuthorize("@ss.hasPermi('training:trainingbcc:edit')")
+    @Log(title = "装置培训跟踪b", businessType = BusinessType.UPDATE)
+    @PostMapping(value = "/updateStaffIds")
+    public AjaxResult updateStaffIds(@RequestBody TTrainingbcc tTrainingbcc)
+    {
+        return toAjax(tTrainingbccService.updateStaffIds(tTrainingbcc));
+    }
+
+
+    /**
+     * 删除装置培训跟踪b
+     */
+    @PreAuthorize("@ss.hasPermi('training:trainingbcc:remove')")
+    @Log(title = "装置培训跟踪b", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(tTrainingbccService.deleteTTrainingbccByIds(ids));
+    }
+}

+ 112 - 0
master/src/main/java/com/ruoyi/project/training/controller/TTrainingbccDeviceController.java

@@ -0,0 +1,112 @@
+package com.ruoyi.project.training.controller;
+
+import java.util.List;
+
+import com.ruoyi.project.training.domain.TTrainingbcc;
+import com.ruoyi.project.training.service.ITTrainingbccService;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.project.training.domain.TTrainingbccDevice;
+import com.ruoyi.project.training.service.ITTrainingbccDeviceService;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.framework.web.page.TableDataInfo;
+
+/**
+ * 人员-装置级培训关系Controller
+ *
+ * @author ssy
+ * @date 2024-06-19
+ */
+@RestController
+@RequestMapping("/training/bccdevice")
+public class TTrainingbccDeviceController extends BaseController
+{
+    @Autowired
+    private ITTrainingbccDeviceService tTrainingbccDeviceService;
+    @Autowired
+    private ITTrainingbccService tTrainingbccService;
+    /**
+     * 查询人员-装置级培训关系列表
+     */
+    @PreAuthorize("@ss.hasPermi('training:device:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(TTrainingbccDevice tTrainingbccDevice)
+    {
+        startPage();
+        List<TTrainingbccDevice> list = tTrainingbccDeviceService.selectTTrainingbccDeviceList(tTrainingbccDevice);
+        for (TTrainingbccDevice t: list
+             ) {
+          TTrainingbcc tTrainingbcc = tTrainingbccService.selectTTrainingbccById(t.getRegularId());
+            t.setTrainingbcc(tTrainingbcc);
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出人员-装置级培训关系列表
+     */
+    @PreAuthorize("@ss.hasPermi('training:device:export')")
+    @Log(title = "人员-装置级培训关系", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(TTrainingbccDevice tTrainingbccDevice)
+    {
+        List<TTrainingbccDevice> list = tTrainingbccDeviceService.selectTTrainingbccDeviceList(tTrainingbccDevice);
+        ExcelUtil<TTrainingbccDevice> util = new ExcelUtil<TTrainingbccDevice>(TTrainingbccDevice.class);
+        return util.exportExcel(list, "device");
+    }
+
+    /**
+     * 获取人员-装置级培训关系详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('training:device:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(tTrainingbccDeviceService.selectTTrainingbccDeviceById(id));
+    }
+
+    /**
+     * 新增人员-装置级培训关系
+     */
+    @PreAuthorize("@ss.hasPermi('training:device:add')")
+    @Log(title = "人员-装置级培训关系", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody TTrainingbccDevice tTrainingbccDevice)
+    {
+        return toAjax(tTrainingbccDeviceService.insertTTrainingbccDevice(tTrainingbccDevice));
+    }
+
+    /**
+     * 修改人员-装置级培训关系
+     */
+    @PreAuthorize("@ss.hasPermi('training:device:edit')")
+    @Log(title = "人员-装置级培训关系", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody TTrainingbccDevice tTrainingbccDevice)
+    {
+        return toAjax(tTrainingbccDeviceService.updateTTrainingbccDevice(tTrainingbccDevice));
+    }
+
+    /**
+     * 删除人员-装置级培训关系
+     */
+    @PreAuthorize("@ss.hasPermi('training:device:remove')")
+    @Log(title = "人员-装置级培训关系", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(tTrainingbccDeviceService.deleteTTrainingbccDeviceByIds(ids));
+    }
+}

+ 524 - 0
master/src/main/java/com/ruoyi/project/training/domain/TTrainingbcc.java

@@ -0,0 +1,524 @@
+package com.ruoyi.project.training.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import com.ruoyi.framework.web.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 装置培训跟踪b对象 t_trainingbcc
+ *
+ * @author ssy
+ * @date 2024-06-19
+ */
+public class TTrainingbcc extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 唯一标识ID */
+    private Long id;
+
+    /** 装置名称 */
+    @Excel(name = "装置名称")
+    private String plantCode;
+
+    /** 培训课程 */
+    @Excel(name = "培训课程")
+    private String course;
+
+    /** 课程代码 */
+    @Excel(name = "课程代码")
+    private String courseid;
+
+    /** 培训周期 */
+    @Excel(name = "培训周期")
+    private String period;
+
+    /** 课时 */
+    @Excel(name = "课时")
+    private String duration;
+
+    /** 培训人 */
+    @Excel(name = "培训人")
+    private String trainer;
+
+    /** 培训岗位 */
+    @Excel(name = "培训岗位")
+    private String position;
+
+    /** 删除状态 */
+    private Long delFlag;
+
+    /** 创建人 */
+    @Excel(name = "创建人")
+    private String createrCode;
+
+    /** 创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd" , timezone = "GMT+8")
+    @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date createdate;
+
+    /** 修改人 */
+    @Excel(name = "修改人")
+    private String updaterCode;
+
+    /** 修改时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd" , timezone = "GMT+8")
+    @Excel(name = "修改时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date updatedate;
+
+    /** 备注 */
+    @Excel(name = "备注")
+    private String remarks;
+
+    /** 部门编号 */
+    @Excel(name = "部门编号")
+    private Long deptId;
+
+    /** 培训开始日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd" , timezone = "GMT+8")
+    @Excel(name = "培训开始日期", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date courseStartdate;
+
+    /** 培训结束日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd" , timezone = "GMT+8")
+    @Excel(name = "培训结束日期", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date courseEnddate;
+
+    /** 是否完成 */
+    @Excel(name = "是否完成")
+    private Long isfinish;
+
+    /** 确认人 */
+    @Excel(name = "确认人")
+    private String confirmor;
+
+    /** 年份 */
+    @Excel(name = "年份")
+    private String years;
+
+    /** 培训内容 */
+    @Excel(name = "培训内容")
+    private String content;
+
+    /** 未参会人员名单 */
+    @Excel(name = "未参会人员名单")
+    private String nonParticipants;
+
+    /** 部门 */
+    @Excel(name = "部门")
+    private String unit;
+
+    /** 培训分类 */
+    @Excel(name = "培训分类")
+    private String trainingType;
+
+    /** 图片url */
+    @Excel(name = "图片url")
+    private String picUrl;
+
+    /** 装置级培训ID */
+    @Excel(name = "装置级培训ID")
+    private Long regularId;
+
+    /** 指定岗位 */
+    @Excel(name = "指定岗位")
+    private String designatedPosition;
+
+    /** 指定人员 */
+    @Excel(name = "指定人员")
+    private String designatedStaff;
+
+    /** 学习链接 */
+    @Excel(name = "学习链接")
+    private String fileUrl;
+
+    /** 文件名 */
+    @Excel(name = "文件名")
+    private String fileName;
+
+    /** 需要学习时长 */
+    @Excel(name = "需要学习时长")
+    private Long timerNeed;
+
+    private int haveTraining;
+
+    private int mustTraining;
+    private String trainingPercent;
+    /** 考试ID */
+    @Excel(name = "考试ID")
+    private Long examId;
+
+    private String deptName;
+
+    private String staffIds;
+
+    public int getHaveTraining() {
+        return haveTraining;
+    }
+
+    public void setHaveTraining(int haveTraining) {
+        this.haveTraining = haveTraining;
+    }
+
+    public int getMustTraining() {
+        return mustTraining;
+    }
+
+    public void setMustTraining(int mustTraining) {
+        this.mustTraining = mustTraining;
+    }
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+    public void setPlantCode(String plantCode)
+    {
+        this.plantCode = plantCode;
+    }
+
+    public String getPlantCode()
+    {
+        return plantCode;
+    }
+    public void setCourse(String course)
+    {
+        this.course = course;
+    }
+
+    public String getCourse()
+    {
+        return course;
+    }
+    public void setCourseid(String courseid)
+    {
+        this.courseid = courseid;
+    }
+
+    public String getCourseid()
+    {
+        return courseid;
+    }
+    public void setPeriod(String period)
+    {
+        this.period = period;
+    }
+
+    public String getPeriod()
+    {
+        return period;
+    }
+    public void setDuration(String duration)
+    {
+        this.duration = duration;
+    }
+
+    public String getDuration()
+    {
+        return duration;
+    }
+    public void setTrainer(String trainer)
+    {
+        this.trainer = trainer;
+    }
+
+    public String getTrainer()
+    {
+        return trainer;
+    }
+    public void setPosition(String position)
+    {
+        this.position = position;
+    }
+
+    public String getPosition()
+    {
+        return position;
+    }
+    public void setDelFlag(Long delFlag)
+    {
+        this.delFlag = delFlag;
+    }
+
+    public Long getDelFlag()
+    {
+        return delFlag;
+    }
+    public void setCreaterCode(String createrCode)
+    {
+        this.createrCode = createrCode;
+    }
+
+    public String getCreaterCode()
+    {
+        return createrCode;
+    }
+    public void setCreatedate(Date createdate)
+    {
+        this.createdate = createdate;
+    }
+
+    public Date getCreatedate()
+    {
+        return createdate;
+    }
+    public void setUpdaterCode(String updaterCode)
+    {
+        this.updaterCode = updaterCode;
+    }
+
+    public String getUpdaterCode()
+    {
+        return updaterCode;
+    }
+    public void setUpdatedate(Date updatedate)
+    {
+        this.updatedate = updatedate;
+    }
+
+    public Date getUpdatedate()
+    {
+        return updatedate;
+    }
+    public void setRemarks(String remarks)
+    {
+        this.remarks = remarks;
+    }
+
+    public String getRemarks()
+    {
+        return remarks;
+    }
+    public void setDeptId(Long deptId)
+    {
+        this.deptId = deptId;
+    }
+
+    public Long getDeptId()
+    {
+        return deptId;
+    }
+    public void setCourseStartdate(Date courseStartdate)
+    {
+        this.courseStartdate = courseStartdate;
+    }
+
+    public Date getCourseStartdate()
+    {
+        return courseStartdate;
+    }
+    public void setCourseEnddate(Date courseEnddate)
+    {
+        this.courseEnddate = courseEnddate;
+    }
+
+    public Date getCourseEnddate()
+    {
+        return courseEnddate;
+    }
+    public void setIsfinish(Long isfinish)
+    {
+        this.isfinish = isfinish;
+    }
+
+    public Long getIsfinish()
+    {
+        return isfinish;
+    }
+    public void setConfirmor(String confirmor)
+    {
+        this.confirmor = confirmor;
+    }
+
+    public String getConfirmor()
+    {
+        return confirmor;
+    }
+    public void setYears(String years)
+    {
+        this.years = years;
+    }
+
+    public String getYears()
+    {
+        return years;
+    }
+    public void setContent(String content)
+    {
+        this.content = content;
+    }
+
+    public String getContent()
+    {
+        return content;
+    }
+    public void setNonParticipants(String nonParticipants)
+    {
+        this.nonParticipants = nonParticipants;
+    }
+
+    public String getNonParticipants()
+    {
+        return nonParticipants;
+    }
+    public void setUnit(String unit)
+    {
+        this.unit = unit;
+    }
+
+    public String getTrainingPercent() {
+        return trainingPercent;
+    }
+
+    public void setTrainingPercent(String trainingPercent) {
+        this.trainingPercent = trainingPercent;
+    }
+
+    public String getUnit()
+    {
+        return unit;
+    }
+    public void setTrainingType(String trainingType)
+    {
+        this.trainingType = trainingType;
+    }
+
+    public String getTrainingType()
+    {
+        return trainingType;
+    }
+    public void setPicUrl(String picUrl)
+    {
+        this.picUrl = picUrl;
+    }
+
+    public String getPicUrl()
+    {
+        return picUrl;
+    }
+    public void setRegularId(Long regularId)
+    {
+        this.regularId = regularId;
+    }
+
+    public Long getRegularId()
+    {
+        return regularId;
+    }
+    public void setDesignatedPosition(String designatedPosition)
+    {
+        this.designatedPosition = designatedPosition;
+    }
+
+    public String getDesignatedPosition()
+    {
+        return designatedPosition;
+    }
+    public void setDesignatedStaff(String designatedStaff)
+    {
+        this.designatedStaff = designatedStaff;
+    }
+
+    public String getDesignatedStaff()
+    {
+        return designatedStaff;
+    }
+    public void setFileUrl(String fileUrl)
+    {
+        this.fileUrl = fileUrl;
+    }
+
+    public String getFileUrl()
+    {
+        return fileUrl;
+    }
+    public void setFileName(String fileName)
+    {
+        this.fileName = fileName;
+    }
+
+    public String getFileName()
+    {
+        return fileName;
+    }
+    public void setTimerNeed(Long timerNeed)
+    {
+        this.timerNeed = timerNeed;
+    }
+
+    public Long getTimerNeed()
+    {
+        return timerNeed;
+    }
+    public void setExamId(Long examId)
+    {
+        this.examId = examId;
+    }
+
+    public Long getExamId()
+    {
+        return examId;
+    }
+
+    public String getDeptName() {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName) {
+        this.deptName = deptName;
+    }
+
+    public String getStaffIds() {
+        return staffIds;
+    }
+
+    public void setStaffIds(String staffIds) {
+        this.staffIds = staffIds;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("plantCode", getPlantCode())
+            .append("course", getCourse())
+            .append("courseid", getCourseid())
+            .append("period", getPeriod())
+            .append("duration", getDuration())
+            .append("trainer", getTrainer())
+            .append("position", getPosition())
+            .append("delFlag", getDelFlag())
+            .append("createrCode", getCreaterCode())
+            .append("createdate", getCreatedate())
+            .append("updaterCode", getUpdaterCode())
+            .append("updatedate", getUpdatedate())
+            .append("remarks", getRemarks())
+            .append("deptId", getDeptId())
+            .append("courseStartdate", getCourseStartdate())
+            .append("courseEnddate", getCourseEnddate())
+            .append("isfinish", getIsfinish())
+            .append("confirmor", getConfirmor())
+            .append("years", getYears())
+            .append("content", getContent())
+            .append("nonParticipants", getNonParticipants())
+            .append("unit", getUnit())
+            .append("trainingType", getTrainingType())
+            .append("picUrl", getPicUrl())
+            .append("regularId", getRegularId())
+            .append("designatedPosition", getDesignatedPosition())
+            .append("designatedStaff", getDesignatedStaff())
+            .append("fileUrl", getFileUrl())
+            .append("fileName", getFileName())
+            .append("timerNeed", getTimerNeed())
+            .append("examId", getExamId())
+            .toString();
+    }
+}

+ 278 - 0
master/src/main/java/com/ruoyi/project/training/domain/TTrainingbccDevice.java

@@ -0,0 +1,278 @@
+package com.ruoyi.project.training.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import com.ruoyi.framework.web.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 人员-装置级培训关系对象 t_trainingbcc_device
+ *
+ * @author ssy
+ * @date 2024-06-19
+ */
+public class TTrainingbccDevice extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 唯一标识ID */
+    private Long id;
+
+    /** 人员员工号 */
+    @Excel(name = "人员员工号")
+    private String staffId;
+
+    /** 装置级培训ID */
+    @Excel(name = "装置级培训ID")
+    private Long regularId;
+
+    /** 开始日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd" , timezone = "GMT+8")
+    @Excel(name = "开始日期", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date startDate;
+
+    /** 备注 */
+    @Excel(name = "备注")
+    private String remarks;
+
+    /** 删除状态 */
+    private Long delFlag;
+
+    /** 创建人 */
+    @Excel(name = "创建人")
+    private String createrCode;
+
+    /** 创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd" , timezone = "GMT+8")
+    @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date createdate;
+
+    /** 修改人 */
+    @Excel(name = "修改人")
+    private String updaterCode;
+
+    /** 修改时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd" , timezone = "GMT+8")
+    @Excel(name = "修改时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date updatedate;
+
+    /** 是否为补培人员 */
+    @Excel(name = "是否为补培人员")
+    private String supplementary;
+
+    /** 学习状态 */
+    @Excel(name = "学习状态")
+    private Long learnState;
+
+    /** 考试状态 */
+    @Excel(name = "考试状态")
+    private Long examState;
+
+    /** 考试ID */
+    @Excel(name = "考试ID")
+    private Long examId;
+
+    private Integer examNum;
+
+    @JsonFormat(pattern = "yyyy-MM-dd" , timezone = "GMT+8")
+    private Date examDate;
+
+    private String name;
+
+    /** 学习时长min */
+    @Excel(name = "学习时长min")
+    private Long learnTime;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    private TTrainingbcc trainingbcc;
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+    public void setStaffId(String staffId)
+    {
+        this.staffId = staffId;
+    }
+
+    public String getStaffId()
+    {
+        return staffId;
+    }
+    public void setRegularId(Long regularId)
+    {
+        this.regularId = regularId;
+    }
+
+    public Long getRegularId()
+    {
+        return regularId;
+    }
+    public void setStartDate(Date startDate)
+    {
+        this.startDate = startDate;
+    }
+
+    public Date getStartDate()
+    {
+        return startDate;
+    }
+    public void setRemarks(String remarks)
+    {
+        this.remarks = remarks;
+    }
+
+    public String getRemarks()
+    {
+        return remarks;
+    }
+    public void setDelFlag(Long delFlag)
+    {
+        this.delFlag = delFlag;
+    }
+
+    public Long getDelFlag()
+    {
+        return delFlag;
+    }
+    public void setCreaterCode(String createrCode)
+    {
+        this.createrCode = createrCode;
+    }
+
+    public String getCreaterCode()
+    {
+        return createrCode;
+    }
+    public void setCreatedate(Date createdate)
+    {
+        this.createdate = createdate;
+    }
+
+    public Date getCreatedate()
+    {
+        return createdate;
+    }
+    public void setUpdaterCode(String updaterCode)
+    {
+        this.updaterCode = updaterCode;
+    }
+
+    public String getUpdaterCode()
+    {
+        return updaterCode;
+    }
+    public void setUpdatedate(Date updatedate)
+    {
+        this.updatedate = updatedate;
+    }
+
+    public Date getUpdatedate()
+    {
+        return updatedate;
+    }
+    public void setSupplementary(String supplementary)
+    {
+        this.supplementary = supplementary;
+    }
+
+    public String getSupplementary()
+    {
+        return supplementary;
+    }
+    public void setLearnState(Long learnState)
+    {
+        this.learnState = learnState;
+    }
+
+    public Long getLearnState()
+    {
+        return learnState;
+    }
+    public void setExamState(Long examState)
+    {
+        this.examState = examState;
+    }
+
+    public Long getExamState()
+    {
+        return examState;
+    }
+    public void setExamId(Long examId)
+    {
+        this.examId = examId;
+    }
+
+    public Long getExamId()
+    {
+        return examId;
+    }
+    public void setLearnTime(Long learnTime)
+    {
+        this.learnTime = learnTime;
+    }
+
+    public Long getLearnTime()
+    {
+        return learnTime;
+    }
+
+    public TTrainingbcc getTrainingbcc() {
+        return trainingbcc;
+    }
+
+    public void setTrainingbcc(TTrainingbcc trainingbcc) {
+        this.trainingbcc = trainingbcc;
+    }
+
+    public Integer getExamNum() {
+        return examNum;
+    }
+
+    public void setExamNum(Integer examNum) {
+        this.examNum = examNum;
+    }
+
+    public Date getExamDate() {
+        return examDate;
+    }
+
+    public void setExamDate(Date examDate) {
+        this.examDate = examDate;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("staffId", getStaffId())
+            .append("regularId", getRegularId())
+            .append("startDate", getStartDate())
+            .append("remarks", getRemarks())
+            .append("delFlag", getDelFlag())
+            .append("createrCode", getCreaterCode())
+            .append("createdate", getCreatedate())
+            .append("updaterCode", getUpdaterCode())
+            .append("updatedate", getUpdatedate())
+            .append("supplementary", getSupplementary())
+            .append("learnState", getLearnState())
+            .append("examState", getExamState())
+            .append("examId", getExamId())
+            .append("learnTime", getLearnTime())
+            .toString();
+    }
+}

+ 1 - 1
master/src/main/java/com/ruoyi/project/training/elearn/controller/TElLearnController.java

@@ -60,7 +60,7 @@ public class TElLearnController extends BaseController
             learn.setLearnTime((Integer.parseInt(learnTime) + 1) + "");
             tElLearnService.updateTElLearn(learn);
         }
-        return AjaxResult.success();
+        return AjaxResult.success(learn);
     }
 
     /**

+ 13 - 0
master/src/main/java/com/ruoyi/project/training/elearn/controller/TElResourceController.java

@@ -2,6 +2,9 @@ package com.ruoyi.project.training.elearn.controller;
 
 import java.util.List;
 
+import com.ruoyi.project.training.elearn.domain.TElLearn;
+import com.ruoyi.project.training.elearn.mapper.TElLearnMapper;
+import com.ruoyi.project.training.elearn.service.ITElLearnService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -34,6 +37,9 @@ public class TElResourceController extends BaseController
     @Autowired
     private ITElResourceService tElResourceService;
 
+    @Autowired
+    private ITElLearnService itElLearnService;
+
     /**
      * 查询课件列表
      */
@@ -43,6 +49,13 @@ public class TElResourceController extends BaseController
     {
         startPage();
         List<TElResource> list = tElResourceService.selectFileList(tElResource);
+        Long userId = getUserId();
+        for (TElResource elResource : list) {
+            TElLearn learn = new TElLearn();
+            learn.setUserId(userId);
+            learn.setResourceId(elResource.getId());
+            elResource.setLearnTime(itElLearnService.selectLearnByUserIdAndResourceId(learn).getLearnTime());
+        }
         return getDataTable(list);
     }
 

+ 3 - 0
master/src/main/java/com/ruoyi/project/training/elearn/domain/TElExam.java

@@ -89,6 +89,9 @@ public class TElExam extends BaseEntity
     @Excel(name = "所属部门")
     private Long deptId;
 
+    /** 类型 */
+    private Integer examType;
+
     /** 备注 */
     @Excel(name = "备注")
     private String remarks;

+ 11 - 0
master/src/main/java/com/ruoyi/project/training/elearn/domain/TElResource.java

@@ -42,6 +42,17 @@ public class TElResource extends BaseEntity
     /** 路径 */
     private String fileUrl;
 
+    /** 累计学习时长 */
+    private String learnTime;
+
+    public String getLearnTime() {
+        return learnTime;
+    }
+
+    public void setLearnTime(String learnTime) {
+        this.learnTime = learnTime;
+    }
+
     public Long getFileId() {
         return fileId;
     }

+ 67 - 0
master/src/main/java/com/ruoyi/project/training/mapper/TTrainingbccDeviceMapper.java

@@ -0,0 +1,67 @@
+package com.ruoyi.project.training.mapper;
+
+import java.util.List;
+import com.ruoyi.framework.aspectj.lang.annotation.DataScope;
+import com.ruoyi.project.training.domain.TTrainingbccDevice;
+
+/**
+ * 人员-装置级培训关系Mapper接口
+ *
+ * @author ssy
+ * @date 2024-06-19
+ */
+public interface TTrainingbccDeviceMapper
+{
+    /**
+     * 查询人员-装置级培训关系
+     *
+     * @param id 人员-装置级培训关系ID
+     * @return 人员-装置级培训关系
+     */
+    public TTrainingbccDevice selectTTrainingbccDeviceById(Long id);
+
+    /**
+     * 查询人员-装置级培训关系列表
+     *
+     * @param tTrainingbccDevice 人员-装置级培训关系
+     * @return 人员-装置级培训关系集合
+     */
+    @DataScope(deptAlias = "d")
+    public List<TTrainingbccDevice> selectTTrainingbccDeviceList(TTrainingbccDevice tTrainingbccDevice);
+
+    /**
+     * 新增人员-装置级培训关系
+     *
+     * @param tTrainingbccDevice 人员-装置级培训关系
+     * @return 结果
+     */
+    public int insertTTrainingbccDevice(TTrainingbccDevice tTrainingbccDevice);
+
+    /**
+     * 修改人员-装置级培训关系
+     *
+     * @param tTrainingbccDevice 人员-装置级培训关系
+     * @return 结果
+     */
+    public int updateTTrainingbccDevice(TTrainingbccDevice tTrainingbccDevice);
+
+    /**
+     * 删除人员-装置级培训关系
+     *
+     * @param id 人员-装置级培训关系ID
+     * @return 结果
+     */
+    public int deleteTTrainingbccDeviceById(Long id);
+
+    /**
+     * 批量删除人员-装置级培训关系
+     *
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteTTrainingbccDeviceByIds(Long[] ids);
+
+    void deleteTTrainingbccDeviceByStaff(TTrainingbccDevice device);
+
+    int countTraining(TTrainingbccDevice device);
+}

+ 63 - 0
master/src/main/java/com/ruoyi/project/training/mapper/TTrainingbccMapper.java

@@ -0,0 +1,63 @@
+package com.ruoyi.project.training.mapper;
+
+import java.util.List;
+import com.ruoyi.framework.aspectj.lang.annotation.DataScope;
+import com.ruoyi.project.training.domain.TTrainingbcc;
+
+/**
+ * 装置培训跟踪bMapper接口
+ *
+ * @author ssy
+ * @date 2024-06-19
+ */
+public interface TTrainingbccMapper
+{
+    /**
+     * 查询装置培训跟踪b
+     *
+     * @param id 装置培训跟踪bID
+     * @return 装置培训跟踪b
+     */
+    public TTrainingbcc selectTTrainingbccById(Long id);
+
+    /**
+     * 查询装置培训跟踪b列表
+     *
+     * @param tTrainingbcc 装置培训跟踪b
+     * @return 装置培训跟踪b集合
+     */
+    @DataScope(deptAlias = "d")
+    public List<TTrainingbcc> selectTTrainingbccList(TTrainingbcc tTrainingbcc);
+
+    /**
+     * 新增装置培训跟踪b
+     *
+     * @param tTrainingbcc 装置培训跟踪b
+     * @return 结果
+     */
+    public int insertTTrainingbcc(TTrainingbcc tTrainingbcc);
+
+    /**
+     * 修改装置培训跟踪b
+     *
+     * @param tTrainingbcc 装置培训跟踪b
+     * @return 结果
+     */
+    public int updateTTrainingbcc(TTrainingbcc tTrainingbcc);
+
+    /**
+     * 删除装置培训跟踪b
+     *
+     * @param id 装置培训跟踪bID
+     * @return 结果
+     */
+    public int deleteTTrainingbccById(Long id);
+
+    /**
+     * 批量删除装置培训跟踪b
+     *
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteTTrainingbccByIds(Long[] ids);
+}

+ 61 - 0
master/src/main/java/com/ruoyi/project/training/service/ITTrainingbccDeviceService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.project.training.service;
+
+import java.util.List;
+import com.ruoyi.project.training.domain.TTrainingbccDevice;
+
+/**
+ * 人员-装置级培训关系Service接口
+ *
+ * @author ssy
+ * @date 2024-06-19
+ */
+public interface ITTrainingbccDeviceService
+{
+    /**
+     * 查询人员-装置级培训关系
+     *
+     * @param id 人员-装置级培训关系ID
+     * @return 人员-装置级培训关系
+     */
+    public TTrainingbccDevice selectTTrainingbccDeviceById(Long id);
+
+    /**
+     * 查询人员-装置级培训关系列表
+     *
+     * @param tTrainingbccDevice 人员-装置级培训关系
+     * @return 人员-装置级培训关系集合
+     */
+    public List<TTrainingbccDevice> selectTTrainingbccDeviceList(TTrainingbccDevice tTrainingbccDevice);
+
+    /**
+     * 新增人员-装置级培训关系
+     *
+     * @param tTrainingbccDevice 人员-装置级培训关系
+     * @return 结果
+     */
+    public int insertTTrainingbccDevice(TTrainingbccDevice tTrainingbccDevice);
+
+    /**
+     * 修改人员-装置级培训关系
+     *
+     * @param tTrainingbccDevice 人员-装置级培训关系
+     * @return 结果
+     */
+    public int updateTTrainingbccDevice(TTrainingbccDevice tTrainingbccDevice);
+
+    /**
+     * 批量删除人员-装置级培训关系
+     *
+     * @param ids 需要删除的人员-装置级培训关系ID
+     * @return 结果
+     */
+    public int deleteTTrainingbccDeviceByIds(Long[] ids);
+
+    /**
+     * 删除人员-装置级培训关系信息
+     *
+     * @param id 人员-装置级培训关系ID
+     * @return 结果
+     */
+    public int deleteTTrainingbccDeviceById(Long id);
+}

+ 63 - 0
master/src/main/java/com/ruoyi/project/training/service/ITTrainingbccService.java

@@ -0,0 +1,63 @@
+package com.ruoyi.project.training.service;
+
+import java.util.List;
+import com.ruoyi.project.training.domain.TTrainingbcc;
+
+/**
+ * 装置培训跟踪bService接口
+ *
+ * @author ssy
+ * @date 2024-06-19
+ */
+public interface ITTrainingbccService
+{
+    /**
+     * 查询装置培训跟踪b
+     *
+     * @param id 装置培训跟踪bID
+     * @return 装置培训跟踪b
+     */
+    public TTrainingbcc selectTTrainingbccById(Long id);
+
+    /**
+     * 查询装置培训跟踪b列表
+     *
+     * @param tTrainingbcc 装置培训跟踪b
+     * @return 装置培训跟踪b集合
+     */
+    public List<TTrainingbcc> selectTTrainingbccList(TTrainingbcc tTrainingbcc);
+
+    /**
+     * 新增装置培训跟踪b
+     *
+     * @param tTrainingbcc 装置培训跟踪b
+     * @return 结果
+     */
+    public int insertTTrainingbcc(TTrainingbcc tTrainingbcc);
+
+    /**
+     * 修改装置培训跟踪b
+     *
+     * @param tTrainingbcc 装置培训跟踪b
+     * @return 结果
+     */
+    public int updateTTrainingbcc(TTrainingbcc tTrainingbcc);
+
+    /**
+     * 批量删除装置培训跟踪b
+     *
+     * @param ids 需要删除的装置培训跟踪bID
+     * @return 结果
+     */
+    public int deleteTTrainingbccByIds(Long[] ids);
+
+    /**
+     * 删除装置培训跟踪b信息
+     *
+     * @param id 装置培训跟踪bID
+     * @return 结果
+     */
+    public int deleteTTrainingbccById(Long id);
+
+    int updateStaffIds(TTrainingbcc tTrainingbcc);
+}

+ 93 - 0
master/src/main/java/com/ruoyi/project/training/service/impl/TTrainingbccDeviceServiceImpl.java

@@ -0,0 +1,93 @@
+package com.ruoyi.project.training.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.project.training.mapper.TTrainingbccDeviceMapper;
+import com.ruoyi.project.training.domain.TTrainingbccDevice;
+import com.ruoyi.project.training.service.ITTrainingbccDeviceService;
+
+/**
+ * 人员-装置级培训关系Service业务层处理
+ *
+ * @author ssy
+ * @date 2024-06-19
+ */
+@Service
+public class TTrainingbccDeviceServiceImpl implements ITTrainingbccDeviceService
+{
+    @Autowired
+    private TTrainingbccDeviceMapper tTrainingbccDeviceMapper;
+
+    /**
+     * 查询人员-装置级培训关系
+     *
+     * @param id 人员-装置级培训关系ID
+     * @return 人员-装置级培训关系
+     */
+    @Override
+    public TTrainingbccDevice selectTTrainingbccDeviceById(Long id)
+    {
+        return tTrainingbccDeviceMapper.selectTTrainingbccDeviceById(id);
+    }
+
+    /**
+     * 查询人员-装置级培训关系列表
+     *
+     * @param tTrainingbccDevice 人员-装置级培训关系
+     * @return 人员-装置级培训关系
+     */
+    @Override
+    public List<TTrainingbccDevice> selectTTrainingbccDeviceList(TTrainingbccDevice tTrainingbccDevice)
+    {
+        return tTrainingbccDeviceMapper.selectTTrainingbccDeviceList(tTrainingbccDevice);
+    }
+
+    /**
+     * 新增人员-装置级培训关系
+     *
+     * @param tTrainingbccDevice 人员-装置级培训关系
+     * @return 结果
+     */
+    @Override
+    public int insertTTrainingbccDevice(TTrainingbccDevice tTrainingbccDevice)
+    {
+        return tTrainingbccDeviceMapper.insertTTrainingbccDevice(tTrainingbccDevice);
+    }
+
+    /**
+     * 修改人员-装置级培训关系
+     *
+     * @param tTrainingbccDevice 人员-装置级培训关系
+     * @return 结果
+     */
+    @Override
+    public int updateTTrainingbccDevice(TTrainingbccDevice tTrainingbccDevice)
+    {
+        return tTrainingbccDeviceMapper.updateTTrainingbccDevice(tTrainingbccDevice);
+    }
+
+    /**
+     * 批量删除人员-装置级培训关系
+     *
+     * @param ids 需要删除的人员-装置级培训关系ID
+     * @return 结果
+     */
+    @Override
+    public int deleteTTrainingbccDeviceByIds(Long[] ids)
+    {
+        return tTrainingbccDeviceMapper.deleteTTrainingbccDeviceByIds(ids);
+    }
+
+    /**
+     * 删除人员-装置级培训关系信息
+     *
+     * @param id 人员-装置级培训关系ID
+     * @return 结果
+     */
+    @Override
+    public int deleteTTrainingbccDeviceById(Long id)
+    {
+        return tTrainingbccDeviceMapper.deleteTTrainingbccDeviceById(id);
+    }
+}

+ 168 - 0
master/src/main/java/com/ruoyi/project/training/service/impl/TTrainingbccServiceImpl.java

@@ -0,0 +1,168 @@
+package com.ruoyi.project.training.service.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.alibaba.fastjson.JSON;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.project.training.domain.TTrainingbccDevice;
+import com.ruoyi.project.training.mapper.TTrainingbccDeviceMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.project.training.mapper.TTrainingbccMapper;
+import com.ruoyi.project.training.domain.TTrainingbcc;
+import com.ruoyi.project.training.service.ITTrainingbccService;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+
+/**
+ * 装置培训跟踪bService业务层处理
+ *
+ * @author ssy
+ * @date 2024-06-19
+ */
+@Service
+public class TTrainingbccServiceImpl implements ITTrainingbccService
+{
+    @Resource
+    private TTrainingbccMapper tTrainingbccMapper;
+    @Resource
+    private TTrainingbccDeviceMapper tTrainingbccDeviceMapper;
+
+    protected final Logger logger = LoggerFactory.getLogger(BaseController.class);
+    /**
+     * 查询装置培训跟踪b
+     *
+     * @param id 装置培训跟踪bID
+     * @return 装置培训跟踪b
+     */
+    @Override
+    public TTrainingbcc selectTTrainingbccById(Long id)
+    {
+        return tTrainingbccMapper.selectTTrainingbccById(id);
+    }
+
+    /**
+     * 查询装置培训跟踪b列表
+     *
+     * @param tTrainingbcc 装置培训跟踪b
+     * @return 装置培训跟踪b
+     */
+    @Override
+    public List<TTrainingbcc> selectTTrainingbccList(TTrainingbcc tTrainingbcc)
+    {
+        return tTrainingbccMapper.selectTTrainingbccList(tTrainingbcc);
+    }
+
+    /**
+     * 新增装置培训跟踪b
+     *
+     * @param tTrainingbcc 装置培训跟踪b
+     * @return 结果
+     */
+    @Override
+    public int insertTTrainingbcc(TTrainingbcc tTrainingbcc)
+    {
+        return tTrainingbccMapper.insertTTrainingbcc(tTrainingbcc);
+    }
+
+    /**
+     * 修改装置培训跟踪b
+     *
+     * @param tTrainingbcc 装置培训跟踪b
+     * @return 结果
+     */
+    @Override
+    public int updateTTrainingbcc(TTrainingbcc tTrainingbcc)
+    {
+        return tTrainingbccMapper.updateTTrainingbcc(tTrainingbcc);
+    }
+
+    /**
+     * 批量删除装置培训跟踪b
+     *
+     * @param ids 需要删除的装置培训跟踪bID
+     * @return 结果
+     */
+    @Override
+    public int deleteTTrainingbccByIds(Long[] ids)
+    {
+        return tTrainingbccMapper.deleteTTrainingbccByIds(ids);
+    }
+
+    /**
+     * 删除装置培训跟踪b信息
+     *
+     * @param id 装置培训跟踪bID
+     * @return 结果
+     */
+    @Override
+    public int deleteTTrainingbccById(Long id)
+    {
+        return tTrainingbccMapper.deleteTTrainingbccById(id);
+    }
+
+    @Override
+    @Transactional
+    public int updateStaffIds(TTrainingbcc tTrainingbcc) {
+        TTrainingbccDevice param = new TTrainingbccDevice();
+        param.setRegularId(tTrainingbcc.getId());
+        List<TTrainingbccDevice> list = tTrainingbccDeviceMapper.selectTTrainingbccDeviceList(param);
+        List<String> nowStaff = list.stream()
+                .map(TTrainingbccDevice::getStaffId)
+                .collect(Collectors.toList());
+        logger.info(JSON.toJSONString(tTrainingbcc));
+        List<String> newStaff = Arrays.asList(tTrainingbcc.getStaffIds().split(",").clone());
+
+        // 找出a有b没有的元素
+        List<String> needDel = new ArrayList<>();
+        for (String element : nowStaff) {
+            if (!newStaff.contains(element)) {
+                needDel.add(element);
+            }
+        }
+
+        // 找出b有a没有的元素
+        List<String> needAdd = new ArrayList<>();
+        for (String element : newStaff) {
+            if (!nowStaff.contains(element)) {
+                needAdd.add(element);
+            }
+        }
+
+        //删除
+        for (String staff: needDel
+             ) {
+            if (StringUtils.isNotEmpty(staff))  {
+                TTrainingbccDevice device = new TTrainingbccDevice();
+                device.setRegularId(tTrainingbcc.getId());
+                device.setStaffId(staff);
+                tTrainingbccDeviceMapper.deleteTTrainingbccDeviceByStaff(device);
+            }
+
+        }
+        //新增
+        TTrainingbcc trainingbcc = tTrainingbccMapper.selectTTrainingbccById(tTrainingbcc.getId());
+        for (String staff :needAdd
+             ) {
+            if (StringUtils.isNotEmpty(staff))  {
+                TTrainingbccDevice device = new TTrainingbccDevice();
+                device.setStaffId(staff);
+                device.setRegularId(tTrainingbcc.getId());
+                device.setStartDate(trainingbcc.getCourseStartdate());
+                logger.info(JSON.toJSONString(device));
+                tTrainingbccDeviceMapper.insertTTrainingbccDevice(device);
+            }
+
+        }
+
+
+        return 1;
+    }
+}

+ 1 - 1
master/src/main/resources/application.yml

@@ -193,7 +193,7 @@ gen:
   # 作者
   author: ssy
   # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
-  packageName: com.ruoyi.project.training.elearn # 自动去除表前缀,默认是true
+  packageName: com.ruoyi.project.training # 自动去除表前缀,默认是true
   autoRemovePre: false
   # 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
   tablePrefix: sys_

+ 3 - 0
master/src/main/resources/mybatis/document/TPlantproglistMapper.xml

@@ -201,6 +201,9 @@
             <if test="filedate != null">filedate = #{filedate},</if>
             <if test="reviewdate != null">reviewdate = #{reviewdate},</if>
             <if test="nextreviewdate != null">nextreviewdate = #{nextreviewdate},</if>
+            <if test="nexteditdate == null">nexteditdate = NULL,</if>
+            <if test="reviewdate == null">reviewdate = NULL,</if>
+            <if test="nextreviewdate == null">nextreviewdate = NULL,</if>
             <if test="nexteditdate != null">nexteditdate = #{nexteditdate},</if>
             <if test="item != null">item = #{item},</if>
             <if test="delFlag != null">del_flag = #{delFlag},</if>

+ 148 - 0
master/src/main/resources/mybatis/training/TTrainingbccDeviceMapper.xml

@@ -0,0 +1,148 @@
+<?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.ruoyi.project.training.mapper.TTrainingbccDeviceMapper">
+
+    <resultMap type="TTrainingbccDevice" id="TTrainingbccDeviceResult">
+        <result property="id"    column="id"    />
+        <result property="staffId"    column="staff_id"    />
+        <result property="regularId"    column="regular_id"    />
+        <result property="startDate"    column="start_date"    />
+        <result property="remarks"    column="remarks"    />
+        <result property="delFlag"    column="del_flag"    />
+        <result property="createrCode"    column="creater_code"    />
+        <result property="createdate"    column="createdate"    />
+        <result property="updaterCode"    column="updater_code"    />
+        <result property="updatedate"    column="updatedate"    />
+        <result property="supplementary"    column="supplementary"    />
+        <result property="learnState"    column="learn_state"    />
+        <result property="examState"    column="exam_state"    />
+        <result property="examId"    column="exam_id"    />
+        <result property="learnTime"    column="learn_time"    />
+        <result property="deptName" column="dept_name" />
+    </resultMap>
+
+    <sql id="selectTTrainingbccDeviceVo">
+        select d.id,s.name , d.staff_id, d.regular_id, d.start_date, d.remarks, d.del_flag, d.creater_code, d.createdate, d.updater_code, d.updatedate, d.supplementary, d.learn_state, d.exam_state, d.exam_id, d.learn_time from t_trainingbcc_device d
+       left join t_staffmgr s on s.staffid = d.staff_id
+</sql>
+
+    <select id="selectTTrainingbccDeviceList" parameterType="TTrainingbccDevice" resultMap="TTrainingbccDeviceResult">
+        <include refid="selectTTrainingbccDeviceVo"/>
+        <where>
+            <if test="staffId != null  and staffId != ''"> and staff_id = #{staffId}</if>
+            <if test="regularId != null "> and regular_id = #{regularId}</if>
+            <if test="startDate != null "> and start_date = #{startDate}</if>
+            <if test="remarks != null  and remarks != ''"> and remarks = #{remarks}</if>
+            <if test="createrCode != null  and createrCode != ''"> and creater_code = #{createrCode}</if>
+            <if test="createdate != null "> and createdate = #{createdate}</if>
+            <if test="updaterCode != null  and updaterCode != ''"> and updater_code = #{updaterCode}</if>
+            <if test="updatedate != null "> and updatedate = #{updatedate}</if>
+            <if test="supplementary != null  and supplementary != ''"> and supplementary = #{supplementary}</if>
+            <if test="learnState != null "> and learn_state = #{learnState}</if>
+            <if test="examState != null "> and exam_state = #{examState}</if>
+            <if test="examId != null "> and exam_id = #{examId}</if>
+            <if test="learnTime != null "> and learn_time = #{learnTime}</if>
+            and d.del_flag = 0
+        </where>
+        <!-- 数据范围过滤 -->
+        ${params.dataScope}
+    </select>
+
+    <select id="selectTTrainingbccDeviceById" parameterType="Long" resultMap="TTrainingbccDeviceResult">
+        <include refid="selectTTrainingbccDeviceVo"/>
+        where d.id = #{id}
+    </select>
+
+    <insert id="insertTTrainingbccDevice" parameterType="TTrainingbccDevice">
+        <selectKey keyProperty="id" resultType="long" order="BEFORE">
+            SELECT seq_t_trainingbcc_device.NEXTVAL as id FROM DUAL
+        </selectKey>
+        insert into t_trainingbcc_device
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">id,</if>
+            <if test="staffId != null">staff_id,</if>
+            <if test="regularId != null">regular_id,</if>
+            <if test="startDate != null">start_date,</if>
+            <if test="remarks != null">remarks,</if>
+            <if test="delFlag != null">del_flag,</if>
+            <if test="createrCode != null">creater_code,</if>
+            <if test="createdate != null">createdate,</if>
+            <if test="updaterCode != null">updater_code,</if>
+            <if test="updatedate != null">updatedate,</if>
+            <if test="supplementary != null">supplementary,</if>
+            <if test="learnState != null">learn_state,</if>
+            <if test="examState != null">exam_state,</if>
+            <if test="examId != null">exam_id,</if>
+            <if test="learnTime != null">learn_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="id != null">#{id},</if>
+            <if test="staffId != null">#{staffId},</if>
+            <if test="regularId != null">#{regularId},</if>
+            <if test="startDate != null">#{startDate},</if>
+            <if test="remarks != null">#{remarks},</if>
+            <if test="delFlag != null">#{delFlag},</if>
+            <if test="createrCode != null">#{createrCode},</if>
+            <if test="createdate != null">#{createdate},</if>
+            <if test="updaterCode != null">#{updaterCode},</if>
+            <if test="updatedate != null">#{updatedate},</if>
+            <if test="supplementary != null">#{supplementary},</if>
+            <if test="learnState != null">#{learnState},</if>
+            <if test="examState != null">#{examState},</if>
+            <if test="examId != null">#{examId},</if>
+            <if test="learnTime != null">#{learnTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateTTrainingbccDevice" parameterType="TTrainingbccDevice">
+        update t_trainingbcc_device
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="staffId != null">staff_id = #{staffId},</if>
+            <if test="regularId != null">regular_id = #{regularId},</if>
+            <if test="startDate != null">start_date = #{startDate},</if>
+            <if test="remarks != null">remarks = #{remarks},</if>
+            <if test="delFlag != null">del_flag = #{delFlag},</if>
+            <if test="createrCode != null">creater_code = #{createrCode},</if>
+            <if test="createdate != null">createdate = #{createdate},</if>
+            <if test="updaterCode != null">updater_code = #{updaterCode},</if>
+            <if test="updatedate != null">updatedate = #{updatedate},</if>
+            <if test="supplementary != null">supplementary = #{supplementary},</if>
+            <if test="learnState != null">learn_state = #{learnState},</if>
+            <if test="examState != null">exam_state = #{examState},</if>
+            <if test="examId != null">exam_id = #{examId},</if>
+            <if test="learnTime != null">learn_time = #{learnTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <update id="deleteTTrainingbccDeviceById" parameterType="Long">
+        update t_trainingbcc_device set del_flag = 2 where id = #{id}
+    </update>
+
+    <update id="deleteTTrainingbccDeviceByStaff" parameterType="TTrainingbccDevice">
+        update t_trainingbcc_device set del_flag = 2 where staff_id = #{staffId} and regular_id = #{regularId}
+    </update>
+
+
+
+    <update id="deleteTTrainingbccDeviceByIds" parameterType="String">
+        update t_trainingbcc_device set del_flag = 2 where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </update>
+
+    <select id="countTraining" parameterType="TTrainingbccDevice" resultType="int">
+        select count(1) from t_trainingbcc_device
+        <where>
+            <if test="regularId != null "> and regular_id = #{regularId}</if>
+            <if test="examState != null "> and exam_state = #{examState}</if>
+            and del_flag = 0
+        </where>
+
+    </select>
+
+
+</mapper>

+ 192 - 0
master/src/main/resources/mybatis/training/TTrainingbccMapper.xml

@@ -0,0 +1,192 @@
+<?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.ruoyi.project.training.mapper.TTrainingbccMapper">
+
+    <resultMap type="TTrainingbcc" id="TTrainingbccResult">
+        <result property="id"    column="id"    />
+        <result property="plantCode"    column="plant_code"    />
+        <result property="course"    column="course"    />
+        <result property="courseid"    column="courseid"    />
+        <result property="period"    column="period"    />
+        <result property="duration"    column="duration"    />
+        <result property="trainer"    column="trainer"    />
+        <result property="position"    column="position"    />
+        <result property="delFlag"    column="del_flag"    />
+        <result property="createrCode"    column="creater_code"    />
+        <result property="createdate"    column="createdate"    />
+        <result property="updaterCode"    column="updater_code"    />
+        <result property="updatedate"    column="updatedate"    />
+        <result property="remarks"    column="remarks"    />
+        <result property="deptId"    column="dept_id"    />
+        <result property="courseStartdate"    column="course_startdate"    />
+        <result property="courseEnddate"    column="course_enddate"    />
+        <result property="isfinish"    column="isfinish"    />
+        <result property="confirmor"    column="confirmor"    />
+        <result property="years"    column="years"    />
+        <result property="content"    column="content"    />
+        <result property="nonParticipants"    column="non_participants"    />
+        <result property="unit"    column="unit"    />
+        <result property="trainingType"    column="training_type"    />
+        <result property="picUrl"    column="pic_url"    />
+        <result property="regularId"    column="regular_id"    />
+        <result property="designatedPosition"    column="designated_position"    />
+        <result property="designatedStaff"    column="designated_staff"    />
+        <result property="fileUrl"    column="file_url"    />
+        <result property="fileName"    column="file_name"    />
+        <result property="timerNeed"    column="timer_need"    />
+        <result property="examId"    column="exam_id"    />
+        <result property="deptName" column="dept_name" />
+    </resultMap>
+
+    <sql id="selectTTrainingbccVo">
+        select d.id, d.plant_code, d.course, d.courseid, d.period, d.duration, d.trainer, d.position, d.del_flag, d.creater_code, d.createdate, d.updater_code, d.updatedate, d.remarks, d.dept_id, d.course_startdate, d.course_enddate, d.isfinish, d.confirmor, d.years, d.content, d.non_participants, d.unit, d.training_type, d.pic_url, d.regular_id, d.designated_position, d.designated_staff, d.file_url, d.file_name, d.timer_need, d.exam_id  from t_trainingbcc d
+
+    </sql>
+
+    <select id="selectTTrainingbccList" parameterType="TTrainingbcc" resultMap="TTrainingbccResult">
+        <include refid="selectTTrainingbccVo"/>
+        <where>
+            <if test="years != null ">and years = #{years}</if>
+            <if test="plantCode != null  and plantCode != ''"> and plant_code = #{plantCode}</if>
+            <if test="course != null  and course != ''"> and course like concat(concat('%', #{course}), '%')</if>
+            <if test="courseid != null  and courseid != ''"> and courseid = #{courseid}</if>
+            <if test="period != null  and period != ''"> and period = #{period}</if>
+            <if test="duration != null  and duration != ''"> and duration = #{duration}</if>
+            <if test="trainer != null  and trainer != ''"> and trainer = #{trainer}</if>
+            <if test="position != null  and position != ''"> and position = #{position}</if>
+            <if test="trainingType != null and trainingType != ''">and training_type = #{trainingType}</if>
+            and d.del_flag = 0
+        </where>
+        <!-- 数据范围过滤 -->
+        ${params.dataScope}
+    </select>
+
+    <select id="selectTTrainingbccById" parameterType="Long" resultMap="TTrainingbccResult">
+        <include refid="selectTTrainingbccVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertTTrainingbcc" parameterType="TTrainingbcc">
+        insert into t_trainingbcc
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">id,</if>
+            <if test="plantCode != null">plant_code,</if>
+            <if test="course != null and course != ''">course,</if>
+            <if test="courseid != null">courseid,</if>
+            <if test="period != null">period,</if>
+            <if test="duration != null">duration,</if>
+            <if test="trainer != null">trainer,</if>
+            <if test="position != null">position,</if>
+            <if test="delFlag != null">del_flag,</if>
+            <if test="createrCode != null">creater_code,</if>
+            <if test="createdate != null">createdate,</if>
+            <if test="updaterCode != null">updater_code,</if>
+            <if test="updatedate != null">updatedate,</if>
+            <if test="remarks != null">remarks,</if>
+            <if test="deptId != null">dept_id,</if>
+            <if test="courseStartdate != null">course_startdate,</if>
+            <if test="courseEnddate != null">course_enddate,</if>
+            <if test="isfinish != null">isfinish,</if>
+            <if test="confirmor != null">confirmor,</if>
+            <if test="years != null">years,</if>
+            <if test="content != null">content,</if>
+            <if test="nonParticipants != null">non_participants,</if>
+            <if test="unit != null">unit,</if>
+            <if test="trainingType != null">training_type,</if>
+            <if test="picUrl != null">pic_url,</if>
+            <if test="regularId != null">regular_id,</if>
+            <if test="designatedPosition != null">designated_position,</if>
+            <if test="designatedStaff != null">designated_staff,</if>
+            <if test="fileUrl != null">file_url,</if>
+            <if test="fileName != null">file_name,</if>
+            <if test="timerNeed != null">timer_need,</if>
+            <if test="examId != null">exam_id,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="id != null">#{id},</if>
+            <if test="plantCode != null">#{plantCode},</if>
+            <if test="course != null and course != ''">#{course},</if>
+            <if test="courseid != null">#{courseid},</if>
+            <if test="period != null">#{period},</if>
+            <if test="duration != null">#{duration},</if>
+            <if test="trainer != null">#{trainer},</if>
+            <if test="position != null">#{position},</if>
+            <if test="delFlag != null">#{delFlag},</if>
+            <if test="createrCode != null">#{createrCode},</if>
+            <if test="createdate != null">#{createdate},</if>
+            <if test="updaterCode != null">#{updaterCode},</if>
+            <if test="updatedate != null">#{updatedate},</if>
+            <if test="remarks != null">#{remarks},</if>
+            <if test="deptId != null">#{deptId},</if>
+            <if test="courseStartdate != null">#{courseStartdate},</if>
+            <if test="courseEnddate != null">#{courseEnddate},</if>
+            <if test="isfinish != null">#{isfinish},</if>
+            <if test="confirmor != null">#{confirmor},</if>
+            <if test="years != null">#{years},</if>
+            <if test="content != null">#{content},</if>
+            <if test="nonParticipants != null">#{nonParticipants},</if>
+            <if test="unit != null">#{unit},</if>
+            <if test="trainingType != null">#{trainingType},</if>
+            <if test="picUrl != null">#{picUrl},</if>
+            <if test="regularId != null">#{regularId},</if>
+            <if test="designatedPosition != null">#{designatedPosition},</if>
+            <if test="designatedStaff != null">#{designatedStaff},</if>
+            <if test="fileUrl != null">#{fileUrl},</if>
+            <if test="fileName != null">#{fileName},</if>
+            <if test="timerNeed != null">#{timerNeed},</if>
+            <if test="examId != null">#{examId},</if>
+         </trim>
+    </insert>
+
+    <update id="updateTTrainingbcc" parameterType="TTrainingbcc">
+        update t_trainingbcc
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="plantCode != null">plant_code = #{plantCode},</if>
+            <if test="course != null and course != ''">course = #{course},</if>
+            <if test="courseid != null">courseid = #{courseid},</if>
+            <if test="period != null">period = #{period},</if>
+            <if test="duration != null">duration = #{duration},</if>
+            <if test="trainer != null">trainer = #{trainer},</if>
+            <if test="position != null">position = #{position},</if>
+            <if test="delFlag != null">del_flag = #{delFlag},</if>
+            <if test="createrCode != null">creater_code = #{createrCode},</if>
+            <if test="createdate != null">createdate = #{createdate},</if>
+            <if test="updaterCode != null">updater_code = #{updaterCode},</if>
+            <if test="updatedate != null">updatedate = #{updatedate},</if>
+            <if test="remarks != null">remarks = #{remarks},</if>
+            <if test="deptId != null">dept_id = #{deptId},</if>
+            <if test="courseStartdate != null">course_startdate = #{courseStartdate},</if>
+            <if test="courseEnddate != null">course_enddate = #{courseEnddate},</if>
+            <if test="isfinish != null">isfinish = #{isfinish},</if>
+            <if test="confirmor != null">confirmor = #{confirmor},</if>
+            <if test="years != null">years = #{years},</if>
+            <if test="content != null">content = #{content},</if>
+            <if test="nonParticipants != null">non_participants = #{nonParticipants},</if>
+            <if test="unit != null">unit = #{unit},</if>
+            <if test="trainingType != null">training_type = #{trainingType},</if>
+            <if test="picUrl != null">pic_url = #{picUrl},</if>
+            <if test="regularId != null">regular_id = #{regularId},</if>
+            <if test="designatedPosition != null">designated_position = #{designatedPosition},</if>
+            <if test="designatedStaff != null">designated_staff = #{designatedStaff},</if>
+            <if test="fileUrl != null">file_url = #{fileUrl},</if>
+            <if test="fileName != null">file_name = #{fileName},</if>
+            <if test="timerNeed != null">timer_need = #{timerNeed},</if>
+            <if test="examId != null">exam_id = #{examId},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <update id="deleteTTrainingbccById" parameterType="Long">
+        update t_trainingbcc set del_flag = 2 where id = #{id}
+    </update>
+
+    <update id="deleteTTrainingbccByIds" parameterType="String">
+        update t_trainingbcc set del_flag = 2 where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </update>
+
+</mapper>

+ 1 - 1
master/src/main/resources/mybatis/training/bccnew/TTsNewMapper.xml

@@ -41,7 +41,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <select id="selectTTsNewList" parameterType="TTsNew" resultMap="TTsNewResult">
         <include refid="selectTTsNewVo"/>
         <where>
-            <if test="staffId != null  and staffId != ''"> and staff_id = #{staffId}</if>
+            <if test="staffId != null  and staffId != ''"> and d.staff_id = #{staffId}</if>
             <if test="name != null  and name != ''"> and name like concat(concat('%', #{name}), '%')</if>
             <if test="createrCode != null  and createrCode != ''"> and creater_code = #{createrCode}</if>
             <if test="createdate != null "> and createdate = #{createdate}</if>

+ 7 - 1
master/src/main/resources/mybatis/training/elearn/TElExamMapper.xml

@@ -24,19 +24,22 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="deptId"    column="dept_id"    />
         <result property="remarks"    column="remarks"    />
         <result property="deptName" column="dept_name" />
+        <result property="examType"    column="exam_type"    />
     </resultMap>
 
     <sql id="selectTElExamVo">
-        select d.exam_id, d.title, d.content, d.open_type, d.state, d.time_limit, d.exam_start_time, d.exam_end_time, d.total_score, d.total_time, d.qualify_score, d.del_flag, d.creater_code, d.createdate, d.updater_code, d.updatedate, d.dept_id, d.remarks ,s.dept_name from t_el_exam d
+        select d.exam_id,d.exam_type, d.title, d.content, d.open_type, d.state, d.time_limit, d.exam_start_time, d.exam_end_time, d.total_score, d.total_time, d.qualify_score, d.del_flag, d.creater_code, d.createdate, d.updater_code, d.updatedate, d.dept_id, d.remarks ,s.dept_name from t_el_exam d
       left join sys_dept s on s.dept_id = d.dept_id
     </sql>
 
     <select id="selectTElExamList" parameterType="TElExam" resultMap="TElExamResult">
         <include refid="selectTElExamVo"/>
         <where>
+            <if test="examId != null "> and exam_id = #{examId}</if>
             <if test="title != null  and title != ''"> and title = #{title}</if>
             <if test="content != null  and content != ''"> and content = #{content}</if>
             <if test="openType != null "> and open_type = #{openType}</if>
+            <if test="examType != null "> and exam_type = #{examType}</if>
             <if test="state != null "> and state = #{state}</if>
             <if test="timeLimit != null "> and time_limit = #{timeLimit}</if>
             <if test="examStartTime != null "> and exam_start_time = #{examStartTime}</if>
@@ -71,6 +74,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="title != null">title,</if>
             <if test="content != null">content,</if>
             <if test="openType != null">open_type,</if>
+            <if test="examType != null">exam_type,</if>
             <if test="state != null">state,</if>
             <if test="timeLimit != null">time_limit,</if>
             <if test="examStartTime != null">exam_start_time,</if>
@@ -91,6 +95,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="title != null">#{title},</if>
             <if test="content != null">#{content},</if>
             <if test="openType != null">#{openType},</if>
+            <if test="examType != null">#{examType},</if>
             <if test="state != null">#{state},</if>
             <if test="timeLimit != null">#{timeLimit},</if>
             <if test="examStartTime != null">#{examStartTime},</if>
@@ -114,6 +119,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="title != null">title = #{title},</if>
             <if test="content != null">content = #{content},</if>
             <if test="openType != null">open_type = #{openType},</if>
+            <if test="examType != null">exam_type = #{examType},</if>
             <if test="state != null">state = #{state},</if>
             <if test="timeLimit != null">time_limit = #{timeLimit},</if>
             <if test="examStartTime != null">exam_start_time = #{examStartTime},</if>

+ 2 - 2
master/src/main/resources/mybatis/training/elearn/TElLearnMapper.xml

@@ -43,8 +43,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <select id="selectLearnByUserIdAndResourceId" parameterType="TElLearn" resultMap="TElLearnResult">
         <include refid="selectTElLearnVo"/>
         <where>
-            <if test="resourceId != null  and resourceId != ''"> and resource_id = #{resourceId}</if>
-            <if test="userId != null  and userId != ''"> and user_id = #{userId}</if>
+            <if test="resourceId != null  and resourceId != ''"> and d.resource_id = #{resourceId}</if>
+            <if test="userId != null  and userId != ''"> and d.user_id = #{userId}</if>
             and d.del_flag = 0
         </where>
         <!-- 数据范围过滤 -->

BIN
master/src/main/resources/static/word/training/appraisalForm.docx


BIN
master/src/main/resources/static/word/training/targetPlan.docx


+ 53 - 0
ui/src/api/training/bccdevice.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询人员-装置级培训关系列表
+export function listDevice(query) {
+  return request({
+    url: '/training/bccdevice/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询人员-装置级培训关系详细
+export function getDevice(id) {
+  return request({
+    url: '/training/bccdevice/' + id,
+    method: 'get'
+  })
+}
+
+// 新增人员-装置级培训关系
+export function addDevice(data) {
+  return request({
+    url: '/training/bccdevice',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改人员-装置级培训关系
+export function updateDevice(data) {
+  return request({
+    url: '/training/bccdevice',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除人员-装置级培训关系
+export function delDevice(id) {
+  return request({
+    url: '/training/bccdevice/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出人员-装置级培训关系
+export function exportDevice(query) {
+  return request({
+    url: '/training/bccdevice/export',
+    method: 'get',
+    params: query
+  })
+}

+ 13 - 13
ui/src/api/training/bccnew/ysPlan.js

@@ -1,53 +1,53 @@
 import request from '@/utils/request'
 
 // 查询压缩培训模版列表
-export function listYaPlan(query) {
+export function listYsPlan(query) {
   return request({
-    url: '/bccnew/yaPlan/list',
+    url: '/bccnew/ysPlan/list',
     method: 'get',
     params: query
   })
 }
 
 // 查询压缩培训模版详细
-export function getYaPlan(id) {
+export function getYsPlan(id) {
   return request({
-    url: '/bccnew/yaPlan/' + id,
+    url: '/bccnew/ysPlan/' + id,
     method: 'get'
   })
 }
 
 // 新增压缩培训模版
-export function addYaPlan(data) {
+export function addYsPlan(data) {
   return request({
-    url: '/bccnew/yaPlan',
+    url: '/bccnew/ysPlan',
     method: 'post',
     data: data
   })
 }
 
 // 修改压缩培训模版
-export function updateYaPlan(data) {
+export function updateYsPlan(data) {
   return request({
-    url: '/bccnew/yaPlan',
+    url: '/bccnew/ysPlan',
     method: 'put',
     data: data
   })
 }
 
 // 删除压缩培训模版
-export function delYaPlan(id) {
+export function delYsPlan(id) {
   return request({
-    url: '/bccnew/yaPlan/' + id,
+    url: '/bccnew/ysPlan/' + id,
     method: 'delete'
   })
 }
 
 // 导出压缩培训模版
-export function exportYaPlan(query) {
+export function exportYsPlan(query) {
   return request({
-    url: '/bccnew/yaPlan/export',
+    url: '/bccnew/ysPlan/export',
     method: 'get',
     params: query
   })
-}
+}

+ 72 - 0
ui/src/api/training/trainingbcc.js

@@ -0,0 +1,72 @@
+import request from '@/utils/request'
+
+// 查询装置培训跟踪b列表
+export function listTrainingbcc(query) {
+  return request({
+    url: '/training/trainingbcc/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询装置培训跟踪b详细
+export function getTrainingbcc(id) {
+  return request({
+    url: '/training/trainingbcc/' + id,
+    method: 'get'
+  })
+}
+
+// 查询装置培训跟踪b详细
+export function getTrainingbccStaffIds(id) {
+  return request({
+    url: '/training/trainingbcc/staffIds/' + id,
+    method: 'get'
+  })
+}
+
+
+// 新增装置培训跟踪b
+export function addTrainingbcc(data) {
+  return request({
+    url: '/training/trainingbcc',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改装置培训跟踪b
+export function updateTrainingbcc(data) {
+  return request({
+    url: '/training/trainingbcc',
+    method: 'put',
+    data: data
+  })
+}
+
+// 修改装置培训跟踪b
+export function updateTrainingbccStaffIds(data) {
+  return request({
+    url: '/training/trainingbcc/updateStaffIds',
+    method: 'post',
+    data: data
+  })
+}
+
+
+// 删除装置培训跟踪b
+export function delTrainingbcc(id) {
+  return request({
+    url: '/training/trainingbcc/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出装置培训跟踪b
+export function exportTrainingbcc(query) {
+  return request({
+    url: '/training/trainingbcc/export',
+    method: 'get',
+    params: query
+  })
+}

+ 19 - 1
ui/src/router/index.js

@@ -343,6 +343,11 @@ export const constantRoutes = [
         component: (resolve) => require(['@/views/training/bccnew/tsnew/trainingPlan.vue'], resolve),
         name: 'trainingPlan',
         meta: { title: '导师带徒培训计划' }
+      },{
+        path: 'trainingPlan_s/:newId(\\d+)',
+        component: (resolve) => require(['@/views/training/bccnew/tsnew/trainingPlan_student.vue'], resolve),
+        name: 'trainingPlans',
+        meta: { title: '导师带徒培训计划' }
       },
     ]
   },
@@ -593,6 +598,19 @@ export const constantRoutes = [
       }
     ]
   },
+  {
+    path: '/training',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: 'deviceList/:id',
+        component: (resolve) => require(['@/views/training/trainingbcc/deviceList'], resolve),
+        name: 'deviceList',
+        meta: { title: '装置培训详情' }
+      }
+    ]
+  },
   {
     path: '/training/elearn',
     component: Layout,
@@ -605,7 +623,7 @@ export const constantRoutes = [
         meta: { title: '准备考试', noCache: true },
         hidden: true
       },{
-        path: 'paper',
+        path: 'paper/:examId',
         component: () => import('@/views/training/elearn/paper/list'),
         name: 'paper',
         meta: { title: '在线考试', noCache: true },

+ 2 - 0
ui/src/views/components/PlantProgList/index.vue

@@ -117,6 +117,7 @@
       </el-table-column>
       <el-table-column :label="$t('下次修订日期')" align="center" sortable="custom" prop="nexteditdate" width="100">
         <template slot-scope="scope">
+          <span v-if="scope.row.nexteditdate == null">按需</span>
           <span style="vertical-align:middle">{{ parseTime(scope.row.nexteditdate, '{y}-{m}-{d}') }}</span>
           <svg-icon  :icon-class="changeColorPiont(scope.row.nexteditdate)"
                     style="font-size: 8px"></svg-icon>
@@ -126,6 +127,7 @@
                        v-if="this.itemNum !== '5'"/>
       <el-table-column :label="$t('回顾日期')" align="center" prop="reviewdate" width="100" v-if="this.itemNum !== '5'">
         <template slot-scope="scope">
+          <span v-if="scope.row.reviewdate == null">NA</span>
           <span>{{ parseTime(scope.row.reviewdate, '{y}-{m}-{d}') }}</span>
         </template>
       </el-table-column>

+ 2 - 2
ui/src/views/login.vue

@@ -260,8 +260,8 @@ export default {
   justify-content: center;
   align-items: center;
   height: 100%;
-  background-image: url("../assets/image/CPMS20210107.jpg");
-  //background-image: url("../assets/image/cpms-test.jpg");
+  //background-image: url("../assets/image/CPMS20210107.jpg");
+  background-image: url("../assets/image/cpms-test.jpg");
   background-size: cover;
 }
 

+ 439 - 0
ui/src/views/training/bccdevice/index.vue

@@ -0,0 +1,439 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="开始日期" prop="startDate">
+        <el-date-picker clearable size="small" style="width: 200px"
+          v-model="queryParams.startDate"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择开始日期">
+        </el-date-picker>
+      </el-form-item>
+
+      <el-form-item label="学习时长min" prop="learnTime">
+        <el-input
+          v-model="queryParams.learnTime"
+          placeholder="请输入学习时长min"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+        >新增</el-button>
+      </el-col>
+
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="deviceList" @selection-change="handleSelectionChange" :height="clientHeight" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="开始日期" align="center" prop="startDate" width="100">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.startDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="参培人" align="center" prop="name" width="100">
+      </el-table-column>
+      <el-table-column label="培训课程" align="center" prop="trainingbcc.course" width="500">
+      </el-table-column>
+      <el-table-column label="是否为补培人员" align="center" prop="supplementary" :show-overflow-tooltip="true">
+        <template v-slot="scope">
+          <span v-if="scope.row.supplementary == 0" size="small" type="success">否</span>
+          <span v-else-if="scope.row.supplementary == 1" size="small" type="info">是</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="学习状态" align="center" prop="learnState" :show-overflow-tooltip="true">
+        <template v-slot="scope">
+          <el-tag v-if="scope.row.learnState == 1" size="small" type="success">已完成</el-tag>
+          <el-tag v-else-if="scope.row.learnState == 0"  size="small" type="info">未完成</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="考试状态" align="center" prop="examState" :show-overflow-tooltip="true">
+        <template v-slot="scope">
+          <el-tag v-if="scope.row.examState == 1" size="small" type="success">合格</el-tag>
+          <el-tag v-else-if="scope.row.examState == 0" size="small" type="info">未完成</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="学习时长min" align="center" prop="learnTime" :show-overflow-tooltip="true"/>
+      <el-table-column label="操作" align="center" fixed="right" width="120" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleUpdate(scope.row)"
+          >学习</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="hanldeExam(scope.row)"
+          >考试</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改人员-装置级培训关系对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="人员员工号" prop="staffId">
+          <el-input v-model="form.staffId" placeholder="请输入人员员工号" />
+        </el-form-item>
+        <el-form-item label="装置级培训ID" prop="regularId">
+          <el-input v-model="form.regularId" placeholder="请输入装置级培训ID" />
+        </el-form-item>
+        <el-form-item label="开始日期" prop="startDate">
+          <el-date-picker clearable size="small" style="width: 200px"
+            v-model="form.startDate"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择开始日期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="备注" prop="remarks">
+          <el-input v-model="form.remarks" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="删除状态" prop="delFlag">
+          <el-input v-model="form.delFlag" placeholder="请输入删除状态" />
+        </el-form-item>
+        <el-form-item label="创建人" prop="createrCode">
+          <el-input v-model="form.createrCode" placeholder="请输入创建人" />
+        </el-form-item>
+        <el-form-item label="创建时间" prop="createdate">
+          <el-date-picker clearable size="small" style="width: 200px"
+            v-model="form.createdate"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择创建时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="修改人" prop="updaterCode">
+          <el-input v-model="form.updaterCode" placeholder="请输入修改人" />
+        </el-form-item>
+        <el-form-item label="修改时间" prop="updatedate">
+          <el-date-picker clearable size="small" style="width: 200px"
+            v-model="form.updatedate"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择修改时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="是否为补培人员" prop="supplementary">
+          <el-input v-model="form.supplementary" placeholder="请输入是否为补培人员" />
+        </el-form-item>
+        <el-form-item label="学习状态" prop="learnState">
+          <el-input v-model="form.learnState" placeholder="请输入学习状态" />
+        </el-form-item>
+        <el-form-item label="考试状态" prop="examState">
+          <el-input v-model="form.examState" placeholder="请输入考试状态" />
+        </el-form-item>
+        <el-form-item label="考试ID" prop="examId">
+          <el-input v-model="form.examId" placeholder="请输入考试ID" />
+        </el-form-item>
+        <el-form-item label="学习时长min" prop="learnTime">
+          <el-input v-model="form.learnTime" placeholder="请输入学习时长min" />
+        </el-form-item>
+          <el-form-item label="归属部门" prop="deptId">
+              <treeselect v-model="form.deptId" :options="deptOptions" :show-count="true" placeholder="请选择归属部门" />
+          </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+      <!-- 用户导入对话框 -->
+      <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
+          <el-upload
+                  ref="upload"
+                  :limit="1"
+                  accept=".xlsx, .xls"
+                  :headers="upload.headers"
+                  :action="upload.url + '?updateSupport=' + upload.updateSupport"
+                  :disabled="upload.isUploading"
+                  :on-progress="handleFileUploadProgress"
+                  :on-success="handleFileSuccess"
+                  :auto-upload="false"
+                  drag
+          >
+              <i class="el-icon-upload"></i>
+              <div class="el-upload__text">
+                  将文件拖到此处,或
+                  <em>点击上传</em>
+              </div>
+              <div class="el-upload__tip" slot="tip">
+                  <el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
+                  <el-link type="info" style="font-size:12px" @click="importTemplate">下载模板</el-link>
+              </div>
+              <div class="el-upload__tip" style="color:red" slot="tip">提示:仅允许导入“xls”或“xlsx”格式文件!</div>
+          </el-upload>
+          <div slot="footer" class="dialog-footer">
+              <el-button type="primary" @click="submitFileForm">确 定</el-button>
+              <el-button @click="upload.open = false">取 消</el-button>
+          </div>
+      </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listDevice, getDevice, delDevice, addDevice, updateDevice, exportDevice, importTemplate} from "@/api/training/bccdevice";
+import { treeselect } from "@/api/system/dept";
+import { getToken } from "@/utils/auth";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "Device",
+  components: { Treeselect },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: false,
+      // 总条数
+      total: 0,
+      // 人员-装置级培训关系表格数据
+      deviceList: [],
+      // 弹出层标题
+      title: "",
+      // 部门树选项
+      deptOptions: undefined,
+      clientHeight:300,
+      // 是否显示弹出层
+      open: false,
+        // 用户导入参数
+        upload: {
+            // 是否显示弹出层(用户导入)
+            open: false,
+            // 弹出层标题(用户导入)
+            title: "",
+            // 是否禁用上传
+            isUploading: false,
+            // 是否更新已经存在的用户数据
+            updateSupport: 0,
+            // 设置上传的请求头部
+            headers: { Authorization: "Bearer " + getToken() },
+            // 上传的地址
+            url: process.env.VUE_APP_BASE_API + "/training/device/importData"
+        },
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 20,
+        staffId: null,
+        regularId: null,
+        startDate: null,
+        remarks: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        supplementary: null,
+        learnState: null,
+        examState: null,
+        examId: null,
+        learnTime: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  watch: {
+        // 根据名称筛选部门树
+        deptName(val) {
+            this.$refs.tree.filter(val);
+        }
+   },
+  created() {
+      //设置表格高度对应屏幕高度
+      this.$nextTick(() => {
+          this.clientHeight = document.body.clientHeight -250
+      })
+    this.getList();
+    this.getTreeselect();
+  },
+  methods: {
+    /** 查询人员-装置级培训关系列表 */
+    getList() {
+      this.loading = true;
+      listDevice(this.queryParams).then(response => {
+        this.deviceList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+     /** 查询部门下拉树结构 */
+     getTreeselect() {
+          treeselect().then(response => {
+              this.deptOptions = response.data;
+          });
+     },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        staffId: null,
+        regularId: null,
+        startDate: null,
+        remarks: null,
+        delFlag: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        supplementary: null,
+        learnState: null,
+        examState: null,
+        examId: null,
+        learnTime: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    hanldeExam(row){
+      this.$router.push({ name: 'paper', params: { examId: row.examId }})
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加人员-装置级培训关系";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getDevice(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改人员-装置级培训关系";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateDevice(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addDevice(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delDevice(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有人员-装置级培训关系数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportDevice(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        })
+    },
+      /** 导入按钮操作 */
+      handleImport() {
+          this.upload.title = "用户导入";
+          this.upload.open = true;
+      },
+      /** 下载模板操作 */
+      importTemplate() {
+          importTemplate().then(response => {
+              this.download(response.msg);
+          });
+      },
+      // 文件上传中处理
+      handleFileUploadProgress(event, file, fileList) {
+          this.upload.isUploading = true;
+      },
+      // 文件上传成功处理
+      handleFileSuccess(response, file, fileList) {
+          this.upload.open = false;
+          this.upload.isUploading = false;
+          this.$refs.upload.clearFiles();
+          this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
+          this.getList();
+      },
+      // 提交上传文件
+      submitFileForm() {
+          this.$refs.upload.submit();
+      }
+  }
+};
+</script>

+ 75 - 62
ui/src/views/training/bccnew/firstPlanTmpl/index.vue

@@ -93,7 +93,6 @@
     <el-table v-loading="loading" :data="firstPlanTmplList" @selection-change="handleSelectionChange"
               :height="clientHeight" border>
       <el-table-column type="selection" width="55" align="center"/>
-      <el-table-column label="培训员工编号" align="center" prop="newId" :show-overflow-tooltip="true"/>
       <el-table-column label="课程编号" align="center" prop="courseCode" :show-overflow-tooltip="true"/>
       <el-table-column label="培训主题" align="center" prop="topic" :show-overflow-tooltip="true"/>
       <el-table-column label="培训内容" align="center" prop="content" :show-overflow-tooltip="true"/>
@@ -101,14 +100,9 @@
       <el-table-column label="培训小时" align="center" prop="courseHour" :show-overflow-tooltip="true"/>
       <el-table-column label="培训类型" align="center" prop="courseType" :show-overflow-tooltip="true"/>
       <el-table-column label="讲师" align="center" prop="trainer" :show-overflow-tooltip="true"/>
-      <el-table-column label="培训日期" align="center" prop="courseDate" width="100">
-        <template slot-scope="scope">
-          <span>{{ parseTime(scope.row.courseDate, '{y}-{m}-{d}') }}</span>
-        </template>
-      </el-table-column>
-      <el-table-column label="考核情况" align="center" prop="assess" :show-overflow-tooltip="true"/>
+      <el-table-column label="应学习时长" align="center" prop="timerNeed" :show-overflow-tooltip="true"/>
       <el-table-column label="备注" align="center" prop="remarks" :show-overflow-tooltip="true"/>
-      <el-table-column label="操作" align="center" fixed="right" width="120" class-name="small-padding fixed-width">
+      <el-table-column label="操作" align="center" fixed="right" width="230" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button
             size="mini"
@@ -130,9 +124,10 @@
             size="mini"
             type="text"
             icon="el-icon-folder"
-            @click="doc.open=true"
-            v-hasPermi="['newstaff:tnNew:edit']"
-          >学习资料</el-button>
+            @click="uploadFile(scope.row)"
+            v-hasPermi="['bccnew:firstPlanTmpl:edit']"
+          >学习资料
+          </el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -146,11 +141,8 @@
     />
 
     <!-- 添加或修改进组培训模版对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="培训员工编号" prop="newId">
-          <el-input v-model="form.newId" placeholder="请输入培训员工编号"/>
-        </el-form-item>
+    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="130px">
         <el-form-item label="课程编号" prop="courseCode">
           <el-input v-model="form.courseCode" placeholder="请输入课程编号"/>
         </el-form-item>
@@ -172,16 +164,8 @@
         <el-form-item label="讲师" prop="trainer">
           <el-input v-model="form.trainer" placeholder="请输入讲师"/>
         </el-form-item>
-        <el-form-item label="培训日期" prop="courseDate">
-          <el-date-picker clearable size="small" style="width: 200px"
-                          v-model="form.courseDate"
-                          type="date"
-                          value-format="yyyy-MM-dd"
-                          placeholder="选择培训日期">
-          </el-date-picker>
-        </el-form-item>
-        <el-form-item label="考核情况" prop="assess">
-          <el-input v-model="form.assess" placeholder="请输入考核情况"/>
+        <el-form-item label="应学习时长(分)" prop="timerNeed">
+          <el-input-number v-model="form.timerNeed" placeholder="请输入应学习时长" style="width: 100%"/>
         </el-form-item>
         <el-form-item label="备注" prop="remarks">
           <el-input v-model="form.remarks" placeholder="请输入备注"/>
@@ -225,17 +209,19 @@
     </el-dialog>
 
 
-    <el-dialog  :close-on-click-modal="false" v-dialogDrag :title="doc.title" :visible.sync="doc.open" width="1000px" append-to-body >
-      <el-upload v-hasPermi="['training:trainingrecords:file']"
-                 ref="doc"
-                 :limit="50"
-                 :headers="doc.headers"
-                 :action="doc.url + '?pType=' + doc.pType + '&pId=' + doc.pId"
-                 :disabled="doc.isUploading"
-                 :on-progress="handleFileDocProgress"
-                 :on-success="handleFileDocSuccess"
-                 :auto-upload="true"
-                 drag
+    <el-dialog :close-on-click-modal="false" v-dialogDrag :title="doc.title" :visible.sync="doc.open" width="1000px"
+               append-to-body>
+      <el-upload
+        ref="doc"
+        :limit="50"
+        :headers="doc.headers"
+        :action="doc.url+'/'+doc.id"
+        :disabled="doc.isUploading"
+        :on-progress="handleFileDocProgress"
+        :on-success="handleFileDocSuccess"
+        :file-list="doc.file"
+        :auto-upload="true"
+        drag
       >
         <i class="el-icon-upload"></i>
         <div class="el-upload__text">
@@ -246,43 +232,53 @@
       <el-table :data="doc.commonfileList" border>
         <el-table-column :label="$t('文件名')" align="center" prop="fileName" :show-overflow-tooltip="true">
           <template slot-scope="scope">
-            <a  class="link-type"  @click="handleDownload(scope.row)">
+            <a class="link-type" @click="handleDownload(scope.row)">
               <span>{{ scope.row.fileName }}</span>
             </a>
           </template>
         </el-table-column>
-        <el-table-column :label="$t('大小(Kb)')" align="center" prop="fileSize" :show-overflow-tooltip="true" width="80" />
-        <el-table-column :label="$t('上传人')" align="center" prop="creator" :show-overflow-tooltip="true" width="120"/>
+        <!--        <el-table-column :label="$t('大小(Kb)')" align="center" prop="fileSize" :show-overflow-tooltip="true"-->
+        <!--                         width="80"/>-->
+        <!--        <el-table-column :label="$t('上传人')" align="center" prop="creator" :show-overflow-tooltip="true" width="120"/>-->
         <el-table-column :label="$t('操作')" align="center" width="220" class-name="small-padding fixed-width">
           <template slot-scope="scope">
             <el-button
-              v-if="scope.row.fileName.endsWith('pdf')"
+              v-if="scope.row.fileName!=null&&scope.row.fileName.endsWith('pdf')"
               size="mini"
               type="text"
               icon="el-icon-view"
               @click="handleSee(scope.row)"
-            >{{ $t('预览') }}</el-button>
-            <el-button v-hasPermi="['training:trainingrecords:file']"  type="text" size="small" v-if="scope.row.isEdit" @click="save(scope.row)">保存</el-button>
-            <el-button type="text" size="small" v-if="scope.row.isEdit" @click="cancelFile(scope.row, scope.$index)">取消</el-button>
+            >{{ $t('预览') }}
+            </el-button>
+            <el-button v-hasPermi="['training:trainingrecords:file']" type="text" size="small" v-if="scope.row.isEdit"
+                       @click="save(scope.row)">保存
+            </el-button>
+            <el-button type="text" size="small" v-if="scope.row.isEdit" @click="cancelFile(scope.row, scope.$index)">
+              取消
+            </el-button>
             <el-button
               size="mini"
               type="text"
               icon="el-icon-download"
               @click="handleDownload(scope.row)"
-            >{{ $t('下载') }}</el-button>
+            >{{ $t('下载') }}
+            </el-button>
             <el-button
               size="mini"
               type="text"
               icon="el-icon-delete"
               @click="handleDeleteDoc(scope.row)"
               v-hasPermi="['training:trainingrecords:file']"
-            >{{ $t('删除') }}</el-button>
+            >{{ $t('删除') }}
+            </el-button>
           </template>
         </el-table-column>
       </el-table>
-      <el-dialog  :close-on-click-modal="false" v-dialogDrag :title="pdf.title" :visible.sync="pdf.open" width="1300px" append-to-body>
+      <el-dialog :close-on-click-modal="false" v-dialogDrag :title="pdf.title" :visible.sync="pdf.open" width="1300px"
+                 append-to-body>
         <div style="margin-top: -60px;float: right;margin-right: 40px;">
-          <el-button size="mini" type="text" @click="openPdf">{{$t('新页面打开PDF')}}</el-button></div>
+          <el-button size="mini" type="text" @click="openPdf">{{ $t('新页面打开PDF') }}</el-button>
+        </div>
         <div style="margin-top: -30px">
           <iframe :src="pdf.pdfUrl" frameborder="0" width="100%" height="700px"></iframe>
         </div>
@@ -311,7 +307,6 @@ import {treeselect} from "@/api/system/dept";
 import {getToken} from "@/utils/auth";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
-import {delCommonfile} from "@/api/common/commonfile";
 
 export default {
   name: "FirstPlanTmpl",
@@ -319,10 +314,9 @@ export default {
   // components: { Editor },
   data() {
     return {
-
       // 报告附件参数
       doc: {
-        file: "",
+        file: null,
         // 是否显示弹出层(报告附件)
         open: false,
         // 弹出层标题(报告附件)
@@ -333,8 +327,9 @@ export default {
         updateSupport: 0,
         // 报告附件上传位置编号
         ids: 0,
+        id: null,
         // 设置上传的请求头部
-        headers: { Authorization: "Bearer " + getToken() },
+        headers: {Authorization: "Bearer " + getToken()},
         // 上传的地址
         url: process.env.VUE_APP_BASE_API + "/bccnew/firstPlanTmpl/uploadFile",
         commonfileList: null,
@@ -346,7 +341,7 @@ export default {
         pId: null,
         form: {}
       },
-      pdf : {
+      pdf: {
         title: '',
         pdfUrl: '',
         numPages: null,
@@ -433,6 +428,16 @@ export default {
     this.getTreeselect();
   },
   methods: {
+    uploadFile(row) {
+      this.doc.file = null;
+      this.doc.commonfileList = [];
+      this.doc.open = true;
+      this.doc.id = row.id;
+      getFirstPlanTmpl(row.id).then(res => {
+        if (res.data.fileUrl != null)
+          this.doc.commonfileList.push({fileUrl: res.data.fileUrl, fileName: res.data.fileName, id: res.data.id})
+      })
+    },
     // 文件下载处理
     handleDownload(row) {
       var name = row.fileName;
@@ -444,14 +449,14 @@ export default {
       a.setAttribute('href', process.env.VUE_APP_BASE_API + url)
       a.click()
     },
-    openPdf(){
+    openPdf() {
       window.open(this.pdf.pdfUrl);//path是文件的全路径地址
     },
-    handleSee (row){
+    handleSee(row) {
       // window.open(process.env.VUE_APP_BASE_API +'/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl);//path是文件的全路径地址
-      this.pdf.open =true
+      this.pdf.open = true
       this.pdf.title = row.fileName
-      this.pdf.pdfUrl = process.env.VUE_APP_BASE_API +'/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl
+      this.pdf.pdfUrl = process.env.VUE_APP_BASE_API + '/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl
     },
     /** 删除按钮操作 */
     handleDeleteDoc(row) {
@@ -460,11 +465,11 @@ export default {
         confirmButtonText: this.$t('确定'),
         cancelButtonText: this.$t('取消'),
         type: "warning"
-      }).then(function() {
-        return delCommonfile(ids);
+      }).then(function () {
+        return updateFirstPlanTmpl({id: row.id, fileUrl: '', fileName: ''});
       }).then(() => {
-        this.getFileList()
         this.msgSuccess(this.$t('删除成功'));
+        this.doc.commonfileList = [];
       })
     },
     // 上传中处理
@@ -475,8 +480,16 @@ export default {
     //附件上传成功处理
     handleFileDocSuccess(response, file, fileList) {
       this.doc.isUploading = false;
-      this.$alert(response.msg, this.$t('导入结果'), { dangerouslyUseHTMLString: true });
-      this.getFileList()
+      this.$alert(response.msg, this.$t('导入结果'), {dangerouslyUseHTMLString: true});
+      this.getList();
+      this.doc.commonfileList = [];
+      getFirstPlanTmpl(response.data).then(res => {
+        if (res.data.fileUrl != null) {
+          this.doc.commonfileList.push({fileUrl: res.data.fileUrl, fileName: res.data.fileName, id: res.data.id})
+          fileList = null
+          file = null
+        }
+      })
     },
     /** 查询进组培训模版列表 */
     getList() {

+ 2 - 117
ui/src/views/training/bccnew/firstplan/index.vue

@@ -1,15 +1,6 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="培训员工编号" prop="newId">
-        <el-input
-          v-model="queryParams.newId"
-          placeholder="请输入培训员工编号"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
       <el-form-item label="课程编号" prop="courseCode">
         <el-input
           v-model="queryParams.courseCode"
@@ -28,112 +19,6 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="培训天" prop="courseDay">
-        <el-input
-          v-model="queryParams.courseDay"
-          placeholder="请输入培训天"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="培训小时" prop="courseHour">
-        <el-input
-          v-model="queryParams.courseHour"
-          placeholder="请输入培训小时"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="培训类型" prop="courseType">
-        <el-select v-model="queryParams.courseType" placeholder="请选择培训类型" clearable size="small">
-          <el-option label="请选择字典生成" value=""/>
-        </el-select>
-      </el-form-item>
-      <el-form-item label="讲师" prop="trainer">
-        <el-input
-          v-model="queryParams.trainer"
-          placeholder="请输入讲师"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="培训日期" prop="courseDate">
-        <el-date-picker clearable size="small" style="width: 200px"
-                        v-model="queryParams.courseDate"
-                        type="date"
-                        value-format="yyyy-MM-dd"
-                        placeholder="选择培训日期">
-        </el-date-picker>
-      </el-form-item>
-      <el-form-item label="考核情况" prop="assess">
-        <el-input
-          v-model="queryParams.assess"
-          placeholder="请输入考核情况"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="创建人" prop="createrCode">
-        <el-input
-          v-model="queryParams.createrCode"
-          placeholder="请输入创建人"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="创建时间" prop="createdate">
-        <el-date-picker clearable size="small" style="width: 200px"
-                        v-model="queryParams.createdate"
-                        type="date"
-                        value-format="yyyy-MM-dd"
-                        placeholder="选择创建时间">
-        </el-date-picker>
-      </el-form-item>
-      <el-form-item label="修改人" prop="updaterCode">
-        <el-input
-          v-model="queryParams.updaterCode"
-          placeholder="请输入修改人"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="修改时间" prop="updatedate">
-        <el-date-picker clearable size="small" style="width: 200px"
-                        v-model="queryParams.updatedate"
-                        type="date"
-                        value-format="yyyy-MM-dd"
-                        placeholder="选择修改时间">
-        </el-date-picker>
-      </el-form-item>
-      <el-form-item label="部门编号" prop="deptId">
-        <el-input
-          v-model="queryParams.deptId"
-          placeholder="请输入部门编号"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="备注" prop="remarks">
-        <el-input
-          v-model="queryParams.remarks"
-          placeholder="请输入备注"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="培训状态" prop="planStatus">
-        <el-select v-model="queryParams.planStatus" placeholder="请选择培训状态" clearable size="small">
-          <el-option label="请选择字典生成" value=""/>
-        </el-select>
-      </el-form-item>
       <el-form-item>
         <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
         <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@@ -362,7 +247,7 @@
       </el-button>
     </el-dialog>
 
-    <el-dialog :close-on-click-modal="false" v-loading="pdf.loadingFlash" element-loading-background="rgba(0,0,0,0.2)"
+    <el-dialog :close-on-click-modal="false"  element-loading-background="rgba(0,0,0,0.2)"
                v-dialogDrag :title="pdf.title"
                :visible.sync="pdf.open" width="1300px" height="800px" :center="true" append-to-body
                @close="handleClose">
@@ -498,7 +383,7 @@ export default {
     })
     this.getList();
     this.getTreeselect();
-    this.getDicts("training_newstaff_status").then(response => {
+    this.getDicts("training_bccnew_status").then(response => {
       this.planStatusOptions = response.data;
     });
   },

+ 534 - 0
ui/src/views/training/bccnew/firstplan/index_student.vue

@@ -0,0 +1,534 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="课程编号" prop="courseCode">
+        <el-input
+          v-model="queryParams.courseCode"
+          placeholder="请输入课程编号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="培训主题" prop="topic">
+        <el-input
+          v-model="queryParams.topic"
+          placeholder="请输入培训主题"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="firstplanList" @selection-change="handleSelectionChange" :height="clientHeight"
+              border>
+      <el-table-column type="selection" width="55" align="center"/>
+      <el-table-column label="课程编号" align="center" prop="courseCode" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="培训主题" align="center" prop="topic" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="培训内容" align="center" prop="content" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="培训天" align="center" prop="courseDay" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="培训小时" align="center" prop="courseHour" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="培训类型" align="center" prop="courseType" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="讲师" align="center" prop="trainer" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="培训日期" align="center" prop="courseDate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.courseDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="考核情况" align="center" prop="assess" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="第一次成绩" align="center" prop="score1" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="第二次成绩" align="center" prop="score2" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="第三次成绩" align="center" prop="score3" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="备注" align="center" prop="remarks" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="培训状态" align="center" prop="planStatus" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="操作" align="center" fixed="right" width="120" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-folder"
+            @click="openFileDialog(scope.row)"
+          >学习资料
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改进组培训对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="130px">
+        <el-form-item label="课程编号" prop="courseCode">
+          <el-input v-model="form.courseCode" placeholder="请输入课程编号"/>
+        </el-form-item>
+        <el-form-item label="培训主题" prop="topic">
+          <el-input v-model="form.topic" placeholder="请输入培训主题"/>
+        </el-form-item>
+        <el-form-item label="培训内容">
+          <el-input v-model="form.content" placeholder="请输入培训内容"/>
+        </el-form-item>
+        <el-form-item label="培训天" prop="courseDay">
+          <el-input v-model="form.courseDay" placeholder="请输入培训天"/>
+        </el-form-item>
+        <el-form-item label="培训小时" prop="courseHour">
+          <el-input v-model="form.courseHour" placeholder="请输入培训小时"/>
+        </el-form-item>
+        <el-form-item label="培训类型" prop="courseType">
+          <el-input v-model="form.courseType" placeholder="请输入培训类型"/>
+          <el-option label="请选择字典生成" value=""/>
+        </el-form-item>
+        <el-form-item label="讲师" prop="trainer">
+          <el-input v-model="form.trainer" placeholder="请输入讲师"/>
+        </el-form-item>
+        <el-form-item label="培训日期" prop="courseDate">
+          <el-date-picker clearable size="small" style="width: 200px"
+                          v-model="form.courseDate"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          placeholder="选择培训日期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="考核情况" prop="assess">
+          <el-input v-model="form.assess" placeholder="请输入考核情况"/>
+        </el-form-item>
+        <el-form-item label="培训状态">
+          <el-select v-model="form.planStatus" placeholder="请选择培训状态">
+            <el-option
+              v-for="dict in planStatusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="备注" prop="remarks">
+          <el-input v-model="form.remarks" placeholder="请输入备注"/>
+        </el-form-item>
+        <el-form-item label="归属部门" prop="deptId">
+          <treeselect v-model="form.deptId" :options="deptOptions" :show-count="true" placeholder="请选择归属部门"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+    <!-- 用户导入对话框 -->
+    <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
+      <el-upload
+        ref="upload"
+        :limit="1"
+        accept=".xlsx, .xls"
+        :headers="upload.headers"
+        :action="upload.url + '?updateSupport=' + upload.updateSupport"
+        :disabled="upload.isUploading"
+        :on-progress="handleFileUploadProgress"
+        :on-success="handleFileSuccess"
+        :auto-upload="false"
+        drag
+      >
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">
+          将文件拖到此处,或
+          <em>点击上传</em>
+        </div>
+        <div class="el-upload__tip" slot="tip">
+          <el-checkbox v-model="upload.updateSupport"/>
+          是否更新已经存在的用户数据
+          <el-link type="info" style="font-size:12px" @click="importTemplate">下载模板</el-link>
+        </div>
+        <div class="el-upload__tip" style="color:red" slot="tip">提示:仅允许导入“xls”或“xlsx”格式文件!</div>
+      </el-upload>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitFileForm">确 定</el-button>
+        <el-button @click="upload.open = false">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog :visible.sync="file.open" width="30%" append-to-body>
+      <el-descriptions class="margin-top" title="学习资料" :column="1" size="" border>
+        <el-descriptions-item label-style="width:180px">
+          <template slot="label">
+            <i class="el-icon-user"></i>
+            资料名
+          </template>
+          {{ file.data.fileName }}
+        </el-descriptions-item>
+        <el-descriptions-item label-style="width:180px">
+          <template slot="label">
+            <i class="el-icon-mobile-phone"></i>
+            学习进度
+          </template>
+          <el-progress :text-inside="true" :stroke-width="20" :percentage="getCountTime()"
+                       status="success"></el-progress>
+        </el-descriptions-item>
+        <el-descriptions-item label-style="width:180px">
+          <template slot="label">
+            <i class="el-icon-mobile-phone"></i>
+            应学习时长(分)
+          </template>
+          {{ file.data.timerNeed }}
+        </el-descriptions-item>
+        <el-descriptions-item label-style="width:180px">
+          <template slot="label">
+            <i class="el-icon-mobile-phone"></i>
+            已学习时长(分)
+          </template>
+          {{ file.data.timer }}
+        </el-descriptions-item>
+      </el-descriptions>
+      <el-button
+        class="mt10"
+        type="primary"
+        icon="el-icon-video-play"
+        @click="handleStudy(file.data)"
+      >开始学习
+      </el-button>
+    </el-dialog>
+
+    <el-dialog :close-on-click-modal="false" v-loading="pdf.loadingFlash" element-loading-background="rgba(0,0,0,0.2)"
+               v-dialogDrag :title="pdf.title"
+               :visible.sync="pdf.open" width="1300px" height="800px" :center="true" append-to-body
+               @close="handleClose">
+      <div style="margin-top: -30px">
+        <iframe id="iFrame" class="iframe-html" :src="pdf.pdfUrl" frameborder="0" width="100%" height="700px"
+                v-if="ppt"></iframe>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import {
+  addFirstplan,
+  delFirstplan,
+  exportFirstplan,
+  getFirstplan,
+  importTemplate,
+  listFirstplan,
+  updateFirstLearnTime,
+  updateFirstplan
+} from "@/api/training/bccnew/firstplan";
+import {treeselect} from "@/api/system/dept";
+import {getToken} from "@/utils/auth";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+var timer = null;
+export default {
+  name: "FirstplanBccnew_s",
+  components: {Treeselect},
+  props: {
+    newId: {
+      default: null
+    },
+    planType: {}
+  },
+  // components: { Editor },
+  data() {
+    return {
+      file: {
+        open: false,
+        data: {}
+      },
+      ppt: false,
+      pdf: {
+        title: '',
+        pdfUrl: '',
+        numPages: null,
+        open: false,
+        pageNum: 1,
+        pageTotalNum: 1,
+        loadedRatio: 0,
+        loadingFlash: false,
+      },
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: false,
+      // 总条数
+      total: 0,
+      // 进组培训表格数据
+      firstplanList: [],
+      // 培训状态字典
+      planStatusOptions: [],
+      // 弹出层标题
+      title: "",
+      // 部门树选项
+      deptOptions: undefined,
+      clientHeight: 300,
+      // 是否显示弹出层
+      open: false,
+      // 用户导入参数
+      upload: {
+        // 是否显示弹出层(用户导入)
+        open: false,
+        // 弹出层标题(用户导入)
+        title: "",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: {Authorization: "Bearer " + getToken()},
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/bccnew/firstplan/importData"
+      },
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 20,
+        newId: this.newId,
+        courseCode: null,
+        topic: null,
+        content: null,
+        courseDay: null,
+        courseHour: null,
+        courseType: null,
+        trainer: null,
+        courseDate: null,
+        assess: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        deptId: null,
+        remarks: null,
+        planStatus: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {}
+    };
+  },
+  watch: {
+    // 根据名称筛选部门树
+    deptName(val) {
+      this.$refs.tree.filter(val);
+    }
+  },
+  created() {
+    //设置表格高度对应屏幕高度
+    this.$nextTick(() => {
+      this.clientHeight = document.body.clientHeight - 250
+    })
+    this.getList();
+    this.getTreeselect();
+    this.getDicts("training_bccnew_status").then(response => {
+      this.planStatusOptions = response.data;
+    });
+  },
+  methods: {
+    handleClose() {
+      window.clearInterval(timer);
+      this.getList();
+    },
+    handleStudy(row) {
+      //office预览
+      this.pdf.loadingFlash = true
+      this.pdf.open = true
+      this.pdf.title = row.fileName
+      this.pdf.pdfUrl = ""
+      this.ppt = true
+      //如果是PDF等直接可以打开的就不调接口,否则调用接口
+      if (row.fileName!=null && row.fileName.endsWith('pdf')) {
+        this.pdf.pdfUrl = process.env.VUE_APP_BASE_API + '/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl
+        this.loadingFlash = false
+      }
+      let _this = this;
+      timer = window.setInterval(function () {
+        updateFirstLearnTime(row).then(res => {
+        })
+      }, 60000);
+    },
+    getCountTime() {
+      if (this.file.data.timerNeed === 0)
+        return 0;
+      return (this.file.data.timer / this.file.data.timerNeed * 100).toFixed(2)
+    },
+    openFileDialog(row) {
+      this.file.open = true;
+      this.file.data = row
+      console.log(row)
+      if (row.timer === '' || row.timer == null) {
+        this.file.data.timer = 0
+      }
+      if (row.timerNeed === '' || row.timerNeed == null) {
+        this.file.data.timerNeed = 0
+      }
+      console.log(this.file.data)
+    },
+    /** 查询进组培训列表 */
+    getList() {
+      this.loading = true;
+      listFirstplan(this.queryParams).then(response => {
+        this.firstplanList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    /** 查询部门下拉树结构 */
+    getTreeselect() {
+      treeselect().then(response => {
+        this.deptOptions = response.data;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        newId: null,
+        courseCode: null,
+        topic: null,
+        content: null,
+        courseDay: null,
+        courseHour: null,
+        courseType: null,
+        trainer: null,
+        courseDate: null,
+        assess: null,
+        delFlag: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        deptId: null,
+        remarks: null,
+        planStatus: 0
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加进组培训";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getFirstplan(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改进组培训";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateFirstplan(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addFirstplan(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return delFirstplan(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      })
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有进组培训数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return exportFirstplan(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+      })
+    },
+    /** 导入按钮操作 */
+    handleImport() {
+      this.upload.title = "用户导入";
+      this.upload.open = true;
+    },
+    /** 下载模板操作 */
+    importTemplate() {
+      importTemplate().then(response => {
+        this.download(response.msg);
+      });
+    },
+    // 文件上传中处理
+    handleFileUploadProgress(event, file, fileList) {
+      this.upload.isUploading = true;
+    },
+    // 文件上传成功处理
+    handleFileSuccess(response, file, fileList) {
+      this.upload.open = false;
+      this.upload.isUploading = false;
+      this.$refs.upload.clearFiles();
+      this.$alert(response.msg, "导入结果", {dangerouslyUseHTMLString: true});
+      this.getList();
+    },
+    // 提交上传文件
+    submitFileForm() {
+      this.$refs.upload.submit();
+    }
+  }
+};
+</script>

+ 192 - 3
ui/src/views/training/bccnew/flPlan/index.vue

@@ -117,6 +117,14 @@
             @click="handleDelete(scope.row)"
             v-hasPermi="['training:flPlan:remove']"
           >删除</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-folder"
+            @click="uploadFile(scope.row)"
+            v-hasPermi="['bccnew:flPlan:edit']"
+          >学习资料
+          </el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -164,12 +172,12 @@
         <el-form-item label="考核情况" prop="assess">
           <el-input v-model="form.assess" placeholder="请输入考核情况" />
         </el-form-item>
+        <el-form-item label="应学习时长(分)" prop="timerNeed">
+          <el-input-number v-model="form.timerNeed" placeholder="请输入应学习时长" style="width: 100%"/>
+        </el-form-item>
         <el-form-item label="备注" prop="remarks">
           <el-input v-model="form.remarks" placeholder="请输入备注" />
         </el-form-item>
-          <el-form-item label="归属部门" prop="deptId">
-              <treeselect v-model="form.deptId" :options="deptOptions" :show-count="true" placeholder="请选择归属部门" />
-          </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
@@ -206,6 +214,87 @@
               <el-button @click="upload.open = false">取 消</el-button>
           </div>
       </el-dialog>
+
+    <el-dialog :close-on-click-modal="false" v-dialogDrag :title="doc.title" :visible.sync="doc.open" width="1000px"
+               append-to-body>
+      <el-upload
+        ref="doc"
+        :limit="50"
+        :headers="doc.headers"
+        :action="doc.url+'/'+doc.id"
+        :disabled="doc.isUploading"
+        :on-progress="handleFileDocProgress"
+        :on-success="handleFileDocSuccess"
+        :file-list="doc.file"
+        :auto-upload="true"
+        drag
+      >
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">
+          {{ $t('将文件拖到此处,或') }}
+          <em>{{ $t('点击上传') }}</em>
+        </div>
+      </el-upload>
+      <el-table :data="doc.commonfileList" border>
+        <el-table-column :label="$t('文件名')" align="center" prop="fileName" :show-overflow-tooltip="true">
+          <template slot-scope="scope">
+            <a class="link-type" @click="handleDownload(scope.row)">
+              <span>{{ scope.row.fileName }}</span>
+            </a>
+          </template>
+        </el-table-column>
+        <!--        <el-table-column :label="$t('大小(Kb)')" align="center" prop="fileSize" :show-overflow-tooltip="true"-->
+        <!--                         width="80"/>-->
+        <!--        <el-table-column :label="$t('上传人')" align="center" prop="creator" :show-overflow-tooltip="true" width="120"/>-->
+        <el-table-column :label="$t('操作')" align="center" width="220" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button
+              v-if="scope.row.fileName!=null&&scope.row.fileName.endsWith('pdf')"
+              size="mini"
+              type="text"
+              icon="el-icon-view"
+              @click="handleSee(scope.row)"
+            >{{ $t('预览') }}
+            </el-button>
+            <el-button v-hasPermi="['training:trainingrecords:file']" type="text" size="small" v-if="scope.row.isEdit"
+                       @click="save(scope.row)">保存
+            </el-button>
+            <el-button type="text" size="small" v-if="scope.row.isEdit" @click="cancelFile(scope.row, scope.$index)">
+              取消
+            </el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-download"
+              @click="handleDownload(scope.row)"
+            >{{ $t('下载') }}
+            </el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-delete"
+              @click="handleDeleteDoc(scope.row)"
+              v-hasPermi="['training:trainingrecords:file']"
+            >{{ $t('删除') }}
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-dialog :close-on-click-modal="false" v-dialogDrag :title="pdf.title" :visible.sync="pdf.open" width="1300px"
+                 append-to-body>
+        <div style="margin-top: -60px;float: right;margin-right: 40px;">
+          <el-button size="mini" type="text" @click="openPdf">{{ $t('新页面打开PDF') }}</el-button>
+        </div>
+        <div style="margin-top: -30px">
+          <iframe :src="pdf.pdfUrl" frameborder="0" width="100%" height="700px"></iframe>
+        </div>
+      </el-dialog>
+
+      <div slot="footer" class="dialog-footer">
+        <!--        <el-button type="primary" @click="submitFileForm">{{ $t('确 定') }}</el-button>-->
+        <el-button @click="doc.open = false">{{ $t('返 回') }}</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
@@ -216,6 +305,7 @@ import { getToken } from "@/utils/auth";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import Editor from '@/components/Editor/index.vue';
+import {getFirstPlanTmpl, updateFirstPlanTmpl} from "@/api/training/bccnew/firstPlanTmpl";
 
 export default {
   name: "FlPlan",
@@ -223,6 +313,42 @@ export default {
   // components: { Editor },
   data() {
     return {
+      // 报告附件参数
+      doc: {
+        file: null,
+        // 是否显示弹出层(报告附件)
+        open: false,
+        // 弹出层标题(报告附件)
+        title: "附件",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 报告附件上传位置编号
+        ids: 0,
+        id: null,
+        // 设置上传的请求头部
+        headers: {Authorization: "Bearer " + getToken()},
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/bccnew/flPlanTmpl/uploadFile",
+        commonfileList: null,
+        queryParams: {
+          pId: null,
+          pType: 'bccnew'
+        },
+        pType: 'bccnew',
+        pId: null,
+        form: {}
+      },
+      pdf: {
+        title: '',
+        pdfUrl: '',
+        numPages: null,
+        open: false,
+        pageNum: 1,
+        pageTotalNum: 1,
+        loadedRatio: 0,
+      },
       // 遮罩层
       loading: true,
       // 选中数组
@@ -302,6 +428,69 @@ export default {
     this.getTreeselect();
   },
   methods: {
+    uploadFile(row) {
+      this.doc.file = null;
+      this.doc.commonfileList = [];
+      this.doc.open = true;
+      this.doc.id = row.id;
+      getFirstPlanTmpl(row.id).then(res => {
+        if (res.data.fileUrl != null)
+          this.doc.commonfileList.push({fileUrl: res.data.fileUrl, fileName: res.data.fileName, id: res.data.id})
+      })
+    },
+    // 文件下载处理
+    handleDownload(row) {
+      var name = row.fileName;
+      var url = row.fileUrl;
+      var suffix = url.substring(url.lastIndexOf("."), url.length);
+      const a = document.createElement('a')
+      a.setAttribute('download', name)
+      a.setAttribute('target', '_blank')
+      a.setAttribute('href', process.env.VUE_APP_BASE_API + url)
+      a.click()
+    },
+    openPdf() {
+      window.open(this.pdf.pdfUrl);//path是文件的全路径地址
+    },
+    handleSee(row) {
+      // window.open(process.env.VUE_APP_BASE_API +'/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl);//path是文件的全路径地址
+      this.pdf.open = true
+      this.pdf.title = row.fileName
+      this.pdf.pdfUrl = process.env.VUE_APP_BASE_API + '/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl
+    },
+    /** 删除按钮操作 */
+    handleDeleteDoc(row) {
+      const ids = row.id || this.ids;
+      this.$confirm(this.$t('是否确认删除?'), this.$t('警告'), {
+        confirmButtonText: this.$t('确定'),
+        cancelButtonText: this.$t('取消'),
+        type: "warning"
+      }).then(function () {
+        return updateFirstPlanTmpl({id: row.id, fileUrl: '', fileName: ''});
+      }).then(() => {
+        this.msgSuccess(this.$t('删除成功'));
+        this.doc.commonfileList = [];
+      })
+    },
+    // 上传中处理
+    handleFileDocProgress(event, file, fileList) {
+      this.doc.file = file;
+      this.doc.isUploading = true;
+    },
+    //附件上传成功处理
+    handleFileDocSuccess(response, file, fileList) {
+      this.doc.isUploading = false;
+      this.$alert(response.msg, this.$t('导入结果'), {dangerouslyUseHTMLString: true});
+      this.getList();
+      this.doc.commonfileList = [];
+      getFirstPlanTmpl(response.data).then(res => {
+        if (res.data.fileUrl != null) {
+          this.doc.commonfileList.push({fileUrl: res.data.fileUrl, fileName: res.data.fileName, id: res.data.id})
+          fileList = null
+          file = null
+        }
+      })
+    },
     /** 查询分离培训模版列表 */
     getList() {
       this.loading = true;

+ 191 - 3
ui/src/views/training/bccnew/ftPlan/index.vue

@@ -117,6 +117,14 @@
             @click="handleDelete(scope.row)"
             v-hasPermi="['bccnew:ftPlan:remove']"
           >删除</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-folder"
+            @click="uploadFile(scope.row)"
+            v-hasPermi="['bccnew:ftPlan:edit']"
+          >学习资料
+          </el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -164,12 +172,12 @@
         <el-form-item label="考核情况" prop="assess">
           <el-input v-model="form.assess" placeholder="请输入考核情况" />
         </el-form-item>
+        <el-form-item label="应学习时长(分)" prop="timerNeed">
+          <el-input-number v-model="form.timerNeed" placeholder="请输入应学习时长" style="width: 100%"/>
+        </el-form-item>
         <el-form-item label="备注" prop="remarks">
           <el-input v-model="form.remarks" placeholder="请输入备注" />
         </el-form-item>
-          <el-form-item label="归属部门" prop="deptId">
-              <treeselect v-model="form.deptId" :options="deptOptions" :show-count="true" placeholder="请选择归属部门" />
-          </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
@@ -206,6 +214,86 @@
               <el-button @click="upload.open = false">取 消</el-button>
           </div>
       </el-dialog>
+    <el-dialog :close-on-click-modal="false" v-dialogDrag :title="doc.title" :visible.sync="doc.open" width="1000px"
+               append-to-body>
+      <el-upload
+        ref="doc"
+        :limit="50"
+        :headers="doc.headers"
+        :action="doc.url+'/'+doc.id"
+        :disabled="doc.isUploading"
+        :on-progress="handleFileDocProgress"
+        :on-success="handleFileDocSuccess"
+        :file-list="doc.file"
+        :auto-upload="true"
+        drag
+      >
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">
+          {{ $t('将文件拖到此处,或') }}
+          <em>{{ $t('点击上传') }}</em>
+        </div>
+      </el-upload>
+      <el-table :data="doc.commonfileList" border>
+        <el-table-column :label="$t('文件名')" align="center" prop="fileName" :show-overflow-tooltip="true">
+          <template slot-scope="scope">
+            <a class="link-type" @click="handleDownload(scope.row)">
+              <span>{{ scope.row.fileName }}</span>
+            </a>
+          </template>
+        </el-table-column>
+        <!--        <el-table-column :label="$t('大小(Kb)')" align="center" prop="fileSize" :show-overflow-tooltip="true"-->
+        <!--                         width="80"/>-->
+        <!--        <el-table-column :label="$t('上传人')" align="center" prop="creator" :show-overflow-tooltip="true" width="120"/>-->
+        <el-table-column :label="$t('操作')" align="center" width="220" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button
+              v-if="scope.row.fileName!=null&&scope.row.fileName.endsWith('pdf')"
+              size="mini"
+              type="text"
+              icon="el-icon-view"
+              @click="handleSee(scope.row)"
+            >{{ $t('预览') }}
+            </el-button>
+            <el-button v-hasPermi="['training:trainingrecords:file']" type="text" size="small" v-if="scope.row.isEdit"
+                       @click="save(scope.row)">保存
+            </el-button>
+            <el-button type="text" size="small" v-if="scope.row.isEdit" @click="cancelFile(scope.row, scope.$index)">
+              取消
+            </el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-download"
+              @click="handleDownload(scope.row)"
+            >{{ $t('下载') }}
+            </el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-delete"
+              @click="handleDeleteDoc(scope.row)"
+              v-hasPermi="['training:trainingrecords:file']"
+            >{{ $t('删除') }}
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-dialog :close-on-click-modal="false" v-dialogDrag :title="pdf.title" :visible.sync="pdf.open" width="1300px"
+                 append-to-body>
+        <div style="margin-top: -60px;float: right;margin-right: 40px;">
+          <el-button size="mini" type="text" @click="openPdf">{{ $t('新页面打开PDF') }}</el-button>
+        </div>
+        <div style="margin-top: -30px">
+          <iframe :src="pdf.pdfUrl" frameborder="0" width="100%" height="700px"></iframe>
+        </div>
+      </el-dialog>
+
+      <div slot="footer" class="dialog-footer">
+        <!--        <el-button type="primary" @click="submitFileForm">{{ $t('确 定') }}</el-button>-->
+        <el-button @click="doc.open = false">{{ $t('返 回') }}</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
@@ -216,6 +304,7 @@ import { getToken } from "@/utils/auth";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import Editor from '@/components/Editor/index.vue';
+import {getFirstPlanTmpl, updateFirstPlanTmpl} from "@/api/training/bccnew/firstPlanTmpl";
 
 export default {
   name: "FtPlan",
@@ -223,6 +312,42 @@ export default {
   // components: { Editor },
   data() {
     return {
+      // 报告附件参数
+      doc: {
+        file: null,
+        // 是否显示弹出层(报告附件)
+        open: false,
+        // 弹出层标题(报告附件)
+        title: "附件",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 报告附件上传位置编号
+        ids: 0,
+        id: null,
+        // 设置上传的请求头部
+        headers: {Authorization: "Bearer " + getToken()},
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/bccnew/ftPlanTmpl/uploadFile",
+        commonfileList: null,
+        queryParams: {
+          pId: null,
+          pType: 'bccnew'
+        },
+        pType: 'bccnew',
+        pId: null,
+        form: {}
+      },
+      pdf: {
+        title: '',
+        pdfUrl: '',
+        numPages: null,
+        open: false,
+        pageNum: 1,
+        pageTotalNum: 1,
+        loadedRatio: 0,
+      },
       // 遮罩层
       loading: true,
       // 选中数组
@@ -302,6 +427,69 @@ export default {
     this.getTreeselect();
   },
   methods: {
+    uploadFile(row) {
+      this.doc.file = null;
+      this.doc.commonfileList = [];
+      this.doc.open = true;
+      this.doc.id = row.id;
+      getFirstPlanTmpl(row.id).then(res => {
+        if (res.data.fileUrl != null)
+          this.doc.commonfileList.push({fileUrl: res.data.fileUrl, fileName: res.data.fileName, id: res.data.id})
+      })
+    },
+    // 文件下载处理
+    handleDownload(row) {
+      var name = row.fileName;
+      var url = row.fileUrl;
+      var suffix = url.substring(url.lastIndexOf("."), url.length);
+      const a = document.createElement('a')
+      a.setAttribute('download', name)
+      a.setAttribute('target', '_blank')
+      a.setAttribute('href', process.env.VUE_APP_BASE_API + url)
+      a.click()
+    },
+    openPdf() {
+      window.open(this.pdf.pdfUrl);//path是文件的全路径地址
+    },
+    handleSee(row) {
+      // window.open(process.env.VUE_APP_BASE_API +'/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl);//path是文件的全路径地址
+      this.pdf.open = true
+      this.pdf.title = row.fileName
+      this.pdf.pdfUrl = process.env.VUE_APP_BASE_API + '/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl
+    },
+    /** 删除按钮操作 */
+    handleDeleteDoc(row) {
+      const ids = row.id || this.ids;
+      this.$confirm(this.$t('是否确认删除?'), this.$t('警告'), {
+        confirmButtonText: this.$t('确定'),
+        cancelButtonText: this.$t('取消'),
+        type: "warning"
+      }).then(function () {
+        return updateFirstPlanTmpl({id: row.id, fileUrl: '', fileName: ''});
+      }).then(() => {
+        this.msgSuccess(this.$t('删除成功'));
+        this.doc.commonfileList = [];
+      })
+    },
+    // 上传中处理
+    handleFileDocProgress(event, file, fileList) {
+      this.doc.file = file;
+      this.doc.isUploading = true;
+    },
+    //附件上传成功处理
+    handleFileDocSuccess(response, file, fileList) {
+      this.doc.isUploading = false;
+      this.$alert(response.msg, this.$t('导入结果'), {dangerouslyUseHTMLString: true});
+      this.getList();
+      this.doc.commonfileList = [];
+      getFirstPlanTmpl(response.data).then(res => {
+        if (res.data.fileUrl != null) {
+          this.doc.commonfileList.push({fileUrl: res.data.fileUrl, fileName: res.data.fileName, id: res.data.id})
+          fileList = null
+          file = null
+        }
+      })
+    },
     /** 查询芳烃培训模版列表 */
     getList() {
       this.loading = true;

+ 191 - 3
ui/src/views/training/bccnew/ljPlan/index.vue

@@ -117,6 +117,14 @@
             @click="handleDelete(scope.row)"
             v-hasPermi="['bccnew:ljPlan:remove']"
           >删除</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-folder"
+            @click="uploadFile(scope.row)"
+            v-hasPermi="['bccnew:ljPlan:edit']"
+          >学习资料
+          </el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -164,12 +172,12 @@
         <el-form-item label="考核情况" prop="assess">
           <el-input v-model="form.assess" placeholder="请输入考核情况" />
         </el-form-item>
+        <el-form-item label="应学习时长(分)" prop="timerNeed">
+          <el-input-number v-model="form.timerNeed" placeholder="请输入应学习时长" style="width: 100%"/>
+        </el-form-item>
         <el-form-item label="备注" prop="remarks">
           <el-input v-model="form.remarks" placeholder="请输入备注" />
         </el-form-item>
-          <el-form-item label="归属部门" prop="deptId">
-              <treeselect v-model="form.deptId" :options="deptOptions" :show-count="true" placeholder="请选择归属部门" />
-          </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
@@ -206,6 +214,86 @@
               <el-button @click="upload.open = false">取 消</el-button>
           </div>
       </el-dialog>
+    <el-dialog :close-on-click-modal="false" v-dialogDrag :title="doc.title" :visible.sync="doc.open" width="1000px"
+               append-to-body>
+      <el-upload
+        ref="doc"
+        :limit="50"
+        :headers="doc.headers"
+        :action="doc.url+'/'+doc.id"
+        :disabled="doc.isUploading"
+        :on-progress="handleFileDocProgress"
+        :on-success="handleFileDocSuccess"
+        :file-list="doc.file"
+        :auto-upload="true"
+        drag
+      >
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">
+          {{ $t('将文件拖到此处,或') }}
+          <em>{{ $t('点击上传') }}</em>
+        </div>
+      </el-upload>
+      <el-table :data="doc.commonfileList" border>
+        <el-table-column :label="$t('文件名')" align="center" prop="fileName" :show-overflow-tooltip="true">
+          <template slot-scope="scope">
+            <a class="link-type" @click="handleDownload(scope.row)">
+              <span>{{ scope.row.fileName }}</span>
+            </a>
+          </template>
+        </el-table-column>
+        <!--        <el-table-column :label="$t('大小(Kb)')" align="center" prop="fileSize" :show-overflow-tooltip="true"-->
+        <!--                         width="80"/>-->
+        <!--        <el-table-column :label="$t('上传人')" align="center" prop="creator" :show-overflow-tooltip="true" width="120"/>-->
+        <el-table-column :label="$t('操作')" align="center" width="220" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button
+              v-if="scope.row.fileName!=null&&scope.row.fileName.endsWith('pdf')"
+              size="mini"
+              type="text"
+              icon="el-icon-view"
+              @click="handleSee(scope.row)"
+            >{{ $t('预览') }}
+            </el-button>
+            <el-button v-hasPermi="['training:trainingrecords:file']" type="text" size="small" v-if="scope.row.isEdit"
+                       @click="save(scope.row)">保存
+            </el-button>
+            <el-button type="text" size="small" v-if="scope.row.isEdit" @click="cancelFile(scope.row, scope.$index)">
+              取消
+            </el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-download"
+              @click="handleDownload(scope.row)"
+            >{{ $t('下载') }}
+            </el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-delete"
+              @click="handleDeleteDoc(scope.row)"
+              v-hasPermi="['training:trainingrecords:file']"
+            >{{ $t('删除') }}
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-dialog :close-on-click-modal="false" v-dialogDrag :title="pdf.title" :visible.sync="pdf.open" width="1300px"
+                 append-to-body>
+        <div style="margin-top: -60px;float: right;margin-right: 40px;">
+          <el-button size="mini" type="text" @click="openPdf">{{ $t('新页面打开PDF') }}</el-button>
+        </div>
+        <div style="margin-top: -30px">
+          <iframe :src="pdf.pdfUrl" frameborder="0" width="100%" height="700px"></iframe>
+        </div>
+      </el-dialog>
+
+      <div slot="footer" class="dialog-footer">
+        <!--        <el-button type="primary" @click="submitFileForm">{{ $t('确 定') }}</el-button>-->
+        <el-button @click="doc.open = false">{{ $t('返 回') }}</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
@@ -216,6 +304,7 @@ import { getToken } from "@/utils/auth";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import Editor from '@/components/Editor/index.vue';
+import {getFirstPlanTmpl, updateFirstPlanTmpl} from "@/api/training/bccnew/firstPlanTmpl";
 
 export default {
   name: "LjPlan",
@@ -223,6 +312,42 @@ export default {
   // components: { Editor },
   data() {
     return {
+      // 报告附件参数
+      doc: {
+        file: null,
+        // 是否显示弹出层(报告附件)
+        open: false,
+        // 弹出层标题(报告附件)
+        title: "附件",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 报告附件上传位置编号
+        ids: 0,
+        id: null,
+        // 设置上传的请求头部
+        headers: {Authorization: "Bearer " + getToken()},
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/bccnew/ljPlanTmpl/uploadFile",
+        commonfileList: null,
+        queryParams: {
+          pId: null,
+          pType: 'bccnew'
+        },
+        pType: 'bccnew',
+        pId: null,
+        form: {}
+      },
+      pdf: {
+        title: '',
+        pdfUrl: '',
+        numPages: null,
+        open: false,
+        pageNum: 1,
+        pageTotalNum: 1,
+        loadedRatio: 0,
+      },
       // 遮罩层
       loading: true,
       // 选中数组
@@ -302,6 +427,69 @@ export default {
     this.getTreeselect();
   },
   methods: {
+    uploadFile(row) {
+      this.doc.file = null;
+      this.doc.commonfileList = [];
+      this.doc.open = true;
+      this.doc.id = row.id;
+      getFirstPlanTmpl(row.id).then(res => {
+        if (res.data.fileUrl != null)
+          this.doc.commonfileList.push({fileUrl: res.data.fileUrl, fileName: res.data.fileName, id: res.data.id})
+      })
+    },
+    // 文件下载处理
+    handleDownload(row) {
+      var name = row.fileName;
+      var url = row.fileUrl;
+      var suffix = url.substring(url.lastIndexOf("."), url.length);
+      const a = document.createElement('a')
+      a.setAttribute('download', name)
+      a.setAttribute('target', '_blank')
+      a.setAttribute('href', process.env.VUE_APP_BASE_API + url)
+      a.click()
+    },
+    openPdf() {
+      window.open(this.pdf.pdfUrl);//path是文件的全路径地址
+    },
+    handleSee(row) {
+      // window.open(process.env.VUE_APP_BASE_API +'/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl);//path是文件的全路径地址
+      this.pdf.open = true
+      this.pdf.title = row.fileName
+      this.pdf.pdfUrl = process.env.VUE_APP_BASE_API + '/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl
+    },
+    /** 删除按钮操作 */
+    handleDeleteDoc(row) {
+      const ids = row.id || this.ids;
+      this.$confirm(this.$t('是否确认删除?'), this.$t('警告'), {
+        confirmButtonText: this.$t('确定'),
+        cancelButtonText: this.$t('取消'),
+        type: "warning"
+      }).then(function () {
+        return updateFirstPlanTmpl({id: row.id, fileUrl: '', fileName: ''});
+      }).then(() => {
+        this.msgSuccess(this.$t('删除成功'));
+        this.doc.commonfileList = [];
+      })
+    },
+    // 上传中处理
+    handleFileDocProgress(event, file, fileList) {
+      this.doc.file = file;
+      this.doc.isUploading = true;
+    },
+    //附件上传成功处理
+    handleFileDocSuccess(response, file, fileList) {
+      this.doc.isUploading = false;
+      this.$alert(response.msg, this.$t('导入结果'), {dangerouslyUseHTMLString: true});
+      this.getList();
+      this.doc.commonfileList = [];
+      getFirstPlanTmpl(response.data).then(res => {
+        if (res.data.fileUrl != null) {
+          this.doc.commonfileList.push({fileUrl: res.data.fileUrl, fileName: res.data.fileName, id: res.data.id})
+          fileList = null
+          file = null
+        }
+      })
+    },
     /** 查询裂解培训模版列表 */
     getList() {
       this.loading = true;

+ 7 - 6
ui/src/views/training/bccnew/tsnew/index.vue

@@ -156,21 +156,21 @@
       </el-table-column>
       <el-table-column label="带徒协议" align="center" prop="agreement" width="80">
         <template slot-scope="scope">
-          <el-button  icon="el-icon-folder" style="color:#6e96fa;" @click="" circle></el-button>
+          <el-button  icon="el-icon-folder" style="color:#6e96fa;" @click="handleDownloadWord(scope.row, 'mentorAgreement')" circle></el-button>
         </template>
       </el-table-column>
       <el-table-column label="带徒目标" align="center" prop="target" width="80">
         <template slot-scope="scope">
-          <el-button  icon="el-icon-folder" style="color:#6e96fa;" @click="" circle></el-button>
+          <el-button  icon="el-icon-folder" style="color:#6e96fa;" @click="handleDownloadWord(scope.row, 'targetPlan')" circle></el-button>
         </template>
       </el-table-column>
       <el-table-column label="培训考评" align="center" prop="tnNew-score" width="80">
         <template slot-scope="scope">
-          <el-button  icon="el-icon-folder" style="color:#6e96fa;" @click="" circle></el-button>
+          <el-button  icon="el-icon-folder" style="color:#6e96fa;" @click="handleDownloadWord(scope.row, 'appraisalForm')" circle></el-button>
         </template>
       </el-table-column>
       <el-table-column label="备注" align="center" prop="remarks" :show-overflow-tooltip="true" width="100"/>
-      <el-table-column label="操作" align="center" fixed="right"  class-name="small-padding fixed-width" width="150">
+      <el-table-column label="操作" align="center" fixed="right"  class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button
             size="mini"
@@ -184,12 +184,13 @@
             icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
             v-hasPermi="['newstaff:tnNew:edit']"
-          >修改</el-button>
+          >修改 </el-button>
           <el-dropdown  size="mini">
             <span class="el-dropdown-link">
               <el-button
                 type="text"
                 size="mini"
+                icon="el-icon-download"
               >下载<i class="el-icon-arrow-down"></i></el-button>
             </span>
             <el-dropdown-menu slot="dropdown">
@@ -551,7 +552,7 @@ export default {
     })
     this.getList();
     this.getTreeselect();
-    this.getDicts("training_newstaff_status").then(response => {
+    this.getDicts("training_bccnew_status").then(response => {
       this.planStatusOptions = response.data;
     });
     this.getDicts("training_newstaff_type").then(response => {

+ 754 - 0
ui/src/views/training/bccnew/tsnew/index_s.vue

@@ -0,0 +1,754 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="年度培训标题" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入年度培训标题"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="培训状态" prop="planStatus">
+        <el-select v-model="queryParams.planStatus" placeholder="请选择培训状态" clearable size="small">
+          <el-option
+            v-for="dict in planStatusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="开始时间" prop="startdate">
+        <el-date-picker clearable size="small" style="width: 200px"
+                        v-model="queryParams.startdate"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="选择开始时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="结束时间" prop="enddate">
+        <el-date-picker clearable size="small" style="width: 200px"
+                        v-model="queryParams.enddate"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="选择结束时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="培训类型 " prop="planType">
+        <el-select v-model="queryParams.planType" placeholder="请选择培训类型" clearable size="small">
+          <el-option
+            v-for="dict in planTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+
+    <el-table v-loading="loading" :data="tnNewList" @selection-change="handleSelectionChange" :height="clientHeight"
+              border>
+      <el-table-column type="selection" width="55" align="center"/>
+      <!--      <el-table-column label="培训员工编号" align="center" prop="staffId" :show-overflow-tooltip="true"/>-->
+      <el-table-column label="新员工" align="center" prop="staffName" width="100"/>
+      <el-table-column label="培训状态" align="center" prop="planStatus" width="100" :formatter="planStatusFormat">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.planStatus == 1" size="small" type="success">已完成</el-tag>
+          <el-tag v-else-if="scope.row.planStatus == 0" size="small" type="info">未完成</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="进度" align="center" width="160">
+        <template slot-scope="scope">
+          <el-progress :percentage="scope.row.planFinish"></el-progress>
+        </template>
+      </el-table-column>
+      <el-table-column label="开始时间" align="center" prop="startdate" width="100">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.startdate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="结束时间" align="center" prop="enddate" width="100">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.enddate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <!--      <el-table-column label="导师员工编号" align="center" prop="mentorStaffId" :show-overflow-tooltip="true"/>-->
+      <el-table-column label="导师" align="center" prop="mentorStaffName" width="100"/>
+      <el-table-column label="岗位" align="center" prop="planType" width="100">
+        <template slot-scope="scope">
+          <span v-if="scope.row.planType == 1" size="small" type="success">裂解</span>
+          <span v-else-if="scope.row.planType == 2" size="small" type="success">压缩</span>
+          <span v-else-if="scope.row.planType == 3" size="small" type="success">分离</span>
+          <span v-else-if="scope.row.planType == 4" size="small" type="success">芳烃</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="三级教育记录卡" align="center" prop="three" width="80">
+        <template slot-scope="scope">
+          <el-button icon="el-icon-folder" style="color:#6e96fa;" @click="handleDoc(scope.row , 'tsNew-three')"
+                     circle></el-button>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="上岗能力评测表" align="center" prop="firstplan-score" width="80">
+        <template slot-scope="scope">
+          <el-button icon="el-icon-folder" style="color:#6e96fa;"
+                     @click="handleDoc(scope.row , 'tsNew-firstplan-score')" circle></el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="导师提名表" align="center" prop="agreement" width="80">
+        <template slot-scope="scope">
+          <el-button icon="el-icon-folder" style="color:#6e96fa;" @click="handleDoc(scope.row , 'tsNew-teacher-order')"
+                     circle></el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="带徒协议" align="center" prop="agreement" width="80">
+        <template slot-scope="scope">
+          <el-button icon="el-icon-folder" style="color:#6e96fa;"
+                     @click="handleDownloadWord(scope.row, 'mentorAgreement')" circle></el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="带徒目标" align="center" prop="target" width="80">
+        <template slot-scope="scope">
+          <el-button icon="el-icon-folder" style="color:#6e96fa;" @click="handleDownloadWord(scope.row, 'targetPlan')"
+                     circle></el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="培训考评" align="center" prop="tnNew-score" width="80">
+        <template slot-scope="scope">
+          <el-button icon="el-icon-folder" style="color:#6e96fa;"
+                     @click="handleDownloadWord(scope.row, 'appraisalForm')" circle></el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remarks" :show-overflow-tooltip="true" width="100"/>
+      <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="planList(scope.row)"
+          >培训计划
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改新员工培训对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="培训员工" prop="mentorStaffId">
+          <el-select v-model="form.staffId" filterable :placeholder="$t('请选择')+$t('培训员工')">
+            <el-option
+              v-for="item in userOption"
+              :key="item.staffid"
+              :label="item.name +'  '+ item.deptName"
+              :value="item.staffid"
+              :disabled="item.disabled">
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="培训状态">
+          <el-select v-model="form.planStatus" placeholder="请选择培训状态">
+            <el-option
+              v-for="dict in planStatusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="开始时间" prop="startdate">
+          <el-date-picker clearable size="small" style="width: 200px"
+                          v-model="form.startdate"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          placeholder="选择开始时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="结束时间" prop="enddate">
+          <el-date-picker clearable size="small" style="width: 200px"
+                          v-model="form.enddate"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          placeholder="选择结束时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="导师员工" prop="mentorStaffId">
+          <el-select v-model="form.mentorStaffId" filterable :placeholder="$t('请选择')+$t('导师员工')">
+            <el-option
+              v-for="item in userOption"
+              :key="item.staffid"
+              :label="item.name +'  '+ item.deptName"
+              :value="item.staffid"
+              :disabled="item.disabled">
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="岗位" prop="planType">
+          <el-radio-group v-model="form.planType">
+            <el-radio
+              key="1"
+              :label="1"
+            >裂解
+            </el-radio>
+            <el-radio
+              key="2"
+              :label="2"
+            >压缩
+            </el-radio>
+            <el-radio
+              key="3"
+              :label="3"
+            >分离
+            </el-radio>
+            <el-radio
+              key="4"
+              :label="4"
+            >芳烃
+            </el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remarks">
+          <el-input v-model="form.remarks" placeholder="请输入备注"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+    <!-- 用户导入对话框 -->
+    <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
+      <el-upload
+        ref="upload"
+        :limit="1"
+        accept=".xlsx, .xls"
+        :headers="upload.headers"
+        :action="upload.url + '?updateSupport=' + upload.updateSupport"
+        :disabled="upload.isUploading"
+        :on-progress="handleFileUploadProgress"
+        :on-success="handleFileSuccess"
+        :auto-upload="false"
+        drag
+      >
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">
+          将文件拖到此处,或
+          <em>点击上传</em>
+        </div>
+        <div class="el-upload__tip" slot="tip">
+          <el-checkbox v-model="upload.updateSupport"/>
+          是否更新已经存在的用户数据
+          <el-link type="info" style="font-size:12px" @click="importTemplate">下载模板</el-link>
+        </div>
+        <div class="el-upload__tip" style="color:red" slot="tip">提示:仅允许导入“xls”或“xlsx”格式文件!</div>
+      </el-upload>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitFileForm">确 定</el-button>
+        <el-button @click="upload.open = false">取 消</el-button>
+      </div>
+    </el-dialog>
+    <!-- 报告附件对话框 -->
+    <el-dialog :close-on-click-modal="false" v-dialogDrag :title="doc.title" :visible.sync="doc.open" width="1000px"
+               append-to-body>
+      <el-upload v-hasPermi="['training:trainingrecords:file']"
+                 ref="doc"
+                 :limit="50"
+                 :headers="doc.headers"
+                 :action="doc.url + '?pType=' + doc.pType + '&pId=' + doc.pId"
+                 :disabled="doc.isUploading"
+                 :on-progress="handleFileDocProgress"
+                 :on-success="handleFileDocSuccess"
+                 :auto-upload="true"
+                 drag
+      >
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">
+          {{ $t('将文件拖到此处,或') }}
+          <em>{{ $t('点击上传') }}</em>
+        </div>
+      </el-upload>
+      <el-table :data="doc.commonfileList" border>
+        <el-table-column :label="$t('文件名')" align="center" prop="fileName" :show-overflow-tooltip="true">
+          <template slot-scope="scope">
+            <a class="link-type" @click="handleDownload(scope.row)">
+              <span>{{ scope.row.fileName }}</span>
+            </a>
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('大小(Kb)')" align="center" prop="fileSize" :show-overflow-tooltip="true"
+                         width="80"/>
+        <el-table-column :label="$t('上传人')" align="center" prop="creator" :show-overflow-tooltip="true" width="120"/>
+        <!--        <el-table-column :label="$t('培训日期')" align="center" prop="pDate"  width="150">-->
+        <!--          <template slot-scope="scope">-->
+        <!--            <el-date-picker-->
+        <!--              v-if="scope.row.isEdit"-->
+        <!--              v-model="scope.row.pDate"-->
+        <!--              type="date"-->
+        <!--              value-format="yyyy-MM-dd"-->
+        <!--              placeholder="日期">-->
+        <!--            </el-date-picker>-->
+        <!--            <span v-else>{{ parseTime(scope.row.pDate, '{y}-{m}-{d}') }}</span>-->
+        <!--          </template>-->
+        <!--        </el-table-column>-->
+        <el-table-column :label="$t('操作')" align="center" width="220" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button
+              v-if="scope.row.fileName.endsWith('pdf')"
+              size="mini"
+              type="text"
+              icon="el-icon-view"
+              @click="handleSee(scope.row)"
+            >{{ $t('预览') }}
+            </el-button>
+            <el-button v-hasPermi="['training:trainingrecords:file']" type="text" size="small" v-if="scope.row.isEdit"
+                       @click="save(scope.row)">保存
+            </el-button>
+            <el-button type="text" size="small" v-if="scope.row.isEdit" @click="cancelFile(scope.row, scope.$index)">
+              取消
+            </el-button>
+            <!--            <el-button v-hasPermi="['training:trainingrecords:file']" v-if="!scope.row.isEdit" @click="edit(scope.row)" icon="el-icon-edit" type="text" size="mini">编辑</el-button>-->
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-download"
+              @click="handleDownload(scope.row)"
+            >{{ $t('下载') }}
+            </el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-delete"
+              @click="handleDeleteDoc(scope.row)"
+              v-hasPermi="['training:trainingrecords:file']"
+            >{{ $t('删除') }}
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-dialog :close-on-click-modal="false" v-dialogDrag :title="pdf.title" :visible.sync="pdf.open" width="1300px"
+                 append-to-body>
+        <div style="margin-top: -60px;float: right;margin-right: 40px;">
+          <el-button size="mini" type="text" @click="openPdf">{{ $t('新页面打开PDF') }}</el-button>
+        </div>
+        <div style="margin-top: -30px">
+          <iframe :src="pdf.pdfUrl" frameborder="0" width="100%" height="700px"></iframe>
+        </div>
+      </el-dialog>
+
+      <div slot="footer" class="dialog-footer">
+        <!--        <el-button type="primary" @click="submitFileForm">{{ $t('确 定') }}</el-button>-->
+        <el-button @click="doc.open = false">{{ $t('返 回') }}</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  addTsnew,
+  delTsnew,
+  exportTsnew,
+  getTsnew,
+  importTemplate,
+  listTsnew,
+  updateTsnew
+} from "@/api/training/bccnew/tsnew";
+import {treeselect} from "@/api/system/dept";
+import {getToken} from "@/utils/auth";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import {listStaff} from "@/api/training/newstaff/tnNew";
+import {allFileList, delCommonfile} from "@/api/common/commonfile";
+
+export default {
+  name: "Tsnew",
+  components: {Treeselect},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: false,
+      // 总条数
+      total: 0,
+      // 新员工培训表格数据
+      tnNewList: [],
+      // 弹出层标题
+      title: "",
+      // 部门树选项
+      deptOptions: undefined,
+      clientHeight: 300,
+      // 培训状态字典
+      planStatusOptions: [],
+      // 培训类型 1-新员工 2-转岗字典
+      planTypeOptions: [],
+      userOption: [],
+      // 是否显示弹出层
+      open: false,
+      // 用户导入参数
+      upload: {
+        // 是否显示弹出层(用户导入)
+        open: false,
+        // 弹出层标题(用户导入)
+        title: "",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: {Authorization: "Bearer " + getToken()},
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/newstaff/tsNew/importData"
+      },
+      // 报告附件参数
+      doc: {
+        file: "",
+        // 是否显示弹出层(报告附件)
+        open: false,
+        // 弹出层标题(报告附件)
+        title: "附件",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 报告附件上传位置编号
+        ids: 0,
+        // 设置上传的请求头部
+        headers: {Authorization: "Bearer " + getToken()},
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/common/commonfile/uploadFile",
+        commonfileList: null,
+        queryParams: {
+          pId: null,
+          pType: 'traning'
+        },
+        pType: 'traning',
+        pId: null,
+        form: {}
+      },
+      pdf: {
+        title: '',
+        pdfUrl: '',
+        numPages: null,
+        open: false,
+        pageNum: 1,
+        pageTotalNum: 1,
+        loadedRatio: 0,
+      },
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 20,
+        name: null,
+        isStudent: '1',
+        planStatus: null,
+        startdate: null,
+        enddate: null,
+        planType: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {}
+    };
+  },
+  watch: {
+    // 根据名称筛选部门树
+    deptName(val) {
+      this.$refs.tree.filter(val);
+    }
+  },
+  created() {
+    //设置表格高度对应屏幕高度
+    this.$nextTick(() => {
+      this.clientHeight = document.body.clientHeight - 250
+    })
+    this.getList();
+    this.getTreeselect();
+    this.getDicts("training_bccnew_status").then(response => {
+      this.planStatusOptions = response.data;
+    });
+    this.getDicts("training_newstaff_type").then(response => {
+      this.planTypeOptions = response.data;
+    });
+    listStaff(this.queryParams).then(response => {
+      this.userOption = response.data;
+    });
+  },
+  methods: {
+    // 文件下载处理
+    handleDownloadWord(row, type) {
+      console.log(row)
+      if (type == 'mentorAgreement') {
+        var name = row.mentorAgreementWordPath;
+        var url = row.mentorAgreementWordPath;
+      } else if (type == 'targetPlan') {
+        var name = row.targetPlanWordPath;
+        var url = row.targetPlanWordPath;
+      } else if (type == 'appraisalForm') {
+        var name = row.appraisalFormWordPath;
+        var url = row.appraisalFormWordPath;
+      }
+      var suffix = url.substring(url.lastIndexOf("."), url.length);
+      console.log(url)
+      const a = document.createElement('a')
+      a.setAttribute('download', name)
+      a.setAttribute('target', '_blank')
+      a.setAttribute('href', process.env.VUE_APP_BASE_API + url)
+      a.click()
+    },
+    /** 查询新员工培训列表 */
+    getList() {
+      this.loading = true;
+      listTsnew(this.queryParams).then(response => {
+        this.tnNewList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    /** 查询部门下拉树结构 */
+    getTreeselect() {
+      treeselect().then(response => {
+        this.deptOptions = response.data;
+      });
+    },
+    // 培训状态字典翻译
+    planStatusFormat(row, column) {
+      return this.selectDictLabel(this.planStatusOptions, row.planStatus);
+    },
+    // 培训类型 1-新员工 2-转岗字典翻译
+    planTypeFormat(row, column) {
+      return this.selectDictLabel(this.planTypeOptions, row.planType);
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        newId: null,
+        staffId: null,
+        name: null,
+        delFlag: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        deptId: null,
+        planStatus: 0,
+        planYear: null,
+        startdate: null,
+        enddate: null,
+        mentorStaffId: null,
+        planType: null,
+        remarks: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.newId)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    planList(row) {
+      const newId = row.newId
+      this.$router.push("/training/bccnew/trainingPlan_s/" + newId);
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加新员工培训";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const newId = row.newId || this.ids
+      getTsnew(newId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改新员工培训";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.newId != null) {
+            updateTsnew(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addTsnew(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const newIds = row.newId || this.ids;
+      this.$confirm('是否确认删除?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return delTsnew(newIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      })
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有新员工培训数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return exportTsnew(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+      })
+    },
+    /** 导入按钮操作 */
+    handleImport() {
+      this.upload.title = "用户导入";
+      this.upload.open = true;
+    },
+    /** 下载模板操作 */
+    importTemplate() {
+      importTemplate().then(response => {
+        this.download(response.msg);
+      });
+    },
+    // 文件上传中处理
+    handleFileUploadProgress(event, file, fileList) {
+      this.upload.isUploading = true;
+    },
+    // 文件上传成功处理
+    handleFileSuccess(response, file, fileList) {
+      this.upload.open = false;
+      this.upload.isUploading = false;
+      this.$refs.upload.clearFiles();
+      this.$alert(response.msg, "导入结果", {dangerouslyUseHTMLString: true});
+      this.getList();
+    },
+    // 提交上传文件
+    submitFileForm() {
+      this.$refs.upload.submit();
+    },
+    /** 报告附件按钮操作 */
+    handleDoc(row, fileType) {
+      this.doc.pType = fileType
+      this.doc.queryParams.pType = fileType
+      this.doc.id = row.id;
+      this.doc.title = this.$t('附件');
+      this.doc.open = true;
+      this.doc.queryParams.pId = row.newId
+      this.doc.pId = row.newId
+      this.getFileList()
+      this.$nextTick(() => {
+        this.$refs.doc.clearFiles()
+      })
+    },
+    getFileList() {
+      allFileList(this.doc.queryParams).then(response => {
+        response.forEach(element => {
+          element["isEdit"] = false
+        });
+        response.forEach(element => {
+          element["isAdd"] = false
+        });
+        this.doc.commonfileList = response;
+      });
+    },
+    //附件上传中处理
+    handleFileDocProgress(event, file, fileList) {
+      this.doc.file = file;
+      this.doc.isUploading = true;
+    },
+    //附件上传成功处理
+    handleFileDocSuccess(response, file, fileList) {
+      this.doc.isUploading = false;
+      this.$alert(response.msg, this.$t('导入结果'), {dangerouslyUseHTMLString: true});
+      this.getFileList()
+    },
+    // 文件下载处理
+    handleDownload(row) {
+      var name = row.fileName;
+      var url = row.fileUrl;
+      var suffix = url.substring(url.lastIndexOf("."), url.length);
+      const a = document.createElement('a')
+      a.setAttribute('download', name)
+      a.setAttribute('target', '_blank')
+      a.setAttribute('href', process.env.VUE_APP_BASE_API + url)
+      a.click()
+    },
+    openPdf() {
+      window.open(this.pdf.pdfUrl);//path是文件的全路径地址
+    },
+    handleSee(row) {
+      // window.open(process.env.VUE_APP_BASE_API +'/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl);//path是文件的全路径地址
+      this.pdf.open = true
+      this.pdf.title = row.fileName
+      this.pdf.pdfUrl = process.env.VUE_APP_BASE_API + '/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl
+    },
+    /** 删除按钮操作 */
+    handleDeleteDoc(row) {
+      const ids = row.id || this.ids;
+      this.$confirm(this.$t('是否确认删除?'), this.$t('警告'), {
+        confirmButtonText: this.$t('确定'),
+        cancelButtonText: this.$t('取消'),
+        type: "warning"
+      }).then(function () {
+        return delCommonfile(ids);
+      }).then(() => {
+        this.getFileList()
+        this.msgSuccess(this.$t('删除成功'));
+      })
+    },
+  }
+};
+</script>

+ 4 - 4
ui/src/views/training/bccnew/tsnew/score.vue

@@ -201,7 +201,7 @@
       </el-button>
     </el-dialog>
 
-    <el-dialog :close-on-click-modal="false" v-loading="pdf.loadingFlash" element-loading-background="rgba(0,0,0,0.2)"
+    <el-dialog :close-on-click-modal="false"  element-loading-background="rgba(0,0,0,0.2)"
                v-dialogDrag :title="pdf.title"
                :visible.sync="pdf.open" width="1300px" height="800px" :center="true" append-to-body
                @close="handleClose">
@@ -248,6 +248,7 @@ import Treeselect from "@riophae/vue-treeselect";
 
 var timer = null;
 export default {
+  name:"score",
   props: {
     newId: {},
     planType: {}
@@ -315,7 +316,7 @@ export default {
     })
     this.getList();
     this.getTreeselect();
-    this.getDicts("training_newstaff_status").then(response => {
+    this.getDicts("training_bccnew_status").then(response => {
       this.planStatusOptions = response.data;
     });
   },
@@ -326,7 +327,6 @@ export default {
     },
     handleStudy(row) {
       //office预览
-      this.pdf.loadingFlash = true
       this.pdf.open = true
       this.pdf.title = row.fileName
       this.pdf.pdfUrl = ""
@@ -334,7 +334,7 @@ export default {
       //如果是PDF等直接可以打开的就不调接口,否则调用接口
       if (row.fileName.endsWith('pdf')) {
         this.pdf.pdfUrl = process.env.VUE_APP_BASE_API + '/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl
-        this.loadingFlash = false
+
       }
       let _this = this;
       if (this.planType === 1) {

+ 496 - 0
ui/src/views/training/bccnew/tsnew/score_student.vue

@@ -0,0 +1,496 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="10" class="mb8">
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+    <el-table v-loading="loading" :data="dsdtList" :height="clientHeight" @selection-change="handleSelectionChange"
+              border>
+      <el-table-column type="selection" width="55" align="center" fixed="left"/>
+      <el-table-column label="课程编号" align="center" prop="courseCode" :show-overflow-tooltip="true" fixed="left"
+                       width="180"/>
+      <el-table-column label="培训主题" align="center" prop="topic" :show-overflow-tooltip="true" fixed="left"
+                       width="180"/>
+      <el-table-column label="培训内容" align="center" prop="content" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="培训天" align="center" prop="courseDay" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="培训小时" align="center" prop="courseHour" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="详细计划" align="center" prop="detailPlan" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="讲师" align="center" prop="trainer" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="培训日期" align="center" prop="courseDate" width=" 180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.courseDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="考核情况" align="center" prop="assess" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="培训状态" align="center" prop="planStatus" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="第一次成绩" align="center" prop="score1" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="第二次成绩" align="center" prop="score2" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="第三次成绩" align="center" prop="score3" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="备注" align="center" prop="remarks" :show-overflow-tooltip="true" width="180"/>
+      <el-table-column label="操作" align="center" fixed="right" width="230" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-folder"
+            @click="openFileDialog(scope.row)"
+          >学习资料
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <el-dialog :visible.sync="file.open" width="30%" append-to-body>
+      <el-descriptions class="margin-top" title="学习资料" :column="1" size="medium" border>
+        <el-descriptions-item label-style="width:180px">
+          <template slot="label">
+            <i class="el-icon-user"></i>
+            资料名
+          </template>
+          {{ file.data.fileName }}
+        </el-descriptions-item>
+        <el-descriptions-item label-style="width:180px">
+          <template slot="label">
+            <i class="el-icon-mobile-phone"></i>
+            学习进度
+          </template>
+          <el-progress :text-inside="true" :stroke-width="20" :percentage="getCountTime()"
+                       status="success"></el-progress>
+        </el-descriptions-item>
+        <el-descriptions-item label-style="width:180px">
+          <template slot="label">
+            <i class="el-icon-mobile-phone"></i>
+            应学习时长(分)
+          </template>
+          {{ file.data.timerNeed }}
+        </el-descriptions-item>
+        <el-descriptions-item label-style="width:180px">
+          <template slot="label">
+            <i class="el-icon-mobile-phone"></i>
+            已学习时长(分)
+          </template>
+          {{ file.data.timer }}
+        </el-descriptions-item>
+      </el-descriptions>
+      <el-button
+        class="mt10"
+        type="primary"
+        icon="el-icon-video-play"
+        @click="handleStudy(file.data)"
+      >开始学习
+      </el-button>
+    </el-dialog>
+
+    <el-dialog :close-on-click-modal="false"  element-loading-background="rgba(0,0,0,0.2)"
+               v-dialogDrag :title="pdf.title"
+               :visible.sync="pdf.open" width="1300px" height="800px" :center="true" append-to-body
+               @close="handleClose">
+      <div style="margin-top: -30px">
+        <iframe id="iFrame" class="iframe-html" :src="pdf.pdfUrl" frameborder="0" width="100%" height="700px"
+                v-if="ppt"></iframe>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  addLjplandsdt,
+  delLjplandsdt,
+  getLjplandsdt,
+  listLjplandsdt,
+  updateLjLearnTime,
+  updateLjplandsdt
+} from "@/api/training/bccnew/ljplandsdt";
+import {
+  addYsplandsdt,
+  delYsplandsdt,
+  getYsplandsdt,
+  listYsplandsdt, updateYsLearnTime,
+  updateYsplandsdt
+} from "@/api/training/bccnew/ysplandsdt";
+import {
+  addFlplandsdt,
+  delFlplandsdt,
+  getFlplandsdt,
+  listFlplandsdt, updateFlLearnTime,
+  updateFlplandsdt
+} from "@/api/training/bccnew/flplandsdt";
+import {
+  addFtplandsdt,
+  delFtplandsdt,
+  getFtplandsdt,
+  listFtplandsdt, updateFtLearnTime,
+  updateFtplandsdt
+} from "@/api/training/bccnew/ftplandsdt";
+import {treeselect} from "@/api/system/dept";
+import Treeselect from "@riophae/vue-treeselect";
+
+var timer = null;
+export default {
+  name:"score_s",
+  props: {
+    newId: {},
+    planType: {}
+  },
+  components: {Treeselect},
+  data() {
+    return {
+      file: {
+        open: false,
+        data: {}
+      },
+      ppt: false,
+      pdf: {
+        title: '',
+        pdfUrl: '',
+        numPages: null,
+        open: false,
+        pageNum: 1,
+        pageTotalNum: 1,
+        loadedRatio: 0,
+        loadingFlash: false,
+      },
+      // 选中数组
+      ids: [],
+      // 总条数
+      total: 0,
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: false,
+      loading: true,
+      // 弹出层标题
+      title: "",
+      // 部门树选项
+      deptOptions: undefined,
+      // 培训状态字典
+      planStatusOptions: [],
+      clientHeight: 300,
+      // 是否显示弹出层
+      open: false,
+      dsdtList: [],
+      queryParams: {
+        pageNum: 1,
+        pageSize: 20,
+        newId: this.newId
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {}
+    }
+  },
+  watch: {
+    // 根据名称筛选部门树
+    deptName(val) {
+      this.$refs.tree.filter(val);
+    }
+  },
+  created() {
+    //设置表格高度对应屏幕高度
+    this.$nextTick(() => {
+      this.clientHeight = document.body.clientHeight - 250
+    })
+    this.getList();
+    this.getTreeselect();
+    this.getDicts("training_bccnew_status").then(response => {
+      this.planStatusOptions = response.data;
+    });
+  },
+  methods: {
+    handleClose() {
+      window.clearInterval(timer);
+      this.getList();
+    },
+    handleStudy(row) {
+      //office预览
+      this.pdf.open = true
+      this.pdf.title = row.fileName
+      this.pdf.pdfUrl = ""
+      this.ppt = true
+      //如果是PDF等直接可以打开的就不调接口,否则调用接口
+      if (row.fileName.endsWith('pdf')) {
+        this.pdf.pdfUrl = process.env.VUE_APP_BASE_API + '/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl
+
+      }
+      let _this = this;
+      if (this.planType === 1) {
+        timer = window.setInterval(function () {
+          updateLjLearnTime(row).then(res => {
+          })
+        }, 60000);
+      } else if (this.planType === 2) {
+        timer = window.setInterval(function () {
+          updateYsLearnTime(row).then(res => {
+          })
+        }, 60000);
+      } else if (this.planType === 3) {
+        timer = window.setInterval(function () {
+          updateFlLearnTime(row).then(res => {
+          })
+        }, 60000);
+      } else if (this.planType === 4) {
+        timer = window.setInterval(function () {
+          updateFtLearnTime(row).then(res => {
+          })
+        }, 60000);
+      }
+    },
+    getCountTime() {
+      if (this.file.data.timerNeed === 0)
+        return 0;
+      return (this.file.data.timer / this.file.data.timerNeed * 100).toFixed(2)
+    },
+    openFileDialog(row) {
+      this.file.open = true;
+      this.file.data = row
+      console.log(row)
+      if (row.timer === '' || row.timer == null) {
+        this.file.data.timer = 0
+      }
+      if (row.timerNeed === '' || row.timerNeed == null) {
+        this.file.data.timerNeed = 0
+      }
+      console.log(this.file.data)
+    },
+    getList() {
+      if (this.planType == 1) {
+        listLjplandsdt(this.queryParams).then(res => {
+          this.dsdtList = res.rows;
+          this.total = res.total;
+          this.loading = false;
+        })
+      } else if (this.planType == 2) {
+        listYsplandsdt(this.queryParams).then(res => {
+          this.dsdtList = res.rows;
+          this.total = res.total;
+          this.loading = false;
+        })
+      } else if (this.planType == 3) {
+        listFlplandsdt(this.queryParams).then(res => {
+          this.dsdtList = res.rows;
+          this.total = res.total;
+          this.loading = false;
+        })
+      } else if (this.planType == 4) {
+        listFtplandsdt(this.queryParams).then(res => {
+          this.dsdtList = res.rows;
+          this.total = res.total;
+          this.loading = false;
+        })
+      }
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 查询部门下拉树结构 */
+    getTreeselect() {
+      treeselect().then(response => {
+        this.deptOptions = response.data;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        newId: this.newId,
+        courseCode: null,
+        topic: null,
+        content: null,
+        courseDay: null,
+        courseHour: null,
+        detailPlan: null,
+        trainer: null,
+        courseDate: null,
+        assess: null,
+        delFlag: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        deptId: null,
+        remarks: null,
+        planStatus: 0,
+        score1: null,
+        score2: null,
+        score3: null
+      };
+      this.resetForm("form");
+    }, /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      if (this.planType == 1) {
+        this.$confirm('是否确认删除?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function () {
+          return delLjplandsdt(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+      } else if (this.planType == 2) {
+        this.$confirm('是否确认删除?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function () {
+          return delYsplandsdt(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+      } else if (this.planType == 3) {
+        this.$confirm('是否确认删除?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function () {
+          return delFlplandsdt(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+      } else if (this.planType == 4) {
+        this.$confirm('是否确认删除?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function () {
+          return delFtplandsdt(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+      }
+    },
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      if (this.planType == 1) {
+        getLjplandsdt(id).then(response => {
+          this.form = response.data;
+          this.open = true;
+          this.title = "修改课程";
+        });
+      } else if (this.planType == 2) {
+        getYsplandsdt(id).then(response => {
+          this.form = response.data;
+          this.open = true;
+          this.title = "修改课程";
+        });
+      } else if (this.planType == 3) {
+        getFlplandsdt(id).then(response => {
+          this.form = response.data;
+          this.open = true;
+          this.title = "修改课程";
+        });
+      } else if (this.planType == 4) {
+        getFtplandsdt(id).then(response => {
+          this.form = response.data;
+          this.open = true;
+          this.title = "修改课程";
+        });
+      }
+    },
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加课程";
+    }, /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            if (this.planType == 1) {
+              updateLjplandsdt(this.form).then(response => {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              });
+            } else if (this.planType == 2) {
+              updateYsplandsdt(this.form).then(response => {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              });
+            } else if (this.planType == 3) {
+              updateFlplandsdt(this.form).then(response => {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              });
+            } else if (this.planType == 4) {
+              updateFtplandsdt(this.form).then(response => {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              });
+            }
+          } else {
+            if (this.planType == 1) {
+              addLjplandsdt(this.form).then(response => {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              });
+            } else if (this.planType == 2) {
+              addYsplandsdt(this.form).then(response => {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              });
+            } else if (this.planType == 3) {
+              addFlplandsdt(this.form).then(response => {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              });
+            } else if (this.planType == 4) {
+              addFtplandsdt(this.form).then(response => {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              });
+            }
+          }
+        }
+      });
+    },
+  }
+};
+
+
+</script>
+
+<style scoped>
+
+</style>

+ 5 - 5
ui/src/views/training/bccnew/tsnew/trainingPlan.vue

@@ -1,19 +1,19 @@
 <template>
   <div class="app-container" style="padding: 0 0 0 0">
     <el-tabs type="border-card" v-model="activeName" @tab-click="handleClick">
-      <el-tab-pane label="进组前培训" name="first">
+      <el-tab-pane label="装置级培训" name="first">
         <firstplan-bccnew :newId="newId"  item="1" typename="firstplan" v-if="isFirst"></firstplan-bccnew>
       </el-tab-pane>
-      <el-tab-pane label="裂解" name="second" v-if="planType == 1">
+      <el-tab-pane label="导师带徒(裂解" name="second" v-if="planType == 1">
         <score :newId="newId" :planType="1" v-if="isSecond"/>
       </el-tab-pane>
-      <el-tab-pane label="压缩" name="third" v-if="planType == 2">
+      <el-tab-pane label="导师带徒(压缩" name="third" v-if="planType == 2">
         <score :newId="newId" :planType="2" v-if="isThird"/>
       </el-tab-pane>
-      <el-tab-pane label="分离" name="fourth" v-if="planType == 3">
+      <el-tab-pane label="导师带徒(分离" name="fourth" v-if="planType == 3">
         <score :newId="newId" :planType="3" v-if="isFourth"/>
       </el-tab-pane>
-      <el-tab-pane label="芳烃" name="fifth" v-if="planType == 4">
+      <el-tab-pane label="导师带徒(芳烃" name="fifth" v-if="planType == 4">
         <score :newId="newId" :planType="4" v-if="isFifth"/>
       </el-tab-pane>
     </el-tabs>

+ 120 - 0
ui/src/views/training/bccnew/tsnew/trainingPlan_student.vue

@@ -0,0 +1,120 @@
+<template>
+  <div class="app-container" style="padding: 0 0 0 0">
+    <el-tabs type="border-card" v-model="activeName" @tab-click="handleClick">
+      <el-tab-pane label="装置级培训" name="first">
+        <firstplan-bccnew_s :newId="newId"  item="1" typename="firstplan" v-if="isFirst"></firstplan-bccnew_s>
+      </el-tab-pane>
+      <el-tab-pane label="导师带徒(裂解)" name="second" v-if="planType == 1">
+        <score_s :newId="newId" :planType="1" v-if="isSecond"/>
+      </el-tab-pane>
+      <el-tab-pane label="导师带徒(压缩)" name="third" v-if="planType == 2">
+        <score_s :newId="newId" :planType="2" v-if="isThird"/>
+      </el-tab-pane>
+      <el-tab-pane label="导师带徒(分离)" name="fourth" v-if="planType == 3">
+        <score_s :newId="newId" :planType="3" v-if="isFourth"/>
+      </el-tab-pane>
+      <el-tab-pane label="导师带徒(芳烃)" name="fifth" v-if="planType == 4">
+        <score_s :newId="newId" :planType="4" v-if="isFifth"/>
+      </el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+<script>
+import List from "@/views/training/newstaff/firstplan/index.vue";
+import Score from "@/views/training/bccnew/tsnew/score.vue";
+import {listLjplandsdt} from "@/api/training/bccnew/ljplandsdt";
+import {listYsplandsdt} from "@/api/training/bccnew/ysplandsdt";
+import {listFlplandsdt} from "@/api/training/bccnew/flplandsdt";
+import {listFtplandsdt} from "@/api/training/bccnew/ftplandsdt";
+import {getTsnew} from "@/api/training/bccnew/tsnew";
+import Firstplan from "@/views/training/newstaff/firstplan/index.vue";
+import FirstplanBccnew from "@/views/training/bccnew/firstplan/index.vue";
+import FirstplanBccnew_s from "@/views/training/bccnew/firstplan/index_student.vue";
+import Score_s from "@/views/training/bccnew/tsnew/score_student.vue";
+
+export default {
+  name: "trainingPlan_s",
+  components: {Score_s, FirstplanBccnew_s, FirstplanBccnew, Firstplan, Score, List},
+  data() {
+    return {
+      dsdtList: [],
+      clientHeight: 300,
+      // 默认第一个Tab
+      activeName: 'first',
+      isFirst: true,
+      isSecond: false,
+      isThird: false,
+      isFourth: false,
+      isFifth: false,
+      isSixth: false,
+      planType: 1,
+      newId: ''
+    }
+  },
+  created() {
+    //设置表格高度对应屏幕高度
+    this.newId = this.$route.params && this.$route.params.newId;
+    getTsnew(this.newId).then(response => {
+      this.planType = response.data.planType;
+    });
+  },
+  methods: {
+    handleClick(tab) {
+      console.log(tab.name)
+      this.dsdtList = [];
+      if (tab.name === 'first') {
+        this.isFirst = true
+        this.isSecond = false
+        this.isThird = false
+        this.isFourth = false
+        this.isFifth = false
+        this.isSix1th = false
+      } else if (tab.name === 'second') {
+        this.isFirst = false
+        this.isSecond = true
+        this.isThird = false
+        this.isFourth = false
+        this.isFifth = false
+        this.isSixth = false
+      } else if (tab.name === 'third') {
+        this.isFirst = false
+        this.isSecond = false
+        this.isThird = true
+        this.isFourth = false
+        this.isFifth = false
+        this.isSixth = false
+      } else if (tab.name === 'fourth') {
+        this.isFirst = false
+        this.isSecond = false
+        this.isThird = false
+        this.isFourth = true
+        this.isFifth = false
+        this.isSixth = false
+      } else if (tab.name === 'fifth') {
+        listLjplandsdt({newId: this.newId}).then(res => {
+          this.dsdtList = res.data;
+        })
+        this.isFirst = false
+        this.isSecond = false
+        this.isThird = false
+        this.isFourth = false
+        this.isFifth = true
+        this.isSixth = false
+      } else if (tab.name === 'sixth') {
+        listLjplandsdt({newId: this.newId}).then(res => {
+          this.dsdtList = res.data;
+        })
+        this.isFirst = false
+        this.isSecond = false
+        this.isThird = false
+        this.isFourth = false
+        this.isFifth = false
+        this.isSixth = true
+      }
+    }
+  }
+};
+</script>
+<style scoped>
+
+</style>

+ 209 - 21
ui/src/views/training/bccnew/ysPlan/index.vue

@@ -41,7 +41,7 @@
           icon="el-icon-plus"
           size="mini"
           @click="handleAdd"
-          v-hasPermi="['bccnew:yaPlan:add']"
+          v-hasPermi="['bccnew:ysPlan:add']"
         >新增</el-button>
       </el-col>
       <el-col :span="1.5">
@@ -51,7 +51,7 @@
           size="mini"
           :disabled="single"
           @click="handleUpdate"
-          v-hasPermi="['bccnew:yaPlan:edit']"
+          v-hasPermi="['bccnew:ysPlan:edit']"
         >修改</el-button>
       </el-col>
       <el-col :span="1.5">
@@ -61,7 +61,7 @@
           size="mini"
           :disabled="multiple"
           @click="handleDelete"
-          v-hasPermi="['bccnew:yaPlan:remove']"
+          v-hasPermi="['bccnew:ysPlan:remove']"
         >删除</el-button>
       </el-col>
         <el-col :span="1.5">
@@ -70,7 +70,7 @@
                     icon="el-icon-upload2"
                     size="mini"
                     @click="handleImport"
-                    v-hasPermi="['bccnew:yaPlan:edit']"
+                    v-hasPermi="['bccnew:ysPlan:edit']"
             >导入</el-button>
         </el-col>
       <el-col :span="1.5">
@@ -79,13 +79,13 @@
           icon="el-icon-download"
           size="mini"
           @click="handleExport"
-          v-hasPermi="['bccnew:yaPlan:export']"
+          v-hasPermi="['bccnew:ysPlan:export']"
         >导出</el-button>
       </el-col>
 	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
-    <el-table v-loading="loading" :data="yaPlanList" @selection-change="handleSelectionChange" :height="clientHeight" border>
+    <el-table v-loading="loading" :data="ysPlanList" @selection-change="handleSelectionChange" :height="clientHeight" border>
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="课程编号" align="center" prop="courseCode" :show-overflow-tooltip="true"/>
       <el-table-column label="培训主题" align="center" prop="topic" :show-overflow-tooltip="true"/>
@@ -108,15 +108,23 @@
             type="text"
             icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
-            v-hasPermi="['bccnew:yaPlan:edit']"
+            v-hasPermi="['bccnew:ysPlan:edit']"
           >修改</el-button>
           <el-button
             size="mini"
             type="text"
             icon="el-icon-delete"
             @click="handleDelete(scope.row)"
-            v-hasPermi="['bccnew:yaPlan:remove']"
+            v-hasPermi="['bccnew:ysPlan:remove']"
           >删除</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-folder"
+            @click="uploadFile(scope.row)"
+            v-hasPermi="['bccnew:ysPlan:edit']"
+          >学习资料
+          </el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -167,12 +175,12 @@
         <el-form-item label="考核情况" prop="assess">
           <el-input v-model="form.assess" placeholder="请输入考核情况" />
         </el-form-item>
+        <el-form-item label="应学习时长(分)" prop="timerNeed">
+          <el-input-number v-model="form.timerNeed" placeholder="请输入应学习时长" style="width: 100%"/>
+        </el-form-item>
         <el-form-item label="备注" prop="remarks">
           <el-input v-model="form.remarks" placeholder="请输入备注" />
         </el-form-item>
-          <el-form-item label="归属部门" prop="deptId">
-              <treeselect v-model="form.deptId" :options="deptOptions" :show-count="true" placeholder="请选择归属部门" />
-          </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
@@ -209,16 +217,97 @@
               <el-button @click="upload.open = false">取 消</el-button>
           </div>
       </el-dialog>
+    <el-dialog :close-on-click-modal="false" v-dialogDrag :title="doc.title" :visible.sync="doc.open" width="1000px"
+               append-to-body>
+      <el-upload
+        ref="doc"
+        :limit="50"
+        :headers="doc.headers"
+        :action="doc.url+'/'+doc.id"
+        :disabled="doc.isUploading"
+        :on-progress="handleFileDocProgress"
+        :on-success="handleFileDocSuccess"
+        :file-list="doc.file"
+        :auto-upload="true"
+        drag
+      >
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">
+          {{ $t('将文件拖到此处,或') }}
+          <em>{{ $t('点击上传') }}</em>
+        </div>
+      </el-upload>
+      <el-table :data="doc.commonfileList" border>
+        <el-table-column :label="$t('文件名')" align="center" prop="fileName" :show-overflow-tooltip="true">
+          <template slot-scope="scope">
+            <a class="link-type" @click="handleDownload(scope.row)">
+              <span>{{ scope.row.fileName }}</span>
+            </a>
+          </template>
+        </el-table-column>
+        <!--        <el-table-column :label="$t('大小(Kb)')" align="center" prop="fileSize" :show-overflow-tooltip="true"-->
+        <!--                         width="80"/>-->
+        <!--        <el-table-column :label="$t('上传人')" align="center" prop="creator" :show-overflow-tooltip="true" width="120"/>-->
+        <el-table-column :label="$t('操作')" align="center" width="220" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button
+              v-if="scope.row.fileName!=null&&scope.row.fileName.endsWith('pdf')"
+              size="mini"
+              type="text"
+              icon="el-icon-view"
+              @click="handleSee(scope.row)"
+            >{{ $t('预览') }}
+            </el-button>
+            <el-button v-hasPermi="['training:trainingrecords:file']" type="text" size="small" v-if="scope.row.isEdit"
+                       @click="save(scope.row)">保存
+            </el-button>
+            <el-button type="text" size="small" v-if="scope.row.isEdit" @click="cancelFile(scope.row, scope.$index)">
+              取消
+            </el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-download"
+              @click="handleDownload(scope.row)"
+            >{{ $t('下载') }}
+            </el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-delete"
+              @click="handleDeleteDoc(scope.row)"
+              v-hasPermi="['training:trainingrecords:file']"
+            >{{ $t('删除') }}
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-dialog :close-on-click-modal="false" v-dialogDrag :title="pdf.title" :visible.sync="pdf.open" width="1300px"
+                 append-to-body>
+        <div style="margin-top: -60px;float: right;margin-right: 40px;">
+          <el-button size="mini" type="text" @click="openPdf">{{ $t('新页面打开PDF') }}</el-button>
+        </div>
+        <div style="margin-top: -30px">
+          <iframe :src="pdf.pdfUrl" frameborder="0" width="100%" height="700px"></iframe>
+        </div>
+      </el-dialog>
+
+      <div slot="footer" class="dialog-footer">
+        <!--        <el-button type="primary" @click="submitFileForm">{{ $t('确 定') }}</el-button>-->
+        <el-button @click="doc.open = false">{{ $t('返 回') }}</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
 <script>
-import { listYaPlan, getYaPlan, delYaPlan, addYaPlan, updateYaPlan, exportYaPlan, importTemplate} from "@/api/training/bccnew/ysPlan";
+import { listYsPlan, getYsPlan, delYsPlan, addYsPlan, updateYsPlan, exportYsPlan, importTemplate} from "@/api/training/bccnew/ysPlan";
 import { treeselect } from "@/api/system/dept";
 import { getToken } from "@/utils/auth";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import Editor from '@/components/Editor/index.vue';
+import {getFirstPlanTmpl, updateFirstPlanTmpl} from "@/api/training/bccnew/firstPlanTmpl";
 
 export default {
   name: "YsPlan",
@@ -226,6 +315,42 @@ export default {
   // components: { Editor },
   data() {
     return {
+      // 报告附件参数
+      doc: {
+        file: null,
+        // 是否显示弹出层(报告附件)
+        open: false,
+        // 弹出层标题(报告附件)
+        title: "附件",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 报告附件上传位置编号
+        ids: 0,
+        id: null,
+        // 设置上传的请求头部
+        headers: {Authorization: "Bearer " + getToken()},
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/bccnew/ysPlanTmpl/uploadFile",
+        commonfileList: null,
+        queryParams: {
+          pId: null,
+          pType: 'bccnew'
+        },
+        pType: 'bccnew',
+        pId: null,
+        form: {}
+      },
+      pdf: {
+        title: '',
+        pdfUrl: '',
+        numPages: null,
+        open: false,
+        pageNum: 1,
+        pageTotalNum: 1,
+        loadedRatio: 0,
+      },
       // 遮罩层
       loading: true,
       // 选中数组
@@ -239,7 +364,7 @@ export default {
       // 总条数
       total: 0,
       // 压缩培训模版表格数据
-      yaPlanList: [],
+      ysPlanList: [],
       // 弹出层标题
       title: "",
       // 部门树选项
@@ -260,7 +385,7 @@ export default {
             // 设置上传的请求头部
             headers: { Authorization: "Bearer " + getToken() },
             // 上传的地址
-            url: process.env.VUE_APP_BASE_API + "/bccnew/yaPlan/importData"
+            url: process.env.VUE_APP_BASE_API + "/bccnew/ysPlan/importData"
         },
       // 查询参数
       queryParams: {
@@ -305,11 +430,74 @@ export default {
     this.getTreeselect();
   },
   methods: {
+    uploadFile(row) {
+      this.doc.file = null;
+      this.doc.commonfileList = [];
+      this.doc.open = true;
+      this.doc.id = row.id;
+      getFirstPlanTmpl(row.id).then(res => {
+        if (res.data.fileUrl != null)
+          this.doc.commonfileList.push({fileUrl: res.data.fileUrl, fileName: res.data.fileName, id: res.data.id})
+      })
+    },
+    // 文件下载处理
+    handleDownload(row) {
+      var name = row.fileName;
+      var url = row.fileUrl;
+      var suffix = url.substring(url.lastIndexOf("."), url.length);
+      const a = document.createElement('a')
+      a.setAttribute('download', name)
+      a.setAttribute('target', '_blank')
+      a.setAttribute('href', process.env.VUE_APP_BASE_API + url)
+      a.click()
+    },
+    openPdf() {
+      window.open(this.pdf.pdfUrl);//path是文件的全路径地址
+    },
+    handleSee(row) {
+      // window.open(process.env.VUE_APP_BASE_API +'/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl);//path是文件的全路径地址
+      this.pdf.open = true
+      this.pdf.title = row.fileName
+      this.pdf.pdfUrl = process.env.VUE_APP_BASE_API + '/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl
+    },
+    /** 删除按钮操作 */
+    handleDeleteDoc(row) {
+      const ids = row.id || this.ids;
+      this.$confirm(this.$t('是否确认删除?'), this.$t('警告'), {
+        confirmButtonText: this.$t('确定'),
+        cancelButtonText: this.$t('取消'),
+        type: "warning"
+      }).then(function () {
+        return updateFirstPlanTmpl({id: row.id, fileUrl: '', fileName: ''});
+      }).then(() => {
+        this.msgSuccess(this.$t('删除成功'));
+        this.doc.commonfileList = [];
+      })
+    },
+    // 上传中处理
+    handleFileDocProgress(event, file, fileList) {
+      this.doc.file = file;
+      this.doc.isUploading = true;
+    },
+    //附件上传成功处理
+    handleFileDocSuccess(response, file, fileList) {
+      this.doc.isUploading = false;
+      this.$alert(response.msg, this.$t('导入结果'), {dangerouslyUseHTMLString: true});
+      this.getList();
+      this.doc.commonfileList = [];
+      getFirstPlanTmpl(response.data).then(res => {
+        if (res.data.fileUrl != null) {
+          this.doc.commonfileList.push({fileUrl: res.data.fileUrl, fileName: res.data.fileName, id: res.data.id})
+          fileList = null
+          file = null
+        }
+      })
+    },
     /** 查询压缩培训模版列表 */
     getList() {
       this.loading = true;
-      listYaPlan(this.queryParams).then(response => {
-        this.yaPlanList = response.rows;
+      listYsPlan(this.queryParams).then(response => {
+        this.ysPlanList = response.rows;
         this.total = response.total;
         this.loading = false;
       });
@@ -375,7 +563,7 @@ export default {
     handleUpdate(row) {
       this.reset();
       const id = row.id || this.ids
-      getYaPlan(id).then(response => {
+      getYsPlan(id).then(response => {
         this.form = response.data;
         this.open = true;
         this.title = "修改压缩培训模版";
@@ -386,13 +574,13 @@ export default {
       this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.form.id != null) {
-            updateYaPlan(this.form).then(response => {
+            updateYsPlan(this.form).then(response => {
               this.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
-            addYaPlan(this.form).then(response => {
+            addYsPlan(this.form).then(response => {
               this.msgSuccess("新增成功");
               this.open = false;
               this.getList();
@@ -409,7 +597,7 @@ export default {
           cancelButtonText: "取消",
           type: "warning"
         }).then(function() {
-          return delYaPlan(ids);
+          return delYsPlan(ids);
         }).then(() => {
           this.getList();
           this.msgSuccess("删除成功");
@@ -423,7 +611,7 @@ export default {
           cancelButtonText: "取消",
           type: "warning"
         }).then(function() {
-          return exportYaPlan(queryParams);
+          return exportYsPlan(queryParams);
         }).then(response => {
           this.download(response.msg);
         })

+ 13 - 4
ui/src/views/training/elearn/learn/index.vue

@@ -25,6 +25,11 @@
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="主题" align="center" prop="title" :show-overflow-tooltip="true"/>
       <el-table-column label="文件名" align="center" prop="fileName" :show-overflow-tooltip="true"/>
+      <el-table-column label="累计学习时长" align="center" prop="learnTime" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          <span>{{ scope.row.learnTime }}</span> min
+        </template>
+      </el-table-column>
       <el-table-column label="操作" align="center" fixed="right" width="240" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button
@@ -32,14 +37,12 @@
             type="text"
             @click="handleStudy(scope.row)"
             icon="el-icon-video-play"
-            v-hasPermi="['elearn:resource:edit']"
           >开始学习</el-button>
           <el-button
             size="mini"
             type="text"
             @click="handleHistory(scope.row)"
             icon="el-icon-document"
-            v-hasPermi="['elearn:resource:remove']"
           >学习记录</el-button>
         </template>
       </el-table-column>
@@ -136,6 +139,9 @@
 
     <el-dialog  :close-on-click-modal="false"  v-loading="loadingFlash" element-loading-background="rgba(0,0,0,0.2)" v-dialogDrag :title="pdf.title"
                 :visible.sync="pdf.open" width="1300px" height="800px" :center="true" append-to-body @close="handleClose">
+      <div style="margin-top: -60px;float: right;margin-right: 40px;">
+        <br/>累计学习时长:{{learnTime}} min
+      </div>
       <div style="margin-top: -30px">
         <iframe id="iFrame" class="iframe-html" :src="pdf.pdfUrl" frameborder="0" width="100%" height="700px"
                 v-if="ppt"></iframe>
@@ -171,6 +177,7 @@
     components: { Treeselect },
     data() {
       return {
+        learnTime: null,
         history: {
           open: false,
           title: "",
@@ -298,7 +305,7 @@
       handleHistory(row) {
         this.history.title = row.fileName + " 学习记录";
         this.history.open = true;
-        listLearn({"resourceId": row.resourceId}).then(response => {
+        listLearn({"resourceId": row.id}).then(response => {
           this.historyList = response.data;
           this.historyLoading = false;
         });
@@ -319,10 +326,12 @@
           this.pdf.pdfUrl = process.env.VUE_APP_BASE_API + '/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl
           this.loadingFlash = false
         }
+        this.learnTime = row.learnTime;
         let _this = this;
         timer = window.setInterval(function() {
           updateLearnTime(row).then(response => {
-            // _this.$forceUpdate();
+            console.log(response)
+            this.learnTime = response.data.learnTime;
           });
         }, 60000);
       },

+ 2 - 0
ui/src/views/training/elearn/paper/list.vue

@@ -161,6 +161,7 @@ export default {
         },
       // 查询参数
       queryParams: {
+        examId: null,
         pageNum: 1,
         pageSize: 20,
         title: null,
@@ -235,6 +236,7 @@ export default {
 
   },
   created() {
+    this.queryParams.examId = this.$route.params.examId
       //设置表格高度对应屏幕高度
       this.$nextTick(() => {
           this.clientHeight = document.body.clientHeight -250

+ 9 - 0
ui/src/views/training/elearn/resource/index.vue

@@ -132,6 +132,7 @@
                  :on-success="handleFileDocSuccess"
                  :auto-upload="true"
                  drag
+                 v-show="showUpload"
       >
         <i class="el-icon-upload"></i>
         <div class="el-upload__text">
@@ -202,6 +203,7 @@ export default {
   components: { Treeselect },
   data() {
     return {
+      showUpload: true,
       doc: {
         file: "",
         // 是否显示弹出层(报告附件)
@@ -323,6 +325,13 @@ export default {
           element["isAdd"] = false
         });
         this.doc.commonfileList = response;
+        if (this.doc.commonfileList.length > 0) {
+          this.showUpload = false;
+        } else {
+          this.showUpload = true;
+        }
+        console.log(this.doc.commonfileList)
+        console.log(this.showUpload)
       });
     },
     //附件上传中处理

+ 437 - 0
ui/src/views/training/trainingbcc/deviceList.vue

@@ -0,0 +1,437 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="开始日期" prop="startDate">
+        <el-date-picker clearable size="small" style="width: 200px"
+          v-model="queryParams.startDate"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择开始日期">
+        </el-date-picker>
+      </el-form-item>
+
+      <el-form-item label="学习时长min" prop="learnTime">
+        <el-input
+          v-model="queryParams.learnTime"
+          placeholder="请输入学习时长min"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+        >新增</el-button>
+      </el-col>
+
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="deviceList" @selection-change="handleSelectionChange" :height="clientHeight" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="开始日期" align="center" prop="startDate" width="100">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.startDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="培训课程" align="center" prop="trainingbcc.course" width="500">
+      </el-table-column>
+      <el-table-column label="参培人" align="center" prop="name" width="100">
+      </el-table-column>
+      <el-table-column label="是否为补培人员" align="center" prop="supplementary" :show-overflow-tooltip="true">
+        <template v-slot="scope">
+          <span v-if="scope.row.supplementary == 0" size="small" type="success">否</span>
+          <span v-else-if="scope.row.supplementary == 1" size="small" type="info">是</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="学习状态" align="center" prop="learnState" :show-overflow-tooltip="true">
+        <template v-slot="scope">
+          <el-tag v-if="scope.row.learnState == 1" size="small" type="success">已完成</el-tag>
+          <el-tag v-else-if="scope.row.learnState == 0"  size="small" type="info">未完成</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="学习时长min" align="center" prop="learnTime" :show-overflow-tooltip="true"/>
+
+      <el-table-column label="考试状态" align="center" prop="examState" :show-overflow-tooltip="true">
+        <template v-slot="scope">
+          <el-tag v-if="scope.row.examState == 1" size="small" type="success">合格</el-tag>
+          <el-tag v-else-if="scope.row.examState == 0" size="small" type="info">未完成</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="考试次数" align="center" prop="examNum" :show-overflow-tooltip="true"/>
+
+      <el-table-column label="操作" align="center" fixed="right" width="120" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="hanldeExamPaper(scope.row)"
+          >考试成绩</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改人员-装置级培训关系对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="人员员工号" prop="staffId">
+          <el-input v-model="form.staffId" placeholder="请输入人员员工号" />
+        </el-form-item>
+        <el-form-item label="装置级培训ID" prop="regularId">
+          <el-input v-model="form.regularId" placeholder="请输入装置级培训ID" />
+        </el-form-item>
+        <el-form-item label="开始日期" prop="startDate">
+          <el-date-picker clearable size="small" style="width: 200px"
+            v-model="form.startDate"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择开始日期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="备注" prop="remarks">
+          <el-input v-model="form.remarks" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="删除状态" prop="delFlag">
+          <el-input v-model="form.delFlag" placeholder="请输入删除状态" />
+        </el-form-item>
+        <el-form-item label="创建人" prop="createrCode">
+          <el-input v-model="form.createrCode" placeholder="请输入创建人" />
+        </el-form-item>
+        <el-form-item label="创建时间" prop="createdate">
+          <el-date-picker clearable size="small" style="width: 200px"
+            v-model="form.createdate"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择创建时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="修改人" prop="updaterCode">
+          <el-input v-model="form.updaterCode" placeholder="请输入修改人" />
+        </el-form-item>
+        <el-form-item label="修改时间" prop="updatedate">
+          <el-date-picker clearable size="small" style="width: 200px"
+            v-model="form.updatedate"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择修改时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="是否为补培人员" prop="supplementary">
+          <el-input v-model="form.supplementary" placeholder="请输入是否为补培人员" />
+        </el-form-item>
+        <el-form-item label="学习状态" prop="learnState">
+          <el-input v-model="form.learnState" placeholder="请输入学习状态" />
+        </el-form-item>
+        <el-form-item label="考试状态" prop="examState">
+          <el-input v-model="form.examState" placeholder="请输入考试状态" />
+        </el-form-item>
+        <el-form-item label="考试ID" prop="examId">
+          <el-input v-model="form.examId" placeholder="请输入考试ID" />
+        </el-form-item>
+        <el-form-item label="学习时长min" prop="learnTime">
+          <el-input v-model="form.learnTime" placeholder="请输入学习时长min" />
+        </el-form-item>
+          <el-form-item label="归属部门" prop="deptId">
+              <treeselect v-model="form.deptId" :options="deptOptions" :show-count="true" placeholder="请选择归属部门" />
+          </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+      <!-- 用户导入对话框 -->
+      <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
+          <el-upload
+                  ref="upload"
+                  :limit="1"
+                  accept=".xlsx, .xls"
+                  :headers="upload.headers"
+                  :action="upload.url + '?updateSupport=' + upload.updateSupport"
+                  :disabled="upload.isUploading"
+                  :on-progress="handleFileUploadProgress"
+                  :on-success="handleFileSuccess"
+                  :auto-upload="false"
+                  drag
+          >
+              <i class="el-icon-upload"></i>
+              <div class="el-upload__text">
+                  将文件拖到此处,或
+                  <em>点击上传</em>
+              </div>
+              <div class="el-upload__tip" slot="tip">
+                  <el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
+                  <el-link type="info" style="font-size:12px" @click="importTemplate">下载模板</el-link>
+              </div>
+              <div class="el-upload__tip" style="color:red" slot="tip">提示:仅允许导入“xls”或“xlsx”格式文件!</div>
+          </el-upload>
+          <div slot="footer" class="dialog-footer">
+              <el-button type="primary" @click="submitFileForm">确 定</el-button>
+              <el-button @click="upload.open = false">取 消</el-button>
+          </div>
+      </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listDevice, getDevice, delDevice, addDevice, updateDevice, exportDevice, importTemplate} from "@/api/training/bccdevice";
+import { treeselect } from "@/api/system/dept";
+import { getToken } from "@/utils/auth";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "Device",
+  components: { Treeselect },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: false,
+      // 总条数
+      total: 0,
+      // 人员-装置级培训关系表格数据
+      deviceList: [],
+      // 弹出层标题
+      title: "",
+      // 部门树选项
+      deptOptions: undefined,
+      clientHeight:300,
+      // 是否显示弹出层
+      open: false,
+        // 用户导入参数
+        upload: {
+            // 是否显示弹出层(用户导入)
+            open: false,
+            // 弹出层标题(用户导入)
+            title: "",
+            // 是否禁用上传
+            isUploading: false,
+            // 是否更新已经存在的用户数据
+            updateSupport: 0,
+            // 设置上传的请求头部
+            headers: { Authorization: "Bearer " + getToken() },
+            // 上传的地址
+            url: process.env.VUE_APP_BASE_API + "/training/device/importData"
+        },
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 20,
+        staffId: null,
+        regularId: null,
+        startDate: null,
+        remarks: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        supplementary: null,
+        learnState: null,
+        examState: null,
+        examId: null,
+        learnTime: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  watch: {
+        // 根据名称筛选部门树
+        deptName(val) {
+            this.$refs.tree.filter(val);
+        }
+   },
+  created() {
+    this.queryParams.regularId = this.$route.params.id
+      //设置表格高度对应屏幕高度
+      this.$nextTick(() => {
+          this.clientHeight = document.body.clientHeight -250
+      })
+    this.getList();
+    this.getTreeselect();
+  },
+  methods: {
+    /** 查询人员-装置级培训关系列表 */
+    getList() {
+      this.loading = true;
+      listDevice(this.queryParams).then(response => {
+        this.deviceList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+     /** 查询部门下拉树结构 */
+     getTreeselect() {
+          treeselect().then(response => {
+              this.deptOptions = response.data;
+          });
+     },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        staffId: null,
+        regularId: null,
+        startDate: null,
+        remarks: null,
+        delFlag: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        supplementary: null,
+        learnState: null,
+        examState: null,
+        examId: null,
+        learnTime: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    hanldeExam(row){
+      this.$router.push({ name: 'paper', params: { examId: row.examId }})
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加人员-装置级培训关系";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getDevice(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改人员-装置级培训关系";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateDevice(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addDevice(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delDevice(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有人员-装置级培训关系数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportDevice(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        })
+    },
+      /** 导入按钮操作 */
+      handleImport() {
+          this.upload.title = "用户导入";
+          this.upload.open = true;
+      },
+      /** 下载模板操作 */
+      importTemplate() {
+          importTemplate().then(response => {
+              this.download(response.msg);
+          });
+      },
+      // 文件上传中处理
+      handleFileUploadProgress(event, file, fileList) {
+          this.upload.isUploading = true;
+      },
+      // 文件上传成功处理
+      handleFileSuccess(response, file, fileList) {
+          this.upload.open = false;
+          this.upload.isUploading = false;
+          this.$refs.upload.clearFiles();
+          this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
+          this.getList();
+      },
+      // 提交上传文件
+      submitFileForm() {
+          this.$refs.upload.submit();
+      }
+  }
+};
+</script>

+ 1280 - 0
ui/src/views/training/trainingbcc/index.vue

@@ -0,0 +1,1280 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item :label="$t('年份')" prop="years">
+        <el-date-picker clearable size="small" style="width: 200px"
+                        v-model="queryParams.years"
+                        type="year"
+                        value-format="yyyy"
+                        :placeholder="$t('请选择') + $t('年份')"
+                        @change="handleQuery" >
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item :label="$t('培训课程')" prop="course">
+        <el-input
+          v-model="queryParams.course"
+          :placeholder="$t('请输入') + $t('培训课程')"
+          clearable
+          size="small"
+          @input="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item :label="$t('培训类型')" prop="trainingType" label-width="50">
+        <el-select v-model="queryParams.trainingType" @change="handleQuery"    :placeholder="$t('请选择') + $t('培训类型')" clearable size="small">
+          <el-option
+            v-for="dict in trainingTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item :label="$t('是否完成')" prop="isfinish" label-width="50">
+        <el-select v-model="queryParams.isfinish" @change="handleQuery"    :placeholder="$t('请选择') + $t('是否完成')" clearable size="small">
+          <el-option
+            v-for="dict in isfinishOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item :label="$t('未参培情况')" prop="isNon" label-width="50">
+        <el-select v-model="queryParams.isNon" @change="handleQuery"    :placeholder="$t('请选择') + $t('是否未参培')" clearable size="small">
+          <el-option
+            key="0"
+            label="全部"
+            value="0"
+          />
+          <el-option
+            key="1"
+            label="未参培"
+            value="1"
+          />
+          <el-option
+            key="2"
+            label="已完成"
+            value="2"
+          />
+          <el-option
+            key="3"
+            label="未完成"
+            value="3"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item :label="$t('培训开始日期')" label-width="60">
+        <el-date-picker
+          v-model="chooseDate"
+          @change="handleQuery"
+          type="daterange"
+          align="right"
+          unlink-panels
+          :range-separator="$t('至')"
+          :start-placeholder="$t('开始日期')"
+          :end-placeholder="$t('结束日期')"
+          value-format="yyyy-MM-dd"
+          :picker-options="pickerOptions">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">{{ $t('搜索') }}</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">{{ $t('重置') }}</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['training:training:add']"
+        >{{ $t('新增') }}</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['training:training:edit']"
+        >{{ $t('修改') }}</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['training:training:remove']"
+        >{{ $t('删除') }}</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['training:training:export']"
+        >{{ $t('导出') }}</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-row>
+      <el-col :span="24">
+        <el-button type="primary" plain @click="selectCourse('10')">定期类</el-button>
+        <el-button type="primary" plain @click="selectCourse('12')">
+          EHS类培训、学习及信息通告
+        </el-button>
+        <el-button type="primary" plain @click="selectCourse('14')">
+          程序和操作手册培训更新培训
+        </el-button>
+        <el-button type="primary" plain @click="selectCourse('16')">事件报告和调查</el-button>
+        <el-button type="primary" plain @click="selectCourse('20')">MOC培训</el-button>
+      </el-col>
+    </el-row>
+    <el-table v-loading="loading" :data="trainingList" @selection-change="handleSelectionChange" :cell-style="tableCellStyle" :height="clientHeight" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column :label="$t('年份')" align="center" prop="years" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('培训课程')" align="center" prop="course" width="250" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('培训类型')" align="center" prop="trainingType" width="120" :formatter="trainingTypeFormat"/>
+      <el-table-column :label="$t('培训内容')" align="center" prop="content" width="250" :show-overflow-tooltip="true" />
+      <el-table-column :label="$t('课程代码')" align="center" prop="courseid" width="150" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('是否完成')" align="center" prop="isfinish" width="120">
+        <template slot-scope="scope">
+            <el-progress :percentage="scope.row.trainingPercent"></el-progress>
+          <span > ({{ scope.row.haveTraining }}/{{ scope.row.mustTraining }})</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('培训周期')" align="center" prop="period" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('课时')" align="center" prop="duration" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('培训人')" align="center" prop="trainer" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('培训岗位')" align="center" prop="position" width="250" :show-overflow-tooltip="true" />
+      <el-table-column :label="$t('培训开始日期')" align="center" prop="courseStartdate" width="100">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.courseStartdate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('培训结束日期')" align="center" prop="courseEnddate" width="100">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.courseEnddate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+<!--      <el-table-column :label="$t('未参培人员名单')" align="center" prop="nonParticipants" width="200" :show-overflow-tooltip="true" />-->
+      <el-table-column :label="$t('备注')" align="center" prop="remarks" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('操作')" align="center" fixed="right" width="270" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['training:training:edit']"
+          >{{ $t('修改') }}</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleStaffmgr(scope.row)"
+            v-hasPermi="['training:training:edit']"
+          >人员名单</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleDetail(scope.row)"
+            v-hasPermi="['training:training:edit']"
+          >培训详情</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+
+    <!-- 添加或修改培训计划对话框 -->
+    <el-dialog  :close-on-click-modal="false" v-dialogDrag :title="title" :visible.sync="open" width="80%" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="110px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训课程')" prop="course">
+              <el-input v-model="form.course" :placeholder="$t('请输入') + $t('培训课程')" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训类型')" prop="trainingType">
+              <el-select v-model="form.trainingType" :placeholder="$t('请选择') + $t('培训类型')">
+                <el-option
+                  v-for="dict in trainingTypeOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训内容')" prop="content">
+              <el-input v-model="form.content" :placeholder="$t('请输入') + $t('培训内容')" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('课程代码')" prop="courseid">
+              <el-input v-model="form.courseid" :placeholder="$t('请输入') + $t('课程代码')" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训周期')" prop="period">
+              <el-input v-model="form.period" :placeholder="$t('请输入') + $t('培训周期')" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('课时')" prop="duration">
+              <el-input v-model="form.duration" :placeholder="$t('请输入') + $t('课时')" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训人')" prop="trainer">
+              <el-select v-model="form.trainer" filterable multiple :placeholder="$t('请选择') + $t('培训人')">
+                <el-option
+                  v-for="dict in stffmgrOptions"
+                  :key="dict.staffid"
+                  :label="dict.name"
+                  :value="dict.staffid">
+                  <span style="float: left">{{ dict.name }}</span>
+                  <span style="float: right; color: #8492a6; font-size: 13px">{{ dict.staffid }}</span>
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训岗位')" prop="position">
+              <el-select v-model="form.position" multiple :placeholder="$t('请选择') + $t('培训岗位')" @change="changePosition"  style="width: 400px">
+                <el-option
+                  v-for="dict in positionOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('是否存在') +$t('指定人员')" prop="haveDesignated" >
+              <el-checkbox v-model="haveDesignated" @change="changeHave"></el-checkbox>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('年份')" prop="years">
+              <el-date-picker clearable size="small" style="width: 200px"
+                              v-model="form.years"
+                              type="years"
+                              value-format="yyyy"
+                              @change="handleStaff"
+                              :placeholder="$t('请选择') + $t('年份')">
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('指定人员') + $t('岗位')" prop="designatedPosition" v-if="haveDesignated === true">
+              <el-select v-model="designatedPositions" multiple :placeholder="$t('请选择') + $t('指定岗位')" @change="changeDesignated" style="width: 400px">
+                <el-option
+                  v-for="dict in designatedPositionOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训开始日期')" prop="courseStartdate">
+              <el-date-picker clearable size="small" style="width: 200px"
+                              v-model="form.courseStartdate"
+                              type="date"
+                              value-format="yyyy-MM-dd"
+                              :placeholder="$t('请选择') + $t('培训开始日期')">
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('指定人员')" prop="designatedStaff" v-if="haveDesignated === true && designatedPositions.length > 0">
+              <el-select v-model="designatedStaffs" filterable multiple :placeholder="$t('请选择') + $t('指定人员')"  style="width: 400px">
+                <el-option
+                  v-for="dict in designatedStaffsOptions"
+                  :key="dict.staffid"
+                  :label="dict.name"
+                  :value="dict.staffid">
+                  <span style="float: left">{{ dict.name }}</span>
+                  <span style="float: right; color: #8492a6; font-size: 13px">{{ dict.staffid }}</span>
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训结束日期')" prop="courseEnddate">
+              <el-date-picker clearable size="small" style="width: 200px"
+                              v-model="form.courseEnddate"
+                              type="date"
+                              value-format="yyyy-MM-dd"
+                              :placeholder="$t('请选择') + $t('培训结束日期')">
+              </el-date-picker>
+            </el-form-item >
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('是否完成')" prop="isfinish">
+              <el-select v-model="form.isfinish" :placeholder="$t('请选择') + $t('是否完成')">
+                <el-option
+                  v-for="dict in isfinishOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="parseInt(dict.dictValue)"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="培训考试" prop="examId">
+              <el-select v-model="form.examId" filterable  :placeholder="$t('请选择') + $t('培训考试')">
+                <el-option
+                  v-for="dict in examOptions"
+                  :key="dict.examId"
+                  :label="dict.title"
+                  :value="dict.examId">
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('备注')" prop="remarks">
+              <el-input v-model="form.remarks" :placeholder="$t('请输入') + $t('备注')" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm" :disabled="submitDisabled">{{ $t('确 定') }}</el-button>
+        <el-button @click="cancel">{{ $t('取 消') }}</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 添加参与公司级培训人员名单对话框 -->
+    <el-dialog  :close-on-click-modal="false" v-dialogDrag title="培训人员名单" :visible.sync="personOpen" width="1500px" append-to-body>
+      <el-form ref="personForm" :model="personForm"  label-width="80px">
+
+        <el-form-item :label="$t('课程名称')" prop="item">
+          <el-input v-model="personForm.course" disabled />
+        </el-form-item>
+        <el-form-item :label="$t('实际岗位')">
+          <el-checkbox-group v-model="checkboxPost" size="medium" @change="postChange">
+            <el-checkbox-button v-for="post in positionOptions" :label="post.dictValue" :key="post.dictValue">{{post.dictLabel}}</el-checkbox-button>
+          </el-checkbox-group>
+        </el-form-item>
+      </el-form>
+      <div class="staff_checked">
+        <el-transfer v-model="checked" :data="selectPersonOptions" @change="staffChange" :left-default-checked="leftList" filterable
+                     :titles="['无需参培人员', '需要参培人员']"
+        >
+          <span slot-scope="{ option }">{{ option.label }}
+            <span style="float: right; color: #8492a6; font-size: 12px; padding-left: 10px;padding-right: 15px;">{{ option.staffid }}</span>
+            <span style="float: right; color: #8492a6; font-size: 12px; padding-left: 10px;">{{ option.actualpost }}</span>
+          </span>
+        </el-transfer>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitParticipants">{{ $t('确 定') }}</el-button>
+        <el-button @click="cancelParticipants">{{ $t('取 消') }}</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import { listTrainingbcc,getTrainingbccStaffIds,updateTrainingbccStaffIds, getTrainingbcc, delTrainingbcc, addTrainingbcc, updateTrainingbcc, exportTrainingbcc } from "@/api/training/trainingbcc";
+import nonAdd from './trainingNon'
+import newAdd from './trainingNew'
+import {listStaffmgrAll, listAllStaffmgr, listStaffmgr, selectTimeStaffmgr} from "@/api/plant/staffmgr";
+import { treeselect } from "@/api/system/dept";
+import { getToken } from "@/utils/auth";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import { allFileList, listCommonfile, getCommonfile, delCommonfile, addCommonfile, updateCommonfile, exportCommonfile} from "@/api/common/commonfile";
+import {getCompanylevel, updateCompanylevel} from "@/api/training/companylevel";
+import {listExam} from "@/api/training/elearn/exam";
+
+
+export default {
+  name: "Training",
+  components: { Treeselect, nonAdd, newAdd},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      positionVisible: false,
+      showFlag: false,
+      //确认按钮是否可点
+      submitDisabled: false,
+      //左侧选框默认选择
+      leftList: [],
+      // 选中数组
+      ids: [],
+      //人员筛选按钮选择数据
+      checkboxPost: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: false,
+      // 总条数
+      total: 0,
+      // 培训计划表格数据
+      trainingList: [],
+      positionIds: [],
+      trainers: [],
+      units: [],
+      nonParticipants: [],
+      // 弹出层标题
+      title: "",
+      // 部门树选项
+      deptOptions: undefined,
+      clientHeight:300,
+      // 是否显示弹出层
+      open: false,
+      personOpen: false,
+      // 装置名称字典
+      plantCodeOptions: [],
+      // 部门字典
+      unitOptions: [],
+      examOptions: [],
+      // 培训岗位字典
+      positionOptions: [],
+      //选择人员数据
+      checked: [],
+      trainingTypeOptions: [],
+      // 是否完成字典
+      isfinishOptions: [],
+      // 指定岗位字典
+      designatedPositionOptions: [],
+      //指定人员岗位多选
+      designatedPositions: [],
+      //指定人员id多选
+      designatedStaffs: [],
+      selectPersonOptions: [],
+      //是否存在岗位多选
+      haveDesignated: '',
+      //人员表联查
+      stffmgrOptions: undefined,
+      //人员表联查-包含离职
+      stffmgrAllOptions: undefined,
+      //指定人员选项
+      designatedStaffsOptions: [],
+      // 用户导入参数
+      upload: {
+        downloadAction: process.env.VUE_APP_BASE_API + '/common/template',
+        //下载模板类型
+        type: "training",
+        // 是否显示弹出层(用户导入)
+        open: false,
+        // 弹出层标题(用户导入)
+        title: "",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: { Authorization: "Bearer " + getToken() },
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/training/training/importData"
+      },
+      //未参会人员弹窗是否打开
+      nonVisible: false,
+      //新员工弹窗是否打开
+      newVisible: false,
+      // 报告附件参数
+      doc: {
+        file: "",
+        // 是否显示弹出层(报告附件)
+        open: false,
+        // 弹出层标题(报告附件)
+        title: "",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 报告附件上传位置编号
+        ids: 0,
+        // 设置上传的请求头部
+        headers: { Authorization: "Bearer " + getToken() },
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/common/commonfile/uploadFile",
+        commonfileList: null,
+        queryParams: {
+          pId: null,
+          pType: 'training'
+        },
+        pType: 'training',
+        pId: null
+      },
+      pdf : {
+        title: '',
+        pdfUrl: '',
+        numPages: null,
+        open: false,
+        pageNum: 1,
+        pageTotalNum: 1,
+        loadedRatio: 0,
+      },
+      pic: {
+        imageUrl: '',
+        fileList: [],
+        // 设置上传的请求头部
+        headers: { Authorization: "Bearer " + getToken() },
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/training/training/uploadFile",
+      },
+      photoList: [],
+      dialogImageUrl: '',
+      dialogVisible: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 20,
+        course: null,
+        position: [],
+        years: this.getNowTime(),
+        isfinish: null,
+        startDate: null,
+        endDate: null,
+        trainingType: null,
+        isNon: null,
+      },
+      trainingId: null,
+      //地址
+      downloadAction: process.env.VUE_APP_BASE_API + '/training/training/trainingReport',
+      //人员表查询参数
+      staffmgrQueryParams: {},
+      searchStaffmgr: "",
+      //日期快速选择
+      pickerOptions: {
+        shortcuts: [{
+          text: this.$t('最近一周'),
+          onClick(picker) {
+            const end = new Date();
+            const start = new Date();
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+            picker.$emit('pick', [start, end]);
+          }
+        }, {
+          text: this.$t('最近一个月'),
+          onClick(picker) {
+            const end = new Date();
+            const start = new Date();
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+            picker.$emit('pick', [start, end]);
+          }
+        }, {
+          text: this.$t('最近三个月'),
+          onClick(picker) {
+            const end = new Date();
+            const start = new Date();
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+            picker.$emit('pick', [start, end]);
+          }
+        }]
+      },
+      //日期选择器
+      chooseDate: [],
+      // 表单参数
+      form: {},
+      personForm: {},
+      // 表单校验
+      rules: {
+        course: [
+          { required: true, message: this.$t('培训课程') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        trainingType: [
+          { required: true, message: this.$t('培训类型') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        trainer: [
+          { required: true, message: this.$t('培训人') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        unit: [
+          { required: true, message: this.$t('部门') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        position: [
+          { required: true, message: this.$t('培训岗位') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        years: [
+          { required: true, message: this.$t('年份') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        courseStartdate: [
+          { required: true, message: this.$t('培训开始日期') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        isfinish: [
+          { required: true, message: this.$t('是否完成') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        deptId: [
+          { required: true, message: this.$t('部门编号') + this.$t('不能为空'), trigger: "blur" }
+        ]
+      }
+    };
+  },
+  watch: {
+    // 根据名称筛选部门树
+    deptName(val) {
+      this.$refs.tree.filter(val);
+    },
+  },
+  created() {
+    const queryName = this.$route.query && this.$route.query.status;
+    if (queryName == '未参培'){
+      this.queryParams.isNon = "1"
+    }
+    if (queryName == '已完成'){
+      this.queryParams.isNon = "2"
+    }
+    if (queryName == '未完成'){
+      this.queryParams.isNon = "3"
+    }
+
+    this.getStaffmar();
+    this.getStaffmarAll();
+    listExam({ pageNum: 1, pageSize: 1000,  examType: 2 }).then(response => {
+      this.examOptions = response.rows;
+    });
+
+    //设置表格高度对应屏幕高度
+    this.$nextTick(() => {
+      this.clientHeight = (document.body.clientHeight - 80) * 0.8
+    })
+    this.getTreeselect();
+    this.getDicts("PLANT_DIVIDE").then(response => {
+      this.plantCodeOptions = response.data;
+    });
+    this.getDicts("ACTUALPOST").then(response => {
+      this.positionOptions = response.data;
+      this.designatedPositionOptions = response.data;
+      const allData = response.data
+      const data = [];
+      for (let i = 0; i < allData.length; i++) {
+        data.push({
+          key: allData[i].dictValue,
+          label: allData[i].dictLabel,
+        });
+      }
+      this.positionOpt = response.data;
+    });
+    this.getDicts("YES_NO_EN").then(response => {
+      this.isfinishOptions = response.data;
+    });
+    this.getDicts("STAFF_UNIT").then(response => {
+      this.unitOptions = response.data;
+    });
+    this.getDicts("TRAINING_TYPE_BCC").then(response => {
+      this.trainingTypeOptions = response.data;
+    });
+  },
+  methods: {
+    /** 查询培训计划列表 */
+    getList() {
+      let _this = this
+      this.loading = true;
+      listTrainingbcc(this.queryParams).then(response => {
+        this.trainingList = response.rows;
+        this.trainingList.forEach(function (value,key,arr) {
+          var positionid = null;
+          var positionName = null;
+          let unitid = null;
+          let unitName = null;
+          if (value.position != null) {
+            positionid = value.position.split(',');
+            positionid.forEach(function (value, key, arr) {
+              if (key != 0) {
+                positionName = positionName + "," + _this.selectDictLabel(_this.positionOptions, value);
+              }else if (key == 0) {
+                positionName = _this.selectDictLabel(_this.positionOptions, value);
+              }
+            })
+          }
+
+          if (value.unit != null) {
+            unitid = value.unit.split(',');
+            unitid.forEach(function (value, key, arr) {
+              if (key != 0) {
+                unitName = unitName + "," + _this.selectDictLabel(_this.unitOptions, value);
+              }else if (key == 0) {
+                unitName = _this.selectDictLabel(_this.unitOptions, value);
+              }
+            })
+          }
+          _this.trainingList[key].positionid = value.position;
+          _this.trainingList[key].position = positionName;
+          _this.trainingList[key].unitid = value.unit;
+          _this.trainingList[key].unit = unitName;
+
+          var parentName = null;
+          if (value.trainer != null) {
+            let staffId = value.trainer.split(",");
+            staffId.forEach(function (id, index) {
+              _this.stffmgrAllOptions.forEach(function (item) {
+                if (item.staffid === id) {
+                  if (index === 0) {
+                    parentName = item.name
+                  }else {
+                    parentName = parentName + "," + item.name
+                  }
+                }
+              });
+            });
+          }
+          _this.trainingList[key].trainer = parentName;
+        })
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    /** 获取当前年份 */
+    getNowTime() {
+      var now = new Date();
+      var year = now.getFullYear(); //得到年份
+      var defaultDate = `${year}`;
+      defaultDate = `${year}`
+      return defaultDate;
+    },
+    closeChildDialog () {
+      this.showFlag = false
+      this.getList();
+    },
+    /** 查询部门下拉树结构 */
+    getTreeselect() {
+      treeselect().then(response => {
+        this.deptOptions = response.data;
+      });
+    },
+    // 装置名称字典翻译
+    plantCodeFormat(row, column) {
+      return this.selectDictLabel(this.plantCodeOptions, row.plantCode);
+    },
+    // 部门字典翻译
+    unitFormat(row, column) {
+      return this.selectDictLabel(this.unitOptions, row.unit);
+    },
+    // 培训类型翻译
+    trainingTypeFormat(row, column) {
+      return this.selectDictLabel(this.trainingTypeOptions, row.trainingType);
+    },
+    // 培训岗位字典翻译
+    positionFormat(row, column) {
+      return this.selectDictLabel(this.positionOptions, row.position);
+    },
+    // 是否完成字典翻译
+    isfinishFormat(row, column) {
+      return this.selectDictLabel(this.isfinishOptions, row.isfinish);
+    },
+    //获取人员表
+    getStaffmar(year) {
+      this.staffmgrQueryParams.leftYear = year
+      listAllStaffmgr(this.staffmgrQueryParams).then(response => {
+        this.stffmgrOptions = response.rows;
+        //
+        const allData = response.rows
+        const data = [];
+        for (let i = 0; i < allData.length; i++) {
+          data.push({
+            key: allData[i].staffid,
+            label: allData[i].name,
+            staffid: allData[i].staffid,
+            actualpost: this.selectDictLabel(this.positionOptions, allData[i].actualpost)
+          });
+        }
+        this.selectPersonOptions = data;
+
+      });
+    },
+    //年份选择change事件
+    handleStaff(val){
+      this.getStaffmar(val)
+    },
+    //获取人员表--包含离职
+    getStaffmarAll() {
+      listStaffmgrAll(this.staffmgrQueryParams).then(response => {
+        this.stffmgrAllOptions = response.rows;
+        this.getList();
+      });
+    },
+    //遍历人员表
+    forEachStaffmar(id) {
+      let stffmgrName = "";
+      this.stffmgrOptions.forEach(function (item) {
+        if (item.staffid === id) {
+          stffmgrName = item.name
+        }
+      });
+      return stffmgrName
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        plantCode: null,
+        course: null,
+        courseid: null,
+        period: null,
+        duration: null,
+        trainer: null,
+        positionId: [],
+        position: null,
+        content: null,
+        unit : null,
+        years: null,
+        courseStartdate: null,
+        courseEnddate: null,
+        isfinish: null,
+        delFlag: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        remarks: null,
+        deptId: null,
+        startDate: null,
+        endDate: null,
+        nonParticipants: null,
+        trainingType: null,
+        picUrl: null,
+        mustTraining: null,
+        haveTraining: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.queryParams.startDate = this.chooseDate[0];
+      this.queryParams.endDate = this.chooseDate[1];
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.chooseDate = "";
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    //根据分数显示颜色提示
+    tableCellStyle({ row, column, rowIndex, columnIndex }) {
+      if (columnIndex == 6 && row.isfinish == 0){
+        return "color: rgba(255, 26, 26, 0.98) "
+      }
+    },
+    //培训岗位变动
+    changePosition() {
+      let _this = this
+      this.getDicts("ACTUALPOST").then(response => {
+        this.designatedPositionOptions = response.data;
+        this.form.position.forEach(function (value, key, arr) {
+          _this.designatedPositionOptions.forEach(function (positionValue, positionkey, arr) {
+            if (positionValue.dictValue === value) {
+              _this.designatedPositionOptions.splice(positionkey ,1)
+            }
+          })
+        })
+      });
+    },
+    //指定人员训岗位变动
+    changeDesignated() {
+      if (this.designatedPositions.length > 0) {
+        var designatedId = null;
+        this.designatedPositions.forEach(function (value,key,arr) {
+          if (key != 0) {
+            designatedId = designatedId + "," + value;
+          }else if (key == 0) {
+            designatedId = value;
+          }
+        })
+        this.staffmgrQueryParams.actualposts = designatedId;
+        listStaffmgr(this.staffmgrQueryParams).then(response => {
+          this.designatedStaffsOptions = response.rows;
+        });
+
+        let _this = this
+        this.getDicts("ACTUALPOST").then(response => {
+          this.positionOptions = response.data;
+          this.designatedPositions.forEach(function (value, key, arr) {
+            _this.positionOptions.forEach(function (positionValue, positionkey, arr) {
+              if (positionValue.dictValue === value) {
+                _this.positionOptions.splice(positionkey ,1)
+              }
+            })
+          })
+        });
+      }else {
+        this.designatedStaffs = [];
+      }
+    },
+    //指定人员按钮变动
+    changeHave() {
+      if (this.haveDesignated === false) {
+        this.designatedPositions = []
+        this.designatedStaffs = []
+      }
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.submitDisabled = false;
+      this.haveDesignated = false;
+      this.designatedPositions = [];
+      this.getDicts("ACTUALPOST").then(response => {
+        this.positionOptions = response.data;
+      });
+      this.getDicts("ACTUALPOST").then(response => {
+        this.designatedPositionOptions = response.data;
+      });
+      this.form.trainingType = this.queryParams.trainingType
+      this.title = this.$t('新增') + this.$t('空格') + this.$t('培训计划');
+      this.getStaffmar()
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      let _this = this
+      this.submitDisabled = false;
+      const id = row.id || this.ids
+      getTrainingbcc(id).then(response => {
+        this.form = response.data;
+        this.getStaffmar(response.data.years)
+        if (this.form.position != null) {
+          this.form.position = this.form.position.split(',');
+          this.getDicts("ACTUALPOST").then(response => {
+            this.designatedPositionOptions = response.data;
+            this.form.position.forEach(function (value, key, arr) {
+              _this.designatedPositionOptions.forEach(function (positionValue, positionkey, arr) {
+                if (positionValue.dictValue === value) {
+                  _this.designatedPositionOptions.splice(positionkey ,1)
+                }
+              })
+            })
+          })
+        }else {
+          this.getDicts("ACTUALPOST").then(response => {
+            this.designatedPositionOptions = response.data;
+          })
+          this.form.position = [];
+        }
+        if (this.form.designatedPosition != null) {
+          this.designatedPositions = this.form.designatedPosition.split(',');
+          this.getDicts("ACTUALPOST").then(response => {
+            this.positionOptions = response.data;
+            this.designatedPositions.forEach(function (value, key, arr) {
+              _this.positionOptions.forEach(function (positionValue, positionkey, arr) {
+                if (positionValue.dictValue === value) {
+                  _this.positionOptions.splice(positionkey ,1)
+                }
+              })
+            })
+          });
+          this.haveDesignated = true;
+          var designatedId = null;
+          this.designatedPositions.forEach(function (value,key,arr) {
+            if (key != 0) {
+              designatedId = designatedId + "," + value;
+            }else if (key == 0) {
+              designatedId = value;
+            }
+          })
+          this.staffmgrQueryParams.actualposts = designatedId;
+          this.$nextTick(() => {
+            listAllStaffmgr(this.staffmgrQueryParams).then(response => {
+              this.designatedStaffsOptions = response.rows;
+            });
+          })
+        }else {
+          this.haveDesignated = false;
+          this.designatedPositions = [];
+          this.getDicts("ACTUALPOST").then(response => {
+            this.positionOptions = response.data;
+          })
+        }
+        if (this.form.designatedStaff != null) {
+          this.designatedStaffs = this.form.designatedStaff.split(',');
+        }else {
+          this.designatedStaffs = [];
+        }
+        if (this.form.unit != null) {
+          this.form.unit = this.form.unit.split(',');
+          /*this.changeUnit(this.form.unit)*/
+        }else {
+          this.form.unit = [];
+        }
+        if (this.form.nonParticipants != null) {
+          this.nonParticipants = this.form.nonParticipants.split(",");
+        }
+        if (this.form.picUrl!= null){
+          this.photoList =[]
+          let fileList = this.form.picUrl.split(",")
+          for (let i = 0; i < fileList.length; i++) {
+            let item = {url: process.env.VUE_APP_BASE_API +fileList[i],response: {msg: fileList[i]} }
+            this.photoList.push(item)
+          }
+        }
+        if (this.form.trainer != null) {
+          this.form.trainer = this.form.trainer.split(',');
+        }else {
+          this.form.trainer = [];
+        }
+        this.open = true;
+        this.title = this.$t('修改')  + this.$t('培训计划');
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.submitDisabled = true;
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          var trainerId = null;
+          this.form.trainer.forEach(function (value,key,arr) {
+            if (key != 0) {
+              trainerId = trainerId + "," + value;
+            }else if (key == 0) {
+              trainerId = value;
+            }
+          })
+
+          var id = null;
+          this.form.position.forEach(function (value,key,arr) {
+            if (key != 0) {
+              id = id + "," + value;
+            }else if (key == 0) {
+              id = value;
+            }
+          })
+
+          var designatedId = null;
+          this.designatedPositions.forEach(function (value,key,arr) {
+            if (key != 0) {
+              designatedId = designatedId + "," + value;
+            }else if (key == 0) {
+              designatedId = value;
+            }
+          })
+          this.form.designatedPosition = designatedId;
+
+          var staffId = null;
+          this.designatedStaffs.forEach(function (value,key,arr) {
+            if (key != 0) {
+              staffId = staffId + "," + value;
+            }else if (key == 0) {
+              staffId = value;
+            }
+          })
+          this.form.designatedStaff = staffId;
+
+          var u = null;
+          this.form.unit.forEach(function (value,key,arr) {
+            if (key != 0) {
+              u = u + "," + value;
+            }else if (key == 0) {
+              u = value;
+            }
+          })
+
+          var parentId = null;
+          this.nonParticipants.forEach(function (value,key,arr) {
+            if (key != 0) {
+              parentId = parentId + "," + value;
+            }else if (key == 0) {
+              parentId = value;
+            }
+          })
+          this.form.trainer = trainerId;
+          this.form.position = id;
+          this.form.unit = u;
+          // this.form.nonParticipants = parentId;
+          if (this.form.id != null) {
+            updateTrainingbcc(this.form).then(response => {
+              this.msgSuccess(this.$t('修改成功'));
+              this.open = false;
+              this.submitDisabled = false;
+              this.getList();
+            });
+          } else {
+            addTrainingbcc(this.form).then(response => {
+              this.msgSuccess(this.$t('新增成功'));
+              this.open = false;
+              this.submitDisabled = false;
+              this.getList();
+            });
+          }
+        } else {
+          this.submitDisabled = false;
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm(this.$t('是否确认删除?'), this.$t('警告'), {
+        confirmButtonText: this.$t('确定'),
+        cancelButtonText: this.$t('取消'),
+        type: "warning"
+      }).then(function() {
+        return delTrainingbcc(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess(this.$t('删除成功'));
+      })
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm(this.$t('是否确认导出所有培训计划数据项?'), this.$t('警告'), {
+        confirmButtonText: this.$t('确定'),
+        cancelButtonText: this.$t('取消'),
+        type: "warning"
+      }).then(function() {
+        return exportTrainingbcc(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+      })
+    },
+
+    /** 参会人员名单按钮操作 */
+    handleStaffmgr(row) {
+      this.leftList = [];
+      const id = row.id || this.ids
+      getTrainingbccStaffIds(id).then(response => {
+        this.personForm = response.data;
+        if (response.data.staffIds != null) {
+          this.checked = response.data.staffIds.split(",");
+        }else {
+          this.checked = [];
+        }
+        this.personOpen = true;
+      });
+    },
+    handleDetail(row){
+      this.$router.push({ name: 'deviceList', params: { id: row.id }})
+    },
+    //岗位筛选变动
+    postChange() {
+      this.leftList = [];
+      if (this.checkboxPost.length > 0) {
+        this.staffmgrQueryParams.actualposts = this.checkboxPost.toString();
+        this.$nextTick(() => {
+          selectTimeStaffmgr(this.staffmgrQueryParams).then(response => {
+            const allData = response.rows
+            const data = [];
+            for (let i = 0; i < allData.length; i++) {
+              data[i] = allData[i].staffid
+            }
+            this.leftList = data;
+          })
+        })
+      }
+    },
+
+    //选择参会人员变动
+    staffChange() {
+      this.personForm.staffIds = this.checked.toString()
+    },
+
+    selectCourse(val) {
+      this.queryParams.trainingType = val
+      this.handleQuery()
+    },
+    /** 参会人员提交按钮 */
+    submitParticipants() {
+      this.$refs["personForm"].validate(valid => {
+        if (valid) {
+          updateTrainingbccStaffIds(this.personForm).then(response => {
+            this.msgSuccess(this.$t('修改成功'));
+            this.personOpen = false;
+            this.checkboxPost = [];
+            this.getList();
+          });
+        }
+      });
+    },
+    // 选择参会人员取消按钮
+    cancelParticipants() {
+      this.personOpen = false;
+      this.reset();
+    },
+  }
+};
+</script>
+<style scoped>
+.staff_checked >>> .el-transfer-panel {
+  width : 600px;
+}
+.el-transfer-panel__item.el-checkbox {
+  width: 553px !important;
+}
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409EFF;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+
+</style>

+ 1502 - 0
ui/src/views/training/trainingbcc/indexbak.vue

@@ -0,0 +1,1502 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item :label="$t('年份')" prop="year">
+        <el-date-picker clearable size="small" style="width: 200px"
+                        v-model="queryParams.year"
+                        type="year"
+                        value-format="yyyy"
+                        :placeholder="$t('请选择') + $t('年份')"
+                        @change="handleQuery" >
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item :label="$t('培训课程')" prop="course">
+        <el-input
+          v-model="queryParams.course"
+          :placeholder="$t('请输入') + $t('培训课程')"
+          clearable
+          size="small"
+          @input="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item :label="$t('培训类型')" prop="trainingType" label-width="50">
+        <el-select v-model="queryParams.trainingType" @change="handleQuery"    :placeholder="$t('请选择') + $t('培训类型')" clearable size="small">
+          <el-option
+            v-for="dict in trainingTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item :label="$t('是否完成')" prop="isfinish" label-width="50">
+        <el-select v-model="queryParams.isfinish" @change="handleQuery"    :placeholder="$t('请选择') + $t('是否完成')" clearable size="small">
+          <el-option
+            v-for="dict in isfinishOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item :label="$t('未参培情况')" prop="isNon" label-width="50">
+        <el-select v-model="queryParams.isNon" @change="handleQuery"    :placeholder="$t('请选择') + $t('是否未参培')" clearable size="small">
+          <el-option
+            key="0"
+            label="全部"
+            value="0"
+          />
+          <el-option
+            key="1"
+            label="未参培"
+            value="1"
+          />
+          <el-option
+            key="2"
+            label="已完成"
+            value="2"
+          />
+          <el-option
+            key="3"
+            label="未完成"
+            value="3"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item :label="$t('培训开始日期')" label-width="60">
+        <el-date-picker
+          v-model="chooseDate"
+          @change="handleQuery"
+          type="daterange"
+          align="right"
+          unlink-panels
+          :range-separator="$t('至')"
+          :start-placeholder="$t('开始日期')"
+          :end-placeholder="$t('结束日期')"
+          value-format="yyyy-MM-dd"
+          :picker-options="pickerOptions">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">{{ $t('搜索') }}</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">{{ $t('重置') }}</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['training:training:add']"
+        >{{ $t('新增') }}</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['training:training:edit']"
+        >{{ $t('修改') }}</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['training:training:remove']"
+        >{{ $t('删除') }}</el-button>
+      </el-col>
+      <!--<el-col :span="1.5">
+          <el-button
+                  type="info"
+                  icon="el-icon-upload2"
+                  size="mini"
+                  @click="handleImport"
+                  v-hasPermi="['training:training:edit']"
+          >{{ $t('导入') }}</el-button>
+      </el-col>-->
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['training:training:export']"
+        >{{ $t('导出') }}</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-row>
+      <el-col :span="24">
+        <el-button type="primary" plain @click="selectCourse('10')">定期类</el-button>
+        <el-button type="primary" plain @click="selectCourse('12')">{{ $t('程序指导书更新类') }}</el-button>
+        <el-button type="primary" plain @click="selectCourse('14')">{{ $t('事件报告和调查') }}</el-button>
+        <el-button type="primary" plain @click="selectCourse('16')">GIS/GSA</el-button>
+        <el-button type="primary" plain @click="selectCourse('20')">BYC EHS月报</el-button>
+      </el-col>
+    </el-row>
+    <el-table v-loading="loading" :data="trainingList" @selection-change="handleSelectionChange" :cell-style="tableCellStyle" :height="clientHeight" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column :label="$t('年份')" align="center" prop="year" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('培训课程')" align="center" prop="course" width="250" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('培训类型')" align="center" prop="trainingType" width="120" :formatter="trainingTypeFormat"/>
+      <el-table-column :label="$t('培训内容')" align="center" prop="content" width="250" :show-overflow-tooltip="true" />
+      <el-table-column :label="$t('课程代码')" align="center" prop="courseid" width="150" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('是否完成')" align="center" prop="isfinish" width="120">
+        <template slot-scope="scope">
+          <span v-if="scope.row.isfinish === 1">{{ isfinishFormat(scope.row,)}}</span>
+          <span v-if="scope.row.isfinish === 0">{{ isfinishFormat(scope.row,)}} ({{ scope.row.haveTraining }}/{{ scope.row.mustTraining }})</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('培训周期')" align="center" prop="period" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('课时')" align="center" prop="duration" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('培训人')" align="center" prop="trainer" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('部门')" align="center" prop="unit" :show-overflow-tooltip="true" />
+      <el-table-column :label="$t('培训岗位')" align="center" prop="position" width="250" :show-overflow-tooltip="true" />
+      <el-table-column :label="$t('培训开始日期')" align="center" prop="courseStartdate" width="100">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.courseStartdate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('培训结束日期')" align="center" prop="courseEnddate" width="100">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.courseEnddate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('未参培人员名单')" align="center" prop="nonParticipants" width="200" :show-overflow-tooltip="true" />
+      <el-table-column :label="$t('备注')" align="center" prop="remarks" :show-overflow-tooltip="true"/>
+      <el-table-column :label="$t('操作')" align="center" fixed="right" width="270" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['training:training:edit']"
+          >{{ $t('修改') }}</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleStaffmgr(scope.row)"
+            v-hasPermi="['training:training:edit']"
+          >人员名单</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-news"
+            @click="handleNew(scope.row)"
+          >{{ $t('新员工补培') }}</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+    <form ref="downloadFileForm" :action="downloadAction" target="FORMSUBMIT">
+      <input name="trainingId" :value=this.trainingId hidden />
+    </form>
+    <!-- 弹窗, 新增 / 修改 -->
+    <non-add v-if="nonVisible" ref="nonAdd" @refreshDataList="getList" :showFlag="showFlag" @closeChildDialog="closeChildDialog"></non-add>
+    <new-add v-if="newVisible" ref="newAdd" @refreshDataList="getList" :showFlag="showFlag" @closeChildDialog="closeChildDialog"></new-add>
+
+    <!-- 添加或修改培训计划对话框 -->
+    <el-dialog  :close-on-click-modal="false" v-dialogDrag :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="110px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训课程')" prop="course">
+              <el-input v-model="form.course" :placeholder="$t('请输入') + $t('培训课程')" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训类型')" prop="trainingType">
+              <el-select v-model="form.trainingType" :placeholder="$t('请选择') + $t('培训类型')">
+                <el-option
+                  v-for="dict in trainingTypeOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训内容')" prop="content">
+              <el-input v-model="form.content" :placeholder="$t('请输入') + $t('培训内容')" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('课程代码')" prop="courseid">
+              <el-input v-model="form.courseid" :placeholder="$t('请输入') + $t('课程代码')" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训周期')" prop="period">
+              <el-input v-model="form.period" :placeholder="$t('请输入') + $t('培训周期')" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('课时')" prop="duration">
+              <el-input v-model="form.duration" :placeholder="$t('请输入') + $t('课时')" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训人')" prop="trainer">
+              <el-select v-model="form.trainer" filterable multiple :placeholder="$t('请选择') + $t('培训人')">
+                <el-option
+                  v-for="dict in stffmgrOptions"
+                  :key="dict.staffid"
+                  :label="dict.name"
+                  :value="dict.staffid">
+                  <span style="float: left">{{ dict.name }}</span>
+                  <span style="float: right; color: #8492a6; font-size: 13px">{{ dict.staffid }}</span>
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('部门')" prop="unit">
+              <el-select v-model="form.unit" multiple :placeholder="$t('请选择') + $t('部门')" >
+                <el-option
+                  v-for="dict in unitOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训岗位')" prop="position">
+              <el-select v-model="form.position" multiple :placeholder="$t('请选择') + $t('培训岗位')" @change="changePosition">
+                <el-option
+                  v-for="dict in positionOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('是否存在') +$t('指定人员')" prop="haveDesignated" label-width="140px">
+              <el-checkbox v-model="haveDesignated" @change="changeHave"></el-checkbox>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('年份')" prop="year">
+              <el-date-picker clearable size="small" style="width: 200px"
+                              v-model="form.year"
+                              type="year"
+                              value-format="yyyy"
+                              @change="handleStaff"
+                              :placeholder="$t('请选择') + $t('年份')">
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('指定人员') + $t('岗位')" prop="designatedPosition" v-if="haveDesignated === true">
+              <el-select v-model="designatedPositions" multiple :placeholder="$t('请选择') + $t('指定岗位')" @change="changeDesignated">
+                <el-option
+                  v-for="dict in designatedPositionOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训开始日期')" prop="courseStartdate">
+              <el-date-picker clearable size="small" style="width: 200px"
+                              v-model="form.courseStartdate"
+                              type="date"
+                              value-format="yyyy-MM-dd"
+                              :placeholder="$t('请选择') + $t('培训开始日期')">
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('指定人员')" prop="designatedStaff" v-if="haveDesignated === true && designatedPositions.length > 0">
+              <el-select v-model="designatedStaffs" filterable multiple :placeholder="$t('请选择') + $t('指定人员')">
+                <el-option
+                  v-for="dict in designatedStaffsOptions"
+                  :key="dict.staffid"
+                  :label="dict.name"
+                  :value="dict.staffid">
+                  <span style="float: left">{{ dict.name }}</span>
+                  <span style="float: right; color: #8492a6; font-size: 13px">{{ dict.staffid }}</span>
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('培训结束日期')" prop="courseEnddate">
+              <el-date-picker clearable size="small" style="width: 200px"
+                              v-model="form.courseEnddate"
+                              type="date"
+                              value-format="yyyy-MM-dd"
+                              :placeholder="$t('请选择') + $t('培训结束日期')">
+              </el-date-picker>
+            </el-form-item >
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('是否完成')" prop="isfinish">
+              <el-select v-model="form.isfinish" :placeholder="$t('请选择') + $t('是否完成')">
+                <el-option
+                  v-for="dict in isfinishOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="parseInt(dict.dictValue)"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item :label="$t('备注')" prop="remarks">
+              <el-input v-model="form.remarks" :placeholder="$t('请输入') + $t('备注')" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :label="$t('归属部门')" prop="deptId">
+              <treeselect v-model="form.deptId" :options="deptOptions" :show-count="true" :placeholder="$t('请选择') + $t('归属部门')" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item :label="$t('图片')" v-if="this.form.trainingType == '12'" prop="picUrl">
+          <el-upload
+            :action="pic.url"
+            :headers="pic.headers"
+            :file-list="photoList"
+            :limit="5"
+            :on-success="handleAvatarSuccess"
+            :on-exceed="handleExceed"
+            :before-upload="beforeAvatarUpload"
+            list-type="picture-card"
+            :on-preview="handlePictureCardPreview"
+            :on-remove="handleRemove">
+            <i class="el-icon-plus"></i>
+          </el-upload>
+          <el-dialog  :close-on-click-modal="false" v-dialogDrag :visible.sync="dialogVisible" append-to-body>
+            <img width="100%" :src="dialogImageUrl" alt="">
+          </el-dialog>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm" :disabled="submitDisabled">{{ $t('确 定') }}</el-button>
+        <el-button @click="cancel">{{ $t('取 消') }}</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 添加参与公司级培训人员名单对话框 -->
+    <el-dialog  :close-on-click-modal="false" v-dialogDrag title="培训人员名单" :visible.sync="personOpen" width="1500px" append-to-body>
+      <el-form ref="form" :model="personForm" :rules="rules" label-width="80px">
+
+        <el-form-item :label="$t('课程名称')" prop="item">
+          <el-input v-model="personForm.item" disabled />
+        </el-form-item>
+        <el-form-item :label="$t('实际岗位')">
+          <el-checkbox-group v-model="checkboxPost" size="medium" @change="postChange">
+            <el-checkbox-button v-for="post in actualpostOptions" :label="post.key" :key="post.key">{{post.label}}</el-checkbox-button>
+          </el-checkbox-group>
+        </el-form-item>
+        <el-form-item :label="$t('人员姓名')">
+          <el-select v-model="searchStaffmgr" filterable :placeholder="$t('请选择') + $t('人员')">
+            <el-option
+              v-for="dict in stffmgrOptions"
+              :key="dict.staffid"
+              :label="dict.label"
+              :value="dict.staffid">
+              <span style="float: left">{{ dict.label }}</span>
+              <span style="float: right; color: #8492a6; font-size: 13px">{{ dict.staffid }}</span>
+            </el-option>
+          </el-select>
+          <el-button type="primary" @click="insertSearchStaffmgr" style="margin-left: 15px;">{{ $t('添加') }}</el-button>
+        </el-form-item>
+      </el-form>
+      <div class="staff_checked">
+        <el-transfer v-model="checked" :data="stffmgrOptions" @change="staffChange" :left-default-checked="leftList" >
+          <span slot-scope="{ option }">{{ option.label }}
+            <span style="float: right; color: #8492a6; font-size: 12px; padding-left: 10px;padding-right: 15px;">{{ option.staffid }}</span>
+            <span style="float: right; color: #8492a6; font-size: 12px; padding-left: 10px;">{{ option.actualpost }}</span>
+          </span>
+        </el-transfer>
+      </div>
+      <div slot="footer" class="dialog-footer">
+<!--        <el-button type="primary" @click="submitParticipants">{{ $t('确 定') }}</el-button>-->
+<!--        <el-button @click="cancelParticipants">{{ $t('取 消') }}</el-button>-->
+      </div>
+    </el-dialog>
+
+    <!-- 报告附件对话框 -->
+    <el-dialog  :close-on-click-modal="false" v-dialogDrag :title="doc.title" :visible.sync="doc.open" width="700px" append-to-body>
+      <el-upload
+        ref="doc"
+        :limit="50"
+        :headers="doc.headers"
+        :action="doc.url + '?pType=' + doc.pType + '&pId=' + doc.pId"
+        :disabled="doc.isUploading"
+        :on-progress="handleFileDocProgress"
+        :on-success="handleFileDocSuccess"
+        :auto-upload="true"
+        drag
+      >
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">
+          {{ $t('将文件拖到此处,或') }}
+          <em>{{ $t('点击上传') }}</em>
+        </div>
+      </el-upload>
+      <el-table :data="doc.commonfileList" border>
+        <el-table-column :label="$t('文件名')" align="center" prop="fileName" :show-overflow-tooltip="true">
+          <template slot-scope="scope">
+            <a  class="link-type"  @click="handleDownload(scope.row)">
+              <span>{{ scope.row.fileName }}</span>
+            </a>
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('大小(Kb)')" align="center" prop="fileSize" :show-overflow-tooltip="true" width="80" />
+        <el-table-column :label="$t('上传人')" align="center" prop="creator" :show-overflow-tooltip="true" width="120"/>
+        <el-table-column :label="$t('操作')" align="center" width="120" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button
+              v-if="scope.row.fileName.endsWith('pdf')"
+              size="mini"
+              type="text"
+              icon="el-icon-view"
+              @click="handleSee(scope.row)"
+            >{{ $t('预览') }}</el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-download"
+              @click="handleDownload(scope.row)"
+            >{{ $t('下载') }}</el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-delete"
+              @click="handleDeleteDoc(scope.row)"
+            >{{ $t('删除') }}</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-dialog  :close-on-click-modal="false" v-dialogDrag :title="pdf.title" :visible.sync="pdf.open" width="1300px" append-to-body>
+        <div style="margin-top: -60px;float: right;margin-right: 40px;">
+          <el-button size="mini" type="text" @click="openPdf">{{$t('新页面打开PDF')}}</el-button></div>
+        <div style="margin-top: -30px">
+          <iframe :src="pdf.pdfUrl" frameborder="0" width="100%" height="700px"></iframe>
+        </div>
+      </el-dialog>
+      <div slot="footer" class="dialog-footer">
+        <!--        <el-button type="primary" @click="submitFileForm">{{ $t('确 定') }}</el-button>-->
+        <el-button @click="doc.open = false">{{ $t('返 回') }}</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listTrainingbcc, getTrainingbcc, delTrainingbcc, addTrainingbcc, updateTrainingbcc, exportTrainingbcc } from "@/api/training/trainingbcc";
+import nonAdd from './trainingNon'
+import newAdd from './trainingNew'
+import {listStaffmgrAll, listAllStaffmgr, listStaffmgr, selectTimeStaffmgr} from "@/api/plant/staffmgr";
+import { treeselect } from "@/api/system/dept";
+import { getToken } from "@/utils/auth";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import { allFileList, listCommonfile, getCommonfile, delCommonfile, addCommonfile, updateCommonfile, exportCommonfile} from "@/api/common/commonfile";
+import {getCompanylevel} from "@/api/training/companylevel";
+
+
+export default {
+  name: "Training",
+  components: { Treeselect, nonAdd, newAdd},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      positionVisible: false,
+      showFlag: false,
+      //确认按钮是否可点
+      submitDisabled: false,
+      //左侧选框默认选择
+      leftList: [],
+      // 选中数组
+      ids: [],
+      //人员筛选按钮选择数据
+      checkboxPost: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: false,
+      // 总条数
+      total: 0,
+      // 培训计划表格数据
+      trainingList: [],
+      positionIds: [],
+      trainers: [],
+      units: [],
+      nonParticipants: [],
+      // 弹出层标题
+      title: "",
+      // 部门树选项
+      deptOptions: undefined,
+      clientHeight:300,
+      // 是否显示弹出层
+      open: false,
+      personOpen: false,
+      // 装置名称字典
+      plantCodeOptions: [],
+      // 部门字典
+      unitOptions: [],
+      // 培训岗位字典
+      positionOptions: [],
+      positionOpt: [],
+      trainingTypeOptions: [],
+      // 是否完成字典
+      isfinishOptions: [],
+      // 指定岗位字典
+      designatedPositionOptions: [],
+      //指定人员岗位多选
+      designatedPositions: [],
+      //指定人员id多选
+      designatedStaffs: [],
+      //是否存在岗位多选
+      haveDesignated: '',
+      //人员表联查
+      stffmgrOptions: undefined,
+      //人员表联查-包含离职
+      stffmgrAllOptions: undefined,
+      //指定人员选项
+      designatedStaffsOptions: [],
+      // 用户导入参数
+      upload: {
+        downloadAction: process.env.VUE_APP_BASE_API + '/common/template',
+        //下载模板类型
+        type: "training",
+        // 是否显示弹出层(用户导入)
+        open: false,
+        // 弹出层标题(用户导入)
+        title: "",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: { Authorization: "Bearer " + getToken() },
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/training/training/importData"
+      },
+      //未参会人员弹窗是否打开
+      nonVisible: false,
+      //新员工弹窗是否打开
+      newVisible: false,
+      // 报告附件参数
+      doc: {
+        file: "",
+        // 是否显示弹出层(报告附件)
+        open: false,
+        // 弹出层标题(报告附件)
+        title: "",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 报告附件上传位置编号
+        ids: 0,
+        // 设置上传的请求头部
+        headers: { Authorization: "Bearer " + getToken() },
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/common/commonfile/uploadFile",
+        commonfileList: null,
+        queryParams: {
+          pId: null,
+          pType: 'training'
+        },
+        pType: 'training',
+        pId: null
+      },
+      pdf : {
+        title: '',
+        pdfUrl: '',
+        numPages: null,
+        open: false,
+        pageNum: 1,
+        pageTotalNum: 1,
+        loadedRatio: 0,
+      },
+      pic: {
+        imageUrl: '',
+        fileList: [],
+        // 设置上传的请求头部
+        headers: { Authorization: "Bearer " + getToken() },
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/training/training/uploadFile",
+      },
+      photoList: [],
+      dialogImageUrl: '',
+      dialogVisible: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 20,
+        course: null,
+        position: [],
+        year: this.getNowTime(),
+        isfinish: null,
+        startDate: null,
+        endDate: null,
+        trainingType: null,
+        isNon: null,
+      },
+      trainingId: null,
+      //地址
+      downloadAction: process.env.VUE_APP_BASE_API + '/training/training/trainingReport',
+      //人员表查询参数
+      staffmgrQueryParams: {},
+      searchStaffmgr: "",
+      //日期快速选择
+      pickerOptions: {
+        shortcuts: [{
+          text: this.$t('最近一周'),
+          onClick(picker) {
+            const end = new Date();
+            const start = new Date();
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+            picker.$emit('pick', [start, end]);
+          }
+        }, {
+          text: this.$t('最近一个月'),
+          onClick(picker) {
+            const end = new Date();
+            const start = new Date();
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+            picker.$emit('pick', [start, end]);
+          }
+        }, {
+          text: this.$t('最近三个月'),
+          onClick(picker) {
+            const end = new Date();
+            const start = new Date();
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+            picker.$emit('pick', [start, end]);
+          }
+        }]
+      },
+      //日期选择器
+      chooseDate: [],
+      // 表单参数
+      form: {},
+      personForm: {},
+      // 表单校验
+      rules: {
+        course: [
+          { required: true, message: this.$t('培训课程') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        trainingType: [
+          { required: true, message: this.$t('培训类型') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        trainer: [
+          { required: true, message: this.$t('培训人') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        unit: [
+          { required: true, message: this.$t('部门') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        position: [
+          { required: true, message: this.$t('培训岗位') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        year: [
+          { required: true, message: this.$t('年份') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        courseStartdate: [
+          { required: true, message: this.$t('培训开始日期') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        isfinish: [
+          { required: true, message: this.$t('是否完成') + this.$t('不能为空'), trigger: "blur" }
+        ],
+        deptId: [
+          { required: true, message: this.$t('部门编号') + this.$t('不能为空'), trigger: "blur" }
+        ]
+      }
+    };
+  },
+  watch: {
+    // 根据名称筛选部门树
+    deptName(val) {
+      this.$refs.tree.filter(val);
+    },
+  },
+  created() {
+    const queryName = this.$route.query && this.$route.query.status;
+    if (queryName == '未参培'){
+      this.queryParams.isNon = "1"
+    }
+    if (queryName == '已完成'){
+      this.queryParams.isNon = "2"
+    }
+    if (queryName == '未完成'){
+      this.queryParams.isNon = "3"
+    }
+
+    this.getStaffmar();
+    this.getStaffmarAll();
+    //设置表格高度对应屏幕高度
+    this.$nextTick(() => {
+      this.clientHeight = (document.body.clientHeight - 80) * 0.8
+    })
+    this.getTreeselect();
+    this.getDicts("PLANT_DIVIDE").then(response => {
+      this.plantCodeOptions = response.data;
+    });
+    this.getDicts("ACTUALPOST").then(response => {
+      this.positionOptions = response.data;
+      this.designatedPositionOptions = response.data;
+      const allData = response.data
+      const data = [];
+      for (let i = 0; i < allData.length; i++) {
+        data.push({
+          key: allData[i].dictValue,
+          label: allData[i].dictLabel,
+        });
+      }
+      this.positionOpt = response.data;
+    });
+    this.getDicts("YES_NO_EN").then(response => {
+      this.isfinishOptions = response.data;
+    });
+    this.getDicts("STAFF_UNIT").then(response => {
+      this.unitOptions = response.data;
+    });
+    this.getDicts("TRAINING_TYPE_BCC").then(response => {
+      this.trainingTypeOptions = response.data;
+    });
+  },
+  methods: {
+    /** 查询培训计划列表 */
+    getList() {
+      let _this = this
+      this.loading = true;
+      listTrainingbcc(this.queryParams).then(response => {
+        this.trainingList = response.rows;
+        this.trainingList.forEach(function (value,key,arr) {
+          var positionid = null;
+          var positionName = null;
+          let unitid = null;
+          let unitName = null;
+          if (value.position != null) {
+            positionid = value.position.split(',');
+            positionid.forEach(function (value, key, arr) {
+              if (key != 0) {
+                positionName = positionName + "," + _this.selectDictLabel(_this.positionOptions, value);
+              }else if (key == 0) {
+                positionName = _this.selectDictLabel(_this.positionOptions, value);
+              }
+            })
+          }
+
+          if (value.unit != null) {
+            unitid = value.unit.split(',');
+            unitid.forEach(function (value, key, arr) {
+              if (key != 0) {
+                unitName = unitName + "," + _this.selectDictLabel(_this.unitOptions, value);
+              }else if (key == 0) {
+                unitName = _this.selectDictLabel(_this.unitOptions, value);
+              }
+            })
+          }
+          _this.trainingList[key].positionid = value.position;
+          _this.trainingList[key].position = positionName;
+          _this.trainingList[key].unitid = value.unit;
+          _this.trainingList[key].unit = unitName;
+
+          var parentName = null;
+          if (value.trainer != null) {
+            let staffId = value.trainer.split(",");
+            staffId.forEach(function (id, index) {
+              _this.stffmgrAllOptions.forEach(function (item) {
+                if (item.staffid === id) {
+                  if (index === 0) {
+                    parentName = item.name
+                  }else {
+                    parentName = parentName + "," + item.name
+                  }
+                }
+              });
+            });
+          }
+          _this.trainingList[key].trainer = parentName;
+        })
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    /** 获取当前年份 */
+    getNowTime() {
+      var now = new Date();
+      var year = now.getFullYear(); //得到年份
+      var defaultDate = `${year}`;
+      defaultDate = `${year}`
+      return defaultDate;
+    },
+    closeChildDialog () {
+      this.showFlag = false
+      this.getList();
+    },
+    /** 查询部门下拉树结构 */
+    getTreeselect() {
+      treeselect().then(response => {
+        this.deptOptions = response.data;
+      });
+    },
+    // 装置名称字典翻译
+    plantCodeFormat(row, column) {
+      return this.selectDictLabel(this.plantCodeOptions, row.plantCode);
+    },
+    // 部门字典翻译
+    unitFormat(row, column) {
+      return this.selectDictLabel(this.unitOptions, row.unit);
+    },
+    // 培训类型翻译
+    trainingTypeFormat(row, column) {
+      return this.selectDictLabel(this.trainingTypeOptions, row.trainingType);
+    },
+    // 培训岗位字典翻译
+    positionFormat(row, column) {
+      return this.selectDictLabel(this.positionOptions, row.position);
+    },
+    // 是否完成字典翻译
+    isfinishFormat(row, column) {
+      return this.selectDictLabel(this.isfinishOptions, row.isfinish);
+    },
+    //获取人员表
+    getStaffmar(year) {
+      this.staffmgrQueryParams.leftYear = year
+      listAllStaffmgr(this.staffmgrQueryParams).then(response => {
+        this.stffmgrOptions = response.rows;
+      });
+    },
+    //年份选择change事件
+    handleStaff(val){
+      this.getStaffmar(val)
+    },
+    //获取人员表--包含离职
+    getStaffmarAll() {
+      listStaffmgrAll(this.staffmgrQueryParams).then(response => {
+        this.stffmgrAllOptions = response.rows;
+        this.getList();
+      });
+    },
+    //遍历人员表
+    forEachStaffmar(id) {
+      let stffmgrName = "";
+      this.stffmgrOptions.forEach(function (item) {
+        if (item.staffid === id) {
+          stffmgrName = item.name
+        }
+      });
+      return stffmgrName
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        plantCode: null,
+        course: null,
+        courseid: null,
+        period: null,
+        duration: null,
+        trainer: null,
+        positionId: [],
+        position: null,
+        content: null,
+        unit : null,
+        year: null,
+        courseStartdate: null,
+        courseEnddate: null,
+        isfinish: null,
+        delFlag: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        remarks: null,
+        deptId: null,
+        startDate: null,
+        endDate: null,
+        nonParticipants: null,
+        trainingType: null,
+        picUrl: null,
+        mustTraining: null,
+        haveTraining: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.queryParams.startDate = this.chooseDate[0];
+      this.queryParams.endDate = this.chooseDate[1];
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.chooseDate = "";
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    //根据分数显示颜色提示
+    tableCellStyle({ row, column, rowIndex, columnIndex }) {
+      if (columnIndex == 6 && row.isfinish == 0){
+        return "color: rgba(255, 26, 26, 0.98) "
+      }
+    },
+    //培训岗位变动
+    changePosition() {
+      let _this = this
+      this.getDicts("ACTUALPOST").then(response => {
+        this.designatedPositionOptions = response.data;
+        this.form.position.forEach(function (value, key, arr) {
+          _this.designatedPositionOptions.forEach(function (positionValue, positionkey, arr) {
+            if (positionValue.dictValue === value) {
+              _this.designatedPositionOptions.splice(positionkey ,1)
+            }
+          })
+        })
+      });
+    },
+    //指定人员训岗位变动
+    changeDesignated() {
+      if (this.designatedPositions.length > 0) {
+        var designatedId = null;
+        this.designatedPositions.forEach(function (value,key,arr) {
+          if (key != 0) {
+            designatedId = designatedId + "," + value;
+          }else if (key == 0) {
+            designatedId = value;
+          }
+        })
+        this.staffmgrQueryParams.actualposts = designatedId;
+        listStaffmgr(this.staffmgrQueryParams).then(response => {
+          this.designatedStaffsOptions = response.rows;
+        });
+
+        let _this = this
+        this.getDicts("ACTUALPOST").then(response => {
+          this.positionOptions = response.data;
+          this.designatedPositions.forEach(function (value, key, arr) {
+            _this.positionOptions.forEach(function (positionValue, positionkey, arr) {
+              if (positionValue.dictValue === value) {
+                _this.positionOptions.splice(positionkey ,1)
+              }
+            })
+          })
+        });
+      }else {
+        this.designatedStaffs = [];
+      }
+    },
+    //指定人员按钮变动
+    changeHave() {
+      if (this.haveDesignated === false) {
+        this.designatedPositions = []
+        this.designatedStaffs = []
+      }
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.submitDisabled = false;
+      this.haveDesignated = false;
+      this.designatedPositions = [];
+      this.getDicts("ACTUALPOST").then(response => {
+        this.positionOptions = response.data;
+      });
+      this.getDicts("ACTUALPOST").then(response => {
+        this.designatedPositionOptions = response.data;
+      });
+      this.form.trainingType = this.queryParams.trainingType
+      this.title = this.$t('新增') + this.$t('空格') + this.$t('培训计划');
+      this.getStaffmar()
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      let _this = this
+      this.submitDisabled = false;
+      const id = row.id || this.ids
+      getTrainingbcc(id).then(response => {
+        this.form = response.data;
+        this.getStaffmar(response.data.year)
+        if (this.form.position != null) {
+          this.form.position = this.form.position.split(',');
+          this.getDicts("ACTUALPOST").then(response => {
+            this.designatedPositionOptions = response.data;
+            this.form.position.forEach(function (value, key, arr) {
+              _this.designatedPositionOptions.forEach(function (positionValue, positionkey, arr) {
+                if (positionValue.dictValue === value) {
+                  _this.designatedPositionOptions.splice(positionkey ,1)
+                }
+              })
+            })
+          })
+        }else {
+          this.getDicts("ACTUALPOST").then(response => {
+            this.designatedPositionOptions = response.data;
+          })
+          this.form.position = [];
+        }
+        if (this.form.designatedPosition != null) {
+          this.designatedPositions = this.form.designatedPosition.split(',');
+          this.getDicts("ACTUALPOST").then(response => {
+            this.positionOptions = response.data;
+            this.designatedPositions.forEach(function (value, key, arr) {
+              _this.positionOptions.forEach(function (positionValue, positionkey, arr) {
+                if (positionValue.dictValue === value) {
+                  _this.positionOptions.splice(positionkey ,1)
+                }
+              })
+            })
+          });
+          this.haveDesignated = true;
+          var designatedId = null;
+          this.designatedPositions.forEach(function (value,key,arr) {
+            if (key != 0) {
+              designatedId = designatedId + "," + value;
+            }else if (key == 0) {
+              designatedId = value;
+            }
+          })
+          this.staffmgrQueryParams.actualposts = designatedId;
+          this.$nextTick(() => {
+            listAllStaffmgr(this.staffmgrQueryParams).then(response => {
+              this.designatedStaffsOptions = response.rows;
+            });
+          })
+        }else {
+          this.haveDesignated = false;
+          this.designatedPositions = [];
+          this.getDicts("ACTUALPOST").then(response => {
+            this.positionOptions = response.data;
+          })
+        }
+        if (this.form.designatedStaff != null) {
+          this.designatedStaffs = this.form.designatedStaff.split(',');
+        }else {
+          this.designatedStaffs = [];
+        }
+        if (this.form.unit != null) {
+          this.form.unit = this.form.unit.split(',');
+          /*this.changeUnit(this.form.unit)*/
+        }else {
+          this.form.unit = [];
+        }
+        if (this.form.nonParticipants != null) {
+          this.nonParticipants = this.form.nonParticipants.split(",");
+        }
+        if (this.form.picUrl!= null){
+          this.photoList =[]
+          let fileList = this.form.picUrl.split(",")
+          for (let i = 0; i < fileList.length; i++) {
+            let item = {url: process.env.VUE_APP_BASE_API +fileList[i],response: {msg: fileList[i]} }
+            this.photoList.push(item)
+          }
+        }
+        if (this.form.trainer != null) {
+          this.form.trainer = this.form.trainer.split(',');
+        }else {
+          this.form.trainer = [];
+        }
+        this.open = true;
+        this.title = this.$t('修改')  + this.$t('培训计划');
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.submitDisabled = true;
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          var trainerId = null;
+          this.form.trainer.forEach(function (value,key,arr) {
+            if (key != 0) {
+              trainerId = trainerId + "," + value;
+            }else if (key == 0) {
+              trainerId = value;
+            }
+          })
+
+          var id = null;
+          this.form.position.forEach(function (value,key,arr) {
+            if (key != 0) {
+              id = id + "," + value;
+            }else if (key == 0) {
+              id = value;
+            }
+          })
+
+          var designatedId = null;
+          this.designatedPositions.forEach(function (value,key,arr) {
+            if (key != 0) {
+              designatedId = designatedId + "," + value;
+            }else if (key == 0) {
+              designatedId = value;
+            }
+          })
+          this.form.designatedPosition = designatedId;
+
+          var staffId = null;
+          this.designatedStaffs.forEach(function (value,key,arr) {
+            if (key != 0) {
+              staffId = staffId + "," + value;
+            }else if (key == 0) {
+              staffId = value;
+            }
+          })
+          this.form.designatedStaff = staffId;
+
+          var u = null;
+          this.form.unit.forEach(function (value,key,arr) {
+            if (key != 0) {
+              u = u + "," + value;
+            }else if (key == 0) {
+              u = value;
+            }
+          })
+
+          var parentId = null;
+          this.nonParticipants.forEach(function (value,key,arr) {
+            if (key != 0) {
+              parentId = parentId + "," + value;
+            }else if (key == 0) {
+              parentId = value;
+            }
+          })
+          this.form.trainer = trainerId;
+          this.form.position = id;
+          this.form.unit = u;
+          // this.form.nonParticipants = parentId;
+          if (this.form.id != null) {
+            updateTrainingbcc(this.form).then(response => {
+              this.msgSuccess(this.$t('修改成功'));
+              this.open = false;
+              this.submitDisabled = false;
+              this.getList();
+            });
+          } else {
+            addTrainingbcc(this.form).then(response => {
+              this.msgSuccess(this.$t('新增成功'));
+              this.open = false;
+              this.submitDisabled = false;
+              this.getList();
+            });
+          }
+        } else {
+          this.submitDisabled = false;
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm(this.$t('是否确认删除?'), this.$t('警告'), {
+        confirmButtonText: this.$t('确定'),
+        cancelButtonText: this.$t('取消'),
+        type: "warning"
+      }).then(function() {
+        return delTrainingbcc(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess(this.$t('删除成功'));
+      })
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm(this.$t('是否确认导出所有培训计划数据项?'), this.$t('警告'), {
+        confirmButtonText: this.$t('确定'),
+        cancelButtonText: this.$t('取消'),
+        type: "warning"
+      }).then(function() {
+        return exportTrainingbcc(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+      })
+    },
+    /** 导入按钮操作 */
+    handleImport() {
+      this.upload.title = this.$t('用户导入');
+      this.upload.open = true;
+    },
+    /** 下载模板操作 */
+    importTemplate() {
+      this.$refs['downloadFileForm'].submit()
+    },
+    // 文件上传中处理
+    handleFileUploadProgress(event, file, fileList) {
+      this.upload.isUploading = true;
+    },
+    // 文件上传成功处理
+    handleFileSuccess(response, file, fileList) {
+      this.upload.open = false;
+      this.upload.isUploading = false;
+      this.$refs.upload.clearFiles();
+
+      if (response.data[0] != null) {
+        this.$alert(this.$t('成功导入') + response.msg + this.$t('条数据') + "," + this.$t('第') + response.data + this.$t('行数据出现错误导入失败')+"。", this.$t('导入结果'), { dangerouslyUseHTMLString: true });
+      }else {
+        this.$alert(this.$t('成功导入') + response.msg + this.$t('条数据'), this.$t('导入结果'), { dangerouslyUseHTMLString: true });
+      }
+
+      this.getList();
+    },
+    // 提交上传文件
+    submitFileForm() {
+      this.$refs.upload.submit();
+    },
+    /** 报告附件按钮操作 */
+    handleDoc(row) {
+      this.doc.id = row.id;
+      this.doc.title = row.course;
+      this.doc.open = true;
+      this.doc.queryParams.pId = row.id
+      this.doc.pId = row.id
+      this.getFileList()
+      this.$nextTick(() => {
+        this.$refs.doc.clearFiles()
+      })
+    },
+    /** 未参培人员名单按钮操作 */
+    handleDocNon(row) {
+      this.nonVisible = true
+      this.$nextTick(() => {
+        this.$refs.nonAdd.init(row)
+      })
+    },
+    /** 新员工补培按钮操作 */
+    handleNew(row) {
+      this.newVisible = true
+      this.$nextTick(() => {
+        this.$refs.newAdd.init(row)
+      })
+    },
+    /** 参会人员名单按钮操作 */
+    handleStaffmgr(row) {
+      this.leftList = [];
+      const id = row.id || this.ids
+      getTrainingbcc(id).then(response => {
+        this.personForm = response.data;
+        this.personOpen = true;
+      });
+    },
+    //岗位筛选变动
+    postChange() {
+      this.leftList = [];
+      if (this.checkboxPost.length > 0) {
+        this.staffmgrQueryParams.actualposts = this.checkboxPost.toString();
+        this.$nextTick(() => {
+          selectTimeStaffmgr(this.staffmgrQueryParams).then(response => {
+            const allData = response.rows
+            const data = [];
+            for (let i = 0; i < allData.length; i++) {
+              data[i] = allData[i].staffid
+            }
+            this.leftList = data;
+          })
+        })
+      }
+    },
+    /** 参会人员人名搜索添加按钮 */
+    insertSearchStaffmgr() {
+      const data = [];
+      for (let i = 0; i < this.leftList.length; i++) {
+        data.push(this.leftList[i])
+      }
+      data.push(this.searchStaffmgr)
+      this.leftList = data
+      this.$nextTick(() => {
+        this.searchStaffmgr = "";
+      })
+    },
+    //选择参会人员变动
+    staffChange() {
+      this.form.staffId = this.checked.toString()
+    },
+    getFileList (){
+      allFileList(this.doc.queryParams).then(response => {
+        this.doc.commonfileList = response;
+      });
+    },
+    //附件上传中处理
+    handleFileDocProgress(event, file, fileList) {
+      this.doc.file = file;
+      this.doc.isUploading = true;
+    },
+    //附件上传成功处理
+    handleFileDocSuccess(response, file, fileList) {
+      this.doc.isUploading = false;
+      this.$alert(response.msg, this.$t('导入结果'), { dangerouslyUseHTMLString: true });
+      this.getFileList()
+    },
+    //pdf预览
+    openPdf(){
+      window.open(this.pdf.pdfUrl);//path是文件的全路径地址
+    },
+    handleSee (row){
+      this.pdf.open =true
+      this.pdf.title = row.fileName
+      this.pdf.pdfUrl = process.env.VUE_APP_BASE_API +'/pdf/web/viewer.html?file=' + process.env.VUE_APP_BASE_API + row.fileUrl
+    },
+    /** 删除按钮操作 */
+    handleDeleteDoc(row) {
+      const ids = row.id || this.ids;
+      this.$confirm(this.$t('是否确认删除?'), this.$t('警告'), {
+        confirmButtonText: this.$t('确定'),
+        cancelButtonText: this.$t('取消'),
+        type: "warning"
+      }).then(function() {
+        return delCommonfile(ids);
+      }).then(() => {
+        this.getFileList()
+        this.msgSuccess(this.$t('删除成功'));
+      })
+    },
+    // 文件下载处理
+    handleDownload(row) {
+      var name = row.fileName;
+      var url = row.fileUrl;
+      var suffix = url.substring(url.lastIndexOf("."), url.length);
+      const a = document.createElement('a')
+      a.setAttribute('download', name)
+      a.setAttribute('target', '_blank')
+      a.setAttribute('href', process.env.VUE_APP_BASE_API + url)
+      a.click()
+    },
+    changeUnit(val) {
+      let unitArr = []
+      unitArr = val
+      let flag = false
+      for (let i = 0; i < unitArr.length; i++) {
+        if (unitArr[i] == 10) {
+          this.positionVisible = true
+          flag =true
+          break
+        }
+      }
+      if (!flag) {
+        this.positionVisible = false
+        this.form.position = null
+      }
+    },
+    selectCourse(val) {
+      this.queryParams.trainingType = val
+      this.handleQuery()
+    },
+    /** 生成签名按钮操作 */
+    getReport(row) {
+      this.trainingId = row.id
+      console.log(row.id)
+      this.$nextTick(() => {
+        this.$refs['downloadFileForm'].submit()
+      })
+    },
+    handleExceed(files, fileList) {
+      this.$message.warning(this.$t('当前限制选择 5 个文件'));
+    },
+    handleRemove(file, fileList) {
+      this.form.picUrl = fileList.map((obj)=>{return obj.response.msg}).join(",");
+      console.log(this.form.picUrl)
+    },
+    handleAvatarSuccess(res, file, fileList) {
+      console.log(fileList)
+      this.photoList = fileList
+      this.form.picUrl = fileList.map((obj)=>{return obj.response.msg}).join(",");
+      console.log(this.form.picUrl)
+    },
+    handlePictureCardPreview(file) {
+      this.dialogImageUrl = file.url;
+      this.dialogVisible = true;
+    },
+    beforeAvatarUpload(file) {
+      const isJPG = file.type === 'image/jpeg' || file.type === 'image/png'
+      const isLt2M = file.size / 1024 / 1024 < 2
+
+      if (!isJPG) {
+        this.$message.error(this.$t('上传图片只能是 JPG/PNG 格式!'));
+      }
+      if (!isLt2M) {
+        this.$message.error(this.$t('上传头像图片大小不能超过 2MB!'));
+      }
+      return isJPG && isLt2M;
+    }
+  }
+};
+</script>
+<style>
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409EFF;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+</style>

+ 261 - 0
ui/src/views/training/trainingbcc/trainingNew.vue

@@ -0,0 +1,261 @@
+<template>
+  <el-dialog  :close-on-click-modal="false" v-dialogDrag
+    :title="$t('新员工补培')"
+
+    :visible.sync="visible"
+    @close="closeDialog">
+    <el-form :inline="true" :model="queryParams" @keyup.enter.native="getDataList()">
+      <el-form-item>
+        <el-button v-hasPermi="['training:training:trainingNon']" type="primary" @click="add()">{{ $t('新增') }}</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table :data="trainingNonList" border>
+      <el-table-column :label="$t('新员工补培')" align="center" header-align="center" prop="staffId" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          <el-select v-model="scope.row.staffId" v-if="scope.row.isEdit" filterable :placeholder="$t('请选择') + $t('未参会人员名单')">
+            <el-option
+              v-for="dict in stffmgrOptions"
+              :key="dict.staffid"
+              :label="dict.name"
+              :value="dict.staffid">
+              <span style="float: left">{{ dict.name }}</span>
+              <span style="float: right; color: #8492a6; font-size: 13px">{{ dict.staffid }}</span>
+            </el-option>
+          </el-select>
+          <span v-else>{{scope.row.name}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('培训日期')" align="center" header-align="center" prop="trainingDate">
+        <template slot-scope="scope">
+          <el-date-picker
+            v-if="scope.row.isEdit"
+            v-model="scope.row.trainingDate"
+            type="date"
+            value-format="yyyy-MM-dd"
+            :placeholder="$t('日期')">
+          </el-date-picker>
+          <span v-else>{{ parseTime(scope.row.trainingDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('补培讲师')" align="center" header-align="center" prop="trainingStaff" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          <el-select v-model="scope.row.trainingStaff" v-if="scope.row.isEdit" filterable :placeholder="$t('请选择') + $t('补培讲师')">
+            <el-option
+              v-for="dict in trainingstaffOptions"
+              :key="dict.staffid"
+              :label="dict.name"
+              :value="dict.staffid">
+              <span style="float: left">{{ dict.name }}</span>
+              <span style="float: right; color: #8492a6; font-size: 13px">{{ dict.staffid }}</span>
+            </el-option>
+          </el-select>
+          <span v-else>{{scope.row.staffName}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('备注')" align="center" header-align="center" prop="remarks" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          <el-input v-if="scope.row.isEdit" v-model="scope.row.remarks"></el-input>
+          <span v-else>{{scope.row.remarks}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('操作')" align="center" fixed="right" width="120" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button v-hasPermi="['training:training:trainingNon']" type="text" size="small" v-if="scope.row.isEdit" @click="save(scope.row)">{{ $t('保存') }}</el-button>
+          <el-button type="text" size="small" v-if="scope.row.isEdit" @click="cancel(scope.row, scope.$index)">{{ $t('取消') }}</el-button>
+          <el-button v-hasPermi="['training:training:trainingNon']" v-if="!scope.row.isEdit" @click="edit(scope.row)" type="text" size="mini">{{ $t('编辑') }}</el-button>
+          <el-button v-hasPermi="['training:training:trainingNon']" v-if="!scope.row.isEdit" type="text" size="small" @click="deleteHandle(scope.row)">{{ $t('删除') }}</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+  </el-dialog>
+</template>
+
+<script>
+import { listTrainingNon, getTrainingNon, delTrainingNon, addTrainingNon, updateTrainingNon, exportTrainingNon, importTemplate} from "@/api/training/trainingNon";
+import { listStaffmgr,listAllStaffmgr, selectByStaffId } from "@/api/plant/staffmgr";
+
+export default {
+  name: "TrainingNew",
+  props: {
+    // 接受父级组件的显示标记,用于被watch
+    showFlag: {
+      type: Boolean
+    }
+  },
+  data() {
+    return {
+      visible: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 20,
+        trainingId: '',
+        isNew: 1
+      },
+      //人员表查询参数
+      staffmgrQueryParams: {
+        staffid: null,
+        unit: null,
+        actualposts: null
+      },
+      trainingStaffQueryParams: {},
+      // 培训计划未参加人员表格数据
+      trainingNonList: [],
+      //人员表联查
+      stffmgrOptions: undefined,
+      trainingstaffOptions: undefined,
+      //指定人员名单
+      designatedStaffs: [],
+      // 总条数
+      total: 0,
+      // 表单参数
+      form: {},
+    }
+  },
+  watch: {
+    // 观察父级组件的showFlag,并将showFlag的最新值设置给dialogVisible
+    showFlag (newVal, oldVal) {
+      this.visible = newVal
+    }
+  },
+  methods: {
+    init (row) {
+      this.queryParams.trainingId = row.id || 0
+      this.staffmgrQueryParams.leftYear = row.year
+      this.trainingStaffQueryParams.leftYear = row.year
+      this.staffmgrQueryParams.units = row.unitid
+      this.staffmgrQueryParams.actualposts = row.positionid
+      if (row.designatedStaff != null) {
+        this.designatedStaffs = row.designatedStaff.split(',')
+      }else {
+        this.designatedStaffs = []
+      }
+      this.getStaffmar()
+      this.visible = true
+    },
+    //获取人员表
+    getStaffmar() {
+      listAllStaffmgr(this.staffmgrQueryParams).then(response => {
+        this.stffmgrOptions = response.rows;
+        if (this.designatedStaffs.length > 0) {
+          selectByStaffId(this.designatedStaffs).then(response => {
+            this.stffmgrOptions = this.stffmgrOptions.concat(response.data)
+          })
+        }
+      });
+      listAllStaffmgr(this.trainingStaffQueryParams).then(response => {
+        this.trainingstaffOptions = response.rows;
+      });
+      this.$nextTick(() => {
+        this.getList();
+      })
+    },
+    /** 查询培训计划未参加人员列表 */
+    getList() {
+      this.loading = true;
+      listTrainingNon(this.queryParams).then(response => {
+        this.total = response.total;
+          response.rows.forEach(element => {
+            element["isEdit"] = false
+          });
+          response.rows.forEach(element => {
+            element["isAdd"] = false
+          });
+          this.trainingNonList = response.rows;
+
+        this.loading = false;
+      });
+    },
+    /**
+     * 关闭弹出框事件,触发父级组件的getList方法
+     */
+    closeDialog () {
+      this.$emit('closeChildDialog')
+    },
+      // 取消
+    cancel(row, index) {
+      // 如果是新增的数据
+      if (row.isAdd) {
+        this.trainingNonList.splice(index, 1)
+      } else {
+        // 不是新增的数据  还原数据
+        for (const i in row.oldRow) {
+          row[i] = row.oldRow[i]
+        }
+        row.isEdit = false
+      }
+    },
+    edit(row) {
+      // 备份原始数据
+      row['oldRow'] = JSON.parse(JSON.stringify(row));
+      this.$nextTick(() => {
+        row.isEdit = true;
+      })
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        delFlag: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        remarks: null,
+        trainingDate: null,
+        staffId: null,
+        trainingId: null,
+        trainingStaff: null,
+        isNew: 1
+      };
+      this.resetForm("form");
+    },
+    add() {
+      this.trainingNonList.push({
+        trainingId: this.queryParams.trainingId,
+        staffId: '',
+        trainingDate: '',
+        isNew: 1,
+        isEdit: true,
+        isAdd: true
+      });
+    },
+    save(row) {
+      row.isEdit = false;
+      var that = this;
+      that.loading = true;
+      this.form = row;
+      this.form.trainingId = this.queryParams.trainingId;
+      this.form.isNew = 1;
+      if (row.isAdd == true) {
+        addTrainingNon(this.form).then(response => {
+          this.msgSuccess(this.$t('新增成功'));
+          this.open = false;
+          this.getList();
+        });
+      }else {
+        updateTrainingNon(this.form).then(response => {
+          this.msgSuccess(this.$t('修改成功'));
+          this.open = false;
+          this.getList();
+        });
+      }
+    },
+    /** 删除按钮操作 */
+    deleteHandle(row) {
+      const ids = row.id || this.ids;
+      this.$confirm(this.$t('是否确认删除?'), this.$t('警告'), {
+        confirmButtonText: this.$t('确定'),
+        cancelButtonText: this.$t('取消'),
+        type: "warning"
+        }).then(function() {
+          return delTrainingNon(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess(this.$t('删除成功'));
+        })
+    },
+  }
+};
+</script>

+ 264 - 0
ui/src/views/training/trainingbcc/trainingNon.vue

@@ -0,0 +1,264 @@
+<template>
+  <el-dialog  :close-on-click-modal="false" v-dialogDrag
+    :title="$t('未参会人员名单')"
+
+    :visible.sync="visible"
+    @close="closeDialog">
+    <el-form :inline="true" :model="queryParams" @keyup.enter.native="getDataList()">
+      <el-form-item>
+        <el-button v-hasPermi="['training:training:trainingNon']" type="primary" @click="add()">{{ $t('新增') }}</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table :data="trainingNonList" border>
+      <el-table-column :label="$t('未参会人员姓名')" align="center" header-align="center" prop="staffId" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          <el-select v-model="scope.row.staffId" v-if="scope.row.isEdit" filterable :placeholder="$t('请选择') + $t('未参会人员名单')">
+            <el-option
+              v-for="dict in stffmgrOptions"
+              :key="dict.staffid"
+              :label="dict.name"
+              :value="dict.staffid">
+              <span style="float: left">{{ dict.name }}</span>
+              <span style="float: right; color: #8492a6; font-size: 13px">{{ dict.staffid }}</span>
+            </el-option>
+          </el-select>
+          <span v-else>{{scope.row.name}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('培训日期')" align="center" header-align="center" prop="trainingDate">
+        <template slot-scope="scope">
+          <el-date-picker
+            v-if="scope.row.isEdit"
+            v-model="scope.row.trainingDate"
+            type="date"
+            value-format="yyyy-MM-dd"
+            :placeholder="$t('日期')">
+          </el-date-picker>
+          <span v-else>{{ parseTime(scope.row.trainingDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('补培讲师')" align="center" header-align="center" prop="trainingStaff" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          <el-select v-model="scope.row.trainingStaff" v-if="scope.row.isEdit" filterable :placeholder="$t('请选择') + $t('补培讲师')">
+            <el-option
+              v-for="dict in trainingstaffOptions"
+              :key="dict.staffid"
+              :label="dict.name"
+              :value="dict.staffid">
+              <span style="float: left">{{ dict.name }}</span>
+              <span style="float: right; color: #8492a6; font-size: 13px">{{ dict.staffid }}</span>
+            </el-option>
+          </el-select>
+          <span v-else>{{scope.row.staffName}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('备注')" align="center" header-align="center" prop="remarks" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          <el-input v-if="scope.row.isEdit" v-model="scope.row.remarks"></el-input>
+          <span v-else>{{scope.row.remarks}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('操作')" align="center" fixed="right" width="120" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button v-hasPermi="['training:training:trainingNon']" type="text" size="small" v-if="scope.row.isEdit" @click="save(scope.row)">{{ $t('保存') }}</el-button>
+          <el-button type="text" size="small" v-if="scope.row.isEdit" @click="cancel(scope.row, scope.$index)">{{ $t('取消') }}</el-button>
+          <el-button v-hasPermi="['training:training:trainingNon']" v-if="!scope.row.isEdit" @click="edit(scope.row)" type="text" size="mini">{{ $t('编辑') }}</el-button>
+          <el-button v-hasPermi="['training:training:trainingNon']" v-if="!scope.row.isEdit" type="text" size="small" @click="deleteHandle(scope.row)">{{ $t('删除') }}</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+  </el-dialog>
+</template>
+
+<script>
+import { listTrainingNon, getTrainingNon, delTrainingNon, addTrainingNon, updateTrainingNon, exportTrainingNon, importTemplate} from "@/api/training/trainingNon";
+import { listStaffmgr,listAllStaffmgr, selectByStaffId } from "@/api/plant/staffmgr";
+
+export default {
+  name: "TrainingNon",
+  props: {
+    // 接受父级组件的显示标记,用于被watch
+    showFlag: {
+      type: Boolean
+    }
+  },
+  data() {
+    return {
+      visible: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 20,
+        trainingId: '',
+        isNew: 0
+      },
+      //人员表查询参数
+      staffmgrQueryParams: {
+        staffid: null,
+        unit: null,
+        actualposts: null,
+        leftYear: null
+      },
+      trainingStaffQueryParams: {
+        leftYear: null
+      },
+      // 培训计划未参加人员表格数据
+      trainingNonList: [],
+      //人员表联查
+      stffmgrOptions: undefined,
+      trainingstaffOptions: undefined,
+      //指定人员名单
+      designatedStaffs: [],
+      // 总条数
+      total: 0,
+      // 表单参数
+      form: {},
+    }
+  },
+  watch: {
+    // 观察父级组件的showFlag,并将showFlag的最新值设置给dialogVisible
+    showFlag (newVal, oldVal) {
+      this.visible = newVal
+    }
+  },
+  methods: {
+    init (row) {
+      this.queryParams.trainingId = row.id || 0
+      this.staffmgrQueryParams.leftYear = row.year
+      this.trainingStaffQueryParams.leftYear = row.year
+      this.staffmgrQueryParams.units = row.unitid
+      this.staffmgrQueryParams.actualposts = row.positionid
+      if (row.designatedStaff != null) {
+        this.designatedStaffs = row.designatedStaff.split(',')
+      }else {
+        this.designatedStaffs = []
+      }
+      this.getStaffmar()
+      this.visible = true
+    },
+    //获取人员表
+    getStaffmar() {
+      listAllStaffmgr(this.staffmgrQueryParams).then(response => {
+        this.stffmgrOptions = response.rows;
+        if (this.designatedStaffs.length > 0) {
+          selectByStaffId(this.designatedStaffs).then(response => {
+            this.stffmgrOptions = this.stffmgrOptions.concat(response.data)
+          })
+        }
+      });
+      listAllStaffmgr(this.trainingStaffQueryParams).then(response => {
+        this.trainingstaffOptions = response.rows;
+      });
+      this.$nextTick(() => {
+        this.getList();
+      })
+    },
+    /** 查询培训计划未参加人员列表 */
+    getList() {
+      this.loading = true;
+      listTrainingNon(this.queryParams).then(response => {
+        this.total = response.total;
+          response.rows.forEach(element => {
+            element["isEdit"] = false
+          });
+          response.rows.forEach(element => {
+            element["isAdd"] = false
+          });
+          this.trainingNonList = response.rows;
+
+        this.loading = false;
+      });
+    },
+    /**
+     * 关闭弹出框事件,触发父级组件的getList方法
+     */
+    closeDialog () {
+      this.$emit('closeChildDialog')
+    },
+      // 取消
+    cancel(row, index) {
+      // 如果是新增的数据
+      if (row.isAdd) {
+        this.trainingNonList.splice(index, 1)
+      } else {
+        // 不是新增的数据  还原数据
+        for (const i in row.oldRow) {
+          row[i] = row.oldRow[i]
+        }
+        row.isEdit = false
+      }
+    },
+    edit(row) {
+      // 备份原始数据
+      row['oldRow'] = JSON.parse(JSON.stringify(row));
+      this.$nextTick(() => {
+        row.isEdit = true;
+      })
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        delFlag: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        remarks: null,
+        trainingDate: null,
+        staffId: null,
+        trainingId: null,
+        trainingStaff: null,
+        isNew: 0
+      };
+      this.resetForm("form");
+    },
+    add() {
+      this.trainingNonList.push({
+        trainingId: this.queryParams.trainingId,
+        staffId: '',
+        trainingDate: '',
+        isNew: 0,
+        isEdit: true,
+        isAdd: true
+      });
+    },
+    save(row) {
+      row.isEdit = false;
+      var that = this;
+      that.loading = true;
+      this.form = row;
+      this.form.trainingId = this.queryParams.trainingId;
+      this.form.isNew = 0;
+      if (row.isAdd == true) {
+        addTrainingNon(this.form).then(response => {
+          this.msgSuccess(this.$t('新增成功'));
+          this.open = false;
+          this.getList();
+        });
+      }else {
+        updateTrainingNon(this.form).then(response => {
+          this.msgSuccess(this.$t('修改成功'));
+          this.open = false;
+          this.getList();
+        });
+      }
+    },
+    /** 删除按钮操作 */
+    deleteHandle(row) {
+      const ids = row.id || this.ids;
+      this.$confirm(this.$t('是否确认删除?'), this.$t('警告'), {
+        confirmButtonText: this.$t('确定'),
+        cancelButtonText: this.$t('取消'),
+        type: "warning"
+        }).then(function() {
+          return delTrainingNon(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess(this.$t('删除成功'));
+        })
+    },
+  }
+};
+</script>