dedsudiyu 5 days ago
parent
commit
1355670da0
20 changed files with 2190 additions and 1039 deletions
  1. 96 0
      src/api/safetyEducationExaminationNew/index.js
  2. 51 0
      src/assets/styles/commonality.scss
  3. 35 1
      src/components/fullScreenFileLook/fullScreenFileLook.vue
  4. 1 1
      src/utils/ruoyi.js
  5. 90 22
      src/views/safetyEducationExaminationNew/courseManagement/courseManagement/addPage.vue
  6. 1 0
      src/views/safetyEducationExaminationNew/courseManagement/courseManagement/afterClassEvaluation.vue
  7. 66 31
      src/views/safetyEducationExaminationNew/courseManagement/courseManagement/basicSettings.vue
  8. 148 51
      src/views/safetyEducationExaminationNew/courseManagement/courseManagement/drawerItem.vue
  9. 131 76
      src/views/safetyEducationExaminationNew/courseManagement/courseManagement/index.vue
  10. 146 51
      src/views/safetyEducationExaminationNew/courseManagement/courseManagement/studyCourses.vue
  11. 256 130
      src/views/safetyEducationExaminationNew/courseManagement/coursewareManagement/addPage.vue
  12. 135 68
      src/views/safetyEducationExaminationNew/courseManagement/coursewareManagement/index.vue
  13. 40 38
      src/views/safetyEducationExaminationNew/questionBankManagement/questionBankManagement/index.vue
  14. 229 130
      src/views/safetyEducationExaminationNew/workbench/ExamStatsCard.vue
  15. 136 66
      src/views/safetyEducationExaminationNew/workbench/ResourceCard.vue
  16. 84 46
      src/views/safetyEducationExaminationNew/workbench/SafetyPersonChart.vue
  17. 126 69
      src/views/safetyEducationExaminationNew/workbench/StudentStats.vue
  18. 116 138
      src/views/safetyEducationExaminationNew/workbench/TaskCard.vue
  19. 292 101
      src/views/safetyEducationExaminationNew/workbench/UserInfoCard.vue
  20. 11 20
      src/views/safetyEducationExaminationNew/workbench/index.vue

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

@@ -153,4 +153,100 @@ export function examElKnowledgePointDel(data) {
     data: data
   })
 }
+//查询课件列表
+export function examElCoursewarePage(data) {
+  return request({
+    url: '/exam/elCourseware/page',
+    method: 'post',
+    data: data
+  })
+}
+//删除课件
+export function examElCoursewareDel(data) {
+  return request({
+    url: '/exam/elCourseware/del',
+    method: 'post',
+    data: data
+  })
+}
+//新增课件
+export function examElCoursewareAdd(data) {
+  return request({
+    url: '/exam/elCourseware/add',
+    method: 'post',
+    data: data
+  })
+}
+//编辑课件
+export function examElCoursewareEdit(data) {
+  return request({
+    url: '/exam/elCourseware/edit',
+    method: 'post',
+    data: data
+  })
+}
+//课件详情
+export function examElCoursewareDetail(query) {
+  return request({
+    url: '/exam/elCourseware/detail',
+    method: 'get',
+    params: query
+  })
+}
+//课程列表
+export function examElCoursePage(data) {
+  return request({
+    url: '/exam/elCourse/page',
+    method: 'post',
+    data: data
+  })
+}
+//课程删除
+export function examElCourseDel(data) {
+  return request({
+    url: '/exam/elCourse/del',
+    method: 'post',
+    data: data
+  })
+}
+//课程新增
+export function examElCourseAdd(data) {
+  return request({
+    url: '/exam/elCourse/add',
+    method: 'post',
+    data: data
+  })
+}
+//课程编辑
+export function examElCourseEdit(data) {
+  return request({
+    url: '/exam/elCourse/edit',
+    method: 'post',
+    data: data
+  })
+}
+//课程详情
+export function examElCourseDetail(query) {
+  return request({
+    url: '/exam/elCourse/detail',
+    method: 'get',
+    params: query
+  })
+}
+//课程复制
+export function examElCourseCopy(data) {
+  return request({
+    url: '/exam/elCourse/copy',
+    method: 'post',
+    data: data
+  })
+}
+//试题管理列表
+export function examElQuestionBankList(data) {
+  return request({
+    url: '/exam/elQuestionBank/list',
+    method: 'post',
+    data: data
+  })
+}
 

+ 51 - 0
src/assets/styles/commonality.scss

@@ -1353,6 +1353,57 @@
     cursor: pointer;
   }
 }
+.page-container-top-max-big-box-shadow {
+  height: 60px;
+  display: flex;
+  overflow: hidden;
+  padding: 0 20px;
+  align-items: center;
+  margin:5px 20px 10px 10px;
+  box-shadow: 0 0 8px 1px rgba(0, 0, 0, 0.1);
+  border-radius:6px;
+
+  .top-1-p {
+    flex: 1;
+    font-size: 16px;
+  }
+
+  .top-2-p {
+    height: 35px;
+    line-height: 33px;
+    margin-left: 20px;
+    padding: 0 20px;
+    border-radius: 4px;
+    background-color: #fff;
+    border: 1px solid #999;
+    color: #999;
+    cursor: pointer;
+  }
+
+  .top-3-p {
+    height: 35px;
+    line-height: 33px;
+    margin-left: 20px;
+    padding: 0 20px;
+    border-radius: 4px;
+    background-color: #dedede;
+    border: 1px solid #dedede;
+    color: #333;
+    cursor: pointer;
+  }
+
+  .top-4-p {
+    height: 35px;
+    line-height: 33px;
+    margin-left: 20px;
+    padding: 0 20px;
+    border-radius: 4px;
+    background-color: #0183fa;
+    border: 1px solid #0183fa;
+    color: #fff;
+    cursor: pointer;
+  }
+}
 /************* 单选按钮 位置修复 ****************/
 .el-radio{
   margin-top:5px;

+ 35 - 1
src/components/fullScreenFileLook/fullScreenFileLook.vue

@@ -24,7 +24,7 @@
     <div class="fullScreenFileLook" v-if="showType">
       <div class="fullScreenFileLook-top-button-box">
         <!--下载按钮-->
-        <p class="position-download-p el-icon-download" @click="downloadOffice" v-if="!officeNullType"></p>
+        <p class="position-download-p el-icon-download" @click="downloadOffice" v-if="!officeNullType&&officeType!='text'"></p>
         <p class="title-p">{{lookName}}</p>
         <!--关闭按钮-->
         <p class="position-off-p el-icon-circle-close" @click="outButton"></p>
@@ -50,6 +50,8 @@
             @error="errorHandler"
           />
           <p v-if="officeNullType" class="office-null-text">加载失败...</p>
+          <video v-if="officeType === 'video'" class="video-box" :src="lookUrl" controls></video>
+          <div  v-if="officeType === 'text'" class="rich-text-box" v-html="lookUrl"></div>
         </transition>
       </div>
     </div>
@@ -95,6 +97,9 @@
     methods: {
       //初始化
       initialize(name,url,type){
+        console.log('name',name)
+        console.log('url',url)
+        console.log('type',type)
         if(name&&url&&type){
           this.$set(this,'officeType',type);
           this.$set(this,'lookName',name);
@@ -204,6 +209,8 @@
     }
     .max-img-box{
       flex:1;
+      display: flex;
+      flex-direction: column;
       overflow: scroll;
       position: relative;
       .office-null-text{
@@ -212,6 +219,33 @@
         color:#dedede;
         font-size:16px;
       }
+      .video-box{
+        flex:1;
+      }
+      .rich-text-box {
+        padding:20px 100px;
+        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;
+      }
     }
     //滚动条样式
     .max-img-box::-webkit-scrollbar{

+ 1 - 1
src/utils/ruoyi.js

@@ -219,7 +219,7 @@ export function download(fileName) {
 
 // 通用上传地址
 export function uploadUrl() {
-  return baseURL + "/system/file/upload";
+  return baseURL + "/exam/file/upload";
 }
 
 // 字符串格式化(%s )

+ 90 - 22
src/views/safetyEducationExaminationNew/courseManagement/courseManagement/addPage.vue

@@ -1,10 +1,10 @@
 <!--新建课程-->
 <template>
-  <div class="courseManagement-addPage">
-    <div class="page-container-top-max-big-box">
+  <div class="page-container courseManagement-addPage">
+    <div class="page-container-top-max-big-box-shadow">
       <p class="top-1-p">{{newData.id?'编辑课程':'新建课程'}}</p>
       <p class="top-2-p" @click="backPage()">返回</p>
-      <p class="top-3-p" @click="resetButton()">重置</p>
+      <p class="top-3-p" v-if="newData.id" @click="resetButton()">重置</p>
       <p class="top-4-p" @click="submitButton()">保存</p>
     </div>
     <div class="bottom-max-big-box">
@@ -13,9 +13,9 @@
            @click="tableButton(item.value)"
            v-for="(item,index) in buttonList" :key="index">{{item.name}}</p>
       </div>
-      <basicSettings class="right-max-big-box" v-if="buttonType == 1"></basicSettings>
-      <studyCourses class="right-max-big-box" v-if="buttonType == 2"></studyCourses>
-      <afterClassEvaluation class="right-max-big-box" v-if="buttonType == 3"></afterClassEvaluation>
+      <basicSettings ref="basicSettings" class="right-max-big-box" v-show="buttonType == 1"></basicSettings>
+      <studyCourses ref="studyCourses" class="right-max-big-box" v-show="buttonType == 2"></studyCourses>
+      <afterClassEvaluation class="right-max-big-box" v-show="buttonType == 3"></afterClassEvaluation>
     </div>
   </div>
 </template>
@@ -24,6 +24,7 @@
   //import { getDicts } from "@/api/commonality/noPermission";
   //import { systemUserSelect } from "@/api/commonality/permission";
   //import { getInfo } from "@/api/basicsModules/index";
+  import { examElCourseAdd,examElCourseDetail } from "@/api/safetyEducationExaminationNew/index";
   import basicSettings from "./basicSettings.vue";
   import studyCourses from "./studyCourses.vue";
   import afterClassEvaluation from "./afterClassEvaluation.vue";
@@ -54,37 +55,104 @@
 
     },
     mounted(){
-
+      if (this.propsData.id){
+        this.$set(this,'newData',{
+          id:this.propsData.id
+        });
+        this.$nextTick(()=>{
+          this.examElCourseDetail();
+        })
+      }
     },
     methods:{
-      // 返回按钮
-      backPage(){
-        this.$parent.tableButton(6);
+      //课程详情
+      examElCourseDetail(){
+        examElCourseDetail({id:this.newData.id}).then(response => {
+          console.log('1111')
+          this.$refs.basicSettings.setDataInfo({
+            disciplineTypeId:'',
+            shelfStatus:response.data.shelfStatus,
+            shareStatus:response.data.shareStatus,
+            courseName:response.data.courseName,
+            coverAttachmentPath:response.data.coverAttachmentPath,
+          })
+          this.$refs.studyCourses.setDataInfo({
+
+          })
+        });
       },
+      //切换按钮
       tableButton(val){
         if(this.buttonType != val){
           this.$set(this,'buttonType',val);
         }
       },
+      //重置
       resetButton(){
-        if(this.buttonType == 1){
-          this.$refs.examinationConfiguration.resetButton();
-        }else if(this.buttonType == 2){
-          this.$refs.gradingConfiguration.resetButton();
-        }else if(this.buttonType == 3){
-          this.$refs.classHoursConfiguration.resetButton();
-        }
+
+      },
+      // 返回按钮
+      backPage(){
+        this.$parent.tableButton(6);
       },
       //提交
       submitButton(){
         if(this.buttonType == 1){
-          this.$refs.examinationConfiguration.submitButton();
-        }else if(this.buttonType == 2){
-          this.$refs.gradingConfiguration.submitButton();
-        }else if(this.buttonType == 3){
-          this.$refs.classHoursConfiguration.submitButton();
+          this.$refs.basicSettings.submitButton()
+        }else{
+          this.$refs.basicSettings.checkTheData()
         }
       },
+      pageDataA(data){
+        this.$refs.studyCourses.checkTheData()
+      },
+      pageDataB(data){
+        let self = this;
+        this.$confirm('是否确认保存?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+        }).then(() => {
+          let basicData = JSON.parse(JSON.stringify(this.$refs.basicSettings.newData))
+          let studyData = JSON.parse(JSON.stringify(this.$refs.studyCourses.dataList))
+          let obj = {
+            disciplineTypeId:basicData.disciplineTypeId,
+            shelfStatus:basicData.shelfStatus,
+            shareStatus:basicData.shareStatus,
+            courseName:basicData.courseName,
+            coverAttachmentPath:basicData.coverAttachmentPath,
+            assessmentStatus:0,
+            assessmentTotalScore:0,
+            assessmentPassScore:0,
+            assessmentAnswerDuration:0,
+            coursewareIds:[],
+          }
+          for(let i=0;i<studyData.length;i++){
+            for(let o=0;o<studyData[i].minList.length;o++){
+              obj.coursewareIds.push(studyData[i].minList[o].id)
+            }
+          }
+          if(self.newData.id){
+            self.examElCourseEdit(obj);
+          }else{
+            self.examElCourseAdd(obj);
+          }
+        }).catch(() => {});
+      },
+      examElCourseAdd(obj){
+        examElCourseAdd(obj).then(response => {
+          this.msgSuccess(response.message);
+          this.$parent.tableButton(6);
+        });
+      },
+      examElCourseEdit(obj){
+        obj.id = this.newData.id
+        examElCourseAdd(obj).then(response => {
+          this.msgSuccess(response.message);
+          this.$parent.tableButton(6);
+        });
+      },
     },
   }
 </script>

+ 1 - 0
src/views/safetyEducationExaminationNew/courseManagement/courseManagement/afterClassEvaluation.vue

@@ -22,6 +22,7 @@
     data(){
       return{
         newData:{},
+        rules:{}
       }
     },
     created(){

+ 66 - 31
src/views/safetyEducationExaminationNew/courseManagement/courseManagement/basicSettings.vue

@@ -5,45 +5,45 @@
         <div class="form-big-box">
           <div class="form-box">
             <div class="form-flex-box">
-              <el-form-item label="课程分类" prop="data1">
-                <el-select v-model="newData.data1" placeholder="请选择课程类型" style="width: 160px">
+              <el-form-item label="专业类别" prop="disciplineTypeId">
+                <el-select v-model="newData.disciplineTypeId" placeholder="请选择专业类别" style="width: 160px">
                   <el-option
                     v-for="dict in optionListA"
-                    :key="dict.value"
-                    :label="dict.label"
-                    :value="dict.value"
+                    :key="dict.id"
+                    :label="dict.disciplineName"
+                    :value="dict.id"
                   />
                 </el-select>
               </el-form-item>
-              <el-form-item label="是否上架" prop="data2" label-width="200px">
+              <el-form-item label="是否上架" prop="shelfStatus" label-width="200px">
                 <el-switch
-                  :active-value="true"
-                  :inactive-value="false"
-                  v-model="newData.data2"
+                  :active-value="1"
+                  :inactive-value="0"
+                  v-model="newData.shelfStatus"
                   active-color="#0183FB"
                   inactive-color="#AAAAAA">
                 </el-switch>
               </el-form-item>
-              <el-form-item label="是否共享" prop="data3" label-width="200px">
+              <el-form-item label="是否共享" prop="shareStatus" label-width="200px">
                 <el-switch
-                  :active-value="true"
-                  :inactive-value="false"
-                  v-model="newData.data3"
+                  :active-value="1"
+                  :inactive-value="0"
+                  v-model="newData.shareStatus"
                   active-color="#0183FB"
                   inactive-color="#AAAAAA">
                 </el-switch>
-                <span style="margin-left:15px;">{{newData.data3?'共享开启,全校所有学院单位都可见':'不共享,仅本学院单位及上级都可见'}}</span>
+                <span style="margin-left:15px;">{{newData.shareStatus==1?'共享开启,全校所有学院单位都可见':'不共享,仅本学院单位及上级都可见'}}</span>
               </el-form-item>
             </div>
           </div>
           <div class="form-box">
-            <el-form-item label="课程名称" prop="data4">
-              <el-input v-model="newData.data4" placeholder="请输入课程名称" maxLength="20" style="width:960px;"></el-input>
+            <el-form-item label="课程名称" prop="courseName">
+              <el-input v-model="newData.courseName" placeholder="请输入课程名称" maxLength="20" style="width:960px;"></el-input>
             </el-form-item>
           </div>
           <div class="form-box">
             <div class="form-flex-box">
-              <el-form-item label="课程名称" prop="data5">
+              <el-form-item label="课程封面" prop="coverAttachmentPath">
                 <el-upload
                   style="width:400px;"
                   drag
@@ -59,7 +59,7 @@
                   <p style="line-height:25px;color:#333;">支持jpg/jpeg/png格式图片</p>
                 </el-upload>
               </el-form-item>
-              <img class="img-box" v-if="newData.data5" :src="newData.data5">
+              <img class="img-box" v-if="newData.coverAttachmentPath" :src="newData.coverAttachmentPath">
             </div>
           </div>
         </div>
@@ -72,6 +72,7 @@
   //import { getDicts } from "@/api/commonality/noPermission";
   //import { systemUserSelect } from "@/api/commonality/permission";
   //import { getInfo } from "@/api/basicsModules/index";
+  import { examElDisciplineTypeList, } from "@/api/safetyEducationExaminationNew/index";
   import { getToken } from "@/utils/auth";
   export default {
     name: 'basicSettings',
@@ -87,22 +88,22 @@
         },
         optionListA:[],
         newData:{
-          data1:null,
-          data2:true,
-          data3:true,
-          data4:'',
-          data5:'',
+          disciplineTypeId:null,
+          shelfStatus:1,
+          shareStatus:1,
+          courseName:'',
+          coverAttachmentPath:'',
         },
         rules:{
-          data1: [
-            { required: true, message: "请选择课程分类", trigger: "blur" },
-            { required: true, message: "请选择课程分类", validator: this.spaceJudgment, trigger: "blur" }
+          disciplineTypeId: [
+            { required: true, message: "请选择专业类别", trigger: "blur" },
+            { required: true, message: "请选择专业类别", validator: this.spaceJudgment, trigger: "blur" }
           ],
-          data2: [
+          courseName: [
             { required: true, message: "请输入课程名称", trigger: "blur" },
             { required: true, message: "请输入课程名称", validator: this.spaceJudgment, trigger: "blur" }
           ],
-          data3: [
+          coverAttachmentPath: [
             { required: true, message: "请上传课程封面", trigger: "blur" },
             { required: true, message: "请上传课程封面", validator: this.spaceJudgment, trigger: "blur" }
           ],
@@ -113,13 +114,18 @@
 
     },
     mounted(){
-
+      this.examElDisciplineTypeList();
     },
     methods:{
+      //写入详情
+      setDataInfo(data){
+        console.log('setDataInfo',data);
+        this.$set(this,'newData',data);
+      },
       //图片上传相关
       handleAvatarSuccess(res) {
-        // this.$set(this.newData,'data5',res.data.url);
-        this.$set(this.newData,'data5','http://192.168.1.8/statics/2026/07/21/ecad2625-c47b-4e15-aef3-61ec486f23f6.jpg');
+        this.$set(this.newData,'coverAttachmentPath',res.data.url);
+        // this.$set(this.newData,'coverAttachmentPath','http://192.168.1.8/statics/2026/07/21/ecad2625-c47b-4e15-aef3-61ec486f23f6.jpg');
       },
       beforeAvatarUpload(file,status) {
         return new Promise((resolve, reject) => {
@@ -136,6 +142,35 @@
           }
         })
       },
+      //查询全部专业类别
+      examElDisciplineTypeList(){
+        examElDisciplineTypeList({}).then(response => {
+          this.$set(this,'optionListA',response.data);
+        });
+      },
+      //提交检查
+      submitButton(){
+        this.$refs["form"].validate(valid => {
+          if (valid) {
+            this.$parent.pageDataA();
+          }
+        })
+      },
+      checkTheData(){
+        if(!this.newData.disciplineTypeId){
+          this.msgError('请选择专业类别')
+          return
+        }
+        if(!this.newData.courseName){
+          this.msgError('请输入课程名称')
+          return
+        }
+        if(!this.newData.coverAttachmentPath){
+          this.msgError('请上传课程封面')
+          return
+        }
+        this.$parent.pageDataA();
+      },
     }
   }
 </script>

+ 148 - 51
src/views/safetyEducationExaminationNew/courseManagement/courseManagement/drawerItem.vue

@@ -1,26 +1,28 @@
 <template>
   <div class="page-container studyCourses-drawerItem">
-    <div class="drawerItem-left-box">
+    <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.leftData1" placeholder="关键字搜索知识点" maxLength="20" style="width:260px;">
-            <el-button slot="append" icon="el-icon-search" @click="leftButton()"></el-button>
+          <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.name}}</p>
+           :class="index == leftCheckIndex?'checkIndex':''">{{item.knowledgePointName}}</p>
       </div>
     </div>
     <div class="drawerItem-right-box">
       <el-form class="drawerItem-right-form" :model="queryParams" ref="form">
         <div class="table-top-button-box">
           <div>
-            <p :class="tableType == 1?'check-table-button':''" @click="tableTypeButton(1)">全部</p>
-            <p :class="tableType == 2?'check-table-button':''" @click="tableTypeButton(2)">共享</p>
-            <p :class="tableType == 3?'check-table-button':''" @click="tableTypeButton(3)">不共享</p>
+            <p :class="queryParams.shareStatus == ''?'check-table-button':''" @click="tableTypeButton('')">全部</p>
+            <p :class="queryParams.shareStatus == '1'?'check-table-button':''" @click="tableTypeButton('1')">共享</p>
+            <p :class="queryParams.shareStatus == '0'?'check-table-button':''" @click="tableTypeButton('0')">不共享</p>
           </div>
         </div>
         <el-form-item label="" prop="queryParamsData1">
@@ -34,12 +36,12 @@
           </el-select>
         </el-form-item>
         <el-form-item label="" prop="queryParamsData2">
-          <el-select v-model="queryParams.queryParamsData2" placeholder="专业类别" style="width: 200px">
+          <el-select v-model="queryParams.queryParamsData2" placeholder="来源" style="width: 200px">
             <el-option
               v-for="dict in optionListB"
-              :key="dict.value"
-              :label="dict.label"
-              :value="dict.value"
+              :key="dict.deptId"
+              :label="dict.deptName"
+              :value="dict.deptId"
             />
           </el-select>
         </el-form-item>
@@ -58,21 +60,32 @@
         <el-table class="table-box" v-loading="loading" 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="name"  show-overflow-tooltip/>
-          <el-table-column label="知识点" prop="content" width="120" show-overflow-tooltip/>
-          <el-table-column label="专业类别" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="是否共享" prop="content" width="100" show-overflow-tooltip>
+          <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">
-              <span 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 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>
+              {{scope.row.materialType == 1?'视频':(scope.row.materialType == 3?'文档':(scope.row.materialType == 4?'文章':''))}}
             </template>
           </el-table-column>
-          <el-table-column label="课件类型" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="文件大小" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="要求时长" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="可得学时" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="可得积分" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="来源" prop="content" width="100" show-overflow-tooltip/>
+          <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]"
@@ -80,7 +93,7 @@
                       :total="total"
                       :page.sync="queryParams.page"
                       :limit.sync="queryParams.pageSize"
-                      @pagination="rightGetList"
+                      @pagination="getList"
           />
           <p class="null-p"></p>
           <p class="drawer-item-button-1" @click="returnButton">取消</p>
@@ -95,29 +108,37 @@
   //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:{
-      propsData:{},
+      drawerItemPropsData:{},
     },
     data(){
       return{
+        newData:{
+          knowledgePointId:null,
+          checkIndex:null,
+        },
         // 左侧
         leftData:{
-          leftData1:'',
+          searchValue:'',
         },
-        leftList:[{name:'知识点1',value:'1'},{name:'知识点2',value:'2'},{name:'知识点3',value:'3'},],
+        leftList:[],
         leftCheckIndex:0,
         //右侧
-        tableType:1,
-        optionListA:[],
+        optionListA:[{value:'1',label:'视频'},{value:'3',label:'文档'},{value:'4',label:'文章'},],
         optionListB:[],
         queryParams:{
           page:1,
           pageSize:20,
-          queryParamsData1:null,
-          queryParamsData2:null,
-          queryParamsData3:'',
+          searchValue:'',
+          shareStatus:'',
+          materialType:null,
+          deptId :null,
         },
         rightList:[],
         loading:false,
@@ -129,23 +150,24 @@
 
     },
     mounted(){
-
+      this.$set(this,'newData',this.drawerItemPropsData);
+      this.systemDeptCurrentDept();
+      this.examElKnowledgePointTreeList();
     },
     methods:{
-      // 左侧搜索
-      leftButton(){
-        console.log('左侧搜索')
-      },
       //左侧切换
       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.tableType != val){
-          this.$set(this,'tableType',val);
+        if(this.queryParams.shareStatus != val){
+          this.$set(this.queryParams,'shareStatus',val);
           this.handleQuery();
         }
       },
@@ -163,9 +185,10 @@
         this.$set(this,'queryParams',{
           page:1,
           pageSize:20,
-          queryParamsData1:null,
-          queryParamsData2:null,
-          queryParamsData3:'',
+          searchValue:'',
+          shareStatus:'',
+          materialType:null,
+          deptId :null,
         });
         this.getList();
       },
@@ -175,17 +198,66 @@
       },
       //确定
       confirmButton(){
-        this.$parent.$parent.drawerConfirmButton();
+        let self = this;
+        if(!this.multipleSelection[0]){
+          this.msgError('请选择课件');
+          return
+        }
+        let list = [];
+        let numA = 0
+        let numB = 0
+        for(let i=0;i<self.multipleSelection.length;i++){
+          numA = numA + parseInt(self.multipleSelection[i].minLearningDuration, 10)
+          numB = numB + parseInt(self.multipleSelection[i].creditHours, 10)
+          list.push({
+            id:self.multipleSelection[i].id,
+            minData1:self.multipleSelection[i].coursewareName,
+            minData2:self.multipleSelection[i].deptName,
+            minData3:self.multipleSelection[i].materialType,
+            minData4:self.multipleSelection[i].minLearningDuration,
+            minData5:self.multipleSelection[i].creditHours,
+          })
+        }
+        let obj = {
+          knowledgePointId:this.newData.knowledgePointId,
+          checkIndex:this.newData.checkIndex,
+          data:{},
+          list:[],
+
+        }
+        if(!this.newData.knowledgePointId){
+          obj.data.showType = true;
+          obj.data.data1 = this.leftList[this.leftCheckIndex].knowledgePointName;
+          obj.data.data2 = list.length;
+          obj.data.data3 = numA;
+          obj.data.data4 = numB;
+          obj.data.knowledgePointId = this.leftList[this.leftCheckIndex].id;
+          obj.data.minList = list;
+        }else{
+          obj.list = list;
+        }
+        this.$parent.$parent.drawerConfirmButton(obj);
       },
       //获取数据列表
       getList(){
-        // this.$set(this,'loading',true);
-        // let obj = JSON.parse(JSON.stringify(this.queryParams))
-        // terminalUpgradeWebTaskList(obj).then(response => {
-        //   this.$set(this,'loading',false);
-        //   this.$set(this,'dataList',response.data.records);
-        //   this.$set(this,'total',response.data.total);
-        // });
+        this.$set(this,'loading',true);
+        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,'loading',false);
+          this.$set(this,'rightList',response.data.records);
+          this.$set(this,'total',response.data.total);
+        });
       },
 
       // 2. 指定表格行的唯一标识(必须是数据中绝对唯一的字段,如 id)
@@ -196,7 +268,6 @@
       // 3. 监听勾选状态的变化
       handleSelectionChange(val) {
         this.multipleSelection = val;
-        console.log('当前所有选中的数据:', this.multipleSelection);
       },
 
       // 4. 翻页/改变每页条数时的处理
@@ -219,6 +290,32 @@
           });
         }
       },
+
+      //知识点
+      examElKnowledgePointTreeList(){
+        if(!this.newData.knowledgePointId){
+          examElKnowledgePointTreeList({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 => {
+          this.$set(this,'optionListB',response.data);
+        });
+      },
     },
   }
 </script>

+ 131 - 76
src/views/safetyEducationExaminationNew/courseManagement/courseManagement/index.vue

@@ -7,13 +7,13 @@
                  :inline="true" style="width:100%;">
           <div class="table-top-button-box">
             <div>
-              <p :class="tableType == 1?'check-table-button':''" @click="tableTypeButton(1)">全部</p>
-              <p :class="tableType == 2?'check-table-button':''" @click="tableTypeButton(2)">共享</p>
-              <p :class="tableType == 3?'check-table-button':''" @click="tableTypeButton(3)">不共享</p>
+              <p :class="queryParams.shareStatus == ''?'check-table-button':''" @click="tableTypeButton('')">全部</p>
+              <p :class="queryParams.shareStatus == '1'?'check-table-button':''" @click="tableTypeButton('1')">共享</p>
+              <p :class="queryParams.shareStatus == '0'?'check-table-button':''" @click="tableTypeButton('0')">不共享</p>
             </div>
           </div>
-          <el-form-item label="" prop="queryParamsData1">
-            <el-select v-model="queryParams.queryParamsData1" placeholder="课程分类" style="width: 200px">
+          <el-form-item label="" prop="shelfStatus">
+            <el-select v-model="queryParams.shelfStatus" placeholder="状态" style="width: 200px">
               <el-option
                 v-for="dict in optionListA"
                 :key="dict.value"
@@ -22,30 +22,47 @@
               />
             </el-select>
           </el-form-item>
-          <el-form-item label="" prop="queryParamsData2">
-            <el-select v-model="queryParams.queryParamsData2" placeholder="课程状态" style="width: 200px">
+          <el-form-item label="" prop="knowledgePointIds">
+            <el-cascader
+              style="width: 180px"
+              v-model="queryParams.knowledgePointIds"
+              :options="optionListB"
+              :props="{
+                emitPath:false,
+                checkStrictly: true,
+                value: 'id',
+                label: 'knowledgePointName',
+                children: 'children',
+              }"
+              :show-all-levels="false"
+              filterable
+              placeholder="知识点"
+            ></el-cascader>
+          </el-form-item>
+          <el-form-item label="" prop="disciplineId">
+            <el-select v-model="queryParams.disciplineId" placeholder="专业类别" style="width: 200px">
               <el-option
-                v-for="dict in optionListB"
-                :key="dict.value"
-                :label="dict.label"
-                :value="dict.value"
+                v-for="dict in optionListC"
+                :key="dict.id"
+                :label="dict.disciplineName"
+                :value="dict.id"
               />
             </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="deptId">
+            <el-select v-model="queryParams.deptId" placeholder="来源" style="width: 200px">
               <el-option
-                v-for="dict in optionListC"
-                :key="dict.value"
-                :label="dict.label"
-                :value="dict.value"
+                v-for="dict in optionListD"
+                :key="dict.deptId"
+                :label="dict.deptName"
+                :value="dict.deptId"
               />
             </el-select>
           </el-form-item>
-          <el-form-item label="" prop="queryParamsData4">
+          <el-form-item label="" prop="searchValue">
             <el-input
               maxLength="30"
-              v-model="queryParams.queryParamsData4"
+              v-model="queryParams.searchValue"
               placeholder="搜索名称"
               style="width: 200px"
             />
@@ -55,51 +72,51 @@
           <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" v-loading="loading" border :data="dataList">
-          <el-table-column label="课程名称" prop="name"  show-overflow-tooltip/>
-          <el-table-column label="知识点" prop="content" width="200" show-overflow-tooltip/>
+          <el-table-column label="课程名称" prop="courseName"  show-overflow-tooltip>
+            <template slot-scope="scope">
+              <span @click="tableButton(5,scope.row)" style="color:#0183fa;cursor: pointer">{{scope.row.courseName}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="知识点" prop="knowledgePointNames" width="200" show-overflow-tooltip/>
           <el-table-column label="是否共享" prop="content" width="100" show-overflow-tooltip>
             <template slot-scope="scope">
-              <span 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 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>
+              <span 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)" v-if="scope.row.shareStatus==1">共享</span>
+              <span 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)" v-if="scope.row.shareStatus==0">不共享</span>
             </template>
           </el-table-column>
-          <el-table-column label="课程分类" prop="content" width="120" show-overflow-tooltip/>
-          <el-table-column label="课件总数" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="总时长" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="可得学时" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="状态" prop="state" width="100" show-overflow-tooltip>
+          <el-table-column label="专业类别" prop="disciplineTypeName" width="120" show-overflow-tooltip/>
+          <el-table-column label="课件总数" prop="coursewareTotalCount" width="100" show-overflow-tooltip/>
+          <el-table-column label="总时长" prop="totalLearningDuration" width="100" show-overflow-tooltip/>
+          <el-table-column label="可得学时" prop="totalCreditHours" width="100" show-overflow-tooltip/>
+          <el-table-column label="状态" prop="shelfStatus" width="100" show-overflow-tooltip>
             <template slot-scope="scope">
-              <span style="padding:2px 10px;border:1px solid #5AD8A6;border-radius:4px;color: #5AD8A6;background-color:rgba(90, 216, 166,0.2)">上架</span>
-              <span style="padding:2px 10px;border:1px solid #999999;border-radius:4px;color: #999999;background-color:rgba(153, 153, 153,0.2)">未上架</span>
+              <span style="padding:2px 10px;border:1px solid #5AD8A6;border-radius:4px;color: #5AD8A6;background-color:rgba(90, 216, 166,0.2)" v-if="scope.row.shelfStatus==1">上架</span>
+              <span style="padding:2px 10px;border:1px solid #999999;border-radius:4px;color: #999999;background-color:rgba(153, 153, 153,0.2)" v-if="scope.row.shelfStatus==0">未上架</span>
             </template>
           </el-table-column>
-          <el-table-column label="来源" prop="content" width="120" show-overflow-tooltip/>
-          <el-table-column label="最近更新" prop="createTime" width="200" show-overflow-tooltip>
+          <el-table-column label="来源" prop="deptName" width="120" show-overflow-tooltip/>
+          <el-table-column label="最近更新" prop="updateTime" width="200" show-overflow-tooltip>
             <template slot-scope="scope">
-              <span>{{ parseTime(scope.row.createTime,"{y}-{m}-{d} {h}:{i}") }}</span>
+              <span>{{ parseTime(scope.row.updateTime,"{y}-{m}-{d} {h}:{i}") }}</span>
             </template>
           </el-table-column>
-          <el-table-column label="操作" width="200" show-overflow-tooltip v-if="tableButtonType">
+          <el-table-column label="操作" width="200" show-overflow-tooltip>
             <template slot-scope="scope">
               <div class="table-button-box">
                 <p class="table-button-null"></p>
                 <p class="table-button-p"
                    @click="tableButton(2,scope.row)"
-                   v-hasPermiRouter="['demo:demo:detail']"
                 >复制</p>
                 <p class="table-button-p"
                    @click="tableButton(3,scope.row)"
-                   v-hasPermiRouter="['demo:demo:edit']"
                 >编辑</p>
                 <p class="table-button-p"
                    @click="tableButton(4,scope.row)"
-                   v-hasPermiRouter="['demo:demo:del']"
                 >删除</p>
                 <p class="table-button-null"></p>
               </div>
@@ -122,6 +139,10 @@
   //import { getDicts } from "@/api/commonality/noPermission";
   //import { systemUserSelect } from "@/api/commonality/permission";
   //import { getInfo } from "@/api/basicsModules/index";
+  import {
+    examElCoursePage,examElCourseDel,examElCourseCopy,
+    examElKnowledgePointTreeList,examElDisciplineTypeList,systemDeptCurrentDept,
+  } from "@/api/safetyEducationExaminationNew/index";
   import addPage from "./addPage.vue";
   export default {
     name: 'index',
@@ -136,21 +157,22 @@
         //页面遮罩
         loading:false,
         //下拉列表数据
-        optionListA:[{value:true,label:'启用'},{value:false,label:'停用'}],
-        optionListB:[{value:true,label:'启用'},{value:false,label:'停用'}],
-        optionListC:[{value:true,label:'启用'},{value:false,label:'停用'}],
-        //查询条件
-        tableType:1,
+        optionListA:[{value:1,label:'上架'},{value:0,label:'未上架'}],
+        optionListB:[],
+        optionListC:[],
+        optionListD:[],
         queryParams:{
           page:1,
           pageSize:20,
-          queryParamsData1:null,
-          queryParamsData2:null,
-          queryParamsData3:null,
-          queryParamsData4:"",
+          shareStatus:"",
+          shelfStatus:null,
+          knowledgePointIds:[],
+          disciplineId:null,
+          deptId:null,
+          searchValue:"",
         },
         //列表数据
-        dataList:[{}],
+        dataList:[],
         //数据数量
         total:0,
         //组件传参
@@ -161,13 +183,16 @@
 
     },
     mounted () {
-      //this.getList();
+      this.examElDisciplineTypeList();
+      this.systemDeptCurrentDept();
+      this.examElKnowledgePointTreeList();
+      this.getList();
     },
     methods: {
       //切换按钮
       tableTypeButton(val){
-        if(this.tableType != val){
-          this.$set(this,'tableType',val);
+        if(this.queryParams.shareStatus != val){
+          this.$set(this.queryParams,'shareStatus',val);
           this.handleQuery();
         }
       },
@@ -181,10 +206,12 @@
         this.$set(this,'queryParams',{
           page:1,
           pageSize:20,
-          queryParamsData1:null,
-          queryParamsData2:null,
-          queryParamsData3:null,
-          queryParamsData4:"",
+          shareStatus:"",
+          shelfStatus:null,
+          knowledgePointIds:[],
+          disciplineId:null,
+          deptId:null,
+          searchValue:"",
         });
         this.getList();
       },
@@ -192,7 +219,7 @@
       getList(){
         this.$set(this,'loading',true);
         let obj = JSON.parse(JSON.stringify(this.queryParams))
-        getListFunction(obj).then(response => {
+        examElCoursePage(obj).then(response => {
           this.$set(this,'loading',false);
           this.$set(this,'dataList',response.data.records);
           this.$set(this,'total',response.data.total);
@@ -206,50 +233,78 @@
           this.$set(this,'pageType',2);
           this.$set(this,'propsData',{});
         }else if(type == 2){
-          //详情
-          this.$set(this,'pageType',2);
-          let obj = JSON.parse(JSON.stringify(row))
-          obj.showType = true;
-          this.$set(this,'propsData',obj);
-        }else if(type == 3){
-          //编辑
-          this.$set(this,'pageType',2);
-          let obj = JSON.parse(JSON.stringify(row))
-          obj.showType = false;
-          this.$set(this,'propsData',obj);
-        }else if(type == 4){
-          //删除
-          this.$confirm('是否确认删除?', "警告", {
+          //复制
+          this.$confirm('是否确认复制?', "警告", {
             confirmButtonText: "确定",
             cancelButtonText: "取消",
             type: "warning"
           }).then(function() {
           }).then(() => {
-            deleteFunction({id:row.id}).then(response => {
+            examElCourseCopy({id:row.id}).then(response => {
               self.msgSuccess(response.message)
               self.getList();
             });
           }).catch(() => {});
-        }else if(type == 5){
-          //启用&停用
-          let text = row.state  ? "停用" : "启用";
-          this.$confirm('是否确认' + text + '?', "警告", {
+        }else if(type == 3){
+          //编辑
+          this.$set(this,'pageType',2);
+          let obj = JSON.parse(JSON.stringify(row))
+          this.$set(this,'propsData',obj);
+        }else if(type == 4){
+          //删除
+          this.$confirm('是否确认删除?', "警告", {
             confirmButtonText: "确定",
             cancelButtonText: "取消",
             type: "warning"
           }).then(function() {
           }).then(() => {
-            stateFunction({id:row.id,state:!row.state,}).then(response => {
+            examElCourseDel({id:row.id}).then(response => {
               self.msgSuccess(response.message)
               self.getList();
             });
           }).catch(() => {});
+        }else if(type == 5){
+          //预览课程
+
         }else if(type == 6){
           //返回并刷新
           this.$set(this,'pageType',1);
           this.getList();
         }
       },
+
+      //知识点
+      examElKnowledgePointTreeList(){
+        examElKnowledgePointTreeList({}).then(response => {
+          const list = response.data || [];
+          this.formatTreeData(list);
+          this.$set(this, 'optionListB', list);
+        });
+      },
+      //学院列表
+      systemDeptCurrentDept(){
+        systemDeptCurrentDept({}).then(response => {
+          this.$set(this,'optionListD',response.data);
+        });
+      },
+      //查询全部专业类别
+      examElDisciplineTypeList(){
+        examElDisciplineTypeList({}).then(response => {
+          this.$set(this,'optionListC',response.data);
+        });
+      },
+      formatTreeData(data) {
+        data.forEach(item => {
+          // 如果 children 存在,且是数组,且长度为 0(即 children: [])
+          if (Array.isArray(item.children) && item.children.length === 0) {
+            // 将 children 设为 undefined(或直接 delete item.children;)
+            item.children = undefined;
+          } else if (item.children && item.children.length > 0) {
+            // 如果还有下一级,继续递归处理
+            this.formatTreeData(item.children);
+          }
+        });
+      },
     },
   }
 </script>

+ 146 - 51
src/views/safetyEducationExaminationNew/courseManagement/courseManagement/studyCourses.vue

@@ -6,6 +6,7 @@
     </div>
     <div class="content-box scrollbar-box">
       <!-- 大项列表 -->
+      <p v-if="!dataList[0]" style="color:#999;font-size:16px; line-height:200px;text-align: center;">请添加课件</p>
       <div
         class="for-max-box"
         v-for="(item, index) in dataList"
@@ -28,7 +29,7 @@
 
         <div class="max-big-title-box" v-show="item.showType">
           <div class="big-title-box">
-            <p>课件名称</p><p>专业类别</p><p>课件类型</p><p>要求时长</p><p>可获学时</p><p>操作</p>
+            <p>课件名称</p><p>来源</p><p>课件类型</p><p>要求时长</p><p>可获学时</p><p>操作</p>
           </div>
 
           <!-- 小项列表 -->
@@ -44,13 +45,13 @@
           >
             <p>{{minItem.minData1}}</p>
             <p>{{minItem.minData2}}</p>
-            <p>{{minItem.minData3}}</p>
+            <p>{{minItem.minData3==1?'视频':(minItem.minData3==3?'文档':(minItem.minData3==4?'文章':''))}}</p>
             <p>{{minItem.minData4}}</p>
             <p>{{minItem.minData5}}</p>
             <p class="el-icon-delete-solid" @click="delItem(index, minIndex)"></p>
             <!-- 小项拖拽手柄 -->
             <p class="el-icon-rank drag-handle" title="拖动排序"></p>
-            <p class="el-icon-view"></p>
+            <p class="el-icon-view" @click="lookItem(minItem)"></p>
           </div>
         </div>
       </div>
@@ -63,8 +64,9 @@
       ref="drawer"
       :visible.sync="drawer"
       direction="rtl">
-      <drawerItem ref="drawerItem"></drawerItem>
+      <drawerItem ref="drawerItem" v-if="drawer" :drawerItemPropsData="drawerItemPropsData"></drawerItem>
     </el-drawer>
+    <fullScreenFileLook ref="fullScreenFileLook"></fullScreenFileLook>
   </div>
 </template>
 
@@ -72,11 +74,14 @@
   //import { getDicts } from "@/api/commonality/noPermission";
   //import { systemUserSelect } from "@/api/commonality/permission";
   //import { getInfo } from "@/api/basicsModules/index";
+  import fullScreenFileLook from "@/components/fullScreenFileLook/fullScreenFileLook.vue";
   import drawerItem from "./drawerItem.vue";
+  import { examElCoursewareDetail } from "@/api/safetyEducationExaminationNew/index";
   export default {
     name: 'studyCourses',
     components: {
       drawerItem,
+      fullScreenFileLook
     },
     props:{
       propsData:{},
@@ -89,52 +94,30 @@
         num3:0,
         num4:0,
         dataList:[
-          {
-            showType:true,
-            data1:'知识点1',
-            data2:2,
-            data3:20,
-            data4:4,
-            minList:[
-              {
-                minData1:'名称1.mp4',
-                minData2:'化学类',
-                minData3:'视频',
-                minData4:'5分钟',
-                minData5:'0.5',
-              },
-              {
-                minData1:'名称2.mp4',
-                minData2:'化学类',
-                minData3:'视频',
-                minData4:'5分钟',
-                minData5:'0.5',
-              },
-            ],
-          },
-          {
-            showType:true,
-            data1:'知识点2',
-            data2:2,
-            data3:20,
-            data4:4,
-            minList:[
-              {
-                minData1:'名称3.mp4',
-                minData2:'化学类',
-                minData3:'视频',
-                minData4:'5分钟',
-                minData5:'0.5',
-              },
-              {
-                minData1:'名称4.mp4',
-                minData2:'化学类',
-                minData3:'视频',
-                minData4:'5分钟',
-                minData5:'0.5',
-              },
-            ],
-          },
+          // {
+          //   showType:true,
+          //   data1:'知识点1',
+          //   data2:2,
+          //   data3:20,
+          //   data4:4,
+          //   knowledgePointId:'123',
+          //   minList:[
+          //     {
+          //       minData1:'名称1.mp4',
+          //       minData2:'化学类',
+          //       minData3:'视频',
+          //       minData4:'5分钟',
+          //       minData5:'0.5',
+          //     },
+          //     {
+          //       minData1:'名称2.mp4',
+          //       minData2:'化学类',
+          //       minData3:'视频',
+          //       minData4:'5分钟',
+          //       minData5:'0.5',
+          //     },
+          //   ],
+          // }
         ],
         //拖拽相关
         dragInfo: {
@@ -143,6 +126,10 @@
           smallIndex: null
         },
         drawer:false,
+        drawerItemPropsData:{
+          knowledgePointId:null,
+          checkIndex:null,
+        },
       }
     },
     created(){
@@ -152,20 +139,114 @@
 
     },
     methods:{
+      //写入详情
+      setDataInfo(){
+
+      },
+      //查看课件
+      lookItem(item){
+        //富文本
+        examElCoursewareDetail({id:item.id}).then(response => {
+          //预览
+          let name=response.data.coursewareName;
+          let url='';
+          let type='';
+          if(response.data.materialType == 1){
+            //视频
+            type = 'video'
+            url = response.data.attachmentPath;
+            this.$refs['fullScreenFileLook'].initialize(name,url,type);
+          }else if(response.data.materialType == 3){
+            //文档
+            if(response.data.attachmentType == '.docx'){
+              type = 'docx'
+            }else if(response.data.attachmentType == '.xlsx'){
+              type = 'excel'
+            }else if(response.data.attachmentType == '.pdf'){
+              type = 'pdf'
+            }
+            url = response.data.attachmentPath;
+            this.$refs['fullScreenFileLook'].initialize(name,url,type);
+          }else if(response.data.materialType == 4){
+            type = 'text'
+            url = response.data.articleContent;
+            this.$refs['fullScreenFileLook'].initialize(name,url,type);
+          }
+        });
+      },
       //弹窗返回
       drawerReturnButton(){
         this.$refs.drawer.closeDrawer();
       },
       //弹窗确定
-      drawerConfirmButton(){
+      drawerConfirmButton(data){
+        let self = this;
+        if (!data.knowledgePointId){
+          //大项添加
+          let num = 0;
+          for(let i=0;i<self.dataList.length;i++){
+            if(self.dataList[i].knowledgePointId == data.data.knowledgePointId){
+              //旧大项
+              num++
+              self.dataList[i].minList = [...self.dataList[i].minList, ...data.data.minList]
+              let numA = 0;
+              let numB = 0;
+              let numC = 0;
+              for(let o=0;o<self.dataList[i].minList.length;o++){
+                numA++
+                numB = numB + parseInt(self.dataList[i].minList[o].minData4, 10)
+                numC = numC + parseInt(self.dataList[i].minList[o].minData5, 10)
+              }
+              self.dataList[i].data2 = numA
+              self.dataList[i].data3 = numB
+              self.dataList[i].data4 = numC
+            }
+          }
+          if(num == 0){
+            //新大项
+            this.dataList.push(data.data)
+          }else{
+          }
+        }else{
+          //子项添加
+          self.dataList[data.checkIndex].minList = [...self.dataList[data.checkIndex].minList, ...data.list]
+        }
+        this.statisticalCalculation();
         this.$refs.drawer.closeDrawer();
       },
+      statisticalCalculation(){
+        let self = this;
+        let numA = 0;
+        let numB = 0;
+        let numC = 0;
+        let numD = 0;
+        for(let i=0;i<self.dataList.length;i++){
+          numA++
+          for(let o=0;o<self.dataList[i].minList.length;o++){
+            numB++
+            numC = numC + parseInt(self.dataList[i].minList[o].minData4, 10)
+            numD = numD + parseInt(self.dataList[i].minList[o].minData5, 10)
+          }
+        }
+        this.$set(this,'num1',numA);
+        this.$set(this,'num2',numB);
+        this.$set(this,'num3',numC);
+        this.$set(this,'num4',numD);
+      },
       //添加大项
       addBigItem(){
+        this.$set(this,'drawerItemPropsData',{
+          knowledgePointId:null,
+          checkIndex:null,
+        });
         this.$set(this,'drawer',true);
       },
       //添加子项
       addMinItem(item,index){
+        this.$set(this,'drawerItemPropsData',{
+          knowledgePointId:item.knowledgePointId,
+          checkIndex:index,
+        });
         this.$set(this,'drawer',true);
       },
       //展开收起
@@ -258,6 +339,20 @@
         const minBox = e.currentTarget.closest('.for-max-box');
         return Array.from(this.$el.querySelectorAll('.for-max-box')).indexOf(minBox);
       },
+      //检查数据
+      checkTheData(){
+        let self = this;
+        if(!this.dataList[0]){
+          this.msgError('请添加课件')
+        }
+        for (let i=0;i<self.dataList.length;i++) {
+          if(!self.dataList[i].minList[0]){
+            this.msgError(self.dataList[i].data1+' 未添加课件')
+            return
+          }
+        }
+        this.$parent.pageDataB();
+      },
     },
   }
 </script>

+ 256 - 130
src/views/safetyEducationExaminationNew/courseManagement/coursewareManagement/addPage.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="coursewareManagement-addPage">
-    <div class="page-container-top-max-big-box">
+    <div class="page-container-top-max-big-box-shadow">
       <p class="top-1-p">{{newData.id?'编辑课件':'添加课件'}}</p>
       <p class="top-2-p" @click="backPage()">返回</p>
-      <p class="top-3-p" @click="resetButton()">重置</p>
+      <p class="top-3-p" v-if="newData.id" @click="resetButton()">重置</p>
       <p class="top-4-p" @click="submitButton()">保存</p>
     </div>
     <div class="bottom-max-big-box scrollbar-box">
@@ -22,44 +22,51 @@
                   />
                 </el-select>
               </el-form-item>
-              <el-form-item label="知识点" prop="data2">
-                <el-select v-model="newData.data2" placeholder="请选择知识点" style="width: 400px">
-                  <el-option
-                    v-for="dict in optionListB"
-                    :key="dict.value"
-                    :label="dict.label"
-                    :value="dict.value"
-                  />
-                </el-select>
+              <el-form-item label="知识点" prop="knowledgePointId">
+                <el-cascader
+                  style="width: 400px"
+                  v-model="newData.knowledgePointId"
+                  :options="optionListB"
+                  :props="{
+                    emitPath:false,
+                    checkStrictly: true,
+                    value: 'id',
+                    label: 'knowledgePointName',
+                    children: 'children',
+                  }"
+                  :show-all-levels="false"
+                  filterable
+                  placeholder="请选择知识点"
+                ></el-cascader>
               </el-form-item>
             </div>
           </div>
           <div class="form-box">
             <div class="form-flex-box">
-              <el-form-item label="是否共享" prop="data11" style="width:560px;">
+              <el-form-item label="是否共享" prop="shareStatus" style="width:560px;">
                 <el-switch
-                  :active-value="true"
-                  :inactive-value="false"
-                  v-model="newData.data11"
+                  :active-value="1"
+                  :inactive-value="0"
+                  v-model="newData.shareStatus"
                   active-color="#0183FB"
                   inactive-color="#AAAAAA">
                 </el-switch>
-                <span style="margin-left:15px;">{{newData.data11?'共享开启,全校所有学院单位都可见':'不共享,仅本学院单位及上级都可见'}}</span>
-              </el-form-item>
-              <el-form-item label="专业类别" prop="data3">
-                <el-select v-model="newData.data3" placeholder="请选择专业类别" style="width: 400px">
-                  <el-option
-                    v-for="dict in optionListC"
-                    :key="dict.value"
-                    :label="dict.label"
-                    :value="dict.value"
-                  />
-                </el-select>
+                <span style="margin-left:15px;">{{newData.shareStatus==1?'共享开启,全校所有学院单位都可见':'不共享,仅本学院单位及上级都可见'}}</span>
               </el-form-item>
+              <!--<el-form-item label="专业类别" prop="disciplineTypeId">-->
+                <!--<el-select v-model="newData.disciplineTypeId" placeholder="请选择专业类别" style="width: 400px">-->
+                  <!--<el-option-->
+                    <!--v-for="dict in optionListC"-->
+                    <!--:key="dict.id"-->
+                    <!--:label="dict.disciplineName"-->
+                    <!--:value="dict.id"-->
+                  <!--/>-->
+                <!--</el-select>-->
+              <!--</el-form-item>-->
             </div>
           </div>
           <div class="form-box" v-if="newData.materialType == 1">
-            <el-form-item label="视频上传" prop="data41">
+            <el-form-item label="视频上传" prop="attachments">
               <div class="form-flex-box">
                 <uploader
                   style="width:400px;"
@@ -82,20 +89,21 @@
                   <!--                 <uploader-list></uploader-list> -->
                   <!--                <uploader-files> </uploader-files>-->
                 </uploader>
-                <video v-if="newData.data41" :src="newData.data41" controls
+                <video v-if="newData.attachments[0]" :src="newData.attachments[0].attachmentPath" controls
                        style="width: 424px;height:240px;margin-left: 20px;"></video>
               </div>
             </el-form-item>
           </div>
           <div class="form-box" v-if="newData.materialType == 1">
             <el-form-item label="">
-              <el-input v-model="newData.data411" placeholder="添加视频水印文字" maxLength="20" style="width:960px;"></el-input>
+              <el-input v-model="newData.watermark" placeholder="添加视频水印文字" maxLength="20" style="width:960px;"></el-input>
             </el-form-item>
           </div>
-          <div class="form-box" v-if="newData.materialType == 2">
-            <el-form-item label="文档上传" prop="data42">
+          <div class="form-box" v-if="newData.materialType == 3">
+            <el-form-item label="文档上传" prop="attachments">
               <div class="form-flex-box">
                 <el-upload
+                  v-if="!newData.id"
                   style="width:400px;"
                   drag multiple
                   accept=".xlsx, .docx, .pdf"
@@ -110,84 +118,106 @@
                   <p style="line-height:25px;color:#333;">支持docx/xlsx/pdf格式文档</p>
                   <p style="line-height:25px;color:#333;">支持批量上传文档</p>
                 </el-upload>
+                <el-upload
+                  v-if="newData.id"
+                  style="width:400px;"
+                  drag
+                  accept=".xlsx, .docx, .pdf"
+                  :action="uploadImgUrl"
+                  :show-file-list="false"
+                  :on-success="handleAvatarSuccess"
+                  :headers="headers"
+                  :before-upload="beforeAvatarUpload">
+                  <i class="el-icon-upload"></i>
+                  <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+                  <p style="line-height:25px;color:#333;">上传文件大小不超过1G</p>
+                  <p style="line-height:25px;color:#333;">支持docx/xlsx/pdf格式文档</p>
+                  <p style="line-height:25px;color:#333;">支持批量上传文档</p>
+                </el-upload>
                 <div class="for-up-list-box scrollbar-box">
-                  <div v-for="(item,index) in newData.data42" :key="index">
+                  <div v-for="(item,index) in newData.attachments" :key="index">
                     <p class="el-icon-circle-check"></p>
-                    <p>{{item.name}}</p>
+                    <p>{{item.attachmentName}}</p>
                     <p class="el-icon-close" @click="delList(index)"></p>
                   </div>
                 </div>
               </div>
             </el-form-item>
           </div>
-          <div class="form-box" v-if="newData.materialType == 3">
-            <el-form-item label="文章内容" prop="data43">
+          <div class="form-box" v-if="newData.materialType == 4" style="width:1120px;">
+            <el-form-item label="文章内容" prop="articleContent">
               <div class="rich-text" >
-                <UEditor ref="UEditor" :content="newData.data43" :min-height="192" :width="960" :height="330"/>
+                <tinymce-container
+                  v-model="newData.articleContent"
+                  :height="500"
+                  :max-length="5000"
+                  :upload-url="editorUploadUrl"
+                  :upload-headers="editorUploadHeaders"
+                />
               </div>
             </el-form-item>
           </div>
           <div class="form-box">
-            <el-form-item label="课件名称" prop="data5" v-if="!upDataNumType">
-              <el-input v-model="newData.data5" placeholder="请输入课件名称" maxLength="20" style="width:960px;"></el-input>
+            <el-form-item label="课件名称" prop="coursewareName" v-if="!newData.attachments[1]">
+              <el-input v-model="newData.coursewareName" placeholder="请输入课件名称" maxLength="20" style="width:960px;"></el-input>
             </el-form-item>
-            <el-form-item label="课件名称" v-if="upDataNumType">
-              <el-input :disabled="upDataNumType" placeholder="系统自动使用文件名" maxLength="20" style="width:960px;"></el-input>
+            <el-form-item label="课件名称" v-if="newData.attachments[1]">
+              <el-input :disabled="newData.attachments[1]" placeholder="系统自动使用文件名" maxLength="20" style="width:960px;"></el-input>
             </el-form-item>
           </div>
           <div class="form-box">
-            <el-form-item label="要求时长" prop="data6">
+            <el-form-item label="要求时长" prop="minLearningDuration">
               <el-input-number  class="form-input-number"
                                 style="width:200px"
                                 :min="0"
                                 :max="9999"
                                 :step="1" :precision="0" step-strictly
-                                v-model="newData.data6">
+                                v-model="newData.minLearningDuration">
               </el-input-number>
-              <span style="margin-left:15px;">学时</span>
+              <span style="margin-left:15px;">分钟</span>
             </el-form-item>
           </div>
           <div class="form-box">
             <div class="form-flex-box">
-              <el-form-item label="可得学时" prop="data7" style="width:410px;">
+              <el-form-item label="可得学时" prop="autoCreditHours" style="width:410px;">
                 <el-switch
-                  :active-value="true"
-                  :inactive-value="false"
-                  v-model="newData.data7"
+                  :active-value="0"
+                  :inactive-value="1"
+                  v-model="newData.autoCreditHours"
                   active-color="#0183FB"
                   inactive-color="#AAAAAA">
                 </el-switch>
-                <span style="margin-left:15px;">{{newData.data7?'手工填写开启':'手工填写关闭,系统自动计算'}}</span>
+                <span style="margin-left:15px;">{{newData.autoCreditHours==0?'手工填写开启':'手工填写关闭,系统自动计算'}}</span>
               </el-form-item>
-              <el-form-item label="" prop="data8" label-width="0">
+              <el-form-item label="" prop="creditHours" label-width="0">
                 <el-input-number  class="form-input-number"
-                                  :disabled="!newData.data7"
+                                  :disabled="newData.autoCreditHours==1"
                                   style="width:120px"
                                   :min="0"
                                   :max="9999"
                                   :step="1" :precision="0" step-strictly
-                                  v-model="newData.data8">
+                                  v-model="newData.creditHours">
                 </el-input-number>
                 <span style="margin-left:15px;">分钟</span>
               </el-form-item>
-              <el-form-item label="可得积分" prop="data9" style="width:410px;" label-width="150px">
+              <el-form-item label="可得积分" prop="autoPoints" style="width:410px;" label-width="150px">
                 <el-switch
-                  :active-value="true"
-                  :inactive-value="false"
-                  v-model="newData.data9"
+                  :active-value="0"
+                  :inactive-value="1"
+                  v-model="newData.autoPoints"
                   active-color="#0183FB"
                   inactive-color="#AAAAAA">
                 </el-switch>
-                <span style="margin-left:15px;">{{newData.data9?'手工填写开启':'手工填写关闭,系统自动计算'}}</span>
+                <span style="margin-left:15px;">{{newData.autoPoints==0?'手工填写开启':'手工填写关闭,系统自动计算'}}</span>
               </el-form-item>
-              <el-form-item label="" prop="data10" label-width="0">
+              <el-form-item label="" prop="points" label-width="0">
                 <el-input-number  class="form-input-number"
-                                  :disabled="!newData.data9"
+                                  :disabled="newData.autoPoints==1"
                                   style="width:120px"
                                   :min="0"
                                   :max="9999"
                                   :step="1" :precision="0" step-strictly
-                                  v-model="newData.data10">
+                                  v-model="newData.points">
                 </el-input-number>
                 <span style="margin-left:15px;">积分</span>
               </el-form-item>
@@ -202,24 +232,32 @@
 <script>
   //import { getDicts } from "@/api/commonality/noPermission";
   //import { systemUserSelect } from "@/api/commonality/permission";
-  //import { getInfo } from "@/api/basicsModules/index";
+  import {
+    examElKnowledgePointTreeList,examElDisciplineTypeList,
+    examElCoursewareAdd,examElCoursewareEdit,examElCoursewareDetail,
+  } from "@/api/safetyEducationExaminationNew/index";
   import { getToken } from "@/utils/auth";
+  import TinymceContainer from "@/components/tinymceContainer/index.vue";
   import axios from "axios";
   import SparkMD5 from "spark-md5";
   let httpHeader=window.location.href.split('://')[0]+'://'
   export default {
     name: 'addPage',
+    components: { TinymceContainer },
     props:{
       propsData:{},
     },
     data(){
       return{
+        editorUploadUrl: this.uploadUrl(),
+        editorUploadHeaders: {
+          Authorization:getToken(),
+        },
         //文件上传相关
         uploadImgUrl: this.uploadUrl(), // 上传的图片服务器地址
         headers: {
           Authorization:getToken(),
         },
-        upDataNumType:false,
         //页面状态
         buttonType:1,
         optionListA:[{value:1,label:'视频'},{value:3,label:'文档'},{value:4,label:'文章'}],
@@ -227,46 +265,41 @@
         optionListC:[],
         newData:{
           materialType:null,
-          data2:null,
-          data3:null,
-          data41:'',
-          data411:'',
-          data42:[],
-          data43:'',
-          data5:'',
-          data6:0,
-          data7:true,
-          data8:0,
-          data9:true,
-          data10:0,
-          data11:true,
+          knowledgePointId:null,
+          disciplineTypeId:null,
+          watermark:'',
+          attachments:[],
+          articleContent:'',
+          coursewareName:'',
+          minLearningDuration:0,
+          autoCreditHours:0,
+          creditHours:0,
+          autoPoints:0,
+          points:0,
+          shareStatus:1,
         },
         rules:{
           materialType: [
             { required: true, message: "请选择课件类型", trigger: "blur" },
             { required: true, message: "请选择课件类型", validator: this.spaceJudgment, trigger: "blur" }
           ],
-          data2: [
+          knowledgePointId: [
             { required: true, message: "请选择知识点", trigger: "blur" },
             { required: true, message: "请选择知识点", validator: this.spaceJudgment, trigger: "blur" }
           ],
-          data3: [
+          disciplineTypeId: [
             { required: true, message: "请选择专业类别", trigger: "blur" },
             { required: true, message: "请选择专业类别", validator: this.spaceJudgment, trigger: "blur" }
           ],
-          data41: [
-            { required: true, message: "请上传课件", trigger: "blur" },
-            { required: true, message: "请上传课件", validator: this.spaceJudgment, trigger: "blur" }
-          ],
-          data42: [
+          attachments: [
             { required: true, message: "请上传课件", trigger: "blur" },
             { required: true, message: "请上传课件", validator: this.spaceJudgment, trigger: "blur" }
           ],
-          data43: [
+          articleContent: [
             { required: true, message: "请输入文章", trigger: "blur" },
             { required: true, message: "请输入文章", validator: this.spaceJudgment, trigger: "blur" }
           ],
-          data5: [
+          coursewareName: [
             { required: true, message: "请输入课件名称", trigger: "blur" },
             { required: true, message: "请输入课件名称", validator: this.spaceJudgment, trigger: "blur" }
           ],
@@ -275,7 +308,7 @@
         fileSizeLimit:1,
         fileList:[],
         options: {
-          target: httpHeader+this.judgmentNetworkReturnAddress()+"/system/file/upload/chunk2",
+          target: httpHeader+this.judgmentNetworkReturnAddress()+"/exam/file/upload/chunk2",
           // 开启服务端分片校验功能
           testChunks: true,
           single: true,
@@ -322,15 +355,43 @@
       },
     },
     created(){
-
+      this.getData();
     },
     mounted(){
-
+      this.examElKnowledgePointTreeList();
+      // this.examElDisciplineTypeList();
     },
     methods:{
       getData(){
-
-        this.$refs.UEditor.text=unescape(this.subjectData.details)
+        if(this.propsData.id){
+          examElCoursewareDetail({id:this.propsData.id}).then(response => {
+            this.$set(this,'newData',{
+              id:response.data.id,
+              materialType:response.data.materialType,
+              knowledgePointId:response.data.knowledgePointId,
+              disciplineTypeId:'',
+              watermark:response.data.watermark?response.data.watermark:'',
+              coursewareName:response.data.coursewareName,
+              minLearningDuration:response.data.minLearningDuration,
+              autoCreditHours:response.data.autoCreditHours,
+              creditHours:response.data.creditHours?response.data.creditHours:0,
+              autoPoints:response.data.autoPoints,
+              points:response.data.points?response.data.points:0,
+              shareStatus:response.data.shareStatus,
+            });
+            if(response.data.materialType == 1 || response.data.materialType == 3){
+              this.$set(this.newData,'attachments',[{
+                attachmentPath:response.data.attachmentPath,
+                attachmentName:response.data.attachmentName?response.data.attachmentName:'',
+                attachmentSize:response.data.attachmentSize,
+              }]);
+              this.$set(this.newData,'articleContent','');
+            }else if(response.data.materialType == 4){
+              this.$set(this.newData,'attachments',[]);
+              this.$set(this.newData,'articleContent',response.data.articleContent);
+            }
+          });
+        }
       },
       // 返回按钮
       backPage(){
@@ -338,55 +399,90 @@
       },
       //重置
       resetButton(){
-
+        let self = this;
+        this.$confirm('确认重置数据?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+        }).then(() => {
+          self.getData();
+        }).catch(() => {});
       },
       //提交
       submitButton(){
-        if(this.newData.materialType == 3){
-          this.$set(this.newData,'data43',escape(this.$refs.UEditor.text));
-        }
+        let self = this;
         this.$refs["form"].validate(valid => {
           if (valid) {
-
+            this.$confirm('是否确认保存?', "警告", {
+              confirmButtonText: "确定",
+              cancelButtonText: "取消",
+              type: "warning"
+            }).then(function() {
+            }).then(() => {
+              if(self.newData.id){
+                //编辑课件
+                self.examElCoursewareEdit();
+              }else{
+                //新增课件
+                self.examElCoursewareAdd();
+              }
+            }).catch(() => {});
           }
         })
       },
+      //新增课件
+      examElCoursewareAdd(){
+        let obj = this.newData;
+        examElCoursewareAdd(obj).then(response => {
+          this.msgSuccess(response.message)
+          this.$parent.tableButton(6);
+        });
+      },
+      //编辑课件
+      examElCoursewareEdit(){
+        let obj = this.newData;
+        examElCoursewareEdit(obj).then(response => {
+          this.msgSuccess(response.message)
+          this.$parent.tableButton(6);
+        });
+      },
       //类型切换
       changeUpDataNumType(){
-        if(this.newData.materialType == 2){
-          if(this.newData.data42[1]){
-            this.$set(this,'upDataNumType',true);
-          }else{
-            this.$set(this,'upDataNumType',false);
-          }
-        }else{
-          this.$set(this,'upDataNumType',false);
-        }
+        this.$set(this.newData,'attachments',[]);
       },
       //删除文档
       delList(index){
-        this.newData.data42.splice(index,1);
-        if(this.newData.materialType == 2){
-          if(this.newData.data42[1]){
-            this.$set(this,'upDataNumType',true);
-          }else{
-            this.$set(this,'upDataNumType',false);
-          }
+        this.newData.attachments.splice(index,1);
+        if(!this.newData.attachments[1]){
+          this.$set(this.newData,'coursewareName',this.getLeftPart(this.newData.attachments[0].attachmentName));
+        }else{
+          this.$set(this.newData,'coursewareName','');
         }
       },
       //文档上传验证
       handleAvatarSuccess(res) {
-        if(this.newData.data42.length>9){
+        if(this.newData.attachments.length>9){
           this.msgError('已到达上传数量上限')
           return
         }
-        this.newData.data42.push(res.data);
-        if(this.newData.materialType == 2){
-          if(this.newData.data42[1]){
-            this.$set(this,'upDataNumType',true);
-          }else{
-            this.$set(this,'upDataNumType',false);
-          }
+        if(this.newData.id){
+          this.$set(this.newData,'attachments',[{
+            attachmentPath:res.data.url,
+            attachmentName:this.getLeftPart(res.data.name),
+            attachmentSize:res.data.size+'',
+          }]);
+        }else{
+          this.newData.attachments.push({
+            attachmentPath:res.data.url,
+            attachmentName:this.getLeftPart(res.data.name),
+            attachmentSize:res.data.size+'',
+          });
+        }
+        if(!this.newData.attachments[1]){
+          this.$set(this.newData,'coursewareName',this.getLeftPart(res.data.name));
+        }else{
+          this.$set(this.newData,'coursewareName','');
         }
       },
       beforeAvatarUpload(file) {
@@ -418,7 +514,7 @@
       fileSuccess(rootFile, file, response, chunk) {
         const result = JSON.parse(response);
         if (result.code==200 && !this.skip) {
-          axios.post(httpHeader+this.judgmentNetworkReturnAddress()+"/system/file/upload/merge", {
+          axios.post(httpHeader+this.judgmentNetworkReturnAddress()+"/exam/file/upload/merge", {
             identifier: file.uniqueIdentifier,
             filename: file.name,
             totalChunks: chunk.offset,
@@ -428,17 +524,28 @@
             }
           }).then((res) => {
             if (res.data.code==200) {
-              // this.$set(this.newData,'data41',this.formatFilePath(res.data.data));
-              this.$set(this.newData,'data41','http://192.168.1.8/statics/bigFile/20260721/3a0a0c04-9c34-484d-8fb2-2e46e2d241c8.mp4');
+              this.$set(this.newData,'attachments',[{
+                attachmentPath:res.data.data.url,
+                attachmentName:this.getLeftPart(res.data.data.name),
+                attachmentSize:res.data.data.size+'',
+              }]);
+              this.$set(this.newData,'coursewareName',this.getLeftPart(res.data.data.name));
+              this.$set(this.newData,'minLearningDuration',Math.floor(seconds / res.data.data.duration));
             } else {
-
+              this.msgError('上传出错,请稍后再试')
             }
           }).catch(function (error) {
           });
         } else {
-
+          this.msgError('上传出错,请稍后再试')
         }
       },
+      getLeftPart(str) {
+        const index = str.lastIndexOf('.');
+        // 如果没有找到 '.',直接返回原字符串
+        if (index === -1) return str;
+        return str.substring(0, index);
+      },
       fileComplete(rootFile) {
         // 一个根文件(文件夹)成功上传完成。
         this.fileName=rootFile.name;
@@ -449,10 +556,7 @@
       },
       filesAdded(file, fileList, event) {
         file.forEach((item)=>{
-          if(["image/png","image/jpeg","image/jpg","image/gif",
-            "application/pdf",
-            "video/mp4",
-            "application/vnd.openxmlformats-officedocument.wordprocessingml.document"].indexOf(item.fileType) === -1){
+          if(["video/mp4"].indexOf(item.fileType) === -1){
             this.msgError("文件格式不支持,请上传正确的文件.");
             file.ignored = true;
           }else{
@@ -497,10 +601,32 @@
           fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
         }
       },
-      formatFilePath(path) {
-        if (!path) return '';
-        return path.replace(/\\/g, '/');
-      }
+      //知识点
+      examElKnowledgePointTreeList(){
+        examElKnowledgePointTreeList({}).then(response => {
+          const list = response.data || [];
+          this.formatTreeData(list);
+          this.$set(this, 'optionListB', list);
+        });
+      },
+      //查询全部专业类别
+      examElDisciplineTypeList(){
+        examElDisciplineTypeList({}).then(response => {
+          this.$set(this,'optionListC',response.data);
+        });
+      },
+      formatTreeData(data) {
+        data.forEach(item => {
+          // 如果 children 存在,且是数组,且长度为 0(即 children: [])
+          if (Array.isArray(item.children) && item.children.length === 0) {
+            // 将 children 设为 undefined(或直接 delete item.children;)
+            item.children = undefined;
+          } else if (item.children && item.children.length > 0) {
+            // 如果还有下一级,继续递归处理
+            this.formatTreeData(item.children);
+          }
+        });
+      },
     },
   }
 </script>

+ 135 - 68
src/views/safetyEducationExaminationNew/courseManagement/coursewareManagement/index.vue

@@ -7,9 +7,9 @@
                  :inline="true" style="width:100%;">
           <div class="table-top-button-box">
             <div>
-              <p :class="tableType == 1?'check-table-button':''" @click="tableTypeButton(1)">全部</p>
-              <p :class="tableType == 2?'check-table-button':''" @click="tableTypeButton(2)">共享</p>
-              <p :class="tableType == 3?'check-table-button':''" @click="tableTypeButton(3)">不共享</p>
+              <p :class="queryParams.shareStatus == ''?'check-table-button':''" @click="tableTypeButton('')">全部</p>
+              <p :class="queryParams.shareStatus == '1'?'check-table-button':''" @click="tableTypeButton('1')">共享</p>
+              <p :class="queryParams.shareStatus == '0'?'check-table-button':''" @click="tableTypeButton('0')">不共享</p>
             </div>
           </div>
           <el-form-item label="" prop="materialType">
@@ -22,30 +22,37 @@
               />
             </el-select>
           </el-form-item>
-          <el-form-item label="" prop="queryParamsData2">
-            <el-select v-model="queryParams.queryParamsData2" placeholder="知识点" style="width: 200px">
-              <el-option
-                v-for="dict in optionListB"
-                :key="dict.value"
-                :label="dict.label"
-                :value="dict.value"
-              />
-            </el-select>
+          <el-form-item label="" prop="knowledgePointId">
+            <el-cascader
+              style="width: 180px"
+              v-model="queryParams.knowledgePointId"
+              :options="optionListB"
+              :props="{
+                    emitPath:false,
+                    checkStrictly: true,
+                    value: 'id',
+                    label: 'knowledgePointName',
+                    children: 'children',
+                  }"
+              :show-all-levels="false"
+              filterable
+              placeholder="请选择知识点"
+            ></el-cascader>
           </el-form-item>
-          <el-form-item label="" prop="queryParamsData3">
-            <el-select v-model="queryParams.queryParamsData3" placeholder="来源" style="width: 200px">
+          <el-form-item label="" prop="deptId">
+            <el-select v-model="queryParams.deptId" placeholder="来源" style="width: 200px">
               <el-option
                 v-for="dict in optionListC"
-                :key="dict.value"
-                :label="dict.label"
-                :value="dict.value"
+                :key="dict.deptId"
+                :label="dict.deptName"
+                :value="dict.deptId"
               />
             </el-select>
           </el-form-item>
-          <el-form-item label="" prop="queryParamsData4">
+          <el-form-item label="" prop="searchValue">
             <el-input
               maxLength="30"
-              v-model="queryParams.queryParamsData4"
+              v-model="queryParams.searchValue"
               placeholder="搜索名称"
               style="width: 200px"
             />
@@ -61,22 +68,38 @@
       </div>
       <div class="page-content-box">
         <el-table class="table-box" v-loading="loading" 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="100" show-overflow-tooltip/>
-          <el-table-column label="是否共享" prop="content" width="100" show-overflow-tooltip>
+          <el-table-column label="课件名称" prop="coursewareName"  show-overflow-tooltip>
+            <template slot-scope="scope">
+              <span @click="tableButton(2,scope.row)" style="color:#0183fa;cursor: pointer">{{scope.row.coursewareName}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="知识点" prop="knowledgePointName" width="120" show-overflow-tooltip/>
+          <!--<el-table-column label="专业类别" prop="content" width="100" show-overflow-tooltip/>-->
+          <el-table-column label="是否共享" prop="shareStatus" width="100" 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="100" 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="100" 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="100" show-overflow-tooltip>
             <template slot-scope="scope">
-              <span 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 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>
+              {{scope.row.minLearningDuration}}分钟
             </template>
           </el-table-column>
-          <el-table-column label="课件类型" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="文件大小" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="要求时长" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="可得学时" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="可得积分" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="来源" prop="content" width="100" show-overflow-tooltip/>
-          <el-table-column label="创建人" prop="content" width="100" show-overflow-tooltip/>
+          <el-table-column label="可得学时" prop="creditHours" width="100" show-overflow-tooltip/>
+          <el-table-column label="可得积分" prop="points" width="100" show-overflow-tooltip/>
+          <el-table-column label="来源" prop="deptName" width="100" show-overflow-tooltip/>
+          <el-table-column label="创建人" prop="createName" width="100" show-overflow-tooltip/>
           <el-table-column label="创建时间" prop="createTime" width="160" show-overflow-tooltip>
             <template slot-scope="scope">
               <span>{{ parseTime(scope.row.createTime,"{y}-{m}-{d} {h}:{i}") }}</span>
@@ -109,17 +132,21 @@
       </div>
     </div>
     <add-page :propsData="propsData" v-if="pageType === 2"></add-page>
+    <fullScreenFileLook ref="fullScreenFileLook"></fullScreenFileLook>
   </div>
 </template>
 <script>
-  //import { getDicts } from "@/api/commonality/noPermission";
-  //import { systemUserSelect } from "@/api/commonality/permission";
-  //import { getInfo } from "@/api/basicsModules/index";
+  import fullScreenFileLook from "@/components/fullScreenFileLook/fullScreenFileLook.vue";
+  import {
+    examElCoursewarePage,examElCoursewareDel,examElKnowledgePointTreeList,
+    systemDeptCurrentDept,examElCoursewareDetail
+  } from "@/api/safetyEducationExaminationNew/index";
   import addPage from "./addPage.vue";
   export default {
     name: 'index',
     components: {
       addPage,
+      fullScreenFileLook
     },
     data () {
       return {
@@ -130,15 +157,16 @@
         loading:false,
         //下拉列表数据
         optionListA:[{value:1,label:'视频'},{value:3,label:'文档'},{value:4,label:'文章'}],
-        optionListB:[{value:true,label:'启用'},{value:false,label:'停用'}],
-        optionListC:[{value:true,label:'启用'},{value:false,label:'停用'}],
-        //查询条件
-        tableType:1,
+        optionListB:[],
+        optionListC:[],
         queryParams:{
           page:1,
           pageSize:20,
-          materialType:"",
-          queryParamsData2 :null,
+          searchValue:'',
+          shareStatus:'',
+          materialType:null,
+          knowledgePointId :null,
+          deptId :null,
         },
         //列表数据
         dataList:[],
@@ -152,13 +180,15 @@
 
     },
     mounted () {
-      //this.getList();
+      this.systemDeptCurrentDept();
+      this.examElKnowledgePointTreeList();
+      this.getList();
     },
     methods: {
       //切换按钮
       tableTypeButton(val){
-        if(this.tableType != val){
-          this.$set(this,'tableType',val);
+        if(this.queryParams.shareStatus != val){
+          this.$set(this.queryParams,'shareStatus',val);
           this.handleQuery();
         }
       },
@@ -172,8 +202,11 @@
         this.$set(this,'queryParams',{
           page:1,
           pageSize:20,
-          materialType:"",
-          queryParamsData2 :null,
+          searchValue:'',
+          shareStatus:'',
+          materialType:null,
+          knowledgePointId :null,
+          deptId :null,
         });
         this.getList();
       },
@@ -181,7 +214,7 @@
       getList(){
         this.$set(this,'loading',true);
         let obj = JSON.parse(JSON.stringify(this.queryParams))
-        getListFunction(obj).then(response => {
+        examElCoursewarePage(obj).then(response => {
           this.$set(this,'loading',false);
           this.$set(this,'dataList',response.data.records);
           this.$set(this,'total',response.data.total);
@@ -195,16 +228,38 @@
           this.$set(this,'pageType',2);
           this.$set(this,'propsData',{});
         }else if(type == 2){
-          //详情
-          this.$set(this,'pageType',2);
-          let obj = JSON.parse(JSON.stringify(row))
-          obj.showType = true;
-          this.$set(this,'propsData',obj);
+          //预览
+          let name=row.coursewareName;
+          let url='';
+          let type='';
+          if(row.materialType == 1){
+            //视频
+            type = 'video'
+            url = row.attachmentPath;
+            this.$refs['fullScreenFileLook'].initialize(name,url,type);
+          }else if(row.materialType == 3){
+            //文档
+            if(row.attachmentType == '.docx'){
+              type = 'docx'
+            }else if(row.attachmentType == '.xlsx'){
+              type = 'excel'
+            }else if(row.attachmentType == '.pdf'){
+              type = 'pdf'
+            }
+            url = row.attachmentPath;
+            this.$refs['fullScreenFileLook'].initialize(name,url,type);
+          }else if(row.materialType == 4){
+            //富文本
+            examElCoursewareDetail({id:row.id}).then(response => {
+              type = 'text'
+              url = response.data.articleContent;
+              this.$refs['fullScreenFileLook'].initialize(name,url,type);
+            });
+          }
         }else if(type == 3){
           //编辑
           this.$set(this,'pageType',2);
           let obj = JSON.parse(JSON.stringify(row))
-          obj.showType = false;
           this.$set(this,'propsData',obj);
         }else if(type == 4){
           //删除
@@ -214,21 +269,7 @@
             type: "warning"
           }).then(function() {
           }).then(() => {
-            deleteFunction({id:row.id}).then(response => {
-              self.msgSuccess(response.message)
-              self.getList();
-            });
-          }).catch(() => {});
-        }else if(type == 5){
-          //启用&停用
-          let text = row.state  ? "停用" : "启用";
-          this.$confirm('是否确认' + text + '?', "警告", {
-            confirmButtonText: "确定",
-            cancelButtonText: "取消",
-            type: "warning"
-          }).then(function() {
-          }).then(() => {
-            stateFunction({id:row.id,state:!row.state,}).then(response => {
+            examElCoursewareDel({id:row.id}).then(response => {
               self.msgSuccess(response.message)
               self.getList();
             });
@@ -239,6 +280,32 @@
           this.getList();
         }
       },
+      //知识点
+      examElKnowledgePointTreeList(){
+        examElKnowledgePointTreeList({}).then(response => {
+          const list = response.data || [];
+          this.formatTreeData(list);
+          this.$set(this, 'optionListB', list);
+        });
+      },
+      //学院列表
+      systemDeptCurrentDept(){
+        systemDeptCurrentDept({}).then(response => {
+          this.$set(this,'optionListC',response.data);
+        });
+      },
+      formatTreeData(data) {
+        data.forEach(item => {
+          // 如果 children 存在,且是数组,且长度为 0(即 children: [])
+          if (Array.isArray(item.children) && item.children.length === 0) {
+            // 将 children 设为 undefined(或直接 delete item.children;)
+            item.children = undefined;
+          } else if (item.children && item.children.length > 0) {
+            // 如果还有下一级,继续递归处理
+            this.formatTreeData(item.children);
+          }
+        });
+      },
     },
   }
 </script>

+ 40 - 38
src/views/safetyEducationExaminationNew/questionBankManagement/questionBankManagement/index.vue

@@ -5,8 +5,8 @@
       <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">
-            <el-select v-model="queryParams.queryParamsData1" placeholder="是否共享" style="width: 180px">
+          <el-form-item label="" prop="shareStatus">
+            <el-select v-model="queryParams.shareStatus" placeholder="是否共享" style="width: 180px">
               <el-option
                 v-for="dict in optionListA"
                 :key="dict.value"
@@ -15,9 +15,9 @@
               />
             </el-select>
           </el-form-item>
-          <el-form-item label="" prop="queryParamsData2">
+          <el-form-item label="" prop="knowledgePointId">
             <el-cascader
-              v-model="queryParams.queryParamsData2"
+              v-model="queryParams.knowledgePointId"
               :options="optionListB"
               :props="{
                 emitPath:false,
@@ -32,8 +32,8 @@
               placeholder="知识点"
             ></el-cascader>
           </el-form-item>
-          <el-form-item label="" prop="queryParamsData3">
-            <el-select v-model="queryParams.queryParamsData3" placeholder="题型" style="width: 180px">
+          <el-form-item label="" prop="questionType">
+            <el-select v-model="queryParams.questionType" placeholder="题型" style="width: 180px">
               <el-option
                 v-for="dict in optionListC"
                 :key="dict.value"
@@ -42,8 +42,8 @@
               />
             </el-select>
           </el-form-item>
-          <el-form-item label="" prop="queryParamsData4">
-            <el-select v-model="queryParams.queryParamsData4" placeholder="难度" style="width: 180px">
+          <el-form-item label="" prop="difficulty">
+            <el-select v-model="queryParams.difficulty" placeholder="难度" style="width: 180px">
               <el-option
                 v-for="dict in optionListD"
                 :key="dict.value"
@@ -52,10 +52,10 @@
               />
             </el-select>
           </el-form-item>
-          <el-form-item label="" prop="queryParamsData5">
+          <el-form-item label="" prop="searchValue">
             <el-input
               maxLength="30"
-              v-model="queryParams.queryParamsData5"
+              v-model="queryParams.searchValue"
               placeholder="搜索试题"
               style="width: 200px"
             />
@@ -73,18 +73,26 @@
       </div>
       <div class="page-content-box">
         <el-table class="table-box" v-loading="loading" border :data="dataList">
-          <el-table-column label="题干" prop="name"  show-overflow-tooltip>
+          <el-table-column label="题干" prop="questionContent"  show-overflow-tooltip>
             <template slot-scope="scope">
-              <span>{{ cleanRichText(scope.row) }}</span>
+              <span>{{ scope.row.questionContent }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="知识点" prop="knowledgePointNames" width="200" show-overflow-tooltip/>
+          <el-table-column label="题型" prop="questionType" width="200" show-overflow-tooltip>
+            <template slot-scope="scope">
+              <span>{{ scope.row.questionType == 1?'单选题':(scope.row.questionType == 2?'多选题':(scope.row.questionType == 3?'判断题':'')) }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="难度" prop="content" width="200" show-overflow-tooltip>
+            <template slot-scope="scope">
+              <span>{{ scope.row.questionType == 1?'简单':(scope.row.questionType == 2?'一般':(scope.row.questionType == 3?'较难':(scope.row.questionType == 4?'极难':''))) }}</span>
             </template>
           </el-table-column>
-          <el-table-column label="知识点" prop="content" width="200" show-overflow-tooltip/>
-          <el-table-column label="题型" prop="content" width="200" show-overflow-tooltip/>
-          <el-table-column label="难度" prop="content" width="200" show-overflow-tooltip/>
           <el-table-column label="是否共享" prop="content" width="200" show-overflow-tooltip>
             <template slot-scope="scope">
-              <span 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 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>
+              <span 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)" v-if="scope.row.shareStatus == 1">共享</span>
+              <span 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)" v-if="scope.row.shareStatus == 0">不共享</span>
             </template>
           </el-table-column>
           <el-table-column label="操作" width="200" show-overflow-tooltip>
@@ -117,7 +125,7 @@
 <script>
   //import { getDicts } from "@/api/commonality/noPermission";
   //import { systemUserSelect } from "@/api/commonality/permission";
-  import { examElKnowledgePointTreeList, } from "@/api/safetyEducationExaminationNew/index";
+  import { examElKnowledgePointTreeList,examElQuestionBankList } from "@/api/safetyEducationExaminationNew/index";
   import importComponent from "@/components/importComponent/importComponent.vue";
   import addPage from "./addPage.vue";
   export default {
@@ -144,7 +152,7 @@
           fileName:'导入模板-',                                       //下载模板命名
         },
         //下拉列表数据
-        optionListA:[{value:true,label:'共享'},{value:false,label:'不共享'}],
+        optionListA:[{value:1,label:'共享'},{value:0,label:'不共享'}],
         optionListB:[],
         optionListC:[{value:1,label:'单选'},{value:2,label:'多选'},{value:3,label:'判断'}],
         optionListD:[{value:1,label:'简单'},{value:2,label:'一般'},{value:3,label:'较难'},{value:4,label:'极难'}],
@@ -152,20 +160,14 @@
         queryParams:{
           page:1,
           pageSize:20,
-          queryParamsData1:null,
-          queryParamsData2 :null,
-          queryParamsData3 :null,
-          queryParamsData4 :null,
-          queryParamsData5 :'',
+          shareStatus:null,
+          knowledgePointId :null,
+          questionType :null,
+          difficulty :null,
+          searchValue :'',
         },
         //列表数据
-        dataList:[
-          {text:'<img src="https://example.com/images/test.jpg" alt="测试图片" style="width: 100%; max-width: 600px;" />',name:'321'},
-          {text:'<p>这是一段普通的<strong>测试文本</strong>,里面包含了一个<a href="https://www.example.com" target="_blank">外部链接</a>。</p>\n' +
-              '<p>下面是一张图片:</p>\n' +
-              '<img src="https://example.com/images/test.jpg" alt="测试图片" style="width: 100%; max-width: 600px;" />\n' +
-              '<p>图片下方还有更多文字内容,<em>用于验证正则表达式或DOM解析</em>是否能完美清洗掉所有HTML标签,只保留纯文字。</p>',name:'123'},
-        ],
+        dataList:[],
         //数据数量
         total:0,
         //组件传参
@@ -177,7 +179,7 @@
     },
     mounted () {
       this.examElKnowledgePointTreeList();
-      //this.getList();
+      this.getList();
     },
     methods: {
       //清洗富文本
@@ -198,11 +200,11 @@
         this.$set(this,'queryParams',{
           page:1,
           pageSize:20,
-          queryParamsData1:null,
-          queryParamsData2 :null,
-          queryParamsData3 :null,
-          queryParamsData4 :null,
-          queryParamsData5 :'',
+          shareStatus:null,
+          knowledgePointId :null,
+          questionType :null,
+          difficulty :null,
+          searchValue :'',
         });
         this.getList();
       },
@@ -210,7 +212,7 @@
       getList(){
         this.$set(this,'loading',true);
         let obj = JSON.parse(JSON.stringify(this.queryParams))
-        getListFunction(obj).then(response => {
+        examElQuestionBankList(obj).then(response => {
           this.$set(this,'loading',false);
           this.$set(this,'dataList',response.data.records);
           this.$set(this,'total',response.data.total);

+ 229 - 130
src/views/safetyEducationExaminationNew/workbench/ExamStatsCard.vue

@@ -1,37 +1,42 @@
-<!-- 安监室安全分布表 + 考试成绩统计 -->
+<!-- 安监室/实验室安全分布表 + 考试成绩统计 -->
 <template>
-  <div class="exam-stats-card">
+  <div class="exam-stats-wrap">
+
     <!-- 安监室安全分布表 -->
     <div class="section-card">
       <div class="section-header">
         <span class="section-title">安监室安全分布表</span>
-        <div class="header-actions">
-          <el-button size="mini">年</el-button>
-          <el-button size="mini">季度</el-button>
-          <el-button size="mini">月</el-button>
-          <el-button size="mini" type="primary">下载</el-button>
+        <div class="header-right">
+          <el-radio-group v-model="tableFilter.safetyPeriod" size="mini">
+            <el-radio-button label="年">年</el-radio-button>
+            <el-radio-button label="季度">季度</el-radio-button>
+            <el-radio-button label="月">月</el-radio-button>
+          </el-radio-group>
+          <el-button size="mini" type="primary" icon="el-icon-download">下载</el-button>
         </div>
       </div>
       <el-table :data="tableData.safetyTable" border size="small" stripe>
-        <el-table-column prop="name" label="姓名" min-width="80" />
-        <el-table-column prop="dept" label="部门" min-width="100" />
-        <el-table-column prop="userId" label="用户编号" min-width="100" />
-        <el-table-column prop="eduTitle" label="安全教育名称" min-width="160" />
-        <el-table-column prop="subject" label="科目" min-width="60" />
-        <el-table-column prop="status" label="状态" min-width="60">
+        <el-table-column prop="name" label="姓名" width="70" />
+        <el-table-column prop="dept" label="部门单位" min-width="100" show-overflow-tooltip />
+        <el-table-column prop="userId" label="用户编号" width="100" />
+        <el-table-column prop="eduTitle" label="安全教育名称" min-width="160" show-overflow-tooltip />
+        <el-table-column prop="subject" label="科目" width="60" />
+        <el-table-column prop="status" label="状态" width="80">
           <template slot-scope="scope">
-            <el-tag :type="scope.row.status === '完成' ? 'success' : 'warning'" size="mini">{{ scope.row.status }}</el-tag>
+            <el-tag :type="scope.row.status === '完成' ? 'success' : 'warning'" size="mini" effect="plain">{{ scope.row.status }}</el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="person" label="负责人" min-width="80" />
-        <el-table-column prop="startDate" label="开始时间" min-width="110" />
-        <el-table-column prop="endDate" label="截止时间" min-width="110" />
-        <el-table-column prop="score" label="成绩" min-width="60" />
-        <el-table-column label="操作" min-width="160" fixed="right">
+        <el-table-column prop="person" label="负责人" width="70" />
+        <el-table-column prop="startDate" label="开始时间" width="140" />
+        <el-table-column prop="endDate" label="截止时间" width="140" />
+        <el-table-column prop="score" label="成绩" width="60" align="center" />
+        <el-table-column label="操作" width="170" fixed="right">
           <template slot-scope="scope">
-            <el-button size="mini" type="primary" @click="() => {}">查看</el-button>
-            <el-button size="mini" type="success" @click="() => {}">{{ scope.row.status === '完成' ? '重考' : '考试' }}</el-button>
-            <el-button size="mini" type="warning" @click="() => {}">提醒</el-button>
+            <el-button size="mini" type="primary" plain>查看</el-button>
+            <el-button size="mini" :type="scope.row.status === '完成' ? 'success' : 'warning'" plain>
+              {{ scope.row.status === '完成' ? '重考' : '考试' }}
+            </el-button>
+            <el-button size="mini" type="danger" plain>提醒</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -41,33 +46,37 @@
     <div class="section-card">
       <div class="section-header">
         <span class="section-title">实验室安全分布表</span>
-        <div class="header-actions">
-          <el-button size="mini">年</el-button>
-          <el-button size="mini">季度</el-button>
-          <el-button size="mini">月</el-button>
-          <el-button size="mini" type="primary">下载</el-button>
+        <div class="header-right">
+          <el-radio-group v-model="tableFilter.labPeriod" size="mini">
+            <el-radio-button label="年">年</el-radio-button>
+            <el-radio-button label="季度">季度</el-radio-button>
+            <el-radio-button label="月">月</el-radio-button>
+          </el-radio-group>
+          <el-button size="mini" type="primary" icon="el-icon-download">下载</el-button>
         </div>
       </div>
       <el-table :data="tableData.labTable" border size="small" stripe>
-        <el-table-column prop="name" label="姓名" min-width="80" />
-        <el-table-column prop="dept" label="部门" min-width="100" />
-        <el-table-column prop="userId" label="用户编号" min-width="100" />
-        <el-table-column prop="eduTitle" label="安全教育名称" min-width="160" />
-        <el-table-column prop="subject" label="科目" min-width="60" />
-        <el-table-column prop="status" label="状态" min-width="60">
+        <el-table-column prop="name" label="姓名" width="70" />
+        <el-table-column prop="dept" label="部门单位" min-width="100" show-overflow-tooltip />
+        <el-table-column prop="userId" label="用户编号" width="100" />
+        <el-table-column prop="eduTitle" label="安全教育名称" min-width="160" show-overflow-tooltip />
+        <el-table-column prop="subject" label="科目" width="60" />
+        <el-table-column prop="status" label="状态" width="80">
           <template slot-scope="scope">
-            <el-tag :type="scope.row.status === '完成' ? 'success' : 'warning'" size="mini">{{ scope.row.status }}</el-tag>
+            <el-tag :type="scope.row.status === '完成' ? 'success' : 'warning'" size="mini" effect="plain">{{ scope.row.status }}</el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="person" label="负责人" min-width="80" />
-        <el-table-column prop="startDate" label="开始时间" min-width="110" />
-        <el-table-column prop="endDate" label="截止时间" min-width="110" />
-        <el-table-column prop="score" label="成绩" min-width="60" />
-        <el-table-column label="操作" min-width="160" fixed="right">
+        <el-table-column prop="person" label="负责人" width="70" />
+        <el-table-column prop="startDate" label="开始时间" width="140" />
+        <el-table-column prop="endDate" label="截止时间" width="140" />
+        <el-table-column prop="score" label="成绩" width="60" align="center" />
+        <el-table-column label="操作" width="170" fixed="right">
           <template slot-scope="scope">
-            <el-button size="mini" type="primary" @click="() => {}">查看</el-button>
-            <el-button size="mini" type="success" @click="() => {}">{{ scope.row.status === '完成' ? '重考' : '考试' }}</el-button>
-            <el-button size="mini" type="warning" @click="() => {}">提醒</el-button>
+            <el-button size="mini" type="primary" plain>查看</el-button>
+            <el-button size="mini" :type="scope.row.status === '完成' ? 'success' : 'warning'" plain>
+              {{ scope.row.status === '完成' ? '重考' : '考试' }}
+            </el-button>
+            <el-button size="mini" type="danger" plain>提醒</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -77,84 +86,123 @@
     <div class="section-card">
       <div class="section-header">
         <span class="section-title">考试成绩统计</span>
-        <div class="header-actions">
-          <el-select v-model="tableData.statsYear" size="mini" style="width:140px">
+        <div class="header-right">
+          <el-select v-model="tableFilter.statsYear" size="mini" style="width:150px">
             <el-option label="2025-2026 学年" value="2025-2026" />
             <el-option label="2024-2025 学年" value="2024-2025" />
           </el-select>
-          <el-button size="mini">季度</el-button>
-          <el-button size="mini">月</el-button>
-          <el-button size="mini" type="primary">下载</el-button>
+          <el-radio-group v-model="tableFilter.statsPeriod" size="mini">
+            <el-radio-button label="季度">季度</el-radio-button>
+            <el-radio-button label="月">月</el-radio-button>
+          </el-radio-group>
+          <el-button size="mini" type="primary" icon="el-icon-download">下载</el-button>
         </div>
       </div>
-      <div class="stats-body">
-        <!-- 柱状图占位 -->
-        <div class="chart-placeholder">
-          <div class="bar-chart-mock">
-            <div v-for="(bar, i) in tableData.barData" :key="i" class="bar-col">
-              <div class="bar green" :style="{height: bar.pass + 'px'}"></div>
-              <div class="bar red" :style="{height: bar.fail + 'px'}"></div>
-              <div class="bar-label">{{ bar.label }}</div>
+
+      <div class="chart-row">
+        <!-- 柱状图 -->
+        <div class="bar-chart-area">
+          <div class="chart-legend">
+            <span class="legend-item"><i class="dot green"></i>优秀 ≥90</span>
+            <span class="legend-item"><i class="dot blue"></i>良好 60-89</span>
+            <span class="legend-item"><i class="dot red"></i>不及格 &lt;60</span>
+            <span class="legend-item"><i class="dot gray"></i>未考</span>
+          </div>
+          <div class="bar-chart">
+            <div class="y-labels">
+              <span v-for="y in [100, 80, 60, 40, 20, 0]" :key="y">{{ y }}</span>
+            </div>
+            <div class="bars-container">
+              <div v-for="(g, i) in chartData.barGroups" :key="i" class="bar-group">
+                <div class="bar-stack">
+                  <div class="seg green" :style="{height: g.excellent + 'px'}"></div>
+                  <div class="seg blue" :style="{height: g.good + 'px'}"></div>
+                  <div class="seg red" :style="{height: g.fail + 'px'}"></div>
+                </div>
+                <div class="bar-label">{{ g.label }}</div>
+              </div>
             </div>
           </div>
         </div>
-        <!-- 饼图占位 -->
-        <div class="pie-placeholder">
-          <div class="pie-mock">
-            <svg viewBox="0 0 100 100" width="120" height="120">
-              <circle cx="50" cy="50" r="40" fill="#67c23a" />
-              <path d="M50,50 L50,10 A40,40 0 0,1 85,65 Z" fill="#f56c6c" />
-              <path d="M50,50 L85,65 A40,40 0 0,1 20,80 Z" fill="#e6a23c" />
+
+        <!-- 饼图 -->
+        <div class="pie-chart-area">
+          <div class="pie-wrap">
+            <svg viewBox="0 0 100 100" width="130" height="130">
+              <circle cx="50" cy="50" r="35" fill="none" stroke="#67c23a" stroke-width="30" stroke-dasharray="132 220" stroke-dashoffset="0" transform="rotate(-90 50 50)" />
+              <circle cx="50" cy="50" r="35" fill="none" stroke="#409eff" stroke-width="30" stroke-dasharray="66 220" stroke-dashoffset="-132" transform="rotate(-90 50 50)" />
+              <circle cx="50" cy="50" r="35" fill="none" stroke="#f56c6c" stroke-width="30" stroke-dasharray="22 220" stroke-dashoffset="-198" transform="rotate(-90 50 50)" />
+              <circle cx="50" cy="50" r="20" fill="#fff" />
             </svg>
           </div>
           <div class="pie-legend">
-            <div><span class="dot green"></span>优秀 ≥90</div>
-            <div><span class="dot yellow"></span>良好 60-89</div>
-            <div><span class="dot red"></span>不及格 &lt;60</div>
+            <div class="p-item"><i class="dot green"></i><span>优秀 ≥90</span></div>
+            <div class="p-item"><i class="dot blue"></i><span>良好 60-89</span></div>
+            <div class="p-item"><i class="dot red"></i><span>不及格 &lt;60</span></div>
           </div>
         </div>
       </div>
+
       <!-- 统计表格 -->
-      <el-table :data="tableData.statsTable" border size="small" stripe>
+      <el-table :data="chartData.statsTable" border size="small" stripe>
         <el-table-column prop="category" label="分类" min-width="120" />
-        <el-table-column prop="name" label="名称" min-width="120" />
-        <el-table-column prop="total" label="总人数" min-width="80" />
-        <el-table-column prop="pass" label="通过人数" min-width="80" />
-        <el-table-column prop="fail" label="未通过人数" min-width="80" />
-        <el-table-column prop="rate" label="通过率" min-width="80" />
+        <el-table-column prop="name" label="名称" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="total" label="参加人数" width="90" align="center" />
+        <el-table-column prop="excellent" label="优秀" width="70" align="center" />
+        <el-table-column prop="good" label="良好" width="70" align="center" />
+        <el-table-column prop="fail" label="不及格" width="80" align="center" />
+        <el-table-column prop="rate" label="通过率" width="80" align="center" />
       </el-table>
     </div>
+
   </div>
 </template>
 
 <script>
+const mockTableRow = (n) => ({
+  name: '姓名',
+  dept: `部门单位名称${n}`,
+  userId: `2025000${String(n).padStart(2, '0')}`,
+  eduTitle: '高校宝安全教育培训与考核内容',
+  subject: '无',
+  status: n % 3 !== 0 ? '完成' : '待完成',
+  person: '负责人',
+  startDate: '2026-04-28 16:30',
+  endDate: '2026-05-28 16:30',
+  score: n % 3 !== 0 ? String(70 + n * 3) : '--'
+})
+
 export default {
   name: 'ExamStatsCard',
   data() {
-    const mockRow = (n) => ({
-      name: '姓名', dept: '部门单位', userId: `202500000${n}`,
-      eduTitle: '高校宝安全教育培训与考核内容', subject: '无',
-      status: n % 2 === 0 ? '完成' : '待完成',
-      person: '负责人', startDate: '2026-04-28 16:30', endDate: '2026-05-28 16:30',
-      score: n % 2 === 0 ? '90' : '--'
-    })
     return {
-      tableData: {
+      tableFilter: {
+        safetyPeriod: '年',
+        labPeriod: '年',
         statsYear: '2025-2026',
-        safetyTable: Array.from({length: 5}, (_, i) => mockRow(i + 1)),
-        labTable: Array.from({length: 5}, (_, i) => mockRow(i + 1)),
-        barData: [
-          { label: '总览', pass: 80, fail: 20 },
-          { label: '生物类', pass: 60, fail: 30 },
-          { label: '辐射类', pass: 70, fail: 15 },
-          { label: '化学', pass: 90, fail: 10 },
-          { label: '科目', pass: 50, fail: 40 },
+        statsPeriod: '季度',
+      },
+      tableData: {
+        safetyTable: Array.from({ length: 6 }, (_, i) => mockTableRow(i + 1)),
+        labTable: Array.from({ length: 6 }, (_, i) => mockTableRow(i + 1)),
+      },
+      chartData: {
+        barGroups: [
+          { label: '生物类', excellent: 60, good: 40, fail: 15 },
+          { label: '辐射类', excellent: 80, good: 30, fail: 10 },
+          { label: '化学', excellent: 50, good: 50, fail: 20 },
+          { label: '总览', excellent: 90, good: 35, fail: 8 },
+          { label: '科目', excellent: 40, good: 60, fail: 25 },
+          { label: '生物类', excellent: 70, good: 45, fail: 12 },
+          { label: '辐射类', excellent: 55, good: 55, fail: 18 },
+          { label: '化学', excellent: 65, good: 38, fail: 14 },
         ],
         statsTable: [
-          { category: '安全教育', name: '安全教育名称', total: 25, pass: 20, fail: 5, rate: '80%' },
-          { category: '安全教育', name: '安全教育名称', total: 30, pass: 28, fail: 2, rate: '93%' },
-          { category: '实验室安全', name: '实验室安全名称', total: 20, pass: 15, fail: 5, rate: '75%' },
-          { category: '化学实验', name: '化学实验名称', total: 18, pass: 16, fail: 2, rate: '89%' },
+          { category: '安全教育', name: '安全教育名称一', total: 25, excellent: 10, good: 12, fail: 3, rate: '88%' },
+          { category: '安全教育', name: '安全教育名称二', total: 30, excellent: 15, good: 12, fail: 3, rate: '90%' },
+          { category: '实验室安全', name: '实验室安全名称', total: 20, excellent: 8, good: 9, fail: 3, rate: '85%' },
+          { category: '化学实验', name: '化学实验名称', total: 18, excellent: 7, good: 8, fail: 3, rate: '83%' },
+          { category: '辐射安全', name: '辐射安全名称', total: 22, excellent: 9, good: 10, fail: 3, rate: '86%' },
         ]
       }
     }
@@ -163,82 +211,133 @@ export default {
 </script>
 
 <style scoped lang="scss">
-.exam-stats-card {
+.exam-stats-wrap {
   .section-card {
     background: #fff;
     border-radius: 6px;
     padding: 16px 20px;
-    margin-bottom: 16px;
-    box-shadow: 0 1px 4px rgba(0,0,0,0.08);
+    margin-bottom: 12px;
+    box-shadow: 0 1px 4px rgba(0,0,0,0.06);
 
     .section-header {
       display: flex;
       justify-content: space-between;
       align-items: center;
       margin-bottom: 14px;
-      .section-title { font-size: 15px; font-weight: bold; color: #333; }
-      .header-actions { display: flex; gap: 8px; align-items: center; }
+
+      .section-title { font-size: 14px; font-weight: 600; color: #333; }
+      .header-right { display: flex; align-items: center; gap: 10px; }
     }
 
-    .stats-body {
+    .chart-row {
       display: flex;
       gap: 24px;
       margin-bottom: 16px;
+      align-items: flex-start;
 
-      .chart-placeholder {
+      .bar-chart-area {
         flex: 1;
-        background: #f5f7fa;
-        border-radius: 4px;
-        padding: 16px;
-        min-height: 160px;
-        display: flex;
-        align-items: flex-end;
 
-        .bar-chart-mock {
+        .chart-legend {
           display: flex;
+          gap: 16px;
+          margin-bottom: 10px;
+          font-size: 12px;
+          color: #555;
+          .legend-item { display: flex; align-items: center; gap: 4px; }
+        }
+
+        .bar-chart {
+          display: flex;
+          gap: 8px;
           align-items: flex-end;
-          gap: 12px;
-          width: 100%;
-          justify-content: space-around;
+          height: 160px;
 
-          .bar-col {
+          .y-labels {
             display: flex;
             flex-direction: column;
-            align-items: center;
-            gap: 2px;
+            justify-content: space-between;
+            font-size: 11px;
+            color: #aaa;
+            height: 100%;
+            padding-bottom: 20px;
+            text-align: right;
+            min-width: 28px;
+          }
 
-            .bar {
-              width: 20px;
-              &.green { background: #67c23a; }
-              &.red { background: #f56c6c; }
-            }
+          .bars-container {
+            flex: 1;
+            display: flex;
+            align-items: flex-end;
+            justify-content: space-around;
+            height: 100%;
+            border-left: 1px solid #eee;
+            border-bottom: 1px solid #eee;
+            padding: 0 8px 20px;
+
+            .bar-group {
+              display: flex;
+              flex-direction: column;
+              align-items: center;
+              position: relative;
+
+              .bar-stack {
+                display: flex;
+                flex-direction: column-reverse;
+                width: 20px;
+                gap: 1px;
 
-            .bar-label { font-size: 11px; color: #666; margin-top: 4px; }
+                .seg {
+                  width: 100%;
+                  border-radius: 1px;
+                  &.green { background: #67c23a; }
+                  &.blue { background: #409eff; }
+                  &.red { background: #f56c6c; }
+                }
+              }
+
+              .bar-label {
+                font-size: 10px;
+                color: #666;
+                margin-top: 4px;
+                white-space: nowrap;
+              }
+            }
           }
         }
       }
 
-      .pie-placeholder {
-        width: 200px;
+      .pie-chart-area {
+        width: 220px;
         display: flex;
-        flex-direction: column;
         align-items: center;
-        justify-content: center;
-        gap: 12px;
+        gap: 16px;
+        padding-top: 28px;
 
         .pie-legend {
-          font-size: 12px;
-          color: #666;
-          div { margin-bottom: 4px; display: flex; align-items: center; gap: 6px; }
-          .dot {
-            width: 10px; height: 10px; border-radius: 50%; display: inline-block;
-            &.green { background: #67c23a; }
-            &.yellow { background: #e6a23c; }
-            &.red { background: #f56c6c; }
+          .p-item {
+            display: flex;
+            align-items: center;
+            gap: 6px;
+            font-size: 12px;
+            color: #555;
+            margin-bottom: 8px;
           }
         }
       }
     }
   }
+
+  .dot {
+    display: inline-block;
+    width: 10px;
+    height: 10px;
+    border-radius: 50%;
+    flex-shrink: 0;
+    &.green { background: #67c23a; }
+    &.blue { background: #409eff; }
+    &.red { background: #f56c6c; }
+    &.gray { background: #c0c4cc; }
+  }
 }
 </style>

+ 136 - 66
src/views/safetyEducationExaminationNew/workbench/ResourceCard.vue

@@ -3,25 +3,34 @@
   <div class="resource-card">
     <div class="card-title">实验室安全素养资源卡</div>
 
-    <!-- 分类 Tab -->
-    <div class="tab-bar">
-      <el-button
-        v-for="tab in resourceData.tabs"
-        :key="tab"
-        :type="resourceData.activeTab === tab ? 'primary' : ''"
-        size="mini"
-        @click="resourceData.activeTab = tab"
-      >{{ tab }}</el-button>
+    <!-- 分类 Tab 横向滚动 -->
+    <div class="tab-scroll-wrap">
+      <div class="tab-bar">
+        <el-button
+          v-for="tab in resourceData.tabs"
+          :key="tab"
+          :type="resourceData.activeTab === tab ? 'primary' : 'default'"
+          size="mini"
+          round
+          @click="resourceData.activeTab = tab"
+        >{{ tab }}</el-button>
+      </div>
     </div>
 
     <div class="resource-body">
       <!-- 左侧:知识学习 + 刷题练习 -->
       <div class="left-panel">
+
         <!-- 知识学习 -->
-        <div class="sub-section">
-          <div class="sub-title">知识学习 <span class="more-link">查看更多</span></div>
-          <div v-for="item in resourceData.knowledgeList" :key="item.name" class="file-item">
-            <i class="el-icon-document file-icon"></i>
+        <div class="sub-block">
+          <div class="sub-header">
+            <span class="sub-title">知识学习</span>
+            <a class="more-link">查看更多</a>
+          </div>
+          <div v-for="item in resourceData.knowledgeList" :key="item.name + item.year" class="file-item">
+            <div class="file-icon-wrap">
+              <i class="el-icon-document file-icon"></i>
+            </div>
             <div class="file-info">
               <div class="file-name">{{ item.name }}</div>
               <div class="file-meta">{{ item.year }}|{{ item.term }}|{{ item.credit }}学分</div>
@@ -31,34 +40,42 @@
         </div>
 
         <!-- 刷题练习 -->
-        <div class="sub-section">
-          <div class="sub-title">刷题练习 <span class="more-link">查看更多</span></div>
+        <div class="sub-block">
+          <div class="sub-header">
+            <span class="sub-title">刷题练习</span>
+            <a class="more-link">查看更多</a>
+          </div>
           <div class="practice-item">
-            <div class="practice-name">
-              <a class="link">2026-09-01 9:30:33</a>
+            <div class="practice-top">
+              <a class="practice-date link">2026-09-01 9:30:33</a>
+              <div class="practice-more"><i class="el-icon-more"></i></div>
             </div>
-            <div class="practice-meta">
-              <span>练习题:32/369</span>
+            <div class="practice-stats">
+              <span>练习题:<b>32/369</b></span>
             </div>
-            <div class="practice-meta">
-              <span>答对率:50%</span>
-              <span style="margin-left:16px">正确数:72%</span>
-              <span style="margin-left:16px">错误数:96%</span>
+            <div class="practice-rates">
+              <span>答对率:<b>50%</b></span>
+              <span>正确数:<b>72%</b></span>
+              <span>错误数:<b>96%</b></span>
             </div>
             <div class="practice-time">2026-09-01 11:03:25</div>
           </div>
         </div>
+
       </div>
 
       <!-- 右侧:视频课程学习 -->
       <div class="right-panel">
-        <div class="sub-title">视频课程学习 <span class="more-link">查看更多</span></div>
+        <div class="sub-header">
+          <span class="sub-title">视频课程学习</span>
+          <a class="more-link">查看更多</a>
+        </div>
         <div class="video-grid">
-          <div v-for="item in resourceData.videoList" :key="item.name" class="video-item">
+          <div v-for="item in resourceData.videoList" :key="item.name + item.idx" class="video-item">
             <div class="video-thumb">
-              <div class="thumb-placeholder">视频缩略图</div>
+              <div class="thumb-inner">视频缩略图</div>
             </div>
-            <div class="video-info">
+            <div class="video-footer">
               <div class="video-name">{{ item.name }}</div>
               <div class="video-meta">{{ item.year }}|{{ item.term }}|{{ item.credit }}学分</div>
               <el-button size="mini" type="primary" plain>学习</el-button>
@@ -77,7 +94,7 @@ export default {
     return {
       resourceData: {
         activeTab: '总览',
-        tabs: ['总览', '生物类', '辐射类', '化学', '总览', '科目', '生物类', '辐射类', '化学', '总览', '科目', '辐射类'],
+        tabs: ['总览', '生物类', '辐射类', '化学', '总览', '科目', '生物类', '辐射类', '化学', '科目'],
         knowledgeList: [
           { name: '课件资料名称.PDF', year: '2026年', term: '1学年', credit: '1' },
           { name: '课件资料名称.PDF', year: '2026年', term: '1学年', credit: '1' },
@@ -86,12 +103,12 @@ export default {
           { name: '课件资料名称.PDF', year: '2026年', term: '1学年', credit: '1' },
         ],
         videoList: [
-          { name: '视频课程名称', year: '2026年', term: '1学年', credit: '1' },
-          { name: '视频课程名称', year: '2026年', term: '1学年', credit: '1' },
-          { name: '视频课程名称', year: '2026年', term: '1学年', credit: '1' },
-          { name: '视频课程名称', year: '2026年', term: '1学年', credit: '1' },
-          { name: '视频课程名称', year: '2026年', term: '1学年', credit: '1' },
-          { name: '视频课程名称', year: '2026年', term: '1学年', credit: '1' },
+          { idx: 1, name: '视频课程名称', year: '2026年', term: '1学年', credit: '1' },
+          { idx: 2, name: '视频课程名称', year: '2026年', term: '1学年', credit: '1' },
+          { idx: 3, name: '视频课程名称', year: '2026年', term: '1学年', credit: '1' },
+          { idx: 4, name: '视频课程名称', year: '2026年', term: '1学年', credit: '1' },
+          { idx: 5, name: '视频课程名称', year: '2026年', term: '1学年', credit: '1' },
+          { idx: 6, name: '视频课程名称', year: '2026年', term: '1学年', credit: '1' },
         ]
       }
     }
@@ -104,41 +121,51 @@ export default {
   background: #fff;
   border-radius: 6px;
   padding: 16px 20px;
-  margin-bottom: 16px;
-  box-shadow: 0 1px 4px rgba(0,0,0,0.08);
+  margin-bottom: 12px;
+  box-shadow: 0 1px 4px rgba(0,0,0,0.06);
 
   .card-title {
-    font-size: 15px;
-    font-weight: bold;
+    font-size: 14px;
+    font-weight: 600;
     color: #333;
     margin-bottom: 12px;
   }
 
-  .tab-bar {
-    display: flex;
-    gap: 6px;
-    flex-wrap: wrap;
+  .tab-scroll-wrap {
+    overflow-x: auto;
     margin-bottom: 16px;
+    padding-bottom: 4px;
+
+    &::-webkit-scrollbar { height: 4px; }
+    &::-webkit-scrollbar-thumb { background: #ddd; border-radius: 2px; }
+
+    .tab-bar {
+      display: flex;
+      gap: 6px;
+      white-space: nowrap;
+      width: max-content;
+    }
   }
 
   .resource-body {
     display: flex;
-    gap: 24px;
+    gap: 20px;
+    align-items: flex-start;
 
-    .left-panel { flex: 1; }
+    .left-panel { flex: 0 0 45%; }
     .right-panel { flex: 1; }
   }
 
-  .sub-section { margin-bottom: 20px; }
+  .sub-block { margin-bottom: 20px; }
 
-  .sub-title {
-    font-size: 14px;
-    font-weight: bold;
-    color: #333;
-    margin-bottom: 10px;
+  .sub-header {
     display: flex;
     justify-content: space-between;
-    .more-link { color: #409eff; font-weight: normal; font-size: 12px; cursor: pointer; }
+    align-items: center;
+    margin-bottom: 10px;
+
+    .sub-title { font-size: 14px; font-weight: 600; color: #333; }
+    .more-link { font-size: 12px; color: #409eff; cursor: pointer; }
   }
 
   .file-item {
@@ -147,21 +174,62 @@ export default {
     gap: 10px;
     padding: 8px 0;
     border-bottom: 1px solid #f5f5f5;
-    .file-icon { font-size: 20px; color: #e6a23c; }
+
+    .file-icon-wrap {
+      width: 32px;
+      height: 32px;
+      background: #fff3e0;
+      border-radius: 4px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      flex-shrink: 0;
+      .file-icon { font-size: 18px; color: #e6a23c; }
+    }
+
     .file-info {
       flex: 1;
-      .file-name { font-size: 13px; color: #333; }
-      .file-meta { font-size: 12px; color: #999; }
+      min-width: 0;
+      .file-name { font-size: 13px; color: #333; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
+      .file-meta { font-size: 12px; color: #999; margin-top: 2px; }
     }
   }
 
   .practice-item {
-    padding: 10px;
     border: 1px solid #eee;
-    border-radius: 4px;
-    .practice-name .link { color: #409eff; font-size: 13px; cursor: pointer; }
-    .practice-meta { font-size: 12px; color: #666; margin-top: 4px; }
-    .practice-time { font-size: 12px; color: #999; margin-top: 6px; text-align: right; }
+    border-radius: 6px;
+    padding: 12px;
+
+    .practice-top {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 8px;
+      .link { color: #409eff; font-size: 13px; cursor: pointer; }
+      .practice-more { color: #ccc; cursor: pointer; font-size: 16px; }
+    }
+
+    .practice-stats {
+      font-size: 13px;
+      color: #555;
+      margin-bottom: 6px;
+      b { color: #333; }
+    }
+
+    .practice-rates {
+      display: flex;
+      gap: 16px;
+      font-size: 12px;
+      color: #666;
+      margin-bottom: 6px;
+      b { color: #409eff; }
+    }
+
+    .practice-time {
+      font-size: 12px;
+      color: #999;
+      text-align: right;
+    }
   }
 
   .video-grid {
@@ -171,19 +239,21 @@ export default {
 
     .video-item {
       border: 1px solid #eee;
-      border-radius: 4px;
+      border-radius: 6px;
       overflow: hidden;
+
       .video-thumb {
-        height: 80px;
-        background: #f5f7fa;
+        height: 72px;
+        background: #f0f2f5;
         display: flex;
         align-items: center;
         justify-content: center;
-        .thumb-placeholder { color: #ccc; font-size: 12px; }
+        .thumb-inner { color: #ccc; font-size: 12px; }
       }
-      .video-info {
-        padding: 8px;
-        .video-name { font-size: 13px; color: #333; margin-bottom: 4px; }
+
+      .video-footer {
+        padding: 8px 10px;
+        .video-name { font-size: 13px; color: #333; margin-bottom: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
         .video-meta { font-size: 12px; color: #999; margin-bottom: 6px; }
       }
     }

+ 84 - 46
src/views/safetyEducationExaminationNew/workbench/SafetyPersonChart.vue

@@ -3,23 +3,29 @@
   <div class="safety-person-card">
     <div class="section-header">
       <span class="section-title">实验室管与人员图</span>
-      <div class="header-actions">
+      <div class="header-right">
         <el-button size="mini" type="primary">实验室管理下载</el-button>
         <el-button size="mini" type="success">实验室人员下载</el-button>
       </div>
     </div>
 
-    <!-- 柱状图占位 -->
+    <!-- 柱状图 -->
     <div class="chart-area">
-      <div class="bar-chart-mock">
+      <div class="chart-legend">
+        <span class="legend-item"><i class="dot orange"></i>实验室管理</span>
+        <span class="legend-item"><i class="dot blue"></i>实验室人员</span>
+      </div>
+      <div class="bar-chart">
         <div class="y-axis">
-          <span v-for="y in chartData.yAxis" :key="y">{{ y }}</span>
+          <span v-for="y in [500, 400, 300, 200, 100, 0]" :key="y">{{ y }}</span>
         </div>
         <div class="bars-wrap">
-          <div v-for="(group, gi) in chartData.groups" :key="gi" class="bar-group">
-            <div class="bar orange" :style="{height: group.v1 + 'px'}" :title="group.v1"></div>
-            <div class="bar blue" :style="{height: group.v2 + 'px'}" :title="group.v2"></div>
-            <div class="group-label">{{ group.label }}</div>
+          <div v-for="(g, i) in chartData.groups" :key="i" class="bar-group">
+            <div class="bars-pair">
+              <div class="bar orange" :style="{height: (g.v1 / 500 * 160) + 'px'}" :title="g.v1"></div>
+              <div class="bar blue" :style="{height: (g.v2 / 500 * 160) + 'px'}" :title="g.v2"></div>
+            </div>
+            <div class="group-label">{{ g.label }}</div>
           </div>
         </div>
       </div>
@@ -27,14 +33,18 @@
 
     <!-- 汇总表格 -->
     <el-table :data="chartData.tableData" border size="small" stripe>
-      <el-table-column prop="category" label="分类" min-width="120" />
-      <el-table-column prop="total1" label="第1学年人数" min-width="100" />
-      <el-table-column prop="total2" label="第2学年人数" min-width="100" />
-      <el-table-column prop="total3" label="第3学年人数" min-width="100" />
-      <el-table-column prop="total4" label="第4学年人数" min-width="100" />
-      <el-table-column prop="total5" label="第5学年人数" min-width="100" />
-      <el-table-column prop="total6" label="第6学年人数" min-width="100" />
-      <el-table-column prop="sum" label="合计" min-width="80" />
+      <el-table-column prop="category" label="分类" min-width="140" show-overflow-tooltip />
+      <el-table-column prop="y1" label="第1学年" width="80" align="center" />
+      <el-table-column prop="y2" label="第2学年" width="80" align="center" />
+      <el-table-column prop="y3" label="第3学年" width="80" align="center" />
+      <el-table-column prop="y4" label="第4学年" width="80" align="center" />
+      <el-table-column prop="y5" label="第5学年" width="80" align="center" />
+      <el-table-column prop="y6" label="第6学年" width="80" align="center" />
+      <el-table-column prop="sum" label="合计" width="80" align="center">
+        <template slot-scope="scope">
+          <b>{{ scope.row.sum }}</b>
+        </template>
+      </el-table-column>
     </el-table>
   </div>
 </template>
@@ -45,21 +55,20 @@ export default {
   data() {
     return {
       chartData: {
-        yAxis: [500, 400, 300, 200, 100, 0],
         groups: [
           { label: '博(一年级)', v1: 60, v2: 100 },
           { label: '博(二年级)', v1: 80, v2: 120 },
-          { label: '硕(一年级)', v1: 200, v2: 300 },
-          { label: '硕(二年级)', v1: 180, v2: 260 },
-          { label: '硕(三年级)', v1: 40, v2: 50 },
+          { label: '硕(一年级)', v1: 250, v2: 320 },
+          { label: '硕(二年级)', v1: 200, v2: 280 },
+          { label: '硕(三年级)', v1: 40, v2: 60 },
         ],
         tableData: [
-          { category: '化学与化工学院', total1: 10, total2: 20, total3: 30, total4: 0, total5: 0, total6: 0, sum: 60 },
-          { category: '生命科学与技术学院', total1: 15, total2: 25, total3: 20, total4: 10, total5: 0, total6: 0, sum: 70 },
-          { category: '环境科学与工程学院', total1: 8, total2: 12, total3: 15, total4: 5, total5: 0, total6: 0, sum: 40 },
-          { category: '电气/工程学院', total1: 20, total2: 30, total3: 25, total4: 15, total5: 5, total6: 0, sum: 95 },
-          { category: '物理学院', total1: 12, total2: 18, total3: 20, total4: 8, total5: 2, total6: 0, sum: 60 },
-          { category: '材料科学与工程学院', total1: 10, total2: 15, total3: 18, total4: 7, total5: 0, total6: 0, sum: 50 },
+          { category: '化学与化工学院', y1: 10, y2: 20, y3: 30, y4: 0, y5: 0, y6: 0, sum: 60 },
+          { category: '生命科学与技术学院', y1: 15, y2: 25, y3: 20, y4: 10, y5: 0, y6: 0, sum: 70 },
+          { category: '环境科学与工程学院', y1: 8, y2: 12, y3: 15, y4: 5, y5: 0, y6: 0, sum: 40 },
+          { category: '电气/工程学院', y1: 20, y2: 30, y3: 25, y4: 15, y5: 5, y6: 0, sum: 95 },
+          { category: '物理学院', y1: 12, y2: 18, y3: 20, y4: 8, y5: 2, y6: 0, sum: 60 },
+          { category: '材料科学与工程学院', y1: 10, y2: 15, y3: 18, y4: 7, y5: 0, y6: 0, sum: 50 },
         ]
       }
     }
@@ -72,59 +81,78 @@ export default {
   background: #fff;
   border-radius: 6px;
   padding: 16px 20px;
-  margin-bottom: 16px;
-  box-shadow: 0 1px 4px rgba(0,0,0,0.08);
+  margin-bottom: 12px;
+  box-shadow: 0 1px 4px rgba(0,0,0,0.06);
 
   .section-header {
     display: flex;
     justify-content: space-between;
     align-items: center;
     margin-bottom: 14px;
-    .section-title { font-size: 15px; font-weight: bold; color: #333; }
-    .header-actions { display: flex; gap: 8px; }
+    .section-title { font-size: 14px; font-weight: 600; color: #333; }
+    .header-right { display: flex; gap: 10px; }
   }
 
   .chart-area {
-    background: #f5f7fa;
+    background: #fafafa;
+    border: 1px solid #f0f0f0;
     border-radius: 4px;
     padding: 16px;
     margin-bottom: 16px;
-    min-height: 200px;
 
-    .bar-chart-mock {
+    .chart-legend {
+      display: flex;
+      gap: 20px;
+      margin-bottom: 12px;
+      font-size: 12px;
+      color: #555;
+      .legend-item { display: flex; align-items: center; gap: 5px; }
+    }
+
+    .bar-chart {
       display: flex;
       gap: 8px;
+      align-items: flex-end;
 
       .y-axis {
         display: flex;
         flex-direction: column;
         justify-content: space-between;
         font-size: 11px;
-        color: #999;
-        padding-bottom: 20px;
-        min-width: 30px;
+        color: #aaa;
+        height: 180px;
+        min-width: 32px;
         text-align: right;
+        padding-bottom: 22px;
       }
 
       .bars-wrap {
+        flex: 1;
         display: flex;
         align-items: flex-end;
-        gap: 16px;
-        flex: 1;
         justify-content: space-around;
+        height: 180px;
+        border-left: 1px solid #e8e8e8;
+        border-bottom: 1px solid #e8e8e8;
+        padding: 0 16px 22px;
 
         .bar-group {
           display: flex;
-          align-items: flex-end;
-          gap: 4px;
-          flex-direction: row;
+          flex-direction: column;
+          align-items: center;
           position: relative;
 
-          .bar {
-            width: 18px;
-            border-radius: 2px 2px 0 0;
-            &.orange { background: #e6a23c; }
-            &.blue { background: #409eff; }
+          .bars-pair {
+            display: flex;
+            gap: 3px;
+            align-items: flex-end;
+
+            .bar {
+              width: 16px;
+              border-radius: 2px 2px 0 0;
+              &.orange { background: #f59e42; }
+              &.blue { background: #4e9cf6; }
+            }
           }
 
           .group-label {
@@ -140,5 +168,15 @@ export default {
       }
     }
   }
+
+  .dot {
+    display: inline-block;
+    width: 10px;
+    height: 10px;
+    border-radius: 2px;
+    flex-shrink: 0;
+    &.orange { background: #f59e42; }
+    &.blue { background: #4e9cf6; }
+  }
 }
 </style>

+ 126 - 69
src/views/safetyEducationExaminationNew/workbench/StudentStats.vue

@@ -3,38 +3,50 @@
   <div class="student-stats-card">
     <div class="section-header">
       <span class="section-title">学期统计</span>
-      <el-button size="mini" type="primary">下载统计</el-button>
+      <el-button size="mini" type="primary" icon="el-icon-download">下载统计</el-button>
     </div>
 
-    <!-- 柱状图占位 -->
+    <!-- 柱状图 -->
     <div class="chart-area">
       <div class="chart-legend">
-        <span><i class="dot green"></i>完成</span>
-        <span><i class="dot blue"></i>待完成</span>
-        <span><i class="dot yellow"></i>未开始</span>
-        <span><i class="dot gray"></i>其他</span>
+        <span class="legend-item"><i class="dot green"></i>完成</span>
+        <span class="legend-item"><i class="dot blue"></i>进行中</span>
+        <span class="legend-item"><i class="dot yellow"></i>未开始</span>
+        <span class="legend-item"><i class="dot gray"></i>其他</span>
       </div>
-      <div class="bar-chart-mock">
-        <div v-for="(col, i) in statsData.chartCols" :key="i" class="chart-col">
-          <div class="stacked-bar">
-            <div class="seg green" :style="{height: col.done + 'px'}"></div>
-            <div class="seg blue" :style="{height: col.pending + 'px'}"></div>
-            <div class="seg yellow" :style="{height: col.notStart + 'px'}"></div>
+      <div class="bar-chart">
+        <div class="y-axis">
+          <span v-for="y in [100, 80, 60, 40, 20, 0]" :key="y">{{ y }}</span>
+        </div>
+        <div class="bars-container">
+          <div v-for="(col, i) in statsData.chartCols" :key="i" class="chart-col">
+            <div class="stacked-bar">
+              <div class="seg gray"   :style="{height: col.other * 1.2 + 'px'}"></div>
+              <div class="seg yellow" :style="{height: col.notStart * 1.2 + 'px'}"></div>
+              <div class="seg blue"   :style="{height: col.pending * 1.2 + 'px'}"></div>
+              <div class="seg green"  :style="{height: col.done * 1.2 + 'px'}"></div>
+            </div>
+            <div class="col-label">{{ col.label }}</div>
           </div>
-          <div class="col-label">{{ col.label }}</div>
         </div>
       </div>
     </div>
 
     <!-- 统计表格 -->
     <el-table :data="statsData.tableData" border size="small" stripe>
-      <el-table-column prop="name" label="姓名" min-width="80" />
-      <el-table-column prop="userId" label="用户编号" min-width="100" />
-      <el-table-column prop="dept" label="部门" min-width="100" />
-      <el-table-column prop="eduName" label="安全教育名称" min-width="160" />
-      <el-table-column prop="term1" label="第1学期" min-width="80" />
-      <el-table-column prop="term2" label="第2学期" min-width="80" />
-      <el-table-column prop="total" label="总计" min-width="80" />
+      <el-table-column prop="name" label="姓名" width="70" />
+      <el-table-column prop="userId" label="用户编号" width="100" />
+      <el-table-column prop="dept" label="部门" min-width="100" show-overflow-tooltip />
+      <el-table-column prop="eduName" label="安全教育名称" min-width="150" show-overflow-tooltip />
+      <el-table-column prop="term1" label="第1学期" width="80" align="center" />
+      <el-table-column prop="term2" label="第2学期" width="80" align="center" />
+      <el-table-column prop="term3" label="第3学期" width="80" align="center" />
+      <el-table-column prop="term4" label="第4学期" width="80" align="center" />
+      <el-table-column prop="total" label="总计" width="80" align="center">
+        <template slot-scope="scope">
+          <b>{{ scope.row.total }}</b>
+        </template>
+      </el-table-column>
     </el-table>
 
     <!-- 分页 -->
@@ -45,12 +57,25 @@
         :total="statsData.total"
         layout="prev, pager, next"
         background
+        small
       />
     </div>
   </div>
 </template>
 
 <script>
+const mockRow = (n) => ({
+  name: '姓名',
+  userId: `2025000${String(n).padStart(2, '0')}`,
+  dept: '部门单位',
+  eduName: '安全教育名称',
+  term1: Math.floor(Math.random() * 15) + 5,
+  term2: Math.floor(Math.random() * 15) + 5,
+  term3: Math.floor(Math.random() * 10),
+  term4: Math.floor(Math.random() * 10),
+  get total() { return this.term1 + this.term2 + this.term3 + this.term4 }
+})
+
 export default {
   name: 'StudentStats',
   data() {
@@ -59,21 +84,16 @@ export default {
         page: 1,
         total: 50,
         chartCols: [
-          { label: '生物类', done: 80, pending: 40, notStart: 20 },
-          { label: '化学类', done: 60, pending: 60, notStart: 30 },
-          { label: '辐射类', done: 100, pending: 20, notStart: 10 },
-          { label: '科目类', done: 50, pending: 50, notStart: 40 },
-          { label: '电气类', done: 70, pending: 30, notStart: 15 },
+          { label: '总览', done: 60, pending: 20, notStart: 10, other: 5 },
+          { label: '生物类', done: 50, pending: 30, notStart: 12, other: 3 },
+          { label: '辐射类', done: 70, pending: 15, notStart: 8, other: 2 },
+          { label: '化学', done: 40, pending: 35, notStart: 15, other: 5 },
+          { label: '科目类', done: 55, pending: 25, notStart: 10, other: 4 },
+          { label: '电气类', done: 65, pending: 20, notStart: 8, other: 3 },
+          { label: '物理类', done: 45, pending: 30, notStart: 14, other: 6 },
+          { label: '材料类', done: 75, pending: 12, notStart: 6, other: 2 },
         ],
-        tableData: [
-          { name: '姓名', userId: '20250001', dept: '部门单位', eduName: '安全教育名称', term1: 10, term2: 20, total: 30 },
-          { name: '姓名', userId: '20250002', dept: '部门单位', eduName: '安全教育名称', term1: 8, term2: 15, total: 23 },
-          { name: '姓名', userId: '20250003', dept: '部门单位', eduName: '安全教育名称', term1: 12, term2: 18, total: 30 },
-          { name: '姓名', userId: '20250004', dept: '部门单位', eduName: '安全教育名称', term1: 5, term2: 10, total: 15 },
-          { name: '姓名', userId: '20250005', dept: '部门单位', eduName: '安全教育名称', term1: 20, term2: 25, total: 45 },
-          { name: '姓名', userId: '20250006', dept: '部门单位', eduName: '安全教育名称', term1: 9, term2: 14, total: 23 },
-          { name: '姓名', userId: '20250007', dept: '部门单位', eduName: '安全教育名称', term1: 11, term2: 22, total: 33 },
-        ]
+        tableData: Array.from({ length: 8 }, (_, i) => mockRow(i + 1))
       }
     }
   }
@@ -85,67 +105,92 @@ export default {
   background: #fff;
   border-radius: 6px;
   padding: 16px 20px;
-  margin-bottom: 16px;
-  box-shadow: 0 1px 4px rgba(0,0,0,0.08);
+  margin-bottom: 12px;
+  box-shadow: 0 1px 4px rgba(0,0,0,0.06);
 
   .section-header {
     display: flex;
     justify-content: space-between;
     align-items: center;
     margin-bottom: 14px;
-    .section-title { font-size: 15px; font-weight: bold; color: #333; }
+    .section-title { font-size: 14px; font-weight: 600; color: #333; }
   }
 
   .chart-area {
-    background: #f5f7fa;
+    background: #fafafa;
+    border: 1px solid #f0f0f0;
     border-radius: 4px;
     padding: 16px;
     margin-bottom: 16px;
 
     .chart-legend {
       display: flex;
-      gap: 16px;
-      margin-bottom: 12px;
+      gap: 20px;
+      margin-bottom: 10px;
       font-size: 12px;
-      color: #666;
-      span { display: flex; align-items: center; gap: 4px; }
-      .dot {
-        width: 10px; height: 10px; border-radius: 2px; display: inline-block;
-        &.green { background: #67c23a; }
-        &.blue { background: #409eff; }
-        &.yellow { background: #e6a23c; }
-        &.gray { background: #c0c4cc; }
-      }
+      color: #555;
+      .legend-item { display: flex; align-items: center; gap: 4px; }
     }
 
-    .bar-chart-mock {
+    .bar-chart {
       display: flex;
+      gap: 8px;
       align-items: flex-end;
-      gap: 24px;
-      justify-content: space-around;
-      min-height: 160px;
 
-      .chart-col {
+      .y-axis {
         display: flex;
         flex-direction: column;
-        align-items: center;
-        gap: 4px;
+        justify-content: space-between;
+        font-size: 11px;
+        color: #aaa;
+        height: 160px;
+        min-width: 28px;
+        text-align: right;
+        padding-bottom: 22px;
+      }
 
-        .stacked-bar {
+      .bars-container {
+        flex: 1;
+        display: flex;
+        align-items: flex-end;
+        justify-content: space-around;
+        height: 160px;
+        border-left: 1px solid #e8e8e8;
+        border-bottom: 1px solid #e8e8e8;
+        padding: 0 8px 22px;
+
+        .chart-col {
           display: flex;
-          flex-direction: column-reverse;
-          width: 24px;
-          gap: 1px;
-
-          .seg {
-            width: 100%;
-            &.green { background: #67c23a; }
-            &.blue { background: #409eff; }
-            &.yellow { background: #e6a23c; }
+          flex-direction: column;
+          align-items: center;
+          position: relative;
+
+          .stacked-bar {
+            display: flex;
+            flex-direction: column;
+            width: 22px;
+            gap: 1px;
+
+            .seg {
+              width: 100%;
+              border-radius: 1px;
+              &.green  { background: #67c23a; }
+              &.blue   { background: #409eff; }
+              &.yellow { background: #e6a23c; }
+              &.gray   { background: #c0c4cc; }
+            }
           }
-        }
 
-        .col-label { font-size: 11px; color: #666; margin-top: 4px; }
+          .col-label {
+            position: absolute;
+            bottom: -18px;
+            left: 50%;
+            transform: translateX(-50%);
+            font-size: 10px;
+            color: #666;
+            white-space: nowrap;
+          }
+        }
       }
     }
   }
@@ -153,7 +198,19 @@ export default {
   .pagination-wrap {
     display: flex;
     justify-content: center;
-    margin-top: 16px;
+    margin-top: 14px;
+  }
+
+  .dot {
+    display: inline-block;
+    width: 10px;
+    height: 10px;
+    border-radius: 2px;
+    flex-shrink: 0;
+    &.green  { background: #67c23a; }
+    &.blue   { background: #409eff; }
+    &.yellow { background: #e6a23c; }
+    &.gray   { background: #c0c4cc; }
   }
 }
 </style>

+ 116 - 138
src/views/safetyEducationExaminationNew/workbench/TaskCard.vue

@@ -1,80 +1,32 @@
 <!-- 工作台任务卡片 -->
 <template>
   <div class="task-card">
-    <div class="card-title">工作台任务卡片</div>
-    <div class="task-grid">
-      <!-- 手势数据统计 -->
-      <div class="task-item">
-        <div class="item-title">手势数据统计 <span class="year-tag">{{ taskData.year }}</span> <span class="status-tag">待完成</span></div>
-        <div class="item-desc">高校宝安全教育培训与考核</div>
-      </div>
-
-      <!-- 学习任务 -->
-      <div class="task-item">
-        <div class="item-title">学习任务</div>
-        <div class="item-desc">高校宝安全教育培训与考核</div>
-        <div class="item-row">
-          <el-checkbox v-model="taskData.studyTask.checked">课程任务名称</el-checkbox>
-        </div>
-        <div class="item-row sub">
-          <el-radio v-model="taskData.studyTask.radio" :label="1">完成</el-radio>
-          <el-radio v-model="taskData.studyTask.radio" :label="0">未完成</el-radio>
-        </div>
-        <div class="item-row">
-          <el-checkbox>课程任务名称</el-checkbox>
+    <div class="top-title-box">
+      <p>工作台任务卡</p>
+    </div>
+    <div class="card-max-big-box">
+      <div class="year-card-box for-max-big-box">
+        <div class="top-title-box">
+          <p>{{yearData.yearMinData1}}</p>
+          <p>{{yearData.yearMinData2}}</p>
+          <p>毕业报告</p>
         </div>
-        <div class="item-row sub">
-          <el-radio v-model="taskData.studyTask.radio2" :label="1">完成</el-radio>
-          <el-radio v-model="taskData.studyTask.radio2" :label="0">未完成</el-radio>
+        <div class="bottom-content-box">
+          <div class="bottom-big-box-1">
+            <p></p>
+            <p></p>
+          </div>
         </div>
       </div>
+      <div class="study-card-box for-max-big-box">
 
-      <!-- 模拟考试 -->
-      <div class="task-item">
-        <div class="item-title">模拟考试</div>
-        <div class="item-desc">高校宝安全教育考试</div>
-        <div class="progress-row">
-          <span class="big-num">200</span><span class="sep">/</span><span>3000</span>
-        </div>
-        <div class="item-desc">已完成进度 距离目标还差多少</div>
-        <div class="item-row">
-          <span class="pct">20%</span>
-          <span class="pct-label">对题率 近期对题率</span>
-        </div>
-      </div>
 
-      <!-- 培训活动 -->
-      <div class="task-item highlight">
-        <div class="item-title">培训活动</div>
-        <div class="item-desc">高校宝安全培训与安全考试考核</div>
-        <div class="act-time">2026-06-10 10:00 至 11:00</div>
-        <el-button type="primary" size="mini" class="sign-btn">签到打卡</el-button>
       </div>
+      <div class="examination-card-box for-max-big-box">
 
-      <!-- 新生入学考试 -->
-      <div class="task-item">
-        <div class="item-title">新生入学考试 <span class="item-desc">高校宝安全教育培训与考核</span></div>
-        <div class="item-row">
-          <span class="label">学习任务</span>
-          <el-tag type="success" size="mini">学习中</el-tag>
-        </div>
-        <div class="item-row">
-          <span class="label">考试状态</span>
-          <span class="value">待完成 每天完成考试后提示</span>
-        </div>
       </div>
+      <div class="for-max-big-box" v-for="(item,index) in dataList" :key="index">
 
-      <!-- 分级鉴定考试 -->
-      <div class="task-item">
-        <div class="item-title">分级鉴定考试 <span class="item-desc">高校宝安全教育培训与考核</span></div>
-        <div class="item-row">
-          <span class="label">学习任务</span>
-          <span class="value">无</span>
-        </div>
-        <div class="item-row">
-          <span class="label">考试状态</span>
-          <span class="value">待完成 每天完成考试后提示</span>
-        </div>
       </div>
     </div>
   </div>
@@ -85,14 +37,39 @@ export default {
   name: 'TaskCard',
   data() {
     return {
-      taskData: {
-        year: '2025-2026',
-        studyTask: {
-          checked: true,
-          radio: 1,
-          radio2: 0,
-        }
-      }
+      //学年数据
+      yearData:{
+        yearMinData1:'学年数据统计',
+        yearMinData2:'按学年统计历年考试通过情况与成绩',
+        yearMinList:[
+          {
+            yearMinListData1:'2025-2026',
+            yearMinListData2:'1',
+            yearMinListData3:'99',
+          },
+          {
+            yearMinListData1:'2025-2026',
+            yearMinListData2:'1',
+            yearMinListData3:'99',
+          },
+          {
+            yearMinListData1:'2025-2026',
+            yearMinListData2:'1',
+            yearMinListData3:'99',
+          },
+        ],
+      },
+      studyData:{
+
+      },
+      examinationData:{
+
+      },
+      dataList:[
+        {
+
+        },
+      ],
     }
   }
 }
@@ -102,82 +79,83 @@ export default {
 .task-card {
   background: #fff;
   border-radius: 6px;
-  padding: 16px 20px;
-  margin-bottom: 16px;
-  box-shadow: 0 1px 4px rgba(0,0,0,0.08);
-
-  .card-title {
-    font-size: 15px;
-    font-weight: bold;
-    color: #333;
-    margin-bottom: 14px;
+  padding: 16px 0 0 0;
+  margin-bottom: 12px;
+  box-shadow: 0 1px 4px rgba(0,0,0,0.06);
+  .top-title-box{
+    display: flex;
+    padding-left:20px;
+    p{
+      flex:1;
+      line-height:20px;
+    }
+    p:nth-child(1){
+      font-size:16px;
+      font-weight:700;
+    }
+    p:nth-child(2){
+      text-align: right;
+      font-size:14px;
+      font-weight:700;
+    }
   }
+  .card-max-big-box{
+    margin-top:20px;
+    .year-card-box{
 
-  .task-grid {
-    display: grid;
-    grid-template-columns: repeat(3, 1fr);
-    gap: 16px;
-
-    .task-item {
-      border: 1px solid #eee;
-      border-radius: 6px;
-      padding: 12px;
-      font-size: 13px;
+    }
+    .study-card-box{
 
-      &.highlight {
-        background: #fff0f0;
-        border-color: #ffcccc;
-      }
+    }
+    .examination-card-box{
 
-      .item-title {
-        font-weight: bold;
-        color: #333;
-        margin-bottom: 6px;
-        display: flex;
-        align-items: center;
-        gap: 8px;
-        flex-wrap: wrap;
-      }
+    }
+    .for-max-big-box{
+      display: inline-block;
+      width:360px;
+      height:290px;
+      margin: 0 0 20px 20px;
+      border-radius:6px;
+      border:1px solid #dedede;
+      box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
+      padding:20px 20px 0 20px;
+      overflow: hidden;
+      .top-title-box{
+        position: relative;
+        p:nth-child(1){
+          font-size:14px;
+          font-weight:700;
+        }
+        p:nth-child(2){
+          font-size:14px;
 
-      .year-tag {
-        font-size: 12px;
-        color: #409eff;
-        font-weight: normal;
+        }
+        p:nth-child(3){
+          font-size:14px;
+          line-height:30px;
+          background-color: #0183fa;
+          color:#fff;
+          border-radius:6px;
+          position: absolute;
+          top:0;
+          right:0;
+          padding:0 10px;
+        }
       }
+      .bottom-content-box{
+        .bottom-big-box-1{
 
-      .status-tag {
-        font-size: 12px;
-        color: #e6a23c;
-        font-weight: normal;
-      }
+        }
+        .bottom-big-box-2{
 
-      .item-desc {
-        color: #999;
-        font-size: 12px;
-        margin-bottom: 8px;
-      }
+        }
+        .bottom-big-box-3{
 
-      .item-row {
-        display: flex;
-        align-items: center;
-        gap: 8px;
-        margin-bottom: 6px;
-        &.sub { padding-left: 22px; }
-        .label { color: #666; min-width: 56px; }
-        .value { color: #333; }
-      }
+        }
+        .bottom-big-box-4{
 
-      .progress-row {
-        margin: 8px 0;
-        .big-num { font-size: 22px; font-weight: bold; color: #333; }
-        .sep { color: #999; margin: 0 2px; }
+        }
       }
-
-      .pct { font-size: 20px; font-weight: bold; color: #409eff; }
-      .pct-label { color: #999; font-size: 12px; }
-
-      .act-time { color: #e6a23c; font-size: 13px; margin: 6px 0; }
-      .sign-btn { margin-top: 6px; }
     }
   }
 }

+ 292 - 101
src/views/safetyEducationExaminationNew/workbench/UserInfoCard.vue

@@ -1,54 +1,84 @@
 <!-- 用户信息卡片 -->
 <template>
   <div class="user-info-card">
-    <div class="card-title">用户信息卡片</div>
-    <div class="card-body">
-      <!-- 左侧:基本信息 -->
-      <div class="left-section">
-        <div class="info-row">
-          <span class="label">姓名</span>
-          <span class="value">Name</span>
-          <span class="label">学号</span>
-          <span class="value">20251001</span>
+    <div class="top-title-box">
+      <p>用户信息卡</p>
+      <p>当前推荐资料类型:{{textName}}</p>
+    </div>
+    <div class="user-info-max-box">
+      <div class="left-max-box">
+        <div class="left-min-box">
+          <p>姓名</p>
+          <p>{{userInfo.data1}}</p>
         </div>
-        <div class="info-row">
-          <span class="label">学历</span>
-          <span class="value">硕士研究生</span>
-          <span class="label">学院</span>
-          <span class="value">学院Name</span>
+        <div class="left-min-box">
+          <p>学工号</p>
+          <p>{{userInfo.data2}}</p>
         </div>
-        <div class="info-row">
-          <span class="label">研究室</span>
-          <span class="value">智无研定实验室</span>
+        <div class="left-min-box">
+          <p>类型</p>
+          <p>{{userInfo.data3}}</p>
         </div>
-        <div class="more-link">查看更多</div>
-      </div>
-
-      <!-- 中间:学年选择 + 课程任务 -->
-      <div class="mid-section">
-        <el-select v-model="userInfo.year" size="small" class="year-select">
-          <el-option v-for="y in userInfo.yearOptions" :key="y" :label="y" :value="y" />
-        </el-select>
-        <div class="mid-row">
-          <span class="label">安全教育</span>
-          <span class="value">无</span>
+        <div class="left-min-box">
+          <p>所属单位</p>
+          <p>{{userInfo.data4}}</p>
         </div>
-        <div class="mid-row">
-          <span class="label">课程任务</span>
-          <span class="value">分级考试</span>
+        <div class="left-min-box">
+          <p>实验室信息</p>
+          <p>{{userInfo.data5?userInfo.data5:'暂无绑定实验室'}}</p>
+          <p @click="bindingSubButton()">去绑定</p>
         </div>
       </div>
-
-      <!-- 右侧:当前学年任务状态 -->
-      <div class="right-section">
-        <div class="section-title">当前学年任务状态</div>
-        <div class="status-grid">
-          <div v-for="item in userInfo.taskStatus" :key="item.label" class="status-item">
-            <span class="s-label">{{ item.label }}</span>
-            <el-tag :type="item.type" size="small">{{ item.value }}</el-tag>
+      <div class="center-max-box">
+        <div class="center-title-box scrollbar-x-box">
+          <p :class="index == checkUserIndex?'check-title-p':''"
+             @click="checkTitleButton(index)"
+            v-for="(item,index) in userInfo.data6" :key="index">{{item.dataName}}</p>
+        </div>
+        <div class="center-data-box">
+          <div class="progress-max-box" v-if="checkUserInfo.dataMax">
+            <el-progress
+              :stroke-width="12" :format="format"
+              :percentage="checkUserInfo.dataNum">
+            </el-progress>
+            <div class="progress-min-box">
+              <p>{{checkUserInfo.dataText}}</p>
+              <p>{{checkUserInfo.dataMin}} / {{checkUserInfo.dataMax}} 学时</p>
+            </div>
+          </div>
+          <div class="center-bottom-box">
+            <div class="center-bottom-min-box">
+              <p>{{checkUserInfo.dataMax>0?'学时完成度':'学时要求'}}</p>
+              <p>{{checkUserInfo.dataMax>0?checkUserInfo.dataNum+'%':'无'}}</p>
+            </div>
+            <div class="center-bottom-min-box">
+              <p>目标考试</p>
+              <p>{{checkUserInfo.dataTarget}}</p>
+            </div>
           </div>
         </div>
       </div>
+      <div class="right-max-box">
+        <p class="right-title-p">当前学年任务状态</p>
+        <div class="right-big-box">
+          <p>考试状态</p>
+          <p :class="userInfo.data7==0?'':(userInfo.data7==1?'color-a':(userInfo.data7==2?'color-b':''))">
+            {{userInfo.data7==0?'暂无':(userInfo.data7==1?'已通过':(userInfo.data7==2?'未通过':''))}}
+          </p>
+        </div>
+        <div class="right-big-box">
+          <p>证书状态</p>
+          <p :class="userInfo.data8==0?'':(userInfo.data8==1?'color-a':(userInfo.data8==2?'color-b':''))">
+            {{userInfo.data8==0?'暂无':(userInfo.data8==1?'已通过':(userInfo.data8==2?'未通过':''))}}
+          </p>
+        </div>
+        <div class="right-big-box">
+          <p>审批状态</p>
+          <p :class="userInfo.data9==0?'':(userInfo.data9==1?'color-a':(userInfo.data9==2?'color-b':''))">
+            {{userInfo.data9==0?'待绑定':(userInfo.data9==1?'已通过':(userInfo.data9==2?'未通过':''))}}
+          </p>
+        </div>
+      </div>
     </div>
   </div>
 </template>
@@ -58,18 +88,77 @@ export default {
   name: 'UserInfoCard',
   data() {
     return {
+      textName:'应知应会通识',
       userInfo: {
-        year: '2025-2026 学年',
-        yearOptions: ['2023-2024 学年', '2024-2025 学年', '2025-2026 学年'],
-        taskStatus: [
-          { label: '考试邀请', value: '完成', type: 'success' },
-          { label: '证件状态', value: '完成', type: 'success' },
-          { label: '课程状态', value: '完成', type: 'success' },
-          { label: '毕业状态', value: '待完成', type: 'warning' },
-        ]
+        data1:'Name',
+        data2:'20261001',
+        data3:'硕士研究生',
+        data4:'学院Name',
+        data5:'',
+        data6:[
+          {
+            dataName:'2025 - 2026',
+            dataText:'当前学年学时完成进度',
+            dataMin:0,
+            dataMax:0,
+            dataNum:75,
+            dataTarget:'分级考试',
+          },
+          {
+            dataName:'| 级实验室',
+            dataText:'当前学年学时完成进度',
+            dataMin:6,
+            dataMax:10,
+            dataNum:75,
+            dataTarget:'应知应会考试',
+          },
+          {
+            dataName:'| 级实验室',
+            dataText:'当前学年学时完成进度',
+            dataMin:6,
+            dataMax:10,
+            dataNum:75,
+            dataTarget:'应知应会考试',
+          },
+        ],
+        data7:0,
+        data8:1,
+        data9:2,
+      },
+      checkUserInfo: {
+        dataName:'2025 - 2026',
+        dataText:'当前学年学时完成进度',
+        dataMin:0,
+        dataMax:0,
+        dataNum:75,
+        dataTarget:'分级考试',
+      },
+      checkUserIndex:0,
+    }
+  },
+  created() {
+
+  },
+  mounted() {
+
+  },
+  methods: {
+    //切换选项卡
+    checkTitleButton(index){
+      if(this.checkUserIndex != index){
+        this.$set(this,'checkUserIndex',index);
+        this.$set(this,'checkUserInfo',JSON.parse(JSON.stringify(this.userInfo.data6[index])));
       }
+    },
+    //绑定实验室按钮
+    bindingSubButton(){
+
+    },
+    //进度条去除描述
+    format(percentage) {
+      return '';
     }
-  }
+  },
 }
 </script>
 
@@ -78,67 +167,169 @@ export default {
   background: #fff;
   border-radius: 6px;
   padding: 16px 20px;
-  margin-bottom: 16px;
-  box-shadow: 0 1px 4px rgba(0,0,0,0.08);
-
-  .card-title {
-    font-size: 15px;
-    font-weight: bold;
-    color: #333;
-    margin-bottom: 14px;
+  margin-bottom: 12px;
+  box-shadow: 0 1px 4px rgba(0,0,0,0.06);
+  .top-title-box{
+    display: flex;
+    p{
+      flex:1;
+      line-height:20px;
+    }
+    p:nth-child(1){
+      font-size:16px;
+      font-weight:700;
+    }
+    p:nth-child(2){
+      text-align: right;
+      font-size:14px;
+      font-weight:700;
+    }
   }
-
-  .card-body {
+  .user-info-max-box{
     display: flex;
-    gap: 32px;
-
-    .left-section {
-      min-width: 260px;
-      .info-row {
-        display: flex;
-        gap: 8px;
-        align-items: center;
-        margin-bottom: 10px;
-        .label { color: #999; font-size: 13px; min-width: 40px; }
-        .value { color: #333; font-size: 13px; }
+    margin-top:20px;
+    .left-max-box{
+      width:460px;
+      height:290px;
+      border-radius:6px;
+      border:1px solid #dedede;
+      box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
+      padding:20px 20px 0 20px;
+      .left-min-box:nth-child(odd){
+        margin-right:20px;
       }
-      .more-link {
-        color: #409eff;
-        font-size: 13px;
-        cursor: pointer;
-        margin-top: 6px;
+      .left-min-box{
+        display: inline-block;
+        overflow:hidden;
+        width:198px;
+        margin-bottom:15px;
+        p{
+          line-height:30px;
+        }
+        p:nth-child(1){
+          font-size:14px;
+          color:#666;
+        }
+        p:nth-child(2){
+          font-size:16px;
+          font-weight:700;
+          display:block;
+          overflow:hidden;
+          text-overflow:ellipsis;
+          white-space:nowrap;
+        }
+        p:nth-child(3){
+          font-size:16px;
+          font-weight:700;
+          color: #0183fa;
+          cursor: pointer;
+        }
       }
     }
-
-    .mid-section {
-      min-width: 200px;
-      .year-select { margin-bottom: 12px; width: 160px; }
-      .mid-row {
-        display: flex;
-        gap: 8px;
-        margin-bottom: 10px;
-        .label { color: #999; font-size: 13px; min-width: 56px; }
-        .value { color: #333; font-size: 13px; }
+    .center-max-box{
+      width:430px;
+      height:290px;
+      border-radius:6px;
+      border:1px solid #dedede;
+      box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
+      padding:20px;
+      margin:0 20px;
+      .center-title-box{
+        height:50px;
+        p{
+          display: inline-block;
+          border:1px solid #999;
+          color:#999;
+          border-radius:6px;
+          padding: 0 15px;
+          height:32px;
+          line-height:30px;
+          margin-right:10px;
+          cursor: pointer;
+        }
+        .check-title-p{
+          color:#fff;
+          border:1px solid #0183fa;
+          background-color: #0183fa;
+        }
+      }
+      .center-data-box{
+        .progress-max-box ::v-deep .el-progress-bar{
+          padding:0;
+        }
+        .progress-max-box{
+          height:90px;
+          margin-top:20px;
+          .progress-min-box{
+            display: flex;
+            p{
+              font-size:16px;
+              font-weight:700;
+              line-height:60px;
+            }
+            p:nth-child(1){
+              flex:1;
+            }
+          }
+        }
+        .center-bottom-box{
+          display: flex;
+          .center-bottom-min-box:nth-child(1){
+            margin-right:10px;
+          }
+          .center-bottom-min-box{
+            background-color: rgba(1,131,250,0.1);
+            padding:10px 20px;
+            border-radius:6px;
+            width:188px;
+            p{
+              line-height: 30px;
+            }
+          }
+        }
       }
     }
-
-    .right-section {
-      flex: 1;
-      .section-title {
-        font-size: 13px;
-        color: #666;
-        margin-bottom: 12px;
-        font-weight: bold;
+    .right-max-box{
+      flex:1;
+      height:290px;
+      border-radius:6px;
+      border:1px solid #dedede;
+      box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
+      padding:20px;
+      .right-title-p{
+        font-size:16px;
+        font-weight:700;
+        line-height:30px;
+        padding-left:20px;
+        margin-bottom:30px;
       }
-      .status-grid {
-        display: grid;
-        grid-template-columns: repeat(3, 1fr);
-        gap: 10px;
-        .status-item {
-          display: flex;
-          align-items: center;
-          gap: 8px;
-          .s-label { color: #666; font-size: 13px; }
+      .right-big-box{
+        background-color: #E9E9E9;
+        border-radius:6px;
+        margin-bottom:10px;
+        display: flex;
+        height: 40px;
+        padding:0 20px;
+        p:nth-child(1){
+          flex:1;
+          line-height:40px;
+        }
+        p:nth-child(2){
+          width:80px;
+          height:30px;
+          line-height:30px;
+          margin:5px 20px 0 0;
+          text-align: center;
+          border-radius:15px;
+          background-color: #EBF0F5;
+        }
+        .color-a{
+          background-color: #E6F5F0 !important;;
+          color:#4D9775 !important;
+        }
+        .color-b{
+          background-color: #EBCACE !important;;
+          color:#E15263 !important;;
         }
       }
     }

+ 11 - 20
src/views/safetyEducationExaminationNew/workbench/index.vue

@@ -1,14 +1,7 @@
 <!-- 工作台 -->
 <template>
   <div class="app-container workbench">
-    <div class="page-container workbenchPage" v-if="pageType === 1">
-      <!-- 顶部通知栏 -->
-      <div class="notice-bar">
-        <span class="notice-label">近期推荐资料(类型):<a class="link">规划官方通告</a></span>
-        <el-button size="mini" type="text" class="notice-btn">通知 ></el-button>
-        <el-button size="mini" type="text" class="notice-btn">监控 ></el-button>
-      </div>
-
+    <div class="page-container workbenchPage scrollbar-box" v-if="pageType === 1">
       <!-- 用户信息卡片 -->
       <user-info-card />
 
@@ -53,6 +46,15 @@
         pageType: 1,
       }
     },
+    created() {
+
+    },
+    mounted() {
+
+    },
+    methods: {
+
+    },
   }
 </script>
 
@@ -62,18 +64,7 @@
       padding: 16px;
       background: #f5f7fa;
       min-height: 100vh;
-
-      .notice-bar {
-        display: flex;
-        align-items: center;
-        justify-content: flex-end;
-        gap: 12px;
-        margin-bottom: 12px;
-        font-size: 13px;
-        .notice-label { color: #666; margin-right: auto; }
-        .link { color: #409eff; cursor: pointer; }
-        .notice-btn { color: #409eff; padding: 0; }
-      }
+      overflow-y: scroll !important;
     }
   }
 </style>