Parcourir la source

修改资料学习只能看一次,重新看为复习;

新增学习记录页面
余思翰 il y a 2 mois
Parent
révision
82d5f32e44

+ 1
- 1
oa-back/ruoyi-system/src/main/resources/mapper/oa/CmcResourceMapper.xml Voir le fichier

@@ -39,7 +39,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
39 39
         <where>  
40 40
             <if test="uploader != null "> and r.uploader = #{uploader}</if>
41 41
             <if test="uploadDept != null "> and r.upload_dept = #{uploadDept}</if>
42
-            <if test="title != null  and title != ''"> and r.title = #{title}</if>
42
+            <if test="title != null  and title != ''"> and r.title like concat('%', #{title}, '%')</if>
43 43
             <if test="sourcePath != null  and sourcePath != ''"> and r.source_path = #{sourcePath}</if>
44 44
             <if test="type != null  and type != ''"> and r.type = #{type}</if>
45 45
             <if test="field != null  and field != ''"> and r.field = #{field}</if>

+ 1
- 1
oa-ui/src/components/FileUpload/index.vue Voir le fichier

@@ -3,7 +3,7 @@
3 3
     <el-upload :action="uploadFileUrl" :data="additionalData" :before-upload="handleBeforeUpload" :file-list="fileList"
4 4
       :limit="limit" :on-error="handleUploadError" :on-exceed="handleExceed" :on-success="handleUploadSuccess"
5 5
       :show-file-list="false" :headers="headers" class="upload-file-uploader" ref="fileUpload"
6
-      accept=".doc,.docx,.xls,.xlsx,.pdf,.rar,.zip,.mp4,.mkv">
6
+      accept=".doc,.docx,.xls,.xlsx,.pdf,.rar,.zip,.mp4">
7 7
       <!-- 上传按钮 -->
8 8
       <el-button size="mini" type="primary" :disabled="disabled">选取文件</el-button>
9 9
       <!-- 上传提示 -->

+ 13
- 0
oa-ui/src/router/index.js Voir le fichier

@@ -352,6 +352,19 @@ export const constantRoutes = [
352 352
     ],
353 353
     hidden: true
354 354
   },
355
+  {
356
+    path: '/reviewStudy/:id',
357
+    component: Layout,
358
+    children: [
359
+      {
360
+        path: '',
361
+        component: () => import('@/views/oa/study/components/reviewStudy'),
362
+        name: 'reviewStudy',
363
+        meta: { title: '视频复习', icon: '' }
364
+      }
365
+    ],
366
+    hidden: true
367
+  },
355 368
   {
356 369
     path: '/pdfStudy/:id',
357 370
     component: Layout,

+ 26
- 15
oa-ui/src/views/oa/study/components/pdfStudy.vue Voir le fichier

@@ -2,27 +2,31 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2025-03-06 14:38:35
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-03-11 16:16:33
5
+ * @LastEditTime: 2025-03-12 11:01:28
6 6
 -->
7 7
 <template>
8 8
   <div>
9
-    <div class="return-btn">
10
-      <div>
11
-        <el-button type="primary" size="mini" icon="el-icon-d-arrow-left"
12
-          @click="$router.push({ path: '/oa/study/myStudy' })">返回我的学习</el-button>
9
+    <div v-if="boxShow">
10
+      <div class="return-btn">
11
+        <div>
12
+          <el-button type="primary" size="mini" icon="el-icon-d-arrow-left"
13
+            @click="$router.push({ path: '/oa/study/myStudy' })">返回我的学习</el-button>
14
+        </div>
15
+        <div class="mt20">
16
+          学习进度:
17
+          <el-progress :text-inside="true" :status="formatStatus(percentage)" text-color="#fff" :stroke-width="26"
18
+            :percentage="percentage"></el-progress>
19
+        </div>
20
+        <div class="mt20" style="color:#E23D28;font-size:12px;line-height:30px;">
21
+          tips:鼠标滚动过快将导致进度计算失败,请隔2秒滚动一次页面。若一直未到100%,请返回我的学习重新进入课程。
22
+        </div>
13 23
       </div>
14
-      <div class="mt20">
15
-        学习进度:
16
-        <el-progress :text-inside="true" :status="formatStatus(percentage)" text-color="#fff" :stroke-width="26"
17
-          :percentage="percentage"></el-progress>
18
-      </div>
19
-      <div class="mt20" style="color:#E23D28;font-size:12px;line-height:30px;">
20
-        tips:鼠标滚动过快将导致进度计算失败,请隔2秒滚动一次页面。若一直未到100%,请返回我的学习重新进入课程。
24
+      <div id="pdf-container">
25
+        <div id="viewer" class="pdfViewer"></div>
21 26
       </div>
22 27
     </div>
23
-    <div id="pdf-container">
24
-
25
-      <div id="viewer" class="pdfViewer"></div>
28
+    <div class="mt20 text-center" v-else>
29
+      抱歉,暂不支持手机端,请前往电脑端观看学习
26 30
     </div>
27 31
   </div>
28 32
 </template>
@@ -35,6 +39,12 @@ import { PDFViewer } from 'pdfjs-dist/web/pdf_viewer'
35 39
 GlobalWorkerOptions.workerSrc = require('pdfjs-dist/build/pdf.worker.min');
36 40
 export default {
37 41
   async mounted() {
42
+    if (this.$store.getters.device === 'mobile') {
43
+      this.boxShow = false;
44
+      return
45
+    } else {
46
+      this.boxShow = true;
47
+    }
38 48
     await this.getData();
39 49
     this.initPDFViewer()
40 50
   },
@@ -52,6 +62,7 @@ export default {
52 62
       observers: new Map(),
53 63
       isComplete: false,
54 64
       percentage: 0,
65
+      boxShow: false,
55 66
     }
56 67
   },
57 68
   methods: {

+ 164
- 0
oa-ui/src/views/oa/study/components/reviewStudy.vue Voir le fichier

@@ -0,0 +1,164 @@
1
+<template>
2
+  <div>
3
+    <div class="video-container">
4
+      <div class="return-btn">
5
+        <el-button type="primary" size="mini" icon="el-icon-d-arrow-left"
6
+          @click="$router.push({ path: '/oa/study/myStudy' })">返回我的学习</el-button>
7
+      </div>
8
+      <video ref="reviewPlayer" width="1300" height="750" class="custom-video video-js vjs-big-play-centered"
9
+        @play="handlePlay" @pause="handlePause" @ended="handleEnd">
10
+      </video>
11
+    </div>
12
+  </div>
13
+</template>
14
+
15
+<script>
16
+import videojs from 'video.js';
17
+import 'video.js/dist/video-js.css';
18
+import { listResource, getResource, delResource, addResource, updateResource } from "@/api/oa/study/resource";
19
+import { listStudy, getStudy, delStudy, addStudy, updateStudy } from "@/api/oa/study/myStudy";
20
+
21
+export default {
22
+  data() {
23
+    return {
24
+      baseUrl: process.env.VUE_APP_BASE_API,
25
+      videoId: '',
26
+      videoPath: '',
27
+      player: null,
28
+      lastPosition: 0,
29
+      getHours: '', //可获得的学时
30
+      isComplete: false, //是否已经看完
31
+      resource: {},
32
+      // 禁用功能配置
33
+      disabledControls: [
34
+        'progressControl', // 隐藏进度条
35
+        'seekBar',         // 禁用拖拽
36
+        'remainingTimeDisplay',
37
+        'playbackRateMenuButton'
38
+      ],
39
+      videoDuration: undefined,
40
+      percentage: 0,
41
+      boxShow: false,
42
+    };
43
+  },
44
+  watch: {
45
+    videoPath() {
46
+      this.$nextTick(() => {
47
+        const video = this.$refs.reviewPlayer;
48
+        if (!video) return;
49
+        video.pause();
50
+        video.removeAttribute("src");
51
+        video.load();
52
+        setTimeout(() => {
53
+          video.src = this.fullVideoPath;
54
+          video.load();
55
+        }, 100);
56
+      });
57
+    }
58
+  },
59
+  computed: {
60
+    fullVideoPath() {
61
+      return `/dev-api/profile/upload/${this.videoPath}`
62
+    }
63
+  },
64
+  created() {
65
+    if (this.$store.getters.device === 'mobile') {
66
+      this.boxShow = false;
67
+      return
68
+    } else {
69
+      this.boxShow = true;
70
+    }
71
+    this.getData();
72
+  },
73
+  mounted() {
74
+    this.initPlayer();
75
+  },
76
+  methods: {
77
+    async getData() {
78
+      let studyId = this.$route.params.id;
79
+      let resData = await getStudy(studyId);
80
+      let data = resData.data
81
+      this.resource = data.resource;
82
+      this.videoPath = data.resource.sourcePath;
83
+      this.percentage = Number(data.lastPoint);
84
+    },
85
+    // 初始化播放器
86
+    initPlayer() {
87
+      const self = this;
88
+      this.player = videojs(this.$refs.reviewPlayer, {
89
+        // 增加错误处理回调
90
+        errorDisplay: false,
91
+        autoplay: false,
92
+        controls: true,
93
+        sources: [{ src: this.fullVideoPath, type: 'video/mp4' }],
94
+        controlBar: {
95
+          // children: this.disabledControls,
96
+          // 自定义禁止拖拽的进度条
97
+          progressControl: true, // 关闭进度条
98
+          volumePanel: true      // 启用音量控制
99
+        },
100
+        userActions: {
101
+          hotkeys: false,
102
+          // 禁用双击全屏
103
+          doubleClick: false
104
+        }
105
+      });
106
+      let retryCount = 0;
107
+      // 增加错误监听
108
+      this.player.on('error', () => {
109
+        console.error('播放器错误:', this.player.error());
110
+        if (retryCount < 3) {
111
+          this.player.src(this.fullVideoPath);
112
+          this.player.load();
113
+          retryCount++;
114
+        }
115
+      });
116
+    },
117
+    // 处理播放事件
118
+    handlePlay() {
119
+    },
120
+
121
+    // 处理暂停事件
122
+    handlePause() {
123
+
124
+    },
125
+
126
+    // 处理视频结束
127
+    async handleEnd() {
128
+
129
+    },
130
+  },
131
+  beforeDestroy() {
132
+    if (this.player) {
133
+      this.player.dispose();
134
+    }
135
+  }
136
+};
137
+</script>
138
+
139
+<style lang="scss" scoped>
140
+.video-container {
141
+  position: relative;
142
+
143
+  .return-btn {
144
+    position: absolute;
145
+    left: 20px;
146
+    top: 30px;
147
+    width: 130px;
148
+  }
149
+
150
+  .custom-video {
151
+    position: absolute;
152
+    left: 50%;
153
+    top: 50%;
154
+    transform: translate(-50%, 0%);
155
+  }
156
+
157
+  .progress-alert {
158
+    position: absolute;
159
+    bottom: 40px;
160
+    width: 100%;
161
+    z-index: 1;
162
+  }
163
+}
164
+</style>

+ 28
- 2
oa-ui/src/views/oa/study/components/studyLeft.vue Voir le fichier

@@ -2,10 +2,24 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2025-03-05 15:01:52
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-03-11 16:47:24
5
+ * @LastEditTime: 2025-03-13 16:09:55
6 6
 -->
7 7
 <template>
8 8
   <div>
9
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px">
10
+      <el-form-item label="资料名称" prop="title">
11
+        <el-input v-model="queryParams.title" placeholder="请输入资料名称" clearable @keyup.enter.native="handleQuery" />
12
+      </el-form-item>
13
+      <el-form-item label="类型" prop="title">
14
+        <el-select v-model="queryParams.type" @change="handleQuery" clearable>
15
+          <el-option label="视频" value="视频"></el-option>
16
+          <el-option label="文档" value="文档"></el-option>
17
+        </el-select>
18
+      </el-form-item>
19
+      <el-form-item>
20
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
21
+      </el-form-item>
22
+    </el-form>
9 23
     <right-toolbar :search="false" @queryTable="getRecordsList"></right-toolbar>
10 24
     <el-table :data="studyList" style="width: 100%" v-loading="loading">
11 25
       <el-table-column align="center" label="序号" type="index" />
@@ -22,7 +36,7 @@
22 36
       <el-table-column align="center" label="操作" width="100px">
23 37
         <template slot-scope="{row}">
24 38
           <el-button type="text" @click="startStudy(row)">
25
-            {{ row.lastPoint == 0 ? '开始学习' : '继续学习' }}
39
+            {{ row.lastPoint == 0 ? '开始学习' : row.lastPoint == 100 ? '复习' : '继续学习' }}
26 40
           </el-button>
27 41
           <el-button style="color: #F56C6C;" type="text" @click="cancelStudy(row)">
28 42
             取消学习
@@ -64,7 +78,19 @@ export default {
64 78
         this.loading = false;
65 79
       });
66 80
     },
81
+    /** 搜索按钮操作 */
82
+    handleQuery() {
83
+      this.queryParams.pageNum = 1;
84
+      this.getRecordsList();
85
+    },
67 86
     startStudy(record) {
87
+      if (record.lastPoint == 100 && record.resource.type === '视频') {
88
+        this.$router.push({
89
+          name: 'reviewStudy',
90
+          params: { id: record.studyId }
91
+        })
92
+        return
93
+      }
68 94
       const routeName = record.resource.type === '视频' ? 'VideoStudy' : 'PdfStudy';
69 95
       this.$router.push({
70 96
         name: routeName,

+ 35
- 4
oa-ui/src/views/oa/study/components/studyRight.vue Voir le fichier

@@ -2,16 +2,25 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2025-03-05 15:36:17
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-03-11 16:48:55
5
+ * @LastEditTime: 2025-03-13 16:13:05
6 6
 -->
7 7
 <template>
8 8
   <div class="right-box">
9 9
     <div class="video">
10 10
       <el-tabs v-model="videoTab" type="card">
11
+        <el-form :model="videoParams" size="small" :inline="true" label-width="68px" @submit.native.prevent>
12
+          <el-form-item label="视频名称" prop="title">
13
+            <el-input v-model="videoParams.title" placeholder="请输入资料名称" clearable
14
+              @keyup.enter.native="handleVideoQuery" />
15
+          </el-form-item>
16
+          <el-form-item>
17
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleVideoQuery">搜索</el-button>
18
+          </el-form-item>
19
+        </el-form>
11 20
         <el-tab-pane label="视频" name="video">
12 21
           <el-table :data="videoList" style="width: 100%">
13 22
             <el-table-column align="center" label="序号" type="index" />
14
-            <el-table-column align="center" label="资料名称" prop="title" />
23
+            <el-table-column align="center" label="名称" prop="title" />
15 24
             <el-table-column align="center" label="学时" prop="hours" />
16 25
             <el-table-column align="center" label="操作">
17 26
               <template slot-scope="{row}">
@@ -29,10 +38,18 @@
29 38
     </div>
30 39
     <div class="pdf">
31 40
       <el-tabs v-model="pdfTab" type="card">
41
+        <el-form :model="pdfParams" size="small" :inline="true" label-width="68px">
42
+          <el-form-item label="文档名称" prop="title">
43
+            <el-input v-model="pdfParams.title" placeholder="请输入资料名称" clearable @keyup.enter.native="handlePdfQuery" />
44
+          </el-form-item>
45
+          <el-form-item>
46
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="handlePdfQuery">搜索</el-button>
47
+          </el-form-item>
48
+        </el-form>
32 49
         <el-tab-pane label="文档" name="pdf">
33 50
           <el-table :data="pdfList" style="width: 100%">
34 51
             <el-table-column align="center" label="序号" type="index" />
35
-            <el-table-column align="center" label="资料名称" prop="title" />
52
+            <el-table-column align="center" label="名称" prop="title" />
36 53
             <el-table-column align="center" label="学时" prop="hours" />
37 54
             <el-table-column align="center" label="操作">
38 55
               <template slot-scope="{row}">
@@ -87,8 +104,22 @@ export default {
87 104
         this.pdfTotal = response.total;
88 105
       });
89 106
     },
107
+    handleVideoQuery() {
108
+      this.videoParams.pageNum = 1;
109
+      this.getVideoList();
110
+    },
111
+    handlePdfQuery() {
112
+      this.pdfParams.pageNum = 1;
113
+      this.getPdfList();
114
+    },
90 115
     addToStudy(row) {
91
-      this.$modal.confirm('是否添加资料名称为"' + row.title + '"到我的学习记录?').then(res => {
116
+      this.$modal.confirm('是否添加资料名称为"' + row.title + '"到我的学习记录?').then(async res => {
117
+        let isRead = await listStudy({ userId: this.$store.getters.userId, resourceId: row.resourceId });
118
+        console.log(isRead);
119
+        if (isRead.total >= 1) {
120
+          this.$message.error('该课程已添加到我的学习记录里,不可再添加,可前往学习记录进行复习。')
121
+          return
122
+        }
92 123
         let obj = {
93 124
           resourceId: row.resourceId,
94 125
           userId: this.$store.getters.userId,

+ 31
- 19
oa-ui/src/views/oa/study/components/videoStudy.vue Voir le fichier

@@ -1,23 +1,28 @@
1 1
 <template>
2
-  <div class="video-container">
3
-    <div class="return-btn">
4
-      <el-button type="primary" size="mini" icon="el-icon-d-arrow-left"
5
-        @click="$router.push({ path: '/oa/study/myStudy' })">返回我的学习</el-button>
6
-      <div class="mt20">
7
-        学习进度:
8
-        <el-progress :text-inside="true" :status="formatStatus(percentage)" text-color="#fff" :stroke-width="26"
9
-          :percentage="percentage"></el-progress>
10
-      </div>
11
-      <div class="mt20" style="color:#E23D28;font-size:12px;line-height:30px;">
12
-        tips:视频不可拖动进度条,每隔30秒会自动保存,暂停也会保存视频进度,若出现学习进度一直不到100%,请退出后重新进入课程。
2
+  <div>
3
+    <div class="video-container" v-if="boxShow">
4
+      <div class="return-btn">
5
+        <el-button type="primary" size="mini" icon="el-icon-d-arrow-left"
6
+          @click="$router.push({ path: '/oa/study/myStudy' })">返回我的学习</el-button>
7
+        <div class="mt20">
8
+          学习进度:
9
+          <el-progress :text-inside="true" :status="formatStatus(percentage)" text-color="#fff" :stroke-width="26"
10
+            :percentage="percentage"></el-progress>
11
+        </div>
12
+        <div class="mt20" style="color:#E23D28;font-size:12px;line-height:30px;">
13
+          tips:视频不可拖动进度条,每隔30秒会自动保存,暂停也会保存视频进度,若出现学习进度一直不到100%,请退出后重新进入课程。
14
+        </div>
13 15
       </div>
16
+      <video ref="videoPlayer" width="1300" height="750" class="custom-video video-js vjs-big-play-centered"
17
+        @play="handlePlay" @pause="handlePause" @ended="handleEnd">
18
+      </video>
19
+      <el-alert v-if="showProgressTip" type="info" :closable="false" class="progress-alert">
20
+        已为您定位到上次播放位置:{{ formatTime(lastPosition) }}
21
+      </el-alert>
22
+    </div>
23
+    <div class="mt20 text-center" v-else>
24
+      抱歉,暂不支持手机端,请前往电脑端观看学习
14 25
     </div>
15
-    <video ref="videoPlayer" width="1300" height="750" class="custom-video video-js vjs-big-play-centered"
16
-      @play="handlePlay" @pause="handlePause" @ended="handleEnd">
17
-    </video>
18
-    <el-alert v-if="showProgressTip" type="info" :closable="false" class="progress-alert">
19
-      已为您定位到上次播放位置:{{ formatTime(lastPosition) }}
20
-    </el-alert>
21 26
   </div>
22 27
 </template>
23 28
 
@@ -48,6 +53,7 @@ export default {
48 53
       ],
49 54
       videoDuration: undefined,
50 55
       percentage: 0,
56
+      boxShow: false,
51 57
     };
52 58
   },
53 59
   watch: {
@@ -71,6 +77,12 @@ export default {
71 77
     }
72 78
   },
73 79
   created() {
80
+    if (this.$store.getters.device === 'mobile') {
81
+      this.boxShow = false;
82
+      return
83
+    } else {
84
+      this.boxShow = true;
85
+    }
74 86
     this.getData();
75 87
   },
76 88
   mounted() {
@@ -91,7 +103,7 @@ export default {
91 103
       if (Number(data.lastPoint) == 100) {
92 104
         this.isComplete = true;
93 105
         this.getHours = data.resource.hours;
94
-        this.$message.warning('视频已学习完毕,若要再次学习,请在学习记录里重新添加该课程。')
106
+        this.$message.warning('视频已学习完毕,若要再次学习,请重新点击复习。')
95 107
       }
96 108
     },
97 109
     // 初始化播放器
@@ -172,7 +184,7 @@ export default {
172 184
 
173 185
     // 处理视频结束
174 186
     async handleEnd() {
175
-      this.$message.warning('视频已学习完毕,若要再次学习,请在学习记录里重新添加该课程。')
187
+      this.$message.warning('视频已学习完毕,若要再次学习,请重新点击复习。')
176 188
       await updateStudy({
177 189
         studyId: this.videoId,
178 190
         lastPoint: 100,

+ 21
- 8
oa-ui/src/views/oa/study/myStudy.vue Voir le fichier

@@ -2,12 +2,12 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2025-03-05 14:00:18
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-03-05 15:26:03
5
+ * @LastEditTime: 2025-03-12 10:43:08
6 6
 -->
7 7
 <template>
8 8
   <div>
9 9
     <study-head></study-head>
10
-    <div class="main app-contrainer">
10
+    <!-- <div class="main app-contrainer">
11 11
       <div class="left">
12 12
         <div class="title">
13 13
           我的学习记录
@@ -15,8 +15,6 @@
15 15
         </div>
16 16
         <study-left ref="studyLeft"></study-left>
17 17
       </div>
18
-      <!-- <div class="center">
19
-      </div> -->
20 18
       <div class="right">
21 19
         <div class="title">
22 20
           学习资料库
@@ -24,7 +22,26 @@
24 22
         </div>
25 23
         <study-right ref="studyRight" @refreshList="getStudyList"></study-right>
26 24
       </div>
25
+    </div> -->
26
+    <div class="main app-container">
27
+      <el-row>
28
+        <el-col :md="12" :sm="24" class="left">
29
+          <div class="title">
30
+            我的学习记录
31
+            <div class="line"></div>
32
+          </div>
33
+          <study-left ref="studyLeft"></study-left>
34
+        </el-col>
35
+        <el-col :md="12" :sm="24" class="right">
36
+          <div class="title">
37
+            学习资料库
38
+            <div class="line"></div>
39
+          </div>
40
+          <study-right ref="studyRight" @refreshList="getStudyList"></study-right>
41
+        </el-col>
42
+      </el-row>
27 43
     </div>
44
+
28 45
   </div>
29 46
 </template>
30 47
 
@@ -45,23 +62,19 @@ export default {
45 62
 
46 63
 <style lang="scss" scoped>
47 64
 .main {
48
-  display: flex;
49 65
   margin-top: 50px;
50 66
 
51 67
   .left {
52
-    flex: 1;
53 68
     padding: 10px;
54 69
     border-right: 1px solid #ececec;
55 70
   }
56 71
 
57 72
   .center {
58
-    flex: 1;
59 73
     padding: 10px;
60 74
     border-right: 1px solid #ececec;
61 75
   }
62 76
 
63 77
   .right {
64
-    flex: 1;
65 78
     padding: 10px;
66 79
   }
67 80
 }

+ 290
- 0
oa-ui/src/views/oa/study/record.vue Voir le fichier

@@ -0,0 +1,290 @@
1
+<!--
2
+ * @Author: ysh
3
+ * @Date: 2025-03-12 10:06:03
4
+ * @LastEditors: Please set LastEditors
5
+ * @LastEditTime: 2025-03-13 16:20:48
6
+-->
7
+<template>
8
+  <div class="app-container">
9
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
10
+      <el-form-item label="资料名称" prop="title">
11
+        <el-input v-model="queryParams.title" placeholder="请输入资料名称" clearable @keyup.enter.native="handleQuery" />
12
+      </el-form-item>
13
+      <el-form-item label="类型" prop="title">
14
+        <el-select v-model="queryParams.type" @change="handleQuery" clearable>
15
+          <el-option label="视频" value="视频"></el-option>
16
+          <el-option label="文档" value="文档"></el-option>
17
+        </el-select>
18
+      </el-form-item>
19
+      <el-form-item label="姓名" prop="userId">
20
+        <el-select v-model="queryParams.userId" clearable filterable placeholder="请输入姓名" style="width: 160px"
21
+          @change="handleQuery">
22
+          <el-option v-for="item in $store.state.user.userList" :key="item.userId" :label="item.nickName"
23
+            :value="item.userId">
24
+          </el-option>
25
+        </el-select>
26
+      </el-form-item>
27
+      <el-form-item label="学习年份" prop="lastTime" label-width="100px">
28
+        <el-date-picker clearable v-model="queryParams.lastTime" type="year" value-format="yyyy-MM-dd"
29
+          placeholder="请选择学习年份" @change="handleQuery">
30
+        </el-date-picker>
31
+      </el-form-item>
32
+      <el-form-item>
33
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
34
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
35
+      </el-form-item>
36
+    </el-form>
37
+
38
+    <el-row :gutter="10" class="mb8">
39
+      <!-- <el-col :span="1.5">
40
+        <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
41
+          v-hasPermi="['oa:study:add']">新增</el-button>
42
+      </el-col>
43
+      <el-col :span="1.5">
44
+        <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate"
45
+          v-hasPermi="['oa:study:edit']">修改</el-button>
46
+      </el-col>
47
+      <el-col :span="1.5">
48
+        <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete"
49
+          v-hasPermi="['oa:study:remove']">删除</el-button>
50
+      </el-col> -->
51
+      <el-col :span="1.5">
52
+        <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
53
+          v-hasPermi="['oa:study:export']">导出</el-button>
54
+      </el-col>
55
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
56
+    </el-row>
57
+    <el-row>
58
+      <el-col :span="14" class="left">
59
+        <el-table v-loading="loading" :data="studyList" @selection-change="handleSelectionChange">
60
+          <el-table-column type="selection" width="55" align="center" />
61
+          <el-table-column type="index" label="序号" width="55" align="center" />
62
+          <!-- <el-table-column label="学习id" align="center" prop="studyId" /> -->
63
+          <el-table-column align="center" label="资料名称" prop="resource.title" />
64
+          <el-table-column align="center" label="类型" prop="resource.type"></el-table-column>
65
+          <el-table-column align="center" label="学习进度" prop="lastPoint">
66
+            <template slot-scope="scope">
67
+              <el-progress :text-inside="true" :stroke-width="26" :status="formatStatus(scope.row.lastPoint)"
68
+                :percentage="Number(scope.row.lastPoint)" text-color="#fff"></el-progress>
69
+            </template>
70
+          </el-table-column>
71
+          <el-table-column label="姓名" align="center" prop="user.nickName" />
72
+          <el-table-column label="上次学习时间" align="center" prop="lastTime" width="180">
73
+            <template slot-scope="scope">
74
+              <span>{{ parseTime(scope.row.lastTime, '{y}-{m}-{d}') }}</span>
75
+            </template>
76
+          </el-table-column>
77
+          <el-table-column label="已获学时" align="center" prop="getHours" />
78
+          <!-- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
79
+            <template slot-scope="scope">
80
+              <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
81
+                v-hasPermi="['oa:study:edit']">修改</el-button>
82
+              <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
83
+                v-hasPermi="['oa:study:remove']">删除</el-button>
84
+            </template>
85
+          </el-table-column> -->
86
+        </el-table>
87
+        <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
88
+          :limit.sync="queryParams.pageSize" @pagination="getList" />
89
+      </el-col>
90
+      <el-col :span="10">
91
+        
92
+      </el-col>
93
+    </el-row>
94
+
95
+
96
+
97
+
98
+    <!-- 添加或修改cmc学习记录对话框 -->
99
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
100
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
101
+        <el-form-item label="学习资料id" prop="resourceId">
102
+          <el-input v-model="form.resourceId" placeholder="请输入学习资料id" />
103
+        </el-form-item>
104
+        <el-form-item label="用户id" prop="userId">
105
+          <el-input v-model="form.userId" placeholder="请输入用户id" />
106
+        </el-form-item>
107
+        <el-form-item label="上次位置" prop="lastPoint">
108
+          <el-input v-model="form.lastPoint" placeholder="请输入上次位置" />
109
+        </el-form-item>
110
+        <el-form-item label="上次时间" prop="lastTime">
111
+          <el-date-picker clearable v-model="form.lastTime" type="date" value-format="yyyy-MM-dd" placeholder="请选择上次时间">
112
+          </el-date-picker>
113
+        </el-form-item>
114
+        <el-form-item label="可获学时" prop="getHours">
115
+          <el-input v-model="form.getHours" placeholder="请输入可获学时" />
116
+        </el-form-item>
117
+      </el-form>
118
+      <div slot="footer" class="dialog-footer">
119
+        <el-button type="primary" @click="submitForm">确 定</el-button>
120
+        <el-button @click="cancel">取 消</el-button>
121
+      </div>
122
+    </el-dialog>
123
+  </div>
124
+</template>
125
+
126
+<script>
127
+import { listStudy, getStudy, delStudy, addStudy, updateStudy } from "@/api/oa/study/myStudy";
128
+
129
+export default {
130
+  name: "Study",
131
+  data() {
132
+    return {
133
+      // 遮罩层
134
+      loading: true,
135
+      // 选中数组
136
+      ids: [],
137
+      // 非单个禁用
138
+      single: true,
139
+      // 非多个禁用
140
+      multiple: true,
141
+      // 显示搜索条件
142
+      showSearch: true,
143
+      // 总条数
144
+      total: 0,
145
+      // cmc学习记录表格数据
146
+      studyList: [],
147
+      // 弹出层标题
148
+      title: "",
149
+      // 是否显示弹出层
150
+      open: false,
151
+      // 查询参数
152
+      queryParams: {
153
+        pageNum: 1,
154
+        pageSize: 10,
155
+        resourceId: null,
156
+        userId: null,
157
+        lastPoint: null,
158
+        lastTime: null,
159
+        getHours: null
160
+      },
161
+      // 表单参数
162
+      form: {},
163
+      // 表单校验
164
+      rules: {
165
+      }
166
+    };
167
+  },
168
+  created() {
169
+    this.getList();
170
+  },
171
+  methods: {
172
+    /** 查询cmc学习记录列表 */
173
+    getList() {
174
+      this.loading = true;
175
+      listStudy(this.queryParams).then(response => {
176
+        this.studyList = response.rows;
177
+        this.total = response.total;
178
+        this.loading = false;
179
+      });
180
+    },
181
+    // 取消按钮
182
+    cancel() {
183
+      this.open = false;
184
+      this.reset();
185
+    },
186
+    // 表单重置
187
+    reset() {
188
+      this.form = {
189
+        studyId: null,
190
+        resourceId: null,
191
+        userId: null,
192
+        lastPoint: null,
193
+        lastTime: null,
194
+        getHours: null
195
+      };
196
+      this.resetForm("form");
197
+    },
198
+    /** 搜索按钮操作 */
199
+    handleQuery() {
200
+      this.queryParams.pageNum = 1;
201
+      this.getList();
202
+    },
203
+    /** 重置按钮操作 */
204
+    resetQuery() {
205
+      this.resetForm("queryForm");
206
+      this.handleQuery();
207
+    },
208
+    // 多选框选中数据
209
+    handleSelectionChange(selection) {
210
+      this.ids = selection.map(item => item.studyId)
211
+      this.single = selection.length !== 1
212
+      this.multiple = !selection.length
213
+    },
214
+    /** 新增按钮操作 */
215
+    handleAdd() {
216
+      this.reset();
217
+      this.open = true;
218
+      this.title = "添加cmc学习记录";
219
+    },
220
+    /** 修改按钮操作 */
221
+    handleUpdate(row) {
222
+      this.reset();
223
+      const studyId = row.studyId || this.ids
224
+      getStudy(studyId).then(response => {
225
+        this.form = response.data;
226
+        this.open = true;
227
+        this.title = "修改cmc学习记录";
228
+      });
229
+    },
230
+    /** 提交按钮 */
231
+    submitForm() {
232
+      this.$refs["form"].validate(valid => {
233
+        if (valid) {
234
+          if (this.form.studyId != null) {
235
+            updateStudy(this.form).then(response => {
236
+              this.$modal.msgSuccess("修改成功");
237
+              this.open = false;
238
+              this.getList();
239
+            });
240
+          } else {
241
+            addStudy(this.form).then(response => {
242
+              this.$modal.msgSuccess("新增成功");
243
+              this.open = false;
244
+              this.getList();
245
+            });
246
+          }
247
+        }
248
+      });
249
+    },
250
+    /** 删除按钮操作 */
251
+    handleDelete(row) {
252
+      const studyIds = row.studyId || this.ids;
253
+      this.$modal.confirm('是否确认删除cmc学习记录编号为"' + studyIds + '"的数据项?').then(function () {
254
+        return delStudy(studyIds);
255
+      }).then(() => {
256
+        this.getList();
257
+        this.$modal.msgSuccess("删除成功");
258
+      }).catch(() => { });
259
+    },
260
+    /** 导出按钮操作 */
261
+    handleExport() {
262
+      this.download('oa/study/export', {
263
+        ...this.queryParams
264
+      }, `study_${new Date().getTime()}.xlsx`)
265
+    },
266
+
267
+    formatStatus(row) {
268
+      if (!row) {
269
+        row = 0
270
+        return 'exception'
271
+      }
272
+      if (row <= 20) {
273
+        return 'exception'
274
+      } else if (row > 20 && row <= 50) {
275
+        return 'warning'
276
+      } else if (row > 50 && row <= 80) {
277
+        return null
278
+      } else {
279
+        return 'success'
280
+      }
281
+    },
282
+  }
283
+};
284
+</script>
285
+<style lang="scss" scoped>
286
+.left {
287
+  padding: 10px;
288
+  border-right: 1px solid #ececec;
289
+}
290
+</style>

+ 19
- 4
oa-ui/src/views/oa/study/resource.vue Voir le fichier

@@ -2,7 +2,7 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2025-03-05 09:15:54
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-03-05 13:58:28
5
+ * @LastEditTime: 2025-03-12 10:02:46
6 6
 -->
7 7
 <template>
8 8
   <div class="app-container">
@@ -94,7 +94,7 @@
94 94
         </el-form-item>
95 95
         <el-form-item label="上传附件" prop="sourcePath">
96 96
           <FileUpload v-if="form.sourcePath == null || form.sourcePath == ''" :isShowTip="false" :limit="1"
97
-            :filePathName="'教育学习/学习资料'" :fileType="['pdf', 'mp4', 'mkv']" :fileSize="10240" @input="getDocumentPath">
97
+            :filePathName="'教育学习/学习资料'" :fileType="['pdf', 'mp4']" :fileSize="10240" @input="getDocumentPath">
98 98
           </FileUpload>
99 99
           <div v-if="form.sourcePath">
100 100
             <el-link type="primary" @click="reviewWord(`${baseUrl}${'/profile/upload' + form.sourcePath}`)">
@@ -112,7 +112,7 @@
112 112
               :fileType="['doc', 'docx', 'xls', 'xlsx', 'pdf', 'rar', 'zip']" @input="getDocumentPath"></FileUpload> -->
113 113
           </div>
114 114
           <div style="font-size:12px;color:#e45656">
115
-            tips:文档请上传pdf格式,视频请上传mp4格式
115
+            tips:文档仅支持pdf格式,视频仅支持mp4格式
116 116
           </div>
117 117
         </el-form-item>
118 118
         <el-form-item label="资料类型" prop="type">
@@ -192,6 +192,21 @@ export default {
192 192
       }
193 193
     };
194 194
   },
195
+  watch: {
196
+    'form.sourcePath'(val) {
197
+      console.log(val);
198
+      if (val) {
199
+        let name = this.getFileName(val);
200
+        if (name.includes('pdf')) {
201
+          this.form.type = '文档'
202
+        } else {
203
+          this.form.type = '视频'
204
+        }
205
+      } else {
206
+        this.form.type = ''
207
+      }
208
+    }
209
+  },
195 210
   created() {
196 211
     this.getList();
197 212
   },
@@ -308,7 +323,7 @@ export default {
308 323
         this.form.sourcePath = '';
309 324
       }).catch(() => { });
310 325
     },
311
-    formatterPath(row){
326
+    formatterPath(row) {
312 327
       let name = this.getFileName(row.sourcePath)
313 328
       return name
314 329
     }

Loading…
Annuler
Enregistrer