Pārlūkot izejas kodu

Merge branch 'master' into 康年堂

yh 1 nedēļu atpakaļ
vecāks
revīzija
651368ad7b

+ 3 - 0
.env.prod-heyantang

@@ -38,3 +38,6 @@ VUE_APP_COURSE_DEFAULT = 2
 
 # 路由懒加载
 VUE_CLI_BABEL_TRANSPILE_MODULES = true
+
+
+VUE_APP_LIVE_WS_URL = wss://liveapp.yytcdta.com/ws

+ 4 - 0
.env.prod-jnlzjk

@@ -26,6 +26,10 @@ VUE_APP_COS_REGION = ap-chongqing
 VUE_APP_VIDEO_LINE_1 = https://jnlzjktcpv.ylrzcloud.com
 # 线路二地址
 VUE_APP_VIDEO_LINE_2 = https://jnlzjkobs.ylrztop.com
+#火山云
+VUE_APP_VIDEO_URL = https://jnlzjkvolcengine.ylrztop.com
+#火山云
+VUE_APP_HSY_SPACE = lzjk-2114522511
 
 # 开发环境配置
 ENV = 'production'

+ 4 - 1
.env.prod-qdtst

@@ -26,7 +26,10 @@ VUE_APP_COS_REGION = ap-chongqing
 VUE_APP_VIDEO_LINE_1 = https://qdtsttcpv.ylrzcloud.com
 # 线路二地址
 VUE_APP_VIDEO_LINE_2 = https://qdtstobs.ylrztop.com
-
+#火山云视频地址域名
+VUE_APP_VIDEO_URL = https://qdtstvolcengine.ylrztop.com
+#火山云视频点播空间名
+VUE_APP_HSY_SPACE = qdtst-2114522511
 # 开发环境配置
 ENV = 'development'
 

+ 1 - 0
package.json

@@ -105,6 +105,7 @@
     "quill": "1.3.7",
     "screenfull": "5.0.2",
     "sortablejs": "1.10.2",
+    "tt-uploader": "^1.5.5",
     "vod-js-sdk-v6": "^1.7.0",
     "vue": "2.6.12",
     "vue-baidu-map": "^0.21.22",

+ 3 - 0
src/views/course/courseRedPacketLog/index.vue

@@ -148,6 +148,7 @@
       <el-table-column type="selection" width="55" align="center" />
 <!--      <el-table-column label="记录编号" align="center" prop="logId" />-->
       <el-table-column label="批次单号" align="center" prop="outBatchNo" />
+      <el-table-column label="营期名称" align="center" prop="periodName" />
       <el-table-column label="课程名称" align="center" prop="courseId" >
         <template slot-scope="scope">
           <span prop="status" v-for="(item, index) in courseLists"    v-if="scope.row.courseId==item.dictValue">{{item.dictLabel}}</span>
@@ -215,6 +216,8 @@
 <script>
 import { courseList,videoList,getCourseRedPacketLog, delCourseRedPacketLog, addCourseRedPacketLog, updateCourseRedPacketLog, exportCourseRedPacketLog,listCourseRedPacketLogPage } from "@/api/course/courseRedPacketLog";
 import { getCompanyList } from "@/api/company/company";
+import { periodList } from "@/api/course/userCoursePeriod";
+import {treeselect} from "../../../api/company/companyDept";
 import SelectTree from '@/components/TreeSelect/index.vue'
 import { getDeptData } from '@/api/system/employeeStats'
 

+ 14 - 4
src/views/live/live/index.vue

@@ -388,8 +388,13 @@
         </el-form-item>
         <el-form-item label="直播类型" prop="liveType">
           <el-radio-group v-model="form.liveType">
-            <!--            <el-radio :label="1">直播</el-radio>-->
-            <el-radio :label="2">录播</el-radio>
+            <el-radio
+              v-for="item in liveTypeDictList"
+              :key="item.dictValue"
+              :label="parseInt(item.dictValue)"
+            >
+              {{ item.dictLabel }}
+            </el-radio>
           </el-radio-group>
         </el-form-item>
         <!--        <el-form-item label="直播达人" prop="talentId">-->
@@ -675,6 +680,7 @@ export default {
   components: { Editor, VideoUpload },
   data() {
     return {
+      liveTypeDictList: [],
       currentCheck:null,
       currentCheckTagIndex:null,
       lastCheckTagRow:null,
@@ -798,6 +804,10 @@ export default {
     this.getDicts("live_mark_type").then((response) => {
       this.markTypeDropList = response.data;
     });
+    // 新增:获取直播类型字典
+    this.getDicts("live_type").then((response) => {
+      this.liveTypeDictList = response.data;
+    });
   },
   watch: {
     "form.startTime": {
@@ -1127,8 +1137,8 @@ export default {
         }else{
           for(let index =0 ;index<this.form.liveTagList.length;index ++){
             this.form.liveTagList[index].markType = this.form.liveTagList[index].markType +"";
-            this.selectCompanyChange(this.form.liveTagList[index],index); 
-          }           
+            this.selectCompanyChange(this.form.liveTagList[index],index);
+          }
         }
         setTimeout(() => {
           if (this.form.liveDesc == null) {

+ 155 - 68
src/views/live/liveConsole/LivePlayer.vue

@@ -1,9 +1,22 @@
 <template>
   <div class="live-player">
-    <video v-if="videoParam.liveType == 2" ref="videoPlayer" loop autoplay class="player">
-      <source :src="videoParam.videoUrl" type="application/x-mpegURL">
+    <!-- 修改:所有录播和回放都使用同一个video元素,MP4和HLS都支持 -->
+    <video
+      v-if="videoParam.liveType == 2 || videoParam.liveType == 3"
+      ref="videoPlayer"
+      :loop="videoParam.liveType == 2"
+      autoplay
+      class="player"
+    >
+      <!-- 去掉type,让浏览器自动检测 -->
     </video>
-    <video v-if="videoParam.liveType == 1" ref="livePlayer" loop autoplay class="player">
+
+    <video
+      v-if="videoParam.liveType == 1"
+      ref="livePlayer"
+      autoplay
+      class="player"
+    >
     </video>
   </div>
 </template>
@@ -27,23 +40,33 @@ export default {
   },
   data() {
     return {
-      videoDuration: 0, // 视频总时长(秒)
-      startTime: 0, // 开播时间戳(毫秒)
-      hls: null, // HLS 实例
+      videoDuration: 0,
+      startTime: 0,
+      hls: null,
+      liveHls: null // 分开管理直播和录播的HLS实例
     };
   },
   mounted() {
-
-    // 这里可以添加播放器初始化逻辑
+    this.initPlayer();
   },
   methods: {
     videoPlay(url) {
-      if (Hls.isSupported()) {
-        const videoElement = this.$refs.videoPlayer
-        if (!videoElement) {
-          console.error('找不到 video 元素')
-          return
-        }
+      const videoElement = this.$refs.videoPlayer;
+      if (!videoElement) {
+        console.error('找不到 video 元素');
+        return;
+      }
+
+      // 判断是否是MP4格式
+      const isMp4 = url.toLowerCase().endsWith('.mp4') ||
+        url.toLowerCase().includes('.mp4?');
+
+      // 判断是否是HLS格式(m3u8)
+      const isHls = url.toLowerCase().endsWith('.m3u8') ||
+        url.toLowerCase().includes('.m3u8?');
+
+      if (isHls && Hls.isSupported()) {
+        // HLS格式使用hls.js播放
         this.hls = new Hls();
         this.hls.attachMedia(videoElement);
         this.hls.on(Hls.Events.MEDIA_ATTACHED, () => {
@@ -55,104 +78,165 @@ export default {
         this.hls.on(Hls.Events.ERROR, (event, data) => {
           console.error('HLS 错误:', data);
         });
-        // 1. 初始化开播时间
-        this.startTime = new Date(this.videoParam.startTime).getTime();
+
+        // 录播的时间位置计算
         if (this.videoParam.liveType === 2) {
-          // 2. 监听视频元数据加载完成(获取视频时长)
           videoElement.addEventListener('loadedmetadata', () => {
-            this.videoDuration = videoElement.duration; // 获取视频时长(秒)
-
-            // 初始化视频播放位置
+            this.videoDuration = videoElement.duration;
             this.updateVideoPosition(videoElement);
+          });
+        }
 
+      } else if (isMp4 || !isHls) {
+        // MP4格式或非HLS格式直接使用video元素播放
+        videoElement.src = url;
+
+        // 录播的时间位置计算
+        if (this.videoParam.liveType === 2) {
+          videoElement.addEventListener('loadedmetadata', () => {
+            this.videoDuration = videoElement.duration;
+            this.updateVideoPosition(videoElement);
           });
         }
+
+        // 触发播放
+        videoElement.load();
+        videoElement.play().catch(e => {
+          console.warn('自动播放失败:', e);
+        });
+
       } else {
-        console.error('浏览器不支持 HLS')
+        // 不支持HLS的浏览器,尝试直接播放
+        console.warn('浏览器不支持HLS,尝试直接播放');
+        videoElement.src = url;
+        videoElement.load();
+        videoElement.play().catch(e => {
+          console.warn('播放失败:', e);
+        });
       }
     },
-    updateVideoPosition(video){
-      const currentTime = new Date().getTime(); // 当前时间戳(毫秒)
-      const elapsedTime = currentTime - this.startTime; // 已流逝时间(毫秒)
+
+    updateVideoPosition(video) {
+      const currentTime = new Date().getTime();
+      this.startTime = new Date(this.videoParam.startTime).getTime();
+      const elapsedTime = currentTime - this.startTime;
+
       if (elapsedTime < 0) {
-        // 未开播:视频停在初始位置
         video.currentTime = 0;
         return;
       }
 
-      // 已开播:计算视频循环后的位置(流逝时间 % 视频时长)
-      const elapsedSeconds = elapsedTime / 1000; // 转换为秒
-      // 视频内的播放位置(秒)
-      // 设置视频播放位置
-      video.currentTime = elapsedSeconds % this.videoDuration;
+      const elapsedSeconds = elapsedTime / 1000;
+      if (this.videoDuration > 0) {
+        video.currentTime = elapsedSeconds % this.videoDuration;
+      }
     },
+
     livePlay(url) {
       if (Hls.isSupported()) {
-        const videoElement = this.$refs.livePlayer
+        const videoElement = this.$refs.livePlayer;
         if (!videoElement) {
-          console.error('找不到 video 元素')
-          return
+          console.error('找不到 video 元素');
+          return;
         }
-        this.hls = new Hls();
-        this.hls.attachMedia(videoElement);
-        this.hls.on(Hls.Events.MEDIA_ATTACHED, () => {
-          this.hls.loadSource(url);
-          this.hls.on(Hls.Events.STREAM_LOADED, (event, data) => {
+
+        this.liveHls = new Hls();
+        this.liveHls.attachMedia(videoElement);
+        this.liveHls.on(Hls.Events.MEDIA_ATTACHED, () => {
+          this.liveHls.loadSource(url);
+          this.liveHls.on(Hls.Events.STREAM_LOADED, (event, data) => {
             videoElement.play();
           });
         });
-        this.hls.on(Hls.Events.ERROR, (event, data) => {
+        this.liveHls.on(Hls.Events.ERROR, (event, data) => {
           console.error('HLS 错误:', data);
         });
+
       } else {
-        console.error('浏览器不支持 HLS')
+        // 浏览器原生支持HLS(如Safari)
+        const videoElement = this.$refs.livePlayer;
+        if (videoElement.canPlayType('application/vnd.apple.mpegurl')) {
+          videoElement.src = url;
+          videoElement.play().catch(e => {
+            console.warn('自动播放失败:', e);
+          });
+        } else {
+          console.error('浏览器不支持 HLS');
+        }
       }
     },
+
     initPlayer() {
+      // 清理之前的实例
+      if (this.hls) {
+        this.hls.destroy();
+        this.hls = null;
+      }
+      if (this.liveHls) {
+        this.liveHls.destroy();
+        this.liveHls = null;
+      }
 
       if (this.videoParam.liveType === 1) {
         // 直播
         const isUrl = this.videoParam.livingUrl === null || this.videoParam.livingUrl.trim() === '';
         if (isUrl) {
-          console.error('直播地址为空,无法初始化播放器')
-          return
+          console.error('直播地址为空,无法初始化播放器');
+          return;
         }
         this.$nextTick(() => {
           this.livePlay(this.videoParam.livingUrl);
-        })
+        });
         return;
       }
-      const viUrl = this.videoParam.videoUrl === null || this.videoParam.videoUrl.trim() === ''
+
+      const viUrl = this.videoParam.videoUrl === null || this.videoParam.videoUrl.trim() === '';
       if (viUrl) {
-        console.error('播放地址为空,无法初始化播放器')
-        return
+        console.error('播放地址为空,无法初始化播放器');
+        return;
       }
-      if(this.videoParam.liveType === 2){
-        // 录播
-        this.videoPlay(this.videoParam.videoUrl);
-      } else if(this.videoParam.liveType === 3){
-        // 直播回放
-        this.videoPlay(this.videoParam.videoUrl);
-      }else {
-        console.error('直播类型错误,无法初始化播放器')
+
+      if (this.videoParam.liveType === 2 || this.videoParam.liveType === 3) {
+        // 录播或直播回放
+        this.$nextTick(() => {
+          this.videoPlay(this.videoParam.videoUrl);
+        });
+      } else {
+        console.error('直播类型错误,无法初始化播放器');
       }
-      // 创建播放器实例
-      const videoPlayer = this.$refs.videoPlayer;
-      // 添加播放器事件监听器
-      videoPlayer.addEventListener('play', () => {
-        console.log('播放器已开始播放');
-      });
-      videoPlayer.addEventListener('pause', () => {
-        console.log('播放器已暂停');
-      });
-      videoPlayer.addEventListener('ended', () => {
-        console.log('播放器已结束');
-      });
     }
   },
+
+  watch: {
+    // 监听videoParam变化,重新初始化播放器
+    videoParam: {
+      handler() {
+        this.$nextTick(() => {
+          this.initPlayer();
+        });
+      },
+      deep: true
+    }
+  },
+
   beforeDestroy() {
-    this.hls?.destroy()
-    // 销毁播放器实例
+    // 销毁HLS实例
+    this.hls?.destroy();
+    this.liveHls?.destroy();
+
+    // 清理video元素
+    const videoElements = [
+      this.$refs.videoPlayer,
+      this.$refs.livePlayer
+    ];
+
+    videoElements.forEach(video => {
+      if (video) {
+        video.pause();
+        video.src = '';
+        video.load();
+      }
+    });
   }
 };
 </script>
@@ -166,5 +250,8 @@ export default {
   width: 100%;
   height: auto;
   border-radius: 8px;
+  max-height: 300px; /* 设置最大高度,避免过大 */
+  object-fit: contain; /* 保持比例,不拉伸 */
+  background-color: #000; /* 黑色背景,避免视频加载时显示白色 */
 }
 </style>