Forráskód Böngészése

直播中控台切换报错解决 直播预告上传视频添加

yuhongqi 9 órája
szülő
commit
3fcf21db0a

+ 8 - 3
src/views/live/liveConfig/goods.vue

@@ -317,8 +317,7 @@ export default {
     };
   },
   watch: {
-    // 监听路由的 query 参数变化
-    '$route.query': {
+     '$route.query': {
       handler(newQuery) {
         if (this.$route.params.liveId) {
           this.liveId = this.$route.params.liveId;
@@ -326,6 +325,9 @@ export default {
           this.liveId = this.$route.query.liveId;
         }
         this.goodsParams.liveId = this.liveId
+        if(this.liveId == null) {
+          return;
+        }
         this.getLiveGoodsList();
         this.socket = this.$store.state.liveWs[this.liveId]
       },
@@ -344,6 +346,10 @@ export default {
     // this.socket = this.$store.state.liveWs[this.liveId]
   },
   methods: {
+    handleRouteChange(to, from) {
+      // 处理路由变化逻辑
+      console.log('路由变化:', from.path, '->', to.path);
+    },
     handleSwitchClick(row) {
       // 1. 获取「即将切换到的目标状态」(当前状态取反)
       const targetStatus = !row.isShow
@@ -354,7 +360,6 @@ export default {
           if (res.msg == "目前仅支持单一物品展示") {
             this.$message.error(res.msg)
           }
-
           if (this.socket == null) {
             this.$message.error("请从直播间开启展示状态!");
           } else {

+ 3 - 0
src/views/live/liveConfig/idCard.vue

@@ -28,6 +28,9 @@ export default {
     '$route.query': {
       handler(newQuery) {
         this.liveId = this.$route.params.liveId
+        if(this.liveId == null) {
+          return;
+        }
         getLive(this.liveId).then(res => {
           this.idCardUrl = res.data.idCardUrl;
         })

+ 5 - 2
src/views/live/liveConfig/index.vue

@@ -107,6 +107,7 @@ import Task from './task.vue';
 import LiveRedConf from './liveRedConf.vue'
 import LiveLotteryConf from './liveLotteryConf.vue'
 import LiveReplay from './liveReplay.vue'
+import Preview from './preview.vue'
 import { listLive, getLive, delLive, addLive, updateLive, exportLive,selectCompanyTalent,handleShelfOrUn,handleDeleteSelected } from "@/api/live/live";
 
 
@@ -120,16 +121,18 @@ export default {
     Answer,
     Goods,
     IdCard,
-    Task
+    Task,
+    Preview
   },
   data() {
     return {
-      activeTab: 'basicInfo',
+      activeTab: 'watchReward',
       liveId: null,
       liveInfo: {},
       currentComponent: WatchReward,
       menuList:[
         { name: '观看奖励', label: '观看奖励', index: 'watchReward'},
+        { name: '直播预告', label: '直播预告', index: 'preview'},
         { name: '红包配置', label: '红包配置', index: 'liveRedConf'},
         { name: '抽奖配置', label: '抽奖配置', index: 'liveLotteryConf'},
         // { name: '答题', label: '答题', index: 'answer'},

+ 3 - 0
src/views/live/liveConfig/liveLotteryConf.vue

@@ -466,6 +466,9 @@ export default {
           //设置查询条件直播间ID不可修改
           this.canLiveId = true;
         }
+        if(this.liveId == null) {
+          return;
+        }
         this.getList();
         this.getProducts();
       },

+ 3 - 0
src/views/live/liveConfig/liveRedConf.vue

@@ -282,6 +282,9 @@ export default {
           //设置查询条件直播间ID不可修改
           this.canLiveId = true;
         }
+        if(this.liveId == null) {
+          return;
+        }
         this.getList();
       },
       // 初始化时立即执行一次

+ 0 - 1
src/views/live/liveConfig/liveReplay.vue

@@ -194,7 +194,6 @@ export default {
           this.liveId = this.$route.query.liveId;
         }
         if(this.liveId == null) {
-          this.$message.error("页面错误,请联系管理员");
           return;
         }
         this.getLive();

+ 439 - 0
src/views/live/liveConfig/preview.vue

@@ -0,0 +1,439 @@
+<template>
+  <div class="app-container" v-loading.fullscreen.lock="loading">
+    <!-- 直播回放开关区域 -->
+
+    <!-- 回放内容区域 -->
+    <div class="playback-content">
+      <div>
+        <span>预告内容:</span>
+        <el-button class="upload-btn" type="normal" @click="handleUploadVideo">上传视频</el-button>
+        <!--        <el-button-->
+        <!--          class="upload-btn"-->
+        <!--          type="text"-->
+        <!--          icon="el-icon-plus"-->
+        <!--          @click="handleUploadVideo"-->
+        <!--        >上传视频</el-button>-->
+        <!--        <span class="upload-tip">上传视频大小不可超过5GB</span>-->
+      </div>
+      <el-dialog title="添加直播预告" :visible.sync="open" width="900px" append-to-body>
+        <el-form ref="form" :model="form"  label-width="80px">
+          <video-upload
+            :type = "1"
+            :isPrivate = "isPrivate"
+            :fileKey.sync = "form.fileKey"
+            :fileSize.sync = "form.fileSize"
+            :videoUrl.sync="videoUrl"
+            :fileName.sync="form.fileName"
+            :line_2.sync="form.lineTwo"
+            :line_1.sync="form.lineOne"
+            :thumbnail.sync="form.thumbnail"
+            :uploadType.sync="form.uploadType"
+            :isTranscode.sync="form.isTranscode"
+            :transcodeFileKey.sync="form.transcodeFileKey"
+            @video-duration="handleVideoDuration"
+            @change="handleVideoChange"
+            ref="videoUpload"
+            append-to-body
+          />
+        </el-form>
+        <div slot="footer" class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="open = false">取 消</el-button>
+        </div>
+      </el-dialog>
+
+      <!-- 视频列表 -->
+      <el-table
+        :data="videoList"
+        border
+        style="width: 100%; margin-top: 10px"
+      >
+        <el-table-column prop="duration" label="时长" />
+        <el-table-column prop="updateTime" label="更新时间" />
+        <el-table-column label="视频地址(可点击查看)" prop="videoUrl" >
+          <template slot-scope="scope">
+            <el-tooltip
+              :content="scope.row.videoUrl"
+              placement="top"
+              effect="dark"
+            >
+              <a
+                :href="scope.row.videoUrl"
+                target="_blank"
+                class="video-url-container"
+                rel="noopener noreferrer"
+              >
+                {{
+                  scope.row.videoUrl.length > 32
+                    ? scope.row.videoUrl.substring(0, 32) + '...'
+                    : scope.row.videoUrl
+                }}
+                <i class="el-icon-external-link video-url-icon"></i>
+              </a>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getLive,} from '@/api/live/live'
+import {getLiveVideoByLiveId,addLiveVideo} from '@/api/live/liveVideo'
+import VideoUpload from "@/components/LiveVideoUpload/index.vue";
+
+export default {
+  name: "Preview",
+  components: {VideoUpload},
+  data() {
+    return {
+      loading: true,
+      videoList: [
+
+      ], // 视频列表数据,实际需从接口获取
+      liveId: null,
+      liveInfo: null,
+      isPrivate:null,
+      // 表单参数
+      form: {
+        uploadType: 1,
+        isTranscode:0,
+        transcodeFileKey:null
+      },
+      videoUrl:"",
+      // 是否显示弹出层
+      open: false,
+
+    };
+  },
+  watch: {
+    // 监听路由的 query 参数变化
+    '$route.query': {
+      handler(newQuery) {
+        if (this.$route.params.liveId) {
+          this.liveId = this.$route.params.liveId;
+        }else {
+          this.liveId = this.$route.query.liveId;
+        }
+        if(this.liveId == null) {
+          return;
+        }
+        this.getLive();
+      },
+      // 初始化时立即执行一次
+      immediate: true
+    }
+  },
+  created() {
+    // if (this.$route.params.liveId) {
+    //   this.liveId = this.$route.params.liveId;
+    // }else {
+    //   this.liveId = this.$route.query.liveId;
+    // }
+    // if(this.liveId == null) {
+    //   this.$message.error("页面错误,请联系管理员");
+    //   return;
+    // }
+    // this.getLive();
+  },
+  methods: {
+    submitForm() {
+      this.open = false;
+      const doParam = {
+        liveId: this.liveId,
+        videoUrl: this.videoUrl,
+        videoType: 1,
+        duration: this.form.duration,
+       }
+      addLiveVideo(doParam).then(response => {
+        if (response.code == 200) {
+          this.$message.success("上传成功");
+          this.videoList = []
+          this.videoList.push(doParam)
+        } else {
+          this.$message.warning(response.msg);
+        }
+        this.$refs.form.resetFields();
+      })
+    },
+    handleVideoDuration(duration) {
+      this.form.duration = duration;
+    },
+    handleVideoChange(videoUrl,lineOne){
+      this.videoUrl = videoUrl;
+      this.form.videoUrl = videoUrl;
+      console.log(this.videoUrl)
+    },
+    getLiveVideo() {
+      getLiveVideoByLiveId(this.liveId).then(res => {
+        let dataEntity =
+          {
+            duration: "00:00",
+            status: "回放中",
+            updateTime: "2025-09-08 14:28:24",
+          };
+
+        //将秒数转为时分秒
+        dataEntity.duration = this.convertSeconds(res.data.duration);
+        dataEntity.updateTime = res.data.updateTime;
+        dataEntity.videoUrl = res.data.videoUrl;
+        dataEntity.videoName = this.extractFileName(dataEntity.videoUrl)
+
+        this.videoList.push(dataEntity);
+      });
+    },
+    /**
+     * 提取文件名称核心方法
+     * 逻辑:通过split('/')分割路径,取最后一个非空元素作为文件名称
+     */
+    extractFileName(data) {
+      try {
+        this.errorMsg = '';
+        const trimmedUrl = data.trim();
+        // 用'/'分割路径,过滤空字符串(避免路径末尾有'/'导致的空元素)
+        const pathSegments = trimmedUrl.split('/').filter(segment => segment);
+        if (pathSegments.length === 0) {
+          throw new Error('输入的路径格式无效,请检查后重新输入');
+        }
+        // 最后一个分段即为文件名称
+        const fileName = pathSegments[pathSegments.length - 1];
+        // 简单校验是否为常见视频文件格式(可选,根据需求调整)
+        const videoExtensions = ['mp4', 'mov', 'avi', 'flv', 'mkv'];
+        const fileExtension = fileName.split('.').pop()?.toLowerCase();
+        if (!fileExtension || !videoExtensions.includes(fileExtension)) {
+          this.errorMsg = '提示:提取到的文件可能不是常见视频格式,请注意校验';
+        }
+        return fileName;
+      } catch (err) {
+        this.errorMsg = err.message;
+        return '';
+      }
+    },
+    convertSeconds(data) {
+      // 确保输入是有效的数字
+      const totalSeconds = Math.max(0, parseInt(data) || 0);
+
+      // 计算时、分、秒
+      const hours = Math.floor(totalSeconds / 3600);
+      const minutes = Math.floor((totalSeconds % 3600) / 60);
+      const seconds = totalSeconds % 60;
+
+      // 格式化每个部分为两位数
+      return `${this.padWithZero(hours)}:${this.padWithZero(minutes)}:${this.padWithZero(seconds)}`;
+    },
+    padWithZero(num) {
+      // 将数字转换为两位数格式
+      return num.toString().padStart(2, '0');
+    },
+    getLive() {
+      getLive(this.liveId).then(res => {
+        this.liveInfo = res.data;
+        if (res.data.liveType == 1) {
+          this.getLiveVideo();
+        }
+        this.loading = false;
+      });
+    },
+    resetForm() {
+      this.replayForm={
+        isPlaybackOpen: false, // 直播回放开关状态
+        playbackMode: "1", // 回放模式,默认模式一
+        validityType: "days", // 回放有效期类型,默认天数
+        validDays: 7, // 有效天数
+        isSpeedAllowed: "1", // 是否允许倍速播放,默认允许
+      }
+    },
+    // 上传视频处理
+    handleUploadVideo() {
+      // 模拟上传视频逻辑,实际需调用上传组件或接口
+      if (this.liveInfo.liveType == 1) {
+        this.open = true;
+      }else{
+        this.$message.error("仅直播可上传预告片段");
+      }
+    },
+  },
+};
+</script>
+
+<style scoped>
+.live-playback-setting {
+  font-family: "Microsoft Yahei", sans-serif;
+  color: #333;
+  background-color: #fff;
+  padding: 20px;
+  border-radius: 4px;
+  box-shadow: 0 0 8px rgba(0, 0, 0, 0.1);
+}
+
+.switch-area {
+  display: flex;
+  align-items: center;
+  margin-bottom: 20px;
+}
+.switch-area .switch-label {
+  margin-right: 10px;
+  font-size: 14px;
+}
+.switch-area .switch-desc {
+  color: #999;
+  font-size: 12px;
+}
+
+.playback-mode {
+  background-color: #f9fafc;
+  padding: 15px;
+  border-radius: 4px;
+  margin-bottom: 20px;
+}
+.playback-mode .mode-title {
+  font-size: 14px;
+  margin-bottom: 10px;
+}
+.playback-mode .mode-option {
+  display: flex;
+  align-items: center;
+  margin-bottom: 8px;
+}
+.playback-mode .mode-option .el-radio {
+  margin-left: 2%;
+}
+.playback-mode .mode-option label {
+  font-size: 13px;
+}
+
+.validity-period {
+  background-color: #f9fafc;
+  padding: 15px;
+  border-radius: 4px;
+  margin-bottom: 20px;
+}
+.validity-period .period-title {
+  font-size: 14px;
+  margin-bottom: 10px;
+}
+.validity-period .period-option {
+  display: flex;
+  align-items: center;
+  margin-bottom: 8px;
+}
+.validity-period .period-option .el-radio {
+  margin-left: 2%;
+}
+.validity-period .period-option label {
+  font-size: 13px;
+}
+.validity-period .period-desc {
+  color: #999;
+  font-size: 12px;
+  margin-top: 5px;
+  margin-left: 2%;
+}
+.validity-period .day-input {
+  width: 60px;
+  height: 28px;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  padding: 0 8px;
+  margin: 0 5px;
+}
+
+.speed-play {
+  display: flex;
+  align-items: center;
+  margin-top: 15px;
+}
+.speed-play .speed-label {
+  font-size: 13px;
+  margin-right: 10px;
+}
+.speed-play .el-radio {
+  margin-right: 5px;
+}
+.speed-play .speed-desc {
+  color: #999;
+  font-size: 12px;
+  margin-left: 10px;
+}
+
+.pro-tag {
+  display: inline-block;
+  background-color: #007bff;
+  color: #fff;
+  font-size: 10px;
+  padding: 2px 5px;
+  border-radius: 3px;
+  margin-left: 5px;
+  vertical-align: middle;
+}
+
+.playback-content {
+  margin-top: 20px;
+}
+.playback-content .upload-btn {
+  display: inline-block;
+  background-color: #fff;
+  border: 1px dashed #ddd;
+  color: #007bff;
+  padding: 8px 15px;
+  border-radius: 4px;
+  cursor: pointer;
+  font-size: 13px;
+  margin-bottom: 15px;
+}
+.playback-content .upload-btn:hover {
+  border-color: #007bff;
+}
+.playback-content .upload-tip {
+  font-size: 12px;
+  color: #999;
+  margin-left: 10px;
+}
+
+.video-item {
+  display: flex;
+  align-items: center;
+}
+.video-cover {
+  width: 80px;
+  height: 45px;
+  border-radius: 4px;
+  margin-right: 10px;
+}
+.video-info .video-name {
+  font-size: 13px;
+  margin-bottom: 3px;
+}
+.video-info .video-desc {
+  font-size: 12px;
+  color: #999;
+}
+.video-duration,
+.video-source,
+.video-status,
+.video-update-time {
+  color: #666;
+}
+.video-status .status-dot {
+  display: inline-block;
+  width: 8px;
+  height: 8px;
+  background-color: #007bff;
+  border-radius: 50%;
+  margin-right: 5px;
+  vertical-align: middle;
+}
+.video-operation .el-button {
+  color: #007bff;
+  font-size: 12px;
+  margin-right: 10px;
+}
+.video-url-container {
+  cursor: pointer;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  max-width: 100%;
+}
+</style>

+ 4 - 0
src/views/live/liveConfig/watchReward.vue

@@ -256,7 +256,11 @@ export default {
       handler(newQuery) {
         this.liveId = this.$route.params.liveId
         this.watchRewardForm.liveId = this.liveId
+        if(this.liveId == null) {
+          return;
+        }
         this.getLiveConfig();
+
       },
       // 初始化时立即执行一次
       immediate: true