ソースを参照

直播company 代码提交

yuhongqi 2 日 前
コミット
5a10f25fdf

+ 1 - 1
.env.production

@@ -36,4 +36,4 @@ VUE_APP_BASE_API = '/prod-api'
 VUE_CLI_BABEL_TRANSPILE_MODULES = true
 
 # 直播webSocket地址
-VUE_APP_LIVE_WS_URL = wss://live.test.ylrztop.com/ws/live-api
+VUE_APP_LIVE_WS_URL = ws://127.0.0.1:7014/ws/

+ 0 - 4
src/components/LiveVideoUpload/single.vue

@@ -230,10 +230,6 @@ export default {
     this.reset();
   },
   watch: {
-    localUploadType(newType) {
-      this.$emit("update:uploadType", newType);
-      this.$emit("change");
-    },
     uploadType(newType) {
       this.localUploadType = newType;
     },

+ 40 - 1
src/store/index.js

@@ -6,6 +6,7 @@ import tagsView from './modules/tagsView'
 import permission from './modules/permission'
 import settings from './modules/settings'
 import getters from './getters'
+import {LiveWS} from "@/utils/liveWS";
 
 Vue.use(Vuex)
 
@@ -17,7 +18,45 @@ const store = new Vuex.Store({
     permission,
     settings
   },
-  getters
+  getters,
+  state: {
+    liveWs: {}
+  },
+  mutations: {
+    // 更新为支持多个 WebSocket 连接
+    setLiveWs(state, { ws, liveId }) {
+      // 使用 liveId 作为键来存储不同的 WebSocket 连接
+      Vue.set(state.liveWs, liveId, ws);
+    },
+    // 添加移除 WebSocket 连接的 mutation
+    removeLiveWs(state, liveId) {
+      Vue.delete(state.liveWs, liveId);
+    }
+  },
+  actions: {
+    // 修改 action 以正确传递参数
+    initLiveWs({ commit, state }, { liveWsUrl, liveId, userId }) {
+      // 如果已经存在对应 liveId 的连接,先关闭它
+      if (state.liveWs[liveId]) {
+        state.liveWs[liveId].close();
+      }
+
+      // 创建新的 WebSocket 连接
+      const ws = new LiveWS(liveWsUrl, liveId, userId);
+
+      // 提交到 mutation
+      commit('setLiveWs', { ws, liveId });
+
+      return ws;
+    },
+    // 添加关闭特定 WebSocket 连接的 action
+    closeLiveWs({ commit, state }, liveId) {
+      if (state.liveWs[liveId]) {
+        state.liveWs[liveId].close();
+        commit('removeLiveWs', liveId);
+      }
+    }
+  }
 })
 
 export default store

+ 112 - 0
src/utils/liveWS.js

@@ -0,0 +1,112 @@
+import CryptoJS from 'crypto-js'
+
+export class LiveWS {
+  /**
+   * @param {string} url - WebSocket 服务器地址
+   * @param {number} liveId - 直播间ID
+   * @param {number} userId - 用户ID
+   * @param {number} checkInterval - 检查连接状态的时间间隔,单位毫秒
+   * @param {number} reconnectDelay - 连接断开后重连的延迟,单位毫秒
+   */
+  constructor(url, liveId, userId, checkInterval = 5000, reconnectDelay = 3000) {
+    let timestamp = new Date().getTime()
+    let userType = 1
+    let signature = CryptoJS.HmacSHA256(
+      CryptoJS.enc.Utf8.parse('' + liveId + userId + userType + timestamp),
+      CryptoJS.enc.Utf8.parse(timestamp)).toString(CryptoJS.enc.Hex)
+    this.url = url + `?liveId=${liveId}&userId=${userId}&userType=${userType}&timestamp=${timestamp}&signature=${signature}`;
+    console.log(this.url)
+    this.liveId = liveId;
+    this.userId = userId;
+    this.checkInterval = checkInterval;
+    this.reconnectDelay = reconnectDelay;
+    this.ws = null;
+    this.reconnectTimer = null;
+    this.heartbeatTimer = null;
+    this.isManualClose = false;
+    this.connect();
+    this.startHeartbeat();
+  }
+
+  connect() {
+    // 如果已经有一个连接处于 OPEN 或 CONNECTING 状态,则不再创建新连接
+    if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {
+      return;
+    }
+
+    this.ws = new WebSocket(this.url);
+
+    // 绑定事件
+    this.ws.onopen = (event) => {
+      // 连接成功后,清除重连计时器
+      if (this.reconnectTimer) {
+        clearTimeout(this.reconnectTimer);
+        this.reconnectTimer = null;
+      }
+    };
+
+    this.ws.onmessage = (event) => {
+      this.onmessage(event);
+    };
+
+    this.ws.onerror = (error) => {
+    };
+
+    this.ws.onclose = (event) => {
+      // 如果不是主动关闭,则重连
+      if (!this.isManualClose) {
+        setTimeout(() => this.reconnect(), this.reconnectDelay);
+      }
+    };
+  }
+
+  onmessage(event) {}
+
+  reconnect() {
+    this.connect();
+  }
+
+  // 调度重连
+  scheduleReconnect() {
+    // 避免多次重连定时器同时存在
+    if (this.reconnectTimer) return;
+    this.reconnectTimer = setTimeout(() => {
+      this.connect();
+    }, this.reconnectDelay);
+  }
+
+  // 定时检查连接状态
+  startHeartbeat() {
+    this.heartbeatTimer = setInterval(() => {
+      if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
+        this.scheduleReconnect();
+      } else {
+        // 发送信息
+        this.ws.send(JSON.stringify({'cmd':'heartbeat','msg':'ping', 'liveId': this.liveId, 'userId': this.userId}));
+      }
+    }, this.checkInterval);
+  }
+
+  // 主动关闭 WebSocket 连接,并清除定时任务
+  close() {
+    this.isManualClose = true;
+    if (this.heartbeatTimer) {
+      clearInterval(this.heartbeatTimer);
+    }
+    if (this.reconnectTimer) {
+      clearTimeout(this.reconnectTimer);
+    }
+    if (this.ws) {
+      this.ws.close();
+    }
+  }
+
+  // 发送消息方法
+  send(message) {
+    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
+      this.ws.send(message);
+    } else {
+      console.error("WebSocket is not open. Message not sent.");
+    }
+  }
+}

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

@@ -355,22 +355,26 @@ export default {
     handleSwitchClick(row) {
       // 1. 获取「即将切换到的目标状态」(当前状态取反)
       const targetStatus = !row.isShow
+      if (this.socket == null) {
+        row.isShow = targetStatus
+        this.$message.error("请从直播间开启展示状态!");
+        return;
+      }
       const goodsList = [row.goodsId];
       handleIsShowChange({"goodsIds":goodsList,"isShow":targetStatus,"liveId":this.liveId}).then(res=>{
         if(res.code == 200){
           row.isShow = res.isShow
           if (res.msg == "目前仅支持单一物品展示") {
             this.$message.error(res.msg)
+            return;
           }
-          if (this.socket == null) {
-            this.$message.error("请从直播间开启展示状态!");
-          } else {
-            const msg = {
-              cmd: 'goods',
-              data: {"liveId":this.liveId,"goodsId":goodsList[0],"status":targetStatus ? 1 : 0}
-            }
-            this.socket.send(JSON.stringify(msg));
+
+          const msg = {
+            cmd: 'goods',
+            data: {"liveId":this.liveId,"goodsId":goodsList[0],"status":targetStatus ? 1 : 0}
           }
+          this.socket.send(JSON.stringify(msg));
+
         }
       })
     },

+ 16 - 13
src/views/live/liveRewardRecord/index.vue

@@ -2,12 +2,14 @@
   <div class="app-container">
     <div class="reward-container">
       <!-- 时间步长选择 -->
-      <span class="demonstration">月份选择(可多选)</span>
+      <span class="demonstration">月份选择</span>
       <el-date-picker
-        type="months"
+        type="month"
+        clearable
+
         v-model="selectedTimeStep"
         @change="handleTimeStepChange"
-        placeholder="选择一个或多个日期">
+        placeholder="选择一个日期">
       </el-date-picker>
 
       <el-button
@@ -73,7 +75,6 @@ export default {
   computed: {
   },
   mounted() {
-    this.selectedTimeStep.push(new Date())
     this.initData()
   },
   methods: {
@@ -82,12 +83,8 @@ export default {
         this.$message.error('请选择导出月份')
         return
       }
-      var date = []
-      if (this.selectedTimeStep == null || this.selectedTimeStep.length === 0) {
-        date.push(new Date());
-      } else {
-        date = this.selectedTimeStep
-      }
+      var date = this.checkDate();
+
       this.$confirm('是否确认导出所有直播积分记录?', "警告", {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
@@ -100,13 +97,20 @@ export default {
         this.exportLoading = false;
       }).catch(() => {});
     },
-    initData() {
+    checkDate(){
       var date = []
+
       if (this.selectedTimeStep == null || this.selectedTimeStep.length === 0) {
         date.push(new Date());
       } else {
-        date = this.selectedTimeStep
+        date.push(this.selectedTimeStep);
       }
+      return date
+    },
+    initData() {
+
+      var date = this.checkDate();
+
       statistics({ 'step': date, companyId:0}).then(res => {
         this.timeSeries = res.timeSeries || []
         this.tableData = res.data || []
@@ -127,7 +131,6 @@ export default {
       })
     },
     handleTimeStepChange() {
-      console.log(this.selectedTimeStep)
       this.initData()
     },
   }