dedsudiyu 2 dni temu
rodzic
commit
f8786e5448

+ 97 - 0
src/api/safetyEducationExaminationNew/index.js

@@ -907,3 +907,100 @@ export function examUserPracticeSummary(query) {
     params: query
   })
 }
+/************************** 培训相关 **************************/
+//培训分类配置列表
+export function examElTrainingCategorySimpleList(data) {
+  return request({
+    url: '/exam/elTrainingCategory/simple-list',
+    method: 'post',
+    data: data
+  })
+}
+//培训分类-新增
+export function examElTrainingCategoryBatchSave(data) {
+  return request({
+    url: '/exam//elTrainingCategory/batch-save',
+    method: 'post',
+    data: data
+  })
+}
+//分页查询培训任务
+export function examElTrainingTaskList(data) {
+  return request({
+    url: '/exam/elTrainingTask/list',
+    method: 'post',
+    data: data
+  })
+}
+//查询培训学习进度
+export function examElTrainingTaskProgressDetail(data) {
+  return request({
+    url: '/exam/elTrainingTask/progressDetail',
+    method: 'post',
+    data: data
+  })
+}
+//导出培训记录
+export function examElTrainingTaskSignInExport(data) {
+  return request({
+    url: '/exam/elTrainingTask/signInExport',
+    method: 'post',
+    data: data
+  })
+}
+//新增培训
+export function examElTrainingTaskAdd(data) {
+  return request({
+    url: '/exam/elTrainingTask/add',
+    method: 'post',
+    data: data
+  })
+}
+//编辑培训
+export function examElTrainingTaskEdit(data) {
+  return request({
+    url: '/exam/elTrainingTask/edit',
+    method: 'post',
+    data: data
+  })
+}
+//培训详情
+export function examElTrainingTaskDetail(data) {
+  return request({
+    url: '/exam/elTrainingTask/detail',
+    method: 'post',
+    data: data
+  })
+}
+//培训-启用/停用
+export function examElTrainingTaskPublish(data) {
+  return request({
+    url: '/exam/elTrainingTask/publish',
+    method: 'post',
+    data: data
+  })
+}
+//培训-删除
+export function examElTrainingTaskDel(data) {
+  return request({
+    url: '/exam/elTrainingTask/del',
+    method: 'post',
+    data: data
+  })
+}
+//学生查询培训列表
+export function examUserTrainingList(data) {
+  return request({
+    url: '/exam/user/training/list',
+    method: 'post',
+    data: data
+  })
+}
+//学生查询培训详情
+export function examUserTrainingDetail(data) {
+  return request({
+    url: '/exam/user/training/detail',
+    method: 'post',
+    data: data
+  })
+}

+ 4 - 4
src/views/safetyEducationExaminationNew/examManagement/examinationArrange/addPage.vue

@@ -212,9 +212,9 @@
                           {{scope.row.account?scope.row.account:'-'}}
                         </template>
                       </el-table-column>
-                      <el-table-column label="专业" prop="majorName" width="200">
+                      <el-table-column label="专业" prop="disciplineName" width="200">
                         <template slot-scope="scope">
-                          {{scope.row.majorName?scope.row.majorName:'-'}}
+                          {{scope.row.disciplineName?scope.row.disciplineName:'-'}}
                         </template>
                       </el-table-column>
                       <el-table-column label="学院" prop="deptName" width="180">
@@ -222,9 +222,9 @@
                           {{scope.row.deptName?scope.row.deptName:'-'}}
                         </template>
                       </el-table-column>
-                      <el-table-column label="学年" prop="gradeNumber" width="180">
+                      <el-table-column label="学年" prop="academicYear" width="180">
                         <template slot-scope="scope">
-                          {{scope.row.gradeNumber?scope.row.gradeNumber:'-'}}
+                          {{scope.row.academicYear?scope.row.academicYear:'-'}}
                         </template>
                       </el-table-column>
                       <el-table-column label="操作" width="140" align="center">

+ 6 - 0
src/views/safetyEducationExaminationNew/examManagement/examinationArrange/studentsTakingMakeUpExams.vue

@@ -146,6 +146,9 @@
             <template slot-scope="scope">
               <span v-if="scope.row.resultStatus == 4" class="colorA">缺勤</span>
               <span v-if="scope.row.resultStatus == 3" class="colorB">未通过</span>
+              <span v-if="scope.row.resultStatus == 1">考试中</span>
+              <span v-if="scope.row.resultStatus == 2" class="colorC">通过</span>
+              <span v-if="scope.row.resultStatus == 0">未开始</span>
             </template>
           </el-table-column>
           <el-table-column label="操作" width="200" show-overflow-tooltip>
@@ -434,6 +437,9 @@
     .colorB{
       color:#EF98A2;
     }
+    .colorC{
+      color:#10a37f;
+    }
     .content-box {
       flex: 1;
       display: flex;

+ 13 - 13
src/views/safetyEducationExaminationNew/publicConfiguration/basicConfiguration/trainingConfiguration.vue

@@ -3,9 +3,9 @@
   <div class="page-container trainingConfiguration-addPage">
     <div class="top-box">
       <el-form class="add-form-box" :model="newData" ref="form" label-width="">
-        <el-form-item label="" prop="disciplineName">
+        <el-form-item label="" prop="categoryName">
           <div style="display: flex">
-            <el-input v-model="newData.disciplineName" placeholder="输入培训分类名称" maxLength="20" style="width:500px;"></el-input>
+            <el-input v-model="newData.categoryName" placeholder="输入培训分类名称" maxLength="20" style="width:500px;"></el-input>
             <p class="form-button" @click="addButton()">+ 添加</p>
           </div>
         </el-form-item>
@@ -15,12 +15,12 @@
     <div class="bottom-box scrollbar-box">
       <div class="for-box" v-for="(item,index) in dataList" :key="index">
         <div class="input-box" v-if="editorIndex === index">
-          <el-input v-model="item.disciplineName" placeholder="输入培训分类名称"
+          <el-input v-model="item.categoryName" placeholder="输入培训分类名称"
                     maxLength="20" style="flex:1;margin:10px 0 10px 5px;"></el-input>
           <p @click="confirmButton()">确定</p>
         </div>
         <div class="text-box" v-else>
-          <p>{{item.disciplineName}}</p>
+          <p>{{item.categoryName}}</p>
           <p @click="editorButton(index)">修改</p>
           <p @click="delButton(index)">删除</p>
         </div>
@@ -32,7 +32,7 @@
 <script>
   //import { getDicts } from "@/api/commonality/noPermission";
   //import { systemUserSelect } from "@/api/commonality/permission";
-  import { examElDisciplineTypeList,examElDisciplineTypeBatchSave } from "@/api/safetyEducationExaminationNew/index";
+  import { examElTrainingCategorySimpleList,examElTrainingCategoryBatchSave } from "@/api/safetyEducationExaminationNew/index";
   export default {
     name: 'addPage',
     props: {
@@ -41,7 +41,7 @@
     data() {
       return {
         newData:{
-          disciplineName:'',
+          categoryName:'',
         },
         dataList:[],
         editorIndex:null,
@@ -55,7 +55,7 @@
     },
     methods:{
       initialize(){
-        examElDisciplineTypeList({}).then(response => {
+        examElTrainingCategorySimpleList({}).then(response => {
           this.$set(this,'dataList',response.data);
         });
       },
@@ -65,7 +65,7 @@
       },
       //确定
       confirmButton(){
-        if(!this.dataList[this.editorIndex].disciplineName){
+        if(!this.dataList[this.editorIndex].categoryName){
           this.msgError('输入考试类型名称')
           return
         }
@@ -75,14 +75,14 @@
         this.dataList.splice(index,1)
       },
       addButton(){
-        if(!this.newData.disciplineName){
+        if(!this.newData.categoryName){
           this.msgError('输入考试类型名称')
           return
         }
         this.dataList.push({
-          disciplineName:this.newData.disciplineName
+          categoryName:this.newData.categoryName
         })
-        this.$set(this.newData,'disciplineName','');
+        this.$set(this.newData,'categoryName','');
       },
       //重置
       resetButton(){
@@ -113,11 +113,11 @@
           for(let i=0;i<self.dataList.length;i++){
             let obj = {
               id:self.dataList[i].id?self.dataList[i].id:'',
-              disciplineName:self.dataList[i].disciplineName,
+              categoryName:self.dataList[i].categoryName,
             }
             list.push(obj);
           }
-          examElDisciplineTypeBatchSave(list).then(response => {
+          examElTrainingCategoryBatchSave(list).then(response => {
             self.msgSuccess(response.message);
             self.initialize();
           });

+ 0 - 66
src/views/safetyEducationExaminationNew/trainingManagement/addPage.vue

@@ -1,66 +0,0 @@
-<!-- 新建/编辑培训 -->
-<template>
-  <div class="page-container trainingManagement-addPage">
-    <div class="page-top-title-box">
-      <p class="page-top-title-name-p">{{newData.id?'编辑':'新增'}}</p>
-      <p class="page-top-title-out-p" @click="backPage">返回</p>
-      <p class="page-top-title-add-p" @click="submitForm">提交</p>
-    </div>
-    <div class="content-box">
-      <el-form :model="formData" ref="addForm" :rules="rules" label-width="240px">
-
-      </el-form>
-    </div>
-  </div>
-</template>
-
-<script>
-  //import { getDicts } from "@/api/commonality/noPermission";
-  //import { systemUserSelect } from "@/api/commonality/permission";
-  export default {
-    name: 'addPage',
-    props: {
-      propsData: {}
-    },
-    data() {
-      return {
-        newData: {},
-        formData:{
-
-        },
-      }
-    },
-    created() {
-
-    },
-    mounted() {
-      this.initialize()
-    },
-    methods: {
-      // 初始化
-      initialize() {
-
-      },
-      // 返回按钮
-      backPage() {
-        this.$parent.tableButton(6)
-      },
-      // 提交按钮
-      submitForm() {
-
-      }
-    }
-  }
-</script>
-
-<style scoped lang="scss">
-  .trainingManagement-addPage {
-    .content-box {
-      flex: 1;
-      display: flex;
-      flex-direction: column;
-      overflow: hidden;
-      padding: 20px;
-    }
-  }
-</style>

Plik diff jest za duży
+ 1224 - 0
src/views/safetyEducationExaminationNew/trainingManagement/trainingManagement/addPage.vue


+ 423 - 0
src/views/safetyEducationExaminationNew/trainingManagement/trainingManagement/drawerItem.vue

@@ -0,0 +1,423 @@
+<!--培训管理 - 选择课件-->
+<template>
+  <div class="page-container studyCourses-drawerItem">
+    <div class="drawerItem-left-box" v-if="!newData.knowledgePointId">
+    <!--<div class="drawerItem-left-box">-->
+      <el-form class="drawerItem-left-form" :model="leftData" ref="form">
+        <el-form-item label="" prop="data4" label-width="0">
+          <el-input v-model="leftData.searchValue" placeholder="关键字搜索知识点" maxLength="20" style="width:260px;">
+            <el-button slot="append" icon="el-icon-search" @click="examElKnowledgePointTreeList()"></el-button>
+          </el-input>
+        </el-form-item>
+      </el-form>
+      <div class="drawerItem-left-list-box scrollbar-box">
+        <p v-if="!leftList[0]" style="text-align: center;color:#999;line-height:200px;">暂无数据</p>
+        <p v-for="(item,index) in leftList" :key="index"
+           @click="leftCheckButton(index)"
+           :class="index == leftCheckIndex?'checkIndex':''">{{item.knowledgePointName}}</p>
+      </div>
+    </div>
+    <div class="drawerItem-right-box">
+      <el-form class="drawerItem-right-form" :model="queryParams" ref="form">
+        <el-form-item label="" prop="shareStatus">
+          <el-select v-model="queryParams.shareStatus" placeholder="是否共享" style="width: 120px">
+            <el-option label="共享" value="1"/>
+            <el-option label="不共享" value="0"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="" prop="materialType">
+          <el-select v-model="queryParams.materialType" placeholder="课件类型" style="width: 200px">
+            <el-option
+              v-for="dict in optionListA"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="" prop="deptId">
+          <el-cascader
+            style="width: 180px"
+            v-model="queryParams.deptId"
+            :options="optionListB"
+            :props="{
+                    emitPath:false,
+                    checkStrictly: true,
+                    value: 'deptId',
+                    label: 'deptName',
+                    children: 'child',
+                  }"
+            :show-all-levels="false"
+            filterable
+            placeholder="来源"
+          ></el-cascader>
+        </el-form-item>
+        <el-form-item label="" prop="searchValue">
+          <el-input
+            maxLength="30"
+            v-model="queryParams.searchValue"
+            placeholder="搜索名称"
+            style="width: 200px"
+          />
+        </el-form-item>
+        <p class="page-inquire-common-style-button" @click="handleQuery">查询</p>
+        <p class="page-reset-common-style-button" @click="resetQuery">重置</p>
+      </el-form>
+      <div class="page-content-box">
+        <el-table class="table-box"  border :data="rightList"
+                  ref="multipleTable" :row-key="getRowKey" @selection-change="handleSelectionChange">
+          <el-table-column type="selection" width="55" :reserve-selection="true"></el-table-column>
+          <el-table-column label="课件名称" prop="coursewareName"  show-overflow-tooltip/>
+          <el-table-column label="知识点" prop="knowledgePointName" width="200" show-overflow-tooltip/>
+          <el-table-column label="是否共享" prop="shareStatus" width="140" show-overflow-tooltip>
+            <template slot-scope="scope">
+              <span v-if="scope.row.shareStatus == 1" style="padding:2px 10px;border:1px solid rgb(1, 131, 251);border-radius:4px;color: rgb(1, 131, 251);background-color:rgba(1, 131, 251,0.2)">共享</span>
+              <span v-if="scope.row.shareStatus == 0" style="padding:2px 10px;border:1px solid rgb(245, 154, 35);border-radius:4px;color: rgb(245, 154, 35);background-color:rgba(245, 154, 35,0.2)">不共享</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="课件类型" prop="materialType" width="120" show-overflow-tooltip>
+            <template slot-scope="scope">
+              {{scope.row.materialType == 1?'视频':(scope.row.materialType == 3?'文档':(scope.row.materialType == 4?'文章':''))}}
+            </template>
+          </el-table-column>
+          <el-table-column label="文件大小" prop="attachmentSize" width="120" show-overflow-tooltip>
+            <template slot-scope="scope">
+              {{scope.row.attachmentSize?scope.row.attachmentSize+'Mb':'-'}}
+            </template>
+          </el-table-column>
+          <el-table-column label="要求时长" prop="minLearningDuration" width="120" show-overflow-tooltip>
+            <template slot-scope="scope">
+              {{scope.row.minLearningDuration}}分钟
+            </template>
+          </el-table-column>
+          <el-table-column label="可得学时" prop="creditHours" width="120" show-overflow-tooltip/>
+          <el-table-column label="可得积分" prop="points" width="120" show-overflow-tooltip/>
+          <el-table-column label="来源" prop="deptName" width="240" show-overflow-tooltip/>
+        </el-table>
+        <div class="right-bottom-button-box">
+          <pagination :page-sizes="[20, 30, 40, 50]"
+                      v-show="total>0"
+                      :total="total"
+                      :page.sync="queryParams.page"
+                      :limit.sync="queryParams.pageSize"
+                      @pagination="getList"
+          />
+          <p class="null-p"></p>
+          <p class="drawer-item-button-1" @click="returnButton">取消</p>
+          <p class="drawer-item-button-2" @click="confirmButton">确定</p>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+  //import { getDicts } from "@/api/commonality/noPermission";
+  //import { systemUserSelect } from "@/api/commonality/permission";
+  //import { getInfo } from "@/api/basicsModules/index";
+  import {
+    examElCoursewarePage,examElKnowledgePointTreeList,
+    systemDeptCurrentDept,
+  } from "@/api/safetyEducationExaminationNew/index";
+  export default {
+    name: 'drawerItem',
+    props:{
+      drawerItemPropsData:{},
+    },
+    data(){
+      return{
+        newData:{
+          knowledgePointId:null,
+          checkIndex:null,
+        },
+        // 左侧
+        leftData:{
+          searchValue:'',
+        },
+        leftList:[],
+        leftCheckIndex:0,
+        //右侧
+        optionListA:[{value:'1',label:'视频'},{value:'3',label:'文档'},{value:'4',label:'文章'},],
+        optionListB:[],
+        queryParams:{
+          page:1,
+          pageSize:20,
+          searchValue:'',
+          shareStatus:'',
+          materialType:null,
+          deptId :null,
+        },
+        rightList:[],
+
+        total:0,
+        multipleSelection: [], // 存储所有被勾选的数据
+      }
+    },
+    created(){
+
+    },
+    mounted(){
+      this.$set(this,'newData',this.drawerItemPropsData);
+      this.systemDeptCurrentDept();
+      this.examElKnowledgePointTreeList();
+    },
+    methods:{
+      //左侧切换
+      leftCheckButton(index){
+        if(this.leftCheckIndex != index){
+          this.$set(this,'leftCheckIndex',index);
+          this.$set(this,'multipleSelection',[]);
+          this.$refs.multipleTable.clearSelection();
+          this.resetQuery();
+        }
+      },
+      //右侧切换按钮
+      tableTypeButton(val){
+        if(this.queryParams.shareStatus != val){
+          this.$set(this.queryParams,'shareStatus',val);
+          this.handleQuery();
+        }
+      },
+      //右侧获取数据
+      rightGetList(){
+
+      },
+      //查询
+      handleQuery(){
+        this.$set(this.queryParams,'page',1);
+        this.getList();
+      },
+      //重置
+      resetQuery(){
+        this.$set(this,'queryParams',{
+          page:1,
+          pageSize:20,
+          searchValue:'',
+          shareStatus:'',
+          materialType:null,
+          deptId :null,
+        });
+        this.getList();
+      },
+      //返回
+      returnButton(){
+        this.$parent.$parent.drawerReturnButton();
+      },
+      //确定
+      confirmButton(){
+        let self = this;
+        if(!this.multipleSelection[0]){
+          this.msgError('请选择课件');
+          return
+        }
+        let list = [];
+        for(let i=0;i<self.multipleSelection.length;i++){
+          list.push({
+            coursewareId:self.multipleSelection[i].id,
+            coursewareName:self.multipleSelection[i].coursewareName,
+            creditHours:self.multipleSelection[i].creditHours,
+            points:self.multipleSelection[i].points,
+          })
+        }
+        this.$parent.$parent.drawerConfirmButton(list);
+      },
+      //获取数据列表
+      getList(){
+
+        let obj = JSON.parse(JSON.stringify(this.queryParams))
+        if(!this.newData.knowledgePointId){
+          if(this.leftList[0]){
+            obj.knowledgePointId = this.leftList[this.leftCheckIndex].id;
+          }else{
+            this.$set(this, 'rightList', []);
+            this.$set(this, 'total', 0);
+            return
+          }
+        }else{
+          obj.knowledgePointId = this.newData.knowledgePointId;
+        }
+        examElCoursewarePage(obj).then(response => {
+
+          this.$set(this,'rightList',response.data.records);
+          this.$set(this,'total',response.data.total);
+        });
+      },
+
+      // 2. 指定表格行的唯一标识(必须是数据中绝对唯一的字段,如 id)
+      getRowKey(row) {
+        return row.id;
+      },
+
+      // 3. 监听勾选状态的变化
+      handleSelectionChange(val) {
+        this.multipleSelection = val;
+      },
+
+      // 4. 翻页/改变每页条数时的处理
+      handlePageChange(pageNum) {
+        this.queryParams.pageNum = pageNum;
+        this.getList();
+      },
+      handleSizeChange(pageSize) {
+        this.queryParams.pageSize = pageSize;
+        this.queryParams.pageNum = 1;
+        this.getList();
+      },
+
+      // 5. 核心方法:翻页后恢复之前的勾选状态
+      restoreSelection() {
+        if (this.multipleSelection.length > 0) {
+          this.rightList.forEach(row => {
+            const isSelected = this.multipleSelection.some(item => item.id === row.id);
+            this.$refs.multipleTable.toggleRowSelection(row, isSelected);
+          });
+        }
+      },
+
+      //知识点
+      examElKnowledgePointTreeList(){
+        if(!this.newData.knowledgePointId){
+          examElKnowledgePointTreeList({dataScope:1,searchValue:this.leftData.searchValue}).then(response => {
+            let list = [];
+            for(let i=0;i<response.data.length;i++){
+              list.push({
+                id:response.data[i].id,
+                knowledgePointName:response.data[i].knowledgePointName,
+              })
+            }
+            this.$set(this, 'leftList', list);
+            this.$set(this, 'leftCheckIndex', list[0]?0:null);
+            this.resetQuery();
+          });
+        }else {
+          this.resetQuery();
+        }
+      },
+      //学院列表
+      systemDeptCurrentDept(){
+        systemDeptCurrentDept({}).then(response => {
+          const list = response.data || [];
+          this.formatTreeData(list);
+          this.$set(this,'optionListB',list);
+        });
+      },
+      addAndFormat(val1, val2) {
+        const num1 = parseFloat(val1) || 0;
+        const num2 = parseFloat(val2) || 0;
+        return parseFloat((num1 + num2).toFixed(1));
+      },
+    },
+  }
+</script>
+
+<style scoped lang="scss">
+  .studyCourses-drawerItem{
+    flex:1;
+    display: flex;
+    overflow: hidden;
+    .drawerItem-left-box{
+      width:300px;
+      display: flex;
+      padding:20px;
+      border-right:1px solid #dedede;
+      flex-direction: column;
+      overflow: hidden;
+      .drawerItem-left-form{
+
+      }
+      .drawerItem-left-list-box{
+        flex:1;
+        p{
+          line-height:40px;
+          font-size:16px;
+          color:#333;
+          cursor: pointer;
+        }
+        .checkIndex{
+          color:#0183fa!important;
+        }
+      }
+    }
+    .drawerItem-right-box{
+      flex:1;
+      display: flex;
+      flex-direction: column;
+      overflow: hidden;
+      .drawerItem-right-form{
+        display: flex;
+        margin:20px 0 0 20px;
+        .el-form-item{
+          margin-right:10px;
+        }
+      }
+      .table-top-button-box{
+        display: inline-block;
+        vertical-align: top;
+        margin-right:10px;
+        margin-left:0;
+        div{
+          display: flex;
+          p{
+            border:1px solid #DCDFE6;
+            width:80px;
+            text-align: center;
+            height:40px;
+            line-height:40px;
+            cursor: pointer;
+            font-size:14px;
+          }
+          p:nth-child(1){
+            border-top-left-radius:4px;
+            border-bottom-left-radius:4px;
+          }
+          p:nth-child(2){
+            border-left:none;
+            border-right:none;
+          }
+          p:nth-child(3){
+            border-top-right-radius:4px;
+            border-bottom-right-radius:4px;
+          }
+          .check-table-button{
+            border:1px solid #0183fa;
+            background-color: #0183fa;
+            color:#fff;
+          }
+        }
+      }
+      .page-content-box{
+        padding-top:0;
+        .right-bottom-button-box{
+          display: flex;
+          .null-p{
+            flex:1;
+          }
+          .drawer-item-button-1{
+            background-color: #dedede;
+            border-radius:4px;
+            margin-right:20px;
+            margin-top:15px;
+            line-height:40px;
+            width:80px;
+            text-align: center;
+            font-size:14px;
+            color:#333;
+            cursor: pointer;
+          }
+          .drawer-item-button-2{
+            background-color: #0183fa;
+            border-radius:4px;
+            margin-right:20px;
+            margin-top:15px;
+            line-height:40px;
+            width:80px;
+            text-align: center;
+            font-size:14px;
+            color:#fff;
+            cursor: pointer;
+          }
+        }
+      }
+    }
+  }
+</style>

+ 81 - 72
src/views/safetyEducationExaminationNew/trainingManagement/index.vue

@@ -6,16 +6,16 @@
         <el-form :model="queryParams" class="form-box" ref="queryForm"
                  :inline="true" style="width:100%;"
         >
-          <el-form-item label="" prop="queryParamsData1">
+          <el-form-item label="" prop="searchValue">
             <el-input
               maxLength="30"
-              v-model="queryParams.queryParamsData1"
+              v-model="queryParams.searchValue"
               placeholder="搜索培训名称、主讲人"
               style="width: 200px"
             />
           </el-form-item>
-          <el-form-item label="" prop="queryParamsData2">
-            <el-select v-model="queryParams.queryParamsData2" placeholder="状态" style="width: 200px">
+          <el-form-item label="" prop="status">
+            <el-select v-model="queryParams.status" placeholder="状态" style="width: 200px">
               <el-option
                 v-for="dict in optionListA"
                 :key="dict.value"
@@ -24,8 +24,8 @@
               />
             </el-select>
           </el-form-item>
-          <el-form-item label="" prop="queryParamsData3">
-            <el-select v-model="queryParams.queryParamsData3" placeholder="培训方式" style="width: 200px">
+          <el-form-item label="" prop="trainingMode">
+            <el-select v-model="queryParams.trainingMode" placeholder="培训方式" style="width: 200px">
               <el-option
                 v-for="dict in optionListD"
                 :key="dict.value"
@@ -34,25 +34,25 @@
               />
             </el-select>
           </el-form-item>
-          <el-form-item label="" prop="queryParamsData4">
-            <el-select v-model="queryParams.queryParamsData4" placeholder="分类" style="width: 200px">
+          <el-form-item label="" prop="categoryId">
+            <el-select v-model="queryParams.categoryId" placeholder="分类" style="width: 200px">
               <el-option
                 v-for="dict in optionListB"
-                :key="dict.value"
-                :label="dict.label"
-                :value="dict.value"
+                :key="dict.id"
+                :label="dict.categoryName"
+                :value="dict.id"
               />
             </el-select>
           </el-form-item>
-          <el-form-item label="" prop="deptId">
+          <el-form-item label="" prop="orgDeptId">
             <el-cascader
               style="width: 180px"
-              v-model="queryParams.deptId"
+              v-model="queryParams.orgDeptId"
               :options="optionListC"
               :props="{
                     emitPath:false,
                     checkStrictly: true,
-                    value: 'deptId',
+                    value: 'orgDeptId',
                     label: 'deptName',
                     children: 'child',
                   }"
@@ -79,39 +79,38 @@
           <p class="page-submit-common-style-button"
              style="float: right;"
              @click="tableButton(1)"
-             v-hasPermiRouter="['demo:demo:add']"
           >新增</p>
         </el-form>
       </div>
       <div class="page-content-box">
         <el-table class="table-box" border :data="dataList">
-          <el-table-column label="培训名称" prop="name" show-overflow-tooltip>
+          <el-table-column label="培训名称" prop="trainingName" show-overflow-tooltip>
             <template slot-scope="scope">
-              <span @click="tableButton(2)">{{scope.row.name}}</span>
+              <span @click="tableButton(2)">{{scope.row.trainingName}}</span>
             </template>
           </el-table-column>
-          <el-table-column label="分类" prop="content" width="200" show-overflow-tooltip>
+          <el-table-column label="分类" prop="categoryName" width="140" show-overflow-tooltip>
             <template slot-scope="scope">
-              <span style="color:#1857d4;">{{scope.row.name}}</span>
+              <span style="color:#1857d4;">{{scope.row.categoryName}}</span>
             </template>
           </el-table-column>
-          <el-table-column label="培训时间" prop="createTime" width="200" show-overflow-tooltip>
+          <el-table-column label="培训时间" prop="startDate" width="160" show-overflow-tooltip>
             <template slot-scope="scope">
               <div>
-                <p>{{ parseTime(scope.row.createTime,"{y}-{m}-{d} {h}:{i}") }}</p>
-                <p>10:00 - 12:00</p>
+                <p>{{ parseTime(scope.row.startDate,"{y}-{m}-{d} {h}:{i}") }} 至</p>
+                <p>{{ parseTime(scope.row.endDate,"{y}-{m}-{d} {h}:{i}") }}</p>
               </div>
             </template>
           </el-table-column>
-          <el-table-column label="组织单位" prop="name" width="140" show-overflow-tooltip/>
-          <el-table-column label="培训方式" prop="content" width="100" show-overflow-tooltip>
+          <el-table-column label="组织单位" prop="orgDeptName" width="140" show-overflow-tooltip/>
+          <el-table-column label="培训方式" prop="trainingMode" width="100" show-overflow-tooltip>
             <template slot-scope="scope">
-              <span>{{scope.row.name==1?'线上培训':(scope.row.name==2?'线下培训':'')}}</span>
+              <span>{{scope.row.trainingMode==1?'线上培训':(scope.row.trainingMode==2?'线下培训':'')}}</span>
             </template>
           </el-table-column>
           <el-table-column label="学时/积分" prop="content" width="140" show-overflow-tooltip>
             <template slot-scope="scope">
-              <span style="color:#10a37f;font-weight:600;">学时{{scope.row.name}} +{{scope.row.name}}分</span>
+              <span style="color:#10a37f;font-weight:600;">学时{{scope.row.creditHours}} +{{scope.row.points}}分</span>
             </template>
           </el-table-column>
           <el-table-column label="进度" prop="content" width="140" show-overflow-tooltip>
@@ -123,52 +122,51 @@
               <span>{{scope.row.name}}</span>
             </template>
           </el-table-column>
-          <el-table-column label="状态" prop="content" width="100" show-overflow-tooltip>
+          <el-table-column label="状态" prop="status" width="100" show-overflow-tooltip>
             <template slot-scope="scope">
-              <p :class="scope.row.status==1?'border-color-a':(scope.row.status==2?'border-color-b':(scope.row.status==3?'border-color-c':''))">{{scope.row.status==1?'进行中':(scope.row.status==2?'未开始':(scope.row.status==3?'已结束':''))}}</p>
+              <p :class="scope.row.status==1?'border-color-a':(scope.row.status==2?'border-color-b':(scope.row.status==3?'border-color-c':''))">{{scope.row.status==1?'未开始':(scope.row.status==2?'进行中':(scope.row.status==3?'已结束':''))}}</p>
             </template>
           </el-table-column>
-          <el-table-column label="发布" prop="state" width="100" show-overflow-tooltip>
+          <el-table-column label="发布" prop="publishStatus" width="100" show-overflow-tooltip>
             <template slot-scope="scope">
               <el-switch
+                v-if="scope.row.status==1"
                 @click.native="tableButton(3,scope.row)"
                 class="switch captcha-img"
-                :active-value="true"
-                :inactive-value="false"
+                :active-value="1"
+                :inactive-value="0"
                 active-color="#0183FA"
                 inactive-color="#999"
-                v-model="scope.row.state"
+                v-model="scope.row.publishStatus"
                 active-text="启用"
                 inactive-text="停用"
                 disabled
               ></el-switch>
             </template>
           </el-table-column>
-          <el-table-column label="操作" width="240" show-overflow-tooltip v-if="tableButtonType">
+          <el-table-column label="操作" width="240" show-overflow-tooltip>
             <template slot-scope="scope">
               <div class="table-button-box">
                 <p class="table-button-null"></p>
                 <p class="table-button-p"
                    v-if="scope.row.status==3"
                    @click="tableButton(4,scope.row)"
-                   v-hasPermiRouter="['demo:demo:detail']"
                 >查看记录</p>
                 <p class="table-button-p"
-                   v-if="scope.row.status!=3"
+                   v-if="scope.row.status!=3&&scope.row.trainingMode == 1"
                    @click="tableButton(5,scope.row)"
-                   v-hasPermiRouter="['demo:demo:detail']"
                 >签到码</p>
                 <p class="table-button-p"
+                   v-if="scope.row.status!=1"
                    @click="tableButton(6,scope.row)"
-                   v-hasPermiRouter="['demo:demo:edit']"
                 >进度</p>
                 <p class="table-button-p"
+                   v-if="scope.row.status==1"
                    @click="tableButton(7,scope.row)"
-                   v-hasPermiRouter="['demo:demo:edit']"
                 >编辑</p>
                 <p class="table-button-p"
+                   v-if="scope.row.status==1"
                    @click="tableButton(8,scope.row)"
-                   v-hasPermiRouter="['demo:demo:del']"
                 >删除</p>
                 <p class="table-button-null"></p>
               </div>
@@ -184,7 +182,7 @@
         />
       </div>
     </div>
-    <!--<add-page :propsData="propsData" v-if="pageType === 2"></add-page>-->
+    <add-page :propsData="propsData" v-if="pageType === 2"></add-page>
     <!--培训二维码-->
     <el-dialog class="trainingTask-dialog" title="签到二维码"
                append-to-body v-if="dialogType"
@@ -224,13 +222,13 @@
 </template>
 <script>
   import vueQr from 'vue-qr'
-  //import { getDicts } from "@/api/commonality/noPermission";
-  //import { systemUserSelect } from "@/api/commonality/permission";
-  //import { getInfo } from "@/api/basicsModules/index";
   import trainingProgressDetails from "./trainingProgressDetails.vue";
   import trainingRecordDetails from "./trainingRecordDetails.vue";
+  import addPage from "./addPage.vue";
   import {
-    systemDeptCurrentDept,
+    systemDeptCurrentDept,examElTrainingCategorySimpleList,
+    examElTrainingTaskList,examElTrainingTaskPublish,
+    examElTrainingTaskDel,
   } from "@/api/safetyEducationExaminationNew/index";
   export default {
     name: 'index',
@@ -238,6 +236,7 @@
       vueQr,
       trainingProgressDetails,
       trainingRecordDetails,
+      addPage,
     },
     data() {
       return {
@@ -245,7 +244,7 @@
         //页面状态
         pageType: 1,
         //下拉列表数据
-        optionListA: [{ value: '0', label: '未开始' }, { value: '1', label: '进行中' }, { value: '2', label: '已结束' }],
+        optionListA: [{ value: '1', label: '未开始' }, { value: '2', label: '进行中' }, { value: '3', label: '已结束' }],
         optionListB: [],
         optionListC: [],
         optionListD: [{ value: '1', label: '线上培训' }, { value: '2', label: '线下培训' }],
@@ -253,11 +252,11 @@
         queryParams: {
           page: 1,
           pageSize: 20,
-          queryParamsData1: '',
-          queryParamsData2: null,
-          queryParamsData3: null,
-          queryParamsData4: null,
-          deptId:'',
+          searchValue: '',
+          status: null,
+          trainingMode: null,
+          categoryId: null,
+          orgDeptId:'',
         },
         //时间数据
         dateRange: [],
@@ -289,6 +288,7 @@
     },
     mounted() {
       this.systemDeptCurrentDept();
+      this.examElTrainingCategorySimpleList();
       this.getList();
     },
     methods: {
@@ -303,11 +303,11 @@
         this.$set(this, 'queryParams', {
           page: 1,
           pageSize: 20,
-          queryParamsData1: '',
-          queryParamsData2: null,
-          queryParamsData3: null,
-          queryParamsData4: null,
-          deptId:'',
+          searchValue: '',
+          status: null,
+          trainingMode: null,
+          categoryId: null,
+          orgDeptId:'',
         })
         this.getList()
       },
@@ -321,13 +321,10 @@
           obj.startTime = ''
           obj.endTime = ''
         }
-        // getListFunction(obj).then(response => {
-        //   this.$set(this, 'dataList', response.data.records)
-        //   this.$set(this, 'total', response.data.total)
-        // })
-
-        this.$set(this, 'dataList', [{createTime:'2026-10-10 10:10',status:1},{createTime:'2026-10-10 10:10',status:2},{createTime:'2026-10-10 10:10',status:3}])
-        this.$set(this, 'total', 1)
+        examElTrainingTaskList(obj).then(response => {
+          this.$set(this, 'dataList', response.data.records)
+          this.$set(this, 'total', response.data.total)
+        })
       },
       //操作按钮
       tableButton(type, row) {
@@ -344,14 +341,14 @@
           this.$set(this, 'propsData', obj)
         }else if (type == 3) {
           //启用&停用
-          let text = row.state ? '停用' : '启用'
+          let text = row.publishStatus==1 ? '停用' : '启用'
           this.$confirm('是否确认' + text + '?', '警告', {
             confirmButtonText: '确定',
             cancelButtonText: '取消',
             type: 'warning'
           }).then(function() {
           }).then(() => {
-            stateFunction({ id: row.id, state: !row.state }).then(response => {
+            examElTrainingTaskPublish({ id: row.id, publishStatus: row.publishStatus==1?0:1 }).then(response => {
               self.msgSuccess(response.message)
               self.getList()
             })
@@ -367,8 +364,7 @@
           //签到码
           this.$set(this,'codeData',{
             codeName:'实验室生物安全操作规范培训',
-            vueQrCodeData:this.identification+'?code='+row.id+'&type=onlineTraining',
-            // vueQrCodeData:this.identification+'?code='+row.id+'&type=offlineTraining',
+            vueQrCodeData:this.identification+'?code='+row.id+'&type='+row.trainingMode==1?'onlineTraining':'offlineTraining',
             title:'实验室生物安全操作规范培训',
             playTime:'2026-08-01 10:00–12:00',
             endTime:'2026-08-01 12:30',
@@ -396,7 +392,7 @@
             type: 'warning'
           }).then(function() {
           }).then(() => {
-            deleteFunction({ id: row.id }).then(response => {
+            examElTrainingTaskDel({ id: row.id }).then(response => {
               self.msgSuccess(response.message)
               self.getList()
             })
@@ -414,7 +410,14 @@
       },
       //导出记录
       exportButton(){
-
+        let self = this;
+        self.$confirm(`确认导出数据?`, "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(async () => {
+          self.downloadGet('/exam/elTrainingTask/signInExport?id='+self.dialogListPropsData.id, self.dialogListPropsData.trainingName+'-培训记录.xlsx')
+        }).catch(() => {})
       },
       //学院列表
       systemDeptCurrentDept(){
@@ -424,6 +427,12 @@
           this.$set(this,'optionListC',list);
         });
       },
+      //培训分类列表
+      examElTrainingCategorySimpleList(){
+        examElTrainingCategorySimpleList({}).then(response => {
+          this.$set(this,'optionListB',response.data);
+        });
+      },
       //进度条
       format(percentage) {
         return percentage === 100 ? '' : '';
@@ -482,11 +491,11 @@
         height:auto;
         line-height: 23px;
       }
-      .color-a{
+      .color-b{
         color:#1857d4;
         font-weight:600;
       }
-      .color-b{
+      .color-a{
         color:#e67e22;
         font-weight:600;
       }
@@ -494,7 +503,7 @@
         color:#10a37f;
         font-weight:600;
       }
-      .border-color-a{
+      .border-color-b{
         display: inline-block;
         line-height:23px;
         padding:0 10px;
@@ -502,7 +511,7 @@
         background-color: #fef6ec;
         color:#e67e22;
       }
-      .border-color-b{
+      .border-color-a{
         display: inline-block;
         line-height:23px;
         padding:0 10px;

+ 236 - 0
src/views/safetyEducationExaminationNew/trainingManagement/trainingManagement/selectScope.vue

@@ -0,0 +1,236 @@
+<!-- 选择范围 -->
+<template>
+  <div class="page-container selectScope-addPage">
+    <div class="page-form-title-box">
+      <el-form :model="queryParams" class="form-box" ref="queryForm"
+               :inline="true" style="width:100%;">
+        <el-form-item label="" prop="gradeNumbers">
+          <el-select v-model="queryParams.gradeNumbers" collapse-tags multiple placeholder="学年" style="width: 220px">
+            <el-option
+              v-for="dict in optionListD"
+              :key="dict.gradeNumber"
+              :label="dict.gradeNumber"
+              :value="dict.gradeNumber"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="" prop="deptIds">
+          <el-cascader
+            style="width: 220px"
+            collapse-tags
+            v-model="queryParams.deptIds"
+            :options="optionListB"
+            :props="{
+                    multiple:true,
+                    emitPath:false,
+                    checkStrictly: true,
+                    value: 'deptId',
+                    label: 'deptName',
+                    children: 'child',
+                  }"
+            :show-all-levels="false"
+            filterable
+            placeholder="学院单位"
+          ></el-cascader>
+        </el-form-item>
+        <el-form-item label="" prop="userTypeIds">
+          <el-select v-model="queryParams.userTypeIds" collapse-tags multiple placeholder="用户类别" style="width: 220px">
+            <el-option
+              v-for="dict in optionListC"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="" prop="majorId">
+          <el-select v-model="queryParams.majorId" filterable collapse-tags multiple placeholder="专业" style="width: 220px">
+            <el-option
+              v-for="dict in optionListE"
+              :key="dict.id"
+              :label="dict.name"
+              :value="dict.id"
+            />
+          </el-select>
+        </el-form-item>
+        <p class="page-inquire-common-style-button" @click="handleQuery">查询</p>
+        <p class="page-reset-common-style-button" @click="resetQuery">重置</p>
+        <p class="page-submit-common-style-button"
+           style="float: right;"
+           @click="checkButton()"
+        >确定</p>
+      </el-form>
+    </div>
+    <div class="page-content-box">
+      <el-table class="table-box" border :data="dataList"
+                ref="multipleTable" :row-key="getRowKey" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" :reserve-selection="true"></el-table-column>
+        <el-table-column label="学院单位" prop="deptName"  show-overflow-tooltip>
+          <template slot-scope="scope">
+            {{scope.row.deptName?scope.row.deptName:'-'}}
+          </template>
+        </el-table-column>
+        <el-table-column label="角色" prop="userTypeName" show-overflow-tooltip>
+          <template slot-scope="scope">
+            {{scope.row.userTypeName?scope.row.userTypeName:'-'}}
+          </template>
+        </el-table-column>
+        <el-table-column label="专业" prop="majorName" show-overflow-tooltip>
+          <template slot-scope="scope">
+            {{scope.row.majorName?scope.row.majorName:'-'}}
+          </template>
+        </el-table-column>
+        <el-table-column label="学年" prop="gradeNumber" show-overflow-tooltip>
+          <template slot-scope="scope">
+            {{scope.row.gradeNumber?scope.row.gradeNumber:'-'}}
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination :page-sizes="[20, 30, 40, 50]"
+                  v-show="total>0"
+                  :total="total"
+                  :page.sync="queryParams.page"
+                  :limit.sync="queryParams.pageSize"
+                  @pagination="getList"
+      />
+    </div>
+  </div>
+</template>
+
+<script>
+  import {
+    systemUserGetCategories,systemUserGetAcademicYear,
+    systemUserGetRuleDataByParam,systemUserMajorAllMajors,systemDeptCurrentDept,
+  } from "@/api/safetyEducationExaminationNew/index";
+  export default {
+    name: 'addPage',
+    props: {
+      propsData: {}
+    },
+    data() {
+      return {
+        //下拉列表数据
+        optionListB:[],
+        optionListC:[],
+        optionListD:[],
+        optionListE:[],
+        //查询条件
+        queryParams:{
+          page:1,
+          pageSize:20,
+          gradeNumbers:[],
+          deptIds :[],
+          userTypeIds :[],
+          majorId :[],
+        },
+        //列表数据
+        dataList:[],
+        //数据数量
+        total:0,
+        //存储所有被勾选的数据
+        multipleSelection: [],
+      }
+    },
+    created() {
+
+    },
+    mounted() {
+      this.getList();
+      this.systemUserGetAcademicYear();
+      this.systemUserGetCategories();
+      this.systemUserMajorAllMajors();
+      this.systemDeptCurrentDept();
+    },
+    methods: {
+      // 提交按钮
+      checkButton() {
+        let self = this;
+        if(!this.multipleSelection[0]){
+          this.msgError('请勾选范围')
+          return
+        }
+        let list = [];
+        for(let i=0;i<self.multipleSelection.length;i++){
+          list.push({
+            deptId:self.multipleSelection[i].deptId,
+            deptName:self.multipleSelection[i].deptName,
+            disciplineId:self.multipleSelection[i].majorId,
+            disciplineName:self.multipleSelection[i].majorName,
+            roleId:self.multipleSelection[i].userTypeId,
+            roleName:self.multipleSelection[i].userTypeName,
+            academicYear:self.multipleSelection[i].gradeNumber,
+          })
+        }
+        this.$parent.$parent.drawerOffButton(JSON.parse(JSON.stringify(list)))
+      },
+      //查询按钮
+      handleQuery(){
+        this.$set(this.queryParams,'page',1);
+        this.getList();
+      },
+      //重置按钮
+      resetQuery(){
+        this.$set(this,'queryParams',{
+          page:1,
+          pageSize:20,
+          gradeNumbers:[],
+          deptIds :[],
+          userTypeIds :[],
+          majorId :[],
+        });
+        this.getList();
+      },
+      //获取数据列表
+      getList(){
+
+        let obj = JSON.parse(JSON.stringify(this.queryParams))
+        systemUserGetRuleDataByParam(obj).then(response => {
+
+          this.$set(this,'dataList',response.data.records);
+          this.$set(this,'total',response.data.total);
+        });
+      },
+      //学年下拉列表
+      systemUserGetAcademicYear(){
+        systemUserGetAcademicYear({}).then(response => {
+          this.$set(this,'optionListD',response.data);
+        });
+      },
+      //用户类别下拉列表
+      systemUserGetCategories(){
+        systemUserGetCategories({}).then(response => {
+          this.$set(this,'optionListC',response.data);
+        });
+      },
+      //查询全部专业类别
+      systemUserMajorAllMajors(){
+        systemUserMajorAllMajors({}).then(response => {
+          this.$set(this,'optionListE',response.data);
+        });
+      },
+      //学院列表
+      systemDeptCurrentDept(){
+        systemDeptCurrentDept({}).then(response => {
+          const list = response.data || [];
+          this.formatTreeData(list);
+          this.$set(this,'optionListB',list);
+        });
+      },
+      getRowKey(row) {
+        return row.indexId;
+      },
+      handleSelectionChange(val) {
+        this.multipleSelection = val;
+      },
+    }
+  }
+</script>
+
+<style scoped lang="scss">
+  .selectScope-addPage {
+    flex:1;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+  }
+</style>

+ 234 - 0
src/views/safetyEducationExaminationNew/trainingManagement/trainingManagement/selectUser.vue

@@ -0,0 +1,234 @@
+<!-- 选择用户 -->
+<template>
+  <div class="page-container selectUser-addPage">
+    <div class="page-form-title-box">
+      <el-form :model="queryParams" class="form-box" ref="queryForm"
+               :inline="true" style="width:100%;">
+        <el-form-item label="" prop="gradeNumbers">
+          <el-select v-model="queryParams.gradeNumbers" collapse-tags multiple placeholder="学年" style="width: 220px">
+            <el-option
+              v-for="dict in optionListD"
+              :key="dict.gradeNumber"
+              :label="dict.gradeNumber"
+              :value="dict.gradeNumber"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="" prop="deptIds">
+          <el-cascader
+            collapse-tags
+            style="width: 220px"
+            v-model="queryParams.deptIds"
+            :options="optionListB"
+            :props="{
+                    multiple:true,
+                    emitPath:false,
+                    checkStrictly: true,
+                    value: 'deptId',
+                    label: 'deptName',
+                    children: 'child',
+                  }"
+            :show-all-levels="false"
+            filterable
+            placeholder="学院单位"
+          ></el-cascader>
+        </el-form-item>
+        <el-form-item label="" prop="userTypeIds">
+          <el-select v-model="queryParams.userTypeIds" collapse-tags multiple placeholder="用户类别" style="width: 220px">
+            <el-option
+              v-for="dict in optionListC"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="" prop="majorId">
+          <el-select v-model="queryParams.majorId" collapse-tags multiple placeholder="专业" style="width: 220px">
+            <el-option
+              v-for="dict in optionListE"
+              :key="dict.id"
+              :label="dict.disciplineName"
+              :value="dict.id"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="" prop="searchValue">
+          <el-input
+            maxLength="30"
+            v-model="queryParams.searchValue"
+            placeholder="姓名/学工号"
+            style="width: 220px"
+          />
+        </el-form-item>
+        <p class="page-inquire-common-style-button" @click="handleQuery">查询</p>
+        <p class="page-reset-common-style-button" @click="resetQuery">重置</p>
+        <p class="page-submit-common-style-button"
+           style="float: right;"
+           @click="checkButton()"
+        >确定</p>
+      </el-form>
+    </div>
+    <div class="page-content-box">
+      <el-table class="table-box" border :data="dataList"
+                ref="multipleTable" :row-key="getRowKey" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" :reserve-selection="true"></el-table-column>
+        <el-table-column label="姓名" prop="userName"  show-overflow-tooltip/>
+        <el-table-column label="学工号" prop="account" show-overflow-tooltip/>
+        <el-table-column label="用户类别" prop="userTypeName" show-overflow-tooltip/>
+        <el-table-column label="专业" prop="majorName" show-overflow-tooltip/>
+        <el-table-column label="学年" prop="gradeNumber" show-overflow-tooltip/>
+        <el-table-column label="学院单位" prop="deptName" show-overflow-tooltip/>
+      </el-table>
+      <pagination :page-sizes="[20, 30, 40, 50]"
+                  v-show="total>0"
+                  :total="total"
+                  :page.sync="queryParams.page"
+                  :limit.sync="queryParams.pageSize"
+                  @pagination="getList"
+      />
+    </div>
+  </div>
+</template>
+
+<script>
+  import {
+    systemUserGetCategories,systemUserGetAcademicYear,
+    systemUserGetUserDataByParam,examElDisciplineTypeList,systemDeptCurrentDept,
+  } from "@/api/safetyEducationExaminationNew/index";
+  export default {
+    name: 'addPage',
+    props: {
+      propsData: {}
+    },
+    data() {
+      return {
+        //下拉列表数据
+        optionListA:[],
+        optionListB:[],
+        optionListC:[],
+        optionListD:[],
+        optionListE:[],
+        //查询条件
+        queryParams:{
+          page:1,
+          pageSize:20,
+          gradeNumbers:[],
+          deptIds :[],
+          userTypeIds :[],
+          majorId :[],
+          searchValue :'',
+        },
+        //列表数据
+        dataList:[],
+        //数据数量
+        total:0,
+        //存储所有被勾选的数据
+        multipleSelection: [],
+      }
+    },
+    created() {
+
+    },
+    mounted() {
+      this.getList();
+      this.systemUserGetAcademicYear();
+      this.systemUserGetCategories();
+      this.examElDisciplineTypeList();
+      this.systemDeptCurrentDept();
+    },
+    methods: {
+      // 提交按钮
+      checkButton() {
+        let self = this;
+        if(!this.multipleSelection[0]){
+          this.msgError('请勾选用户')
+          return
+        }
+        let list = [];
+        for(let i=0;i<self.multipleSelection.length;i++){
+          list.push({
+            userId:self.multipleSelection[i].userId,
+            userName:self.multipleSelection[i].userName,
+            deptId:self.multipleSelection[i].deptId,
+            deptName:self.multipleSelection[i].deptName,
+            account:self.multipleSelection[i].account,
+            disciplineId:self.multipleSelection[i].majorId,
+            disciplineName:self.multipleSelection[i].majorName,
+            academicYear:self.multipleSelection[i].gradeNumber,
+          })
+        }
+        this.$parent.$parent.drawerOffButton(JSON.parse(JSON.stringify(list)))
+      },
+      //查询按钮
+      handleQuery(){
+        this.$set(this.queryParams,'page',1);
+        this.getList();
+      },
+      //重置按钮
+      resetQuery(){
+        this.$set(this,'queryParams',{
+          page:1,
+          pageSize:20,
+          gradeNumbers:[],
+          deptIds :[],
+          userTypeIds :[],
+          majorId :[],
+          searchValue :'',
+        });
+        this.getList();
+      },
+      //获取数据列表
+      getList(){
+
+        let obj = JSON.parse(JSON.stringify(this.queryParams))
+        systemUserGetUserDataByParam(obj).then(response => {
+
+          this.$set(this,'dataList',response.data.records);
+          this.$set(this,'total',response.data.total);
+        });
+      },
+      //学年下拉列表
+      systemUserGetAcademicYear(){
+        systemUserGetAcademicYear({}).then(response => {
+          this.$set(this,'optionListD',response.data);
+        });
+      },
+      //用户类别下拉列表
+      systemUserGetCategories(){
+        systemUserGetCategories({}).then(response => {
+          this.$set(this,'optionListC',response.data);
+        });
+      },
+      //查询全部专业类别
+      examElDisciplineTypeList(){
+        examElDisciplineTypeList({}).then(response => {
+          this.$set(this,'optionListE',response.data);
+        });
+      },
+      //学院列表
+      systemDeptCurrentDept(){
+        systemDeptCurrentDept({}).then(response => {
+          const list = response.data || [];
+          this.formatTreeData(list);
+          this.$set(this,'optionListB',list);
+        });
+      },
+      getRowKey(row) {
+        return row.userId;
+      },
+      handleSelectionChange(val) {
+        this.multipleSelection = val;
+      },
+    }
+  }
+</script>
+
+<style scoped lang="scss">
+  .selectUser-addPage {
+    flex:1;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+  }
+</style>

+ 38 - 26
src/views/safetyEducationExaminationNew/trainingManagement/trainingProgressDetails.vue

@@ -1,40 +1,41 @@
 <!-- 培训进度详情 -->
 <template>
   <div class="page-container trainingProgressDetails-addPage">
-    <p class="title-p">实验室生物安全操作规范培训</p>
+    <p class="title-p">{{newData.trainingName}}</p>
     <div class="num-max-box">
       <div class="num-box">
-        <p>{{newData.newData1}}</p>
+        <p>{{newData.newData1?newData.newData1:0}}</p>
         <p>计划人数</p>
       </div>
       <div class="num-box">
-        <p>{{newData.newData2}}</p>
-        <p>已签到</p>
+        <p>{{newData.newData2?newData.newData2:0}}</p>
+        <p>{{newData.trainingMode == 1?'已签到':'已学习'}}</p>
       </div>
       <div class="num-box">
-        <p>{{newData.newData3}}</p>
-        <p>未签到</p>
+        <p>{{newData.newData3?newData.newData3:0}}</p>
+        <p>{{newData.trainingMode == 1?'未签到':'未学习'}}</p>
       </div>
       <div class="num-box">
-        <p>{{newData.newData4}}%</p>
-        <p>签到率</p>
+        <p>{{newData.newData4?newData.newData4:0}}%</p>
+        <p>{{newData.trainingMode == 1?'签到率':'完成率'}}</p>
       </div>
     </div>
     <el-progress stroke-width="10" :text-inside="true" style="margin:15px 0 15px;"
       :percentage="percentage" :format="format"></el-progress>
     <div class="page-content-box">
       <el-table class="table-box" style="padding:0;" border :data="dataList">
-        <el-table-column label="姓名" prop="name" show-overflow-tooltip/>
-        <el-table-column label="学号" prop="content" width="160" show-overflow-tooltip/>
-        <el-table-column label="学院单位" prop="content" width="160" show-overflow-tooltip/>
-        <el-table-column label="签到状态" prop="content" width="160" show-overflow-tooltip>
+        <el-table-column label="姓名" prop="userName" show-overflow-tooltip/>
+        <el-table-column label="学号" prop="account" width="160" show-overflow-tooltip/>
+        <el-table-column label="学院单位" prop="deptName" width="160" show-overflow-tooltip/>
+        <el-table-column :label="newData.trainingMode == 1?'签到状态':'学习状态'" prop="signStatus" width="160" show-overflow-tooltip>
           <template slot-scope="scope">
-            <p :class="scope.row.status==1?'color-a':(scope.row.status==2?'color-b':'')">{{scope.row.status==1?'已签到':(scope.row.status==2?'未签到':'')}}</p>
+            <p v-if="newData.trainingMode == 1" :class="scope.row.signStatus==0?'color-a':(scope.row.signStatus==1?'color-b':'')">{{scope.row.signStatus==0?'已签到':(scope.row.signStatus==1?'未签到':'')}}</p>
+            <p v-if="newData.trainingMode == 2" :class="scope.row.signStatus==0?'color-a':(scope.row.signStatus==1?'color-b':'')">{{scope.row.signStatus==0?'已学习':(scope.row.signStatus==1?'未学习':'')}}</p>
           </template>
         </el-table-column>
-        <el-table-column label="签到时间" prop="content" width="160" show-overflow-tooltip>
+        <el-table-column :label="newData.trainingMode == 1?'签到时间':'学习时间'" prop="signTime" width="160" show-overflow-tooltip>
           <template slot-scope="scope">
-            <span>{{parseTime(scope.row.startTime,"{h}:{i}")}}</span>
+            <span>{{parseTime(scope.row.signTime,"{y}-{m}-{d} {h}:{i}")}}</span>
           </template>
         </el-table-column>
       </el-table>
@@ -52,6 +53,9 @@
 <script>
   //import { getDicts } from "@/api/commonality/noPermission";
   //import { systemUserSelect } from "@/api/commonality/permission";
+  import {
+    examElTrainingTaskProgressDetail,
+  } from "@/api/safetyEducationExaminationNew/index";
   export default {
     name: 'addPage',
     props: {
@@ -60,10 +64,12 @@
     data() {
       return {
         newData: {
-          newData1:'60',
-          newData2:'42',
-          newData3:'18',
-          newData4:'70',
+          newData1:'0',
+          newData2:'0',
+          newData3:'0',
+          newData4:'0',
+          trainingMode:null,
+          trainingName:'',
         },
         //查询条件
         queryParams: {
@@ -71,7 +77,7 @@
           pageSize: 20,
         },
         percentage:70,
-        dataList:[{status:1},{status:2},],
+        dataList:[],
         //数据数量
         total: 0,
       }
@@ -80,18 +86,24 @@
 
     },
     mounted() {
-      this.initialize()
+      this.getList()
     },
     methods: {
       format(percentage) {
         return percentage === 100 ? '' : '';
       },
-      // 初始化
-      initialize() {
-
-      },
       getList(){
-
+        examElTrainingTaskProgressDetail({ id: this.propsData.id }).then(response => {
+          this.$set(this,'newData',{
+            newData1:response.data.trainingMode==1?response.data.totalCount:response.data.participantCount,
+            newData2:response.data.trainingMode==1?response.data.signedCount:response.data.completedCount,
+            newData3:response.data.trainingMode==1?response.data.notSignedCount:response.data.notCompletedCount,
+            newData4:response.data.trainingMode==1?response.data.signRate:response.data.completionRate,
+            trainingMode:response.data.trainingMode,
+            trainingName:response.data.trainingName,
+          });
+          this.$set(this,'dataList',response.data.records);
+        })
       },
     }
   }

+ 108 - 60
src/views/safetyEducationExaminationNew/trainingManagement/trainingRecordDetails.vue

@@ -3,92 +3,93 @@
   <div class="page-container trainingRecordDetails-addPage">
     <div class="top-title-max-box">
       <div class="top-title-big-box">
-        <p>{{newData.newData1}}</p>
-        <p :class="newData.newData2==2?'back-color-b':'back-color-a'">{{newData.newData2==1?'未开始':(newData.newData2==2?'进行中':(newData.newData2==3?'已结束':''))}}</p>
-        <p>{{newData.newData3}}</p>
+        <p>{{newData.trainingName}}</p>
+        <p :class="newData.status==2?'back-color-b':'back-color-a'">{{newData.status==1?'未开始':(newData.status==2?'进行中':(newData.status==3?'已结束':''))}}</p>
+        <p>{{newData.categoryName}}</p>
       </div>
       <div class="top-title-box">
         <div>
           <p>培训时间:</p>
-          <p>{{newData.newData4}}</p>
+          <p>{{newData.startDate}} 至 {{newData.endDate}}</p>
         </div>
         <div>
           <p>培训地点:</p>
-          <p>{{newData.newData5}} {{newData.newData6}}</p>
+          <p>{{newData.locationText}}</p>
         </div>
       </div>
       <div class="top-title-box">
         <div>
           <p>主讲人:</p>
-          <p>{{newData.newData7}}</p>
+          <p>{{newData.speakerName}}</p>
         </div>
         <div>
           <p>可得学时:</p>
-          <p class="colorA">{{newData.newData8}}学时</p>
+          <p class="colorA">{{newData.creditHours}}学时</p>
         </div>
       </div>
       <div class="top-title-box">
         <div>
           <p>可得积分:</p>
-          <p class="colorB">{{newData.newData9}}积分</p>
+          <p class="colorB">{{newData.points}}积分</p>
         </div>
         <div>
           <p>获得证书:</p>
-          <p>{{newData.newData10}}</p>
+          <p>{{newData.certificateName?newData.certificateName:'- -'}}</p>
         </div>
       </div>
     </div>
     <div class="num-max-box">
       <div class="num-box">
-        <p>{{newData.newData11}}</p>
+        <p>{{newData.newData11?newData.newData11:0}}</p>
         <p>计划人数</p>
       </div>
       <div class="num-box">
-        <p>{{newData.newData12}}</p>
-        <p>已签到</p>
+        <p>{{newData.newData12?newData.newData12:0}}</p>
+        <p>{{newData.trainingMode == 1?'已签到':'已学习'}}</p>
       </div>
       <div class="num-box">
-        <p>{{newData.newData13}}</p>
-        <p>未签到</p>
+        <p>{{newData.newData13?newData.newData13:0}}</p>
+        <p>{{newData.trainingMode == 1?'未签到':'未学习'}}</p>
       </div>
       <div class="num-box">
-        <p>{{newData.newData14}}%</p>
-        <p>签到率</p>
+        <p>{{newData.newData14?newData.newData14:0}}%</p>
+        <p>{{newData.trainingMode == 1?'签到率':'完成率'}}</p>
       </div>
     </div>
     <p class="title-p">实验室生物安全操作规范培训</p>
     <div class="page-content-box">
       <el-table class="table-box" style="padding:0;" border :data="dataList">
-        <el-table-column label="姓名" prop="name" show-overflow-tooltip/>
-        <el-table-column label="学号" prop="content" width="120" show-overflow-tooltip/>
-        <el-table-column label="学院单位" prop="content" width="160" show-overflow-tooltip/>
-        <el-table-column label="签到状态" prop="content" width="100" show-overflow-tooltip>
+        <el-table-column label="姓名" prop="userName" show-overflow-tooltip/>
+        <el-table-column label="学号" prop="account" width="120" show-overflow-tooltip/>
+        <el-table-column label="学院单位" prop="deptName" width="160" show-overflow-tooltip/>
+        <el-table-column :label="newData.trainingMode == 1?'签到状态':'学习状态'" prop="content" width="100" show-overflow-tooltip>
           <template slot-scope="scope">
-            <p :class="scope.row.status==1?'color-a':(scope.row.status==2?'color-b':'')">{{scope.row.status==1?'已签到':(scope.row.status==2?'未签到':'')}}</p>
+            <p v-if="newData.trainingMode == 1" :class="scope.row.signStatus==0?'color-a':(scope.row.signStatus==1?'color-b':'')">{{scope.row.signStatus==0?'已签到':(scope.row.signStatus==1?'未签到':'')}}</p>
+            <p v-if="newData.trainingMode == 2" :class="scope.row.signStatus==0?'color-a':(scope.row.signStatus==1?'color-b':'')">{{scope.row.signStatus==0?'已学习':(scope.row.signStatus==1?'未学习':'')}}</p>
           </template>
         </el-table-column>
-        <el-table-column label="签到时间" prop="content" width="100" show-overflow-tooltip>
+        <el-table-column :label="newData.trainingMode == 1?'签到时间':'学习时间'" prop="content" width="140" show-overflow-tooltip>
           <template slot-scope="scope">
-            <span>{{parseTime(scope.row.startTime,"{h}:{i}")}}</span>
+            <span>{{parseTime(scope.row.signTime,"{y}-{m}-{d} {h}:{i}")}}</span>
           </template>
         </el-table-column>
-        <el-table-column label="获得学时" prop="content" width="100" show-overflow-tooltip>
+        <el-table-column label="获得学时" prop="creditHours" width="80" show-overflow-tooltip>
           <template slot-scope="scope">
-            <span class="colorA">{{scope.row.content}}</span>
+            <span class="colorA">{{scope.row.creditHours}}</span>
           </template>
         </el-table-column>
-        <el-table-column label="获得积分" prop="content" width="100" show-overflow-tooltip>
+        <el-table-column label="获得积分" prop="points" width="80" show-overflow-tooltip>
           <template slot-scope="scope">
-            <span class="colorB">{{scope.row.content}}</span>
+            <span class="colorB">{{scope.row.points}}</span>
           </template>
         </el-table-column>
-        <el-table-column label="培训证明" width="100" show-overflow-tooltip>
+        <el-table-column label="培训证明" width="80" show-overflow-tooltip>
           <template slot-scope="scope">
             <div class="table-button-box">
               <p class="table-button-null"></p>
               <p class="table-button-p"
+                 v-if="scope.row.proofImages"
                  @click="tableButton(1,scope.row)"
-                 v-hasPermiRouter="['demo:demo:detail']"
               >查看</p>
               <p class="table-button-null"></p>
             </div>
@@ -99,12 +100,12 @@
             <div class="table-button-box">
               <p class="table-button-null"></p>
               <p class="table-button-p"
+                 v-if="scope.row.certificatePath"
                  @click="tableButton(2,scope.row)"
-                 v-hasPermiRouter="['demo:demo:detail']"
               >查看证书</p>
               <p class="table-button-p"
+                 v-if="scope.row.certificatePath"
                  @click="tableButton(3,scope.row)"
-                 v-hasPermiRouter="['demo:demo:detail']"
               >下载</p>
               <p class="table-button-null"></p>
             </div>
@@ -129,8 +130,9 @@
 <script>
   import fullScreenView from "@/components/fullScreenView/fullScreenView.vue";
   import fullScreenFileLook from "@/components/fullScreenFileLook/fullScreenFileLook.vue";
-  //import { getDicts } from "@/api/commonality/noPermission";
-  //import { systemUserSelect } from "@/api/commonality/permission";
+  import {
+    examElTrainingTaskProgressDetail,
+  } from "@/api/safetyEducationExaminationNew/index";
   export default {
     name: 'addPage',
     components: {
@@ -143,27 +145,28 @@
     data() {
       return {
         newData: {
-          newData1:'辐射安全基础知识讲座',
-          newData2:'1',
-          newData3:'知识讲座',
-          newData4:'2026-07-20 14:00–16:00',
-          newData5:'物理楼',
-          newData6:'C301',
-          newData7:'陈教授',
-          newData8:'2 学时',
-          newData9:'10',
-          newData10:'实验室安全培训证书(通用)',
-          newData11:'40',
-          newData12:'18',
-          newData13:'24',
-          newData14:'60',
+          status:'',
+          categoryName:'',
+          startDate:'',
+          endDate:'',
+          locationText:'',
+          speakerName:'',
+          creditHours:'',
+          points:'',
+          certificateName:'实验室安全培训证书(通用)',
+          newData11:'0',
+          newData12:'0',
+          newData13:'0',
+          newData14:'0',
+          trainingMode:null,
+          trainingName:'',
         },
         //查询条件
         queryParams: {
           page: 1,
           pageSize: 20,
         },
-        dataList:[{status:1},{status:2},],
+        dataList:[],
         //数据数量
         total: 0,
         //预览图片
@@ -174,34 +177,79 @@
 
     },
     mounted() {
-      this.initialize()
+      this.getList()
     },
     methods: {
-      // 初始化
-      initialize() {
-
-      },
       getList(){
-
+        examElTrainingTaskProgressDetail({ id: this.propsData.id }).then(response => {
+          this.$set(this,'newData',{
+            newData11:response.data.trainingMode==1?response.data.totalCount:response.data.participantCount,
+            newData12:response.data.trainingMode==1?response.data.signedCount:response.data.completedCount,
+            newData13:response.data.trainingMode==1?response.data.notSignedCount:response.data.notCompletedCount,
+            newData14:response.data.trainingMode==1?response.data.signRate:response.data.completionRate,
+            trainingMode:response.data.trainingMode,
+            trainingName:response.data.trainingName,
+            certificateName:response.data.certificateName,
+            creditHours:response.data.creditHours,
+            points:response.data.points,
+            status:response.data.status,
+            categoryName:response.data.categoryName,
+            startDate:response.data.startDate,
+            endDate:response.data.endDate,
+            locationText:response.data.locationText,
+            speakerName:response.data.speakerName,
+          });
+          this.$set(this,'dataList',response.data.records);
+        })
       },
-      tableButton(type){
+      tableButton(type,row){
         if(type == 1){
-
+          //培训证明-图片
+          let list = row.proofImages.split(",");
+          // let list = [
+          //   'https://img2.baidu.com/it/u=3422287847,344441285&fm=253&fmt=auto&app=138&f=JPEG?w=604&h=500',
+          //   'https://img1.baidu.com/it/u=597103012,1095897037&fm=253&fmt=auto&app=138&f=JPEG?w=536&h=500',
+          //   'https://img1.baidu.com/it/u=1888248120,3171390833&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=332',
+          // ]
+          this.fullScreenViewClick(list)
         }else if(type == 2){
-
+          //培训证书-pdf
+          this.fullScreenFileLookClick({
+            name:this.newData.certificateName,
+            url:localStorage.getItem('fileBrowseEnvironment') +'/'+row.certificatePath,
+            type:'pdf',
+          });
         }else if(type == 3){
-
+          //下载-pdf
+          this.downloadOffice(this.newData.certificateName,row.certificatePath)
         }
       },
       //查看图片
-      fullScreenViewClick(url){
-        this.$set(this,'fullScreenViewProps',[url]);
+      fullScreenViewClick(list){
+        this.$set(this,'fullScreenViewProps',list);
         this.$refs['fullScreenView'].initialize();
       },
       //查看文件
       fullScreenFileLookClick(item){
         this.$refs['fullScreenFileLook'].initialize(item.name,item.url,item.type);
       },
+      //下载
+      async downloadOffice(lookUrl,lookName) {
+        // 获取图片对象和画布对象
+        const imgUrl = lookUrl
+        const response = await fetch(imgUrl)
+        const blob = await response.blob()
+        // 创建下载链接
+        const url = window.URL.createObjectURL(blob)
+        const link = document.createElement('a')
+        link.href = url
+        link.download = lookName
+        document.body.appendChild(link)
+        link.click()
+        document.body.removeChild(link)
+        // 释放 Blob URL
+        window.URL.revokeObjectURL(url)
+      },
     }
   }
 </script>

+ 374 - 0
src/views/safetyEducationExaminationNew/trainingManagement/trainingTask/index.vue

@@ -0,0 +1,374 @@
+<!-- 培训任务 -->
+<template>
+  <div class="app-container trainingTask">
+    <div class="page-container trainingTaskPage" v-if="pageType === 1">
+      <div class="page-form-title-box">
+        <el-form :model="queryParams" class="form-box" ref="queryForm"
+                 :inline="true" style="width:100%;"
+        >
+          <el-form-item label="" prop="queryParamsData1">
+            <div class="table-top-button-box">
+              <div>
+                <p :class="queryParams.queryParamsData1 === ''?'check-table-button':''" @click="tableTypeButton('')">全部</p>
+                <p :class="queryParams.queryParamsData1 === 1?'check-table-button':''" @click="tableTypeButton(1)">线下培训</p>
+                <p :class="queryParams.queryParamsData1 === 2?'check-table-button':''" @click="tableTypeButton(2)">线上培训</p>
+              </div>
+            </div>
+          </el-form-item>
+          <el-form-item label="" prop="queryParamsData2">
+            <el-select v-model="queryParams.queryParamsData2" placeholder="状态" style="width: 160px">
+              <el-option
+                v-for="dict in optionListA"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="" prop="queryParamsData3">
+            <el-input
+              maxLength="30"
+              v-model="queryParams.queryParamsData3"
+              placeholder="搜索培训名称、主讲人"
+              style="width: 400px"
+            />
+          </el-form-item>
+          <el-form-item label="" prop="queryParamsData4">
+            <el-select v-model="queryParams.queryParamsData4" placeholder="分类" style="width: 160px">
+              <el-option
+                v-for="dict in optionListB"
+                :key="dict.id"
+                :label="dict.categoryName"
+                :value="dict.id"
+              />
+            </el-select>
+          </el-form-item>
+          <p class="page-inquire-common-style-button" @click="handleQuery">查询</p>
+          <p class="page-reset-common-style-button" @click="resetQuery">重置</p>
+        </el-form>
+      </div>
+      <div class="page-content-box">
+        <div class="for-max-big-box">
+          <div class="for-big-box" @click="tableButton(item)" v-for="(item,index) in dataList" :key="index">
+            <div class="top-img-box">
+              <!--<img v-if="item.coverImage" src="item.coverImage">-->
+              <!--<img v-else src="@/assets/ZDimages/basicsModules/image_986222064626770.png">-->
+              <img src="@/assets/ZDimages/basicsModules/image_986222064626770.png">
+              <p class="position-type-p" :class="item.status==2?'colorA':'colorB'">{{item.status==1?'未开始':(item.status==2?'进行中':(item.status==3?'已结束':''))}}</p>
+              <p class="position-time-p">{{item.trainingMode==1?'线上':'线下'}} {{item.trainingMode==1?'课件':''}}</p>
+            </div>
+            <div class="bottom-text-box">
+              <p class="title-p">{{item.trainingName}}</p>
+              <p class="time-p">{{item.startDate}} 至 {{item.endDate}}</p>
+              <!--<p class="address-p">{{item.startDate}} 至 {{item.endDate}}</p>-->
+              <p class="address-p">{{item.locationText}}</p>
+              <div class="bottom-min-text-box">
+                <p class="min-p-1">{{item.categoryName}}</p>
+                <p class="min-p-2">{{item.creditHours}}学时 {{item.points}}积分</p>
+                <div class="type-box" v-if="item.trainingMode==1" :class="item.signStatus==0?'':'check-p'">
+                  <p :class="item.signStatus==0?'':'el-icon-check'"></p>
+                  <p>{{item.signStatus==0?'未签到':'已签到'}}</p>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+        <pagination :page-sizes="[20, 30, 40, 50]"
+                    style="margin:0 20px;"
+                    v-show="total>0"
+                    :total="total"
+                    :page.sync="queryParams.page"
+                    :limit.sync="queryParams.pageSize"
+                    @pagination="getList"
+        />
+      </div>
+    </div>
+    <el-dialog class="trainingTask-dialog"
+               :modal-append-to-body="false"
+               :close-on-click-modal="false" :close-on-press-escape="false"
+               :title="dialogTitle"
+               :visible.sync="dialogType"
+               v-if="dialogType"
+               width="760px"
+               append-to-body>
+      <div class="trainingTask-dialog-content">
+        <info-page :propsData="propsData"></info-page>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+  import {
+    examElTrainingCategorySimpleList,examUserTrainingList,
+  } from "@/api/safetyEducationExaminationNew/index";
+  //import { getDicts } from "@/api/commonality/noPermission";
+  //import { systemUserSelect } from "@/api/commonality/permission";
+  //import { getInfo } from "@/api/basicsModules/index";
+  import infoPage from "./infoPage.vue";
+  export default {
+    name: 'index',
+    components: {
+     infoPage
+    },
+    data() {
+      return {
+        tableButtonType: this.hasPermiDom(['demo:demo:detail', 'demo:demo:edit', 'demo:demo:del']),
+        //页面状态
+        pageType: 1,
+        //下拉列表数据
+        optionListA: [{ value: 1, label: '未开始' }, { value: 2, label: '进行中' }, { value: 3, label: '已结束' }],
+        optionListB: [],
+        //查询条件
+        queryParams: {
+          page: 1,
+          pageSize: 8,
+          queryParamsData1: '',
+          queryParamsData2: null,
+          queryParamsData3: '',
+          queryParamsData4: null,
+        },
+        //列表数据
+        dataList: [],
+        //数据数量
+        total: 0,
+        //组件传参
+        propsData: {},
+        //弹窗
+        dialogTitle:'',
+        dialogType:false,
+      }
+    },
+    created() {
+
+    },
+    mounted() {
+      this.examElTrainingCategorySimpleList();
+      this.getList();
+    },
+    methods: {
+      tableTypeButton(val){
+        if(this.queryParams.queryParamsData1 !== val){
+          this.$set(this.queryParams,'queryParamsData1',val);
+          // this.handleQuery();
+        }
+      },
+      //查询按钮
+      handleQuery() {
+        this.$set(this.queryParams, 'page', 1)
+        this.getList()
+      },
+      //重置按钮
+      resetQuery() {
+        this.$set(this, 'queryParams', {
+          page: 1,
+          pageSize: 8,
+          queryParamsData1: '',
+          queryParamsData2: null,
+          queryParamsData3: '',
+          queryParamsData4: null,
+        })
+        this.getList()
+      },
+      //获取数据列表
+      getList() {
+        let obj = JSON.parse(JSON.stringify(this.queryParams))
+        examUserTrainingList(obj).then(response => {
+          let list = [
+            ...response.data.records,...response.data.records,
+            ...response.data.records,...response.data.records,
+            ...response.data.records,...response.data.records,
+            ...response.data.records,...response.data.records
+          ];
+          this.$set(this,'dataList',list);
+          // this.$set(this, 'dataList', response.data.records)
+          this.$set(this, 'total', response.data.total)
+        })
+      },
+      //操作按钮
+      tableButton(row) {
+        this.$set(this,'dialogTitle',row.trainingName);
+        this.$set(this,'propsData',{id:row.id});
+        this.$set(this,'dialogType',true);
+      },
+      //培训分类列表
+      examElTrainingCategorySimpleList(){
+        examElTrainingCategorySimpleList({}).then(response => {
+          this.$set(this,'optionListB',response.data);
+        });
+      },
+    }
+  }
+</script>
+<style scoped lang="scss">
+  .trainingTask {
+    .trainingTaskPage {
+      .page-content-box{
+        padding:10px 0 20px 10px;
+      }
+      .table-top-button-box{
+        display: inline-block;
+        vertical-align: top;
+        div{
+          display: flex;
+          p{
+            border:1px solid #DCDFE6;
+            padding:0 20px;
+            text-align: center;
+            height:40px;
+            line-height:40px;
+            cursor: pointer;
+            font-size:14px;
+          }
+          p:nth-child(1){
+            border-top-left-radius:4px;
+            border-bottom-left-radius:4px;
+          }
+          p:nth-child(2){
+            border-left:none;
+            border-right:none;
+          }
+          p:nth-child(3){
+            border-top-right-radius:4px;
+            border-bottom-right-radius:4px;
+          }
+          .check-table-button{
+            border:1px solid #0183fa;
+            background-color: #0183fa;
+            color:#fff;
+          }
+        }
+      }
+      .for-max-big-box{
+        flex:1;
+        .for-big-box{
+          display: inline-block;
+          overflow: hidden;
+          width:377px;
+          height:300px;
+          margin:10px 0 0 10px;
+          background: #ffffff;
+          border: 1px solid #dde3ed;
+          border-radius: 8px;
+          cursor: pointer;
+          transition: all .2s;
+          box-shadow: 0 2px 12px rgba(24, 87, 212, .08);
+          .top-img-box{
+            width:377px;
+            height:160px;
+            position: relative;
+            img{
+              width:377px;
+              height:160px;
+              display: block;
+
+            }
+            .position-type-p{
+              position: absolute;
+              top:10px;
+              left:10px;
+              font-size:12px;
+              padding:2px 10px;
+              line-height:14px;
+              color:#fff;
+              border-radius:10px;
+            }
+            .position-time-p{
+              position: absolute;
+              bottom:10px;
+              right:10px;
+              font-size:12px;
+              padding:2px 10px;
+              line-height:14px;
+              color:#fff;
+              border-radius:10px;
+              background-color: #0183fa;
+            }
+            .colorA{
+              background-color: rgba(230, 126, 34, .9);
+            }
+            .colorB{
+              background-color: rgba(136, 150, 167, .9);;
+            }
+          }
+          .bottom-text-box{
+            padding:20px;
+            .title-p{
+              font-size: 15px;
+              font-weight: 600;
+              color: #333;
+              margin-bottom: 10px;
+            }
+            .time-p{
+              height:20px;
+              font-size:13px;
+              line-height:20px;
+              color:#8896a7;
+            }
+            .address-p{
+              height:20px;
+              font-size:13px;
+              line-height:20px;
+              color:#8896a7;
+            }
+            .bottom-min-text-box{
+              display: flex;
+              margin-top:10px;
+              .min-p-1{
+                height: 18px;
+                padding:2px 10px;
+                border-radius: 20px;
+                font-size: 12px;
+                line-height:14px;
+                background-color: #eef3fd;
+                color:#1857d4;
+              }
+              .min-p-2{
+                height: 18px;
+                flex:1;
+                color:#10a37f;
+                padding:2px 20px;
+                font-size: 12px;
+                line-height:14px;
+              }
+              .type-box{
+                height: 18px;
+                color:#fa8c16;
+                padding:2px 0;
+                font-size: 12px;
+                line-height:14px;
+                overflow: hidden;
+                display: flex;
+                p:nth-child(1){
+                  display: inline-block;
+                  width:5px;
+                  height:5px;
+                  background-color:#fa8c16;
+                  border-radius:50%;
+                  margin:5px 4px;
+                }
+              }
+              .check-p{
+                color:#52c41a!important;
+                p:nth-child(1){
+                  line-height:18px;
+                  margin:0 !important;
+                  width:18px!important;
+                  height: 18px!important;
+                  background-color:#ffffff!important;
+                  color:#52c41a!important;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+</style>
+<style lang="scss">
+  .trainingTask-dialog{
+    .el-dialog__body{
+      padding:20px;
+    }
+  }
+</style>

+ 232 - 0
src/views/safetyEducationExaminationNew/trainingManagement/trainingTask/infoPage.vue

@@ -0,0 +1,232 @@
+<!-- 详情弹窗 -->
+<template>
+  <div class="trainingTask-addPage">
+    <div class="top-type-box">
+      <p>暂时没有字段</p>
+      <p>{{newData.trainingMode==1?'线上培训':'线下培训'}}</p>
+      <p>暂时没有字段</p>
+    </div>
+    <div class="title-box">
+      <p></p>
+      <p>培训信息</p>
+    </div>
+    <div class="table-text-box">
+      <div>
+        <p>培训时间</p>
+        <p>{{newData.startDate}} 至 {{newData.startDate}}</p>
+      </div>
+      <div v-if="newData.trainingMode==2">
+        <p>组织地点</p>
+        <p>{{newData.locationText}}</p>
+      </div>
+      <div>
+        <p>组织单位</p>
+        <p>{{newData.orgDeptName}}</p>
+      </div>
+      <div v-if="newData.trainingMode==2">
+        <p>主讲人</p>
+        <p>{{newData.speakerName}}</p>
+      </div>
+      <div v-if="newData.trainingMode==2">
+        <p>可得学时</p>
+        <p>{{newData.creditHours}}</p>
+      </div>
+      <div v-if="newData.trainingMode==2">
+        <p>可得学分</p>
+        <p>{{newData.points}}</p>
+      </div>
+      <div v-if="newData.trainingMode==1">
+        <p>参与人数</p>
+        <p>暂时没有字段</p>
+      </div>
+    </div>
+    <div class="title-box">
+      <p></p>
+      <p>培训说明</p>
+    </div>
+    <div class="rich-text-box" v-html="newData.detailContent"></div>
+    <div class="title-box" v-if="newData.trainingMode==1">
+      <p></p>
+      <p>培训课件</p>
+    </div>
+    <div class="max-for-box" v-if="newData.trainingMode==1">
+      <p class="for-title-p">学员每完成一个课件的学习,获得对应课件的学时和积分</p>
+      <div class="for-max-box" v-for="(item,index) in coursewares" :key="index">
+        <p class="left-icon-p"></p>
+        <div class="text-box">
+          <p>{{item.coursewareName}}</p>
+          <p>{{item.materialType==1?'视频':(item.materialType==3?'文档':(item.materialType==4?'文章':''))}} · 约{{secondsToMinutes(item.minLearningDuration)}}分钟</p>
+        </div>
+        <div class="num-box">
+          <!--<p>+{{}}学时</p>-->
+          <!--<p>+{{}}积分</p>-->
+        </div>
+        <p class="right-p">已学习/未学习</p>
+      </div>
+      <p></p>
+      <div>
+        <p>学习进度</p>
+        <p>/ 课件已完成</p>
+      </div>
+    </div>
+    <div class="title-box">
+      <p></p>
+      <p>附件</p>
+    </div>
+  </div>
+</template>
+
+<script>
+import {
+  examUserTrainingDetail
+} from "@/api/safetyEducationExaminationNew/index";
+  //import { getDicts } from "@/api/commonality/noPermission";
+  //import { systemUserSelect } from "@/api/commonality/permission";
+  export default {
+    name: 'addPage',
+    props: {
+      propsData: {}
+    },
+    data() {
+      return {
+        newData: {}
+      }
+    },
+    created() {
+
+    },
+    mounted() {
+      this.examUserTrainingDetail()
+    },
+    methods: {
+      examUserTrainingDetail(){
+        examUserTrainingDetail({id:this.propsData.id}).then(response => {
+          this.$set(this,'newData',response.data);
+        });
+      },
+      //展示时间换算
+      secondsToMinutes(totalSeconds) {
+        if (typeof totalSeconds !== 'number' || totalSeconds <= 0) {
+          return 1;
+        }
+        return Math.ceil(totalSeconds / 60);
+      },
+    }
+  }
+</script>
+
+<style scoped lang="scss">
+  .trainingTask-addPage {
+    .title-box{
+      display: flex;
+      p:nth-child(1){
+        width:4px;
+        height:16px;
+        background: linear-gradient(180deg, #2e6fe0, #0f3ea8);
+        border-radius:4px;
+        margin:2px 10px 20px 0;
+      }
+      p:nth-child(2){
+        line-height:20px;
+      }
+    }
+    .top-type-box{
+      display: flex;
+      margin-bottom:20px;
+      p:nth-child(1){
+        background-color: #fff7e6;
+        border:1px solid rgb(255, 213, 145);
+        color:#fa8c16;
+        font-size: 12px;
+        line-height:14px;
+        border-radius:10px;
+        padding:2px 10px;
+      }
+      p:nth-child(2){
+        line-height:20px;
+        font-size:12px;
+        color:#1857d4;
+        margin:0 20px;
+      }
+      p:nth-child(3){
+        line-height:20px;
+        font-size:12px;
+        color:#1857d4;
+      }
+    }
+    .table-text-box{
+      border:1px solid #dde3ed;
+      border-radius:8px;
+      margin-bottom:20px;
+      div:nth-child(1){
+        border-top:none;
+      }
+      div{
+        display: flex;
+        border-top:1px solid #dde3ed;
+        p{
+          padding:11px 16px;
+          font-size:14px;
+          line-height:14px;
+        }
+        p:nth-child(1){
+          width:190px;
+          color:#8896a7;
+          background-color: #f4f6fa;
+        }
+        p:nth-child(2){
+
+        }
+      }
+    }
+    .max-for-box{
+      .for-title-p{
+        color:#8896a7;
+        font-size:12px;
+        margin-bottom:12px;
+      }
+      .for-max-box{
+        .left-icon-p{
+
+        }
+        .text-box{
+
+        }
+        .num-box{
+
+        }
+        .right-p{
+
+        }
+      }
+
+    }
+    .rich-text-box {
+      border:1px solid #dde3ed;
+      padding:5px 10px;
+      border-radius:8px;
+      margin-bottom:20px;
+      flex:1;
+      background-color: #fff;
+      line-height: 1.6; /* 基础行高 */
+      word-break: break-word; /* 防止长单词或长链接撑破布局 */
+    }
+
+    /* 穿透样式,控制富文本内部的标签 */
+    .rich-text-box ::v-deep img {
+      max-width: 100% !important; /* 防止图片超出容器 */
+      height: auto !important;
+      display: block;
+      margin: 10px auto;
+    }
+
+    .rich-text-box ::v-deep table {
+      width: 100%;
+      border-collapse: collapse;
+    }
+
+    .rich-text-box ::v-deep p {
+      margin-bottom: 10px;
+    }
+  }
+</style>