Переглянути джерело

Merge branch 'master' of http://47.100.37.243:10191/wutt/manHourHousekeeper

QuYueTing 5 днів тому
батько
коміт
f58a0b2c92

BIN
fhKeeper/formulahousekeeper/course-pc/src/assets/image/yunketang.png


+ 12 - 1
fhKeeper/formulahousekeeper/course-pc/src/routes.js

@@ -9,6 +9,7 @@ import PdfView from './views/pdf/pdfview';
 //课程管理
 import courselist from './views/coursemanagement/list';
 import lecturerList from './views/lecturerManagement/index.vue'
+import offlineTraining from './views/offlineTraining/offlineTraining.vue'
 
 Vue.use(Router)
 
@@ -57,6 +58,16 @@ export const allRouters = [
         name: '',
         hidden: true
     },
+    {
+        path: '/offline-training',
+        component: Home,
+        name: '线下研修班',
+        iconCls: 'iconfont firerock-iconkehu',
+        leaf: true,
+        children: [
+            { path: '/offline-training', component: offlineTraining, name: '线下研修班' }
+        ]
+    },
     {
         path: '*',
         hidden: true,
@@ -65,4 +76,4 @@ export const allRouters = [
 ]
 export default new Router({
     routes: allRouters
-})
+})

+ 25 - 2
fhKeeper/formulahousekeeper/course-pc/src/views/coursemanagement/addVideo.vue

@@ -39,7 +39,7 @@
             ></el-input-number>
           </el-col>
           <el-col :span="5">
-            <el-button size="small" type="primary" @click="previewingVideoVisable = true">预览视频</el-button>
+            <el-button size="small" type="primary" @click="previewingVideoSrc(item)">预览视频</el-button>
             <el-button size="small" type="danger" @click="removeRow(index)">删除</el-button>
           </el-col>
         </el-row>
@@ -49,7 +49,7 @@
     <!-- 预览视频 -->
     <el-dialog title="预览视频" append-to-body :visible.sync="previewingVideoVisable" width="900px" top="6.5vh" :before-close="handleClose">
       <div class="previewingVideo">
-        <video src="http://1.94.62.58:9007/upload/preview/preview_0cdd80f0-14c0-4e75-8736-b0b7764fcb7f.mp4" style="width: 100%;height: 100%;background: rgba(0,0,0,0.5);" poster="https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg" controls></video>
+        <video :src="previewVideoSrc" :poster="require('../../assets/image/yunketang.png')" controls></video>
       </div>
     </el-dialog>
   </div>
@@ -82,10 +82,16 @@ export default {
   data() {
     return {
       videoTypes: [],
+      previewVideoSrc: '',
       previewingVideoVisable: false
     }
   },
   methods: {
+    previewingVideoSrc(row) {
+      console.log(row)
+      this.previewVideoSrc = row.videoUrl
+      this.previewingVideoVisable = true
+    },
     getAllTeachers() {
       this.http.post(`/course-teacher/list`, {}, res => {
         this.videoTypes = res.data || []
@@ -110,6 +116,18 @@ export default {
     },
     onDragEnd() {
       console.log('排序完成', this.videoListComputed)
+    },
+    handleClose(done) {
+      // 清除 video 的 src,释放资源
+      const videoEl = this.$refs.previewVideo
+      if (videoEl) {
+        videoEl.pause()
+        videoEl.removeAttribute('src')
+        videoEl.load()
+      }
+      this.previewingVideoVisable = false
+      this.previewVideoSrc = ''
+      done()
     }
   },
   mounted() {
@@ -151,4 +169,9 @@ export default {
   width: 100%;
   height: 68vh;
 }
+
+.previewingVideo video {
+  width: 100%;
+  height: 100%;
+}
 </style>

+ 56 - 8
fhKeeper/formulahousekeeper/course-pc/src/views/coursemanagement/list.vue

@@ -309,8 +309,44 @@ export default {
     methods: {
         saveVideo() {
             console.log(this.displayVideoList, '<=== 看看数据')
-            return
-            this.addVideoVisable = false
+            const courseInfoId = this.addVideoRow.id
+            const list = this.displayVideoList.map((item, index) => {
+                const { videoName, videoUrl, coursePreviousUrl = '', videoLecturerId, videoPreviewTime, id } = item
+                const obj = {
+                    courseInfoId,
+                    courseSubName: videoName,
+                    courseUrl: this.checkAndAddUpload(videoUrl),
+                    teacherId: videoLecturerId,
+                    seconds: videoPreviewTime * 60,
+                    seq: index + 1
+                }
+                if(coursePreviousUrl) {
+                    obj.coursePreviousUrl = this.checkAndAddUpload(coursePreviousUrl)
+                }
+                if(id) {
+                    obj.id = id
+                }
+                return obj
+            })
+
+            this.saveVideoLoading = true
+            this.http.post(`/course-sub-info/saveCourseSubInfo`, {
+                jsonStr: JSON.stringify(list)
+            }, res => {
+                this.$message({
+                    message: `保存成功`,
+                    type: 'success'
+                });
+                this.saveVideoLoading = false
+                this.addVideoVisable = false
+            }, err => {
+                this.$message({
+                    message: `保存失败`,
+                    type: 'error'
+                });
+                this.addVideoVisable = false
+            })
+            
         },
         uploadVideo(file) {
             this.videoList.unshift(file.file)
@@ -335,7 +371,7 @@ export default {
                     videoError: ''
                 })
                 this.http.uploadFile(`/common/uploadFile`, formData, res => {
-                    this.displayVideoList[i].videoUrl = res.data
+                    this.displayVideoList[i].videoUrl = this.checkAndAddUpload(res.data)
                     this.displayVideoList[i].videoLoading = false
                 }, err => {
                     this.displayVideoList[i].videoLoading = false
@@ -358,11 +394,23 @@ export default {
         },
         // 添加视频
         addVideo(row) {
-            console.log(row, '<===== 单机的对象')
-            this.addVideoRow = row
-            this.videoList = []
-            this.displayVideoList = []
-            this.addVideoVisable = true
+            this.http.post(`/course-sub-info/list`, { courseId: row.id }, res => {
+                this.addVideoRow = row
+                this.videoList = []
+                this.displayVideoList = (res.data || []).map(item => {
+                    return {
+                        videoName: item.courseSubName,
+                        coursePreviousUrl: this.checkAndAddUpload(item.coursePreviousUrl),
+                        videoLoading: false,
+                        videoUrl: this.checkAndAddUpload(item.courseUrl),
+                        videoLecturerId: item.teacherId,
+                        videoPreviewTime: (item.seconds || 0) / 60,
+                        videoError: '',
+                        id: item.id
+                    }
+                })
+                this.addVideoVisable = true
+            })
         },
 
         // 分类管理

+ 336 - 0
fhKeeper/formulahousekeeper/course-pc/src/views/offlineTraining/offlineTraining.vue

@@ -0,0 +1,336 @@
+<template>
+  <div class="offline-training-container">
+    <el-card class="box-card">
+      <div slot="header" class="clearfix">
+        <span>线下研修班介绍</span>
+      </div>
+      
+      <viewer ref="imageWrapper" :images="previewImages" style="opacity: 1;position: absolute;top: -9999px;">
+        <img v-for="(image, index) in previewImages" :src="image" :key="index" />
+      </viewer>
+
+      <el-form ref="form" :model="form" label-width="120px">
+        <div class="form-section">
+          <el-form-item label="分类名称" prop="categoryName">
+            <el-input v-model="form.categoryName" placeholder="请输入分类名称"></el-input>
+          </el-form-item>
+        </div>
+
+        <div class="form-section">
+          <el-form-item label="分类封面" prop="coverImage">
+            <div class="upload-area">
+              <el-upload
+                class="cover-uploader"
+                action="#"
+                :show-file-list="false"
+                :on-change="handleCoverChange"
+                :auto-upload="false"
+                :before-upload="beforeCoverUpload">
+                <img v-if="form.coverImage" :src="form.coverImage" class="cover-preview" @click="previewImage(form.coverImage)">
+                <i v-else class="el-icon-plus cover-uploader-icon"></i>
+              </el-upload>
+              <div class="upload-tip">建议尺寸:800x600px,大小不超过5MB</div>
+            </div>
+          </el-form-item>
+        </div>
+
+        <div class="form-section">
+          <el-form-item label="内容上传" prop="contentType">
+            <el-radio-group v-model="form.contentType" @change="handleContentTypeChange">
+              <el-radio label="image">图片</el-radio>
+              <el-radio label="video">视频</el-radio>
+            </el-radio-group>
+            
+            <div class="upload-area" v-if="form.contentType === 'image'">
+              <el-upload
+                action="#"
+                :show-file-list="false"
+                :on-change="handleImageChange"
+                :auto-upload="false"
+                :before-upload="beforeImageUpload">
+                <el-button size="small" type="primary">点击上传图片</el-button>
+              </el-upload>
+              <div class="upload-preview" v-if="form.contentImage">
+                <img :src="form.contentImage" class="content-preview" @click="previewImage(form.contentImage)">
+              </div>
+            </div>
+
+            <div class="upload-area" v-else-if="form.contentType === 'video'">
+              <el-upload
+                action="#"
+                :show-file-list="false"
+                :on-change="handleVideoChange"
+                :auto-upload="false"
+                :before-upload="beforeVideoUpload">
+                <el-button size="small" type="primary">点击上传视频</el-button>
+              </el-upload>
+              <div class="upload-preview" v-if="form.contentVideo">
+                <video controls class="video-preview">
+                  <source :src="form.contentVideo" type="video/mp4">
+                </video>
+              </div>
+            </div>
+          </el-form-item>
+        </div>
+
+        <div class="action-buttons">
+          <el-button type="primary" @click="submitForm">提交</el-button>
+          <el-button @click="resetForm">重置</el-button>
+        </div>
+      </el-form>
+    </el-card>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      form: {
+        categoryName: '',
+        coverImage: '',
+        contentType: 'image',
+        contentImage: '',
+        contentVideo: ''
+      },
+      previewImages: []
+    }
+  },
+  methods: {
+    previewImage(url) {
+      this.previewImages = [url];
+      this.$nextTick(() => {
+        if (this.$refs.imageWrapper && this.$refs.imageWrapper.$viewer) {
+          this.$refs.imageWrapper.$viewer.show();
+        }
+      });
+    },
+    
+    checkAndAddUpload(str) {
+      if(!str) return '';
+      return str.includes('/upload/') ? str : '/upload/' + str;
+    },
+
+    handleCoverChange(file) {
+      const isImage = file.raw.type.includes('image');
+      const isLt5M = file.raw.size / 1024 / 1024 < 5;
+      
+      if (!isImage) {
+        this.$message.error('只能上传图片文件!');
+        return;
+      }
+      if (!isLt5M) {
+        this.$message.error('图片大小不能超过5MB!');
+        return;
+      }
+
+      const formData = new FormData();
+      formData.append('multipartFile', file.raw);
+      
+      this.http.uploadFile('/common/uploadFile', formData, res => {
+        if (res.code === "ok") {
+          this.form.coverImage = this.checkAndAddUpload(res.data);
+          this.$message.success('封面图片上传成功');
+        } else {
+          this.$message.error(res.msg || '上传失败');
+        }
+      });
+    },
+    
+    beforeCoverUpload(file) {
+      const isImage = file.type.includes('image');
+      const isLt5M = file.size / 1024 / 1024 < 5;
+      
+      if (!isImage) {
+        this.$message.error('只能上传图片文件!');
+        return false;
+      }
+      if (!isLt5M) {
+        this.$message.error('图片大小不能超过5MB!');
+        return false;
+      }
+      return true;
+    },
+    
+    handleImageChange(file) {
+      const isImage = file.raw.type.includes('image');
+      const isLt5M = file.raw.size / 1024 / 1024 < 5;
+      
+      if (!isImage) {
+        this.$message.error('只能上传图片文件!');
+        return;
+      }
+      if (!isLt5M) {
+        this.$message.error('图片大小不能超过5MB!');
+        return;
+      }
+
+      const formData = new FormData();
+      formData.append('multipartFile', file.raw);
+      
+      this.http.uploadFile('/common/uploadFile', formData, res => {
+        if (res.code === "ok") {
+          this.form.contentImage = this.checkAndAddUpload(res.data);
+          this.$message.success('内容图片上传成功');
+        } else {
+          this.$message.error(res.msg || '上传失败');
+        }
+      });
+    },
+    
+    beforeImageUpload(file) {
+      return this.beforeCoverUpload(file);
+    },
+    
+    handleVideoChange(file) {
+      const isVideo = file.raw.type.includes('video');
+      const isLt50M = file.raw.size / 1024 / 1024 < 50;
+      
+      if (!isVideo) {
+        this.$message.error('只能上传视频文件!');
+        return;
+      }
+      if (!isLt50M) {
+        this.$message.error('视频大小不能超过50MB!');
+        return;
+      }
+
+      const formData = new FormData();
+      formData.append('multipartFile', file.raw);
+      
+      this.http.uploadFile('/common/uploadFile', formData, res => {
+        if (res.code === "ok") {
+          this.form.contentVideo = this.checkAndAddUpload(res.data);
+          this.$message.success('视频上传成功');
+        } else {
+          this.$message.error(res.msg || '上传失败');
+        }
+      });
+    },
+    
+    beforeVideoUpload(file) {
+      const isVideo = file.type.includes('video');
+      const isLt50M = file.size / 1024 / 1024 < 50;
+      
+      if (!isVideo) {
+        this.$message.error('只能上传视频文件!');
+        return false;
+      }
+      if (!isLt50M) {
+        this.$message.error('视频大小不能超过50MB!');
+        return false;
+      }
+      return true;
+    },
+
+    handleContentTypeChange(val) {
+      this.form.contentImage = '';
+      this.form.contentVideo = '';
+    },
+
+    submitForm() {
+      this.$refs.form.validate(valid => {
+        if (valid) {
+          // 提交表单逻辑
+          this.$message.success('提交成功!');
+        }
+      });
+    },
+
+    resetForm() {
+      this.$refs.form.resetFields();
+      this.form.contentImage = '';
+      this.form.contentVideo = '';
+    }
+  }
+}
+</script>
+
+<style scoped>
+.offline-training-container {
+  padding: 20px;
+  max-width: 1000px;
+  margin: 0 auto;
+}
+
+.box-card {
+  border-radius: 8px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+}
+
+.form-section {
+  margin-bottom: 24px;
+}
+
+.upload-area {
+  border: 1px dashed #dcdfe6;
+  border-radius: 6px;
+  padding: 20px;
+  margin-bottom: 20px;
+  background-color: #f5f7fa;
+}
+
+.upload-preview {
+  margin-top: 15px;
+  text-align: center;
+}
+
+.cover-uploader {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+  width: 200px;
+  height: 150px;
+  margin: 0 auto;
+}
+
+.cover-uploader:hover {
+  border-color: #409EFF;
+}
+
+.cover-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 200px;
+  height: 150px;
+  line-height: 150px;
+  text-align: center;
+}
+
+.cover-preview {
+  width: 200px;
+  height: 150px;
+  object-fit: cover;
+  border-radius: 4px;
+  cursor: pointer;
+}
+
+.content-preview {
+  max-width: 100%;
+  max-height: 300px;
+  border-radius: 4px;
+  cursor: pointer;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.video-preview {
+  max-width: 100%;
+  max-height: 300px;
+  border-radius: 4px;
+  background-color: #000;
+}
+
+.upload-tip {
+  color: #909399;
+  font-size: 12px;
+  margin-top: 8px;
+  text-align: center;
+}
+
+.action-buttons {
+  margin-top: 24px;
+  text-align: center;
+}
+</style>