ソースを参照

更新直播页面

dusenyao 4 年 前
コミット
c06899d453
2 ファイル変更257 行追加58 行削除
  1. 133 24
      src/views/live/index.vue
  2. 124 34
      src/views/live/live.js

+ 133 - 24
src/views/live/index.vue

@@ -2,17 +2,43 @@
   <div class="live">
     <div>
       <div class="live-page-title">直播间</div>
-      <div class="live-desc">{{ roomData.desc }}{{ roomData.name }}</div>
+      <div class="live-desc">{{ roomData.desc }}</div>
+      <div class="live-info">
+        <span class="live-name">{{ roomData.name }}</span>
+        <el-button @click="stopLive">下课</el-button>
+      </div>
     </div>
-    <div>
-      <div class="live-left-container">
-        <div id="live"></div>
+    <div class="live-container">
+      <div class="live-container-left">
+        <div id="draw-parent"></div>
         <div class="button-group">
-          <el-button @click="stopLive">结束直播</el-button>
+          <div>
+            <el-dropdown placement="top" @command="invite">
+              <el-button>语音连麦</el-button>
+              <el-dropdown-menu slot="dropdown">
+                <el-dropdown-item
+                  v-for="item in speakData.onlineUsers"
+                  :key="item.id"
+                  :command="item.uid"
+                >
+                  {{ item.name }}
+                </el-dropdown-item>
+              </el-dropdown-menu>
+            </el-dropdown>
+            <el-button>视频连麦</el-button>
+            <!-- <el-button>群组讨论</el-button>
+            <el-button>推送课件</el-button> -->
+            <el-button>屏幕画笔</el-button>
+          </div>
+          <div>
+            <el-button @click="publishShareStream">共享屏幕</el-button>
+          </div>
         </div>
       </div>
-      <div class="live-right-container">
-        <div class="live-teacher-lens"></div>
+      <div class="live-container-right">
+        <div class="live-teacher-lens">
+          <div id="live"></div>
+        </div>
       </div>
     </div>
   </div>
@@ -27,18 +53,32 @@ export default {
     return {
       userid: '53A22FC29AD2216D',
       roomid: 'DCDD385394BFEDEB9C33DC5901307461',
-      sessionid: 'E8AD39C4C49765A5E118B74B638E57EF8F94A71FB34D5E8F56ADEF86B20D826E',
+      sessionid: 'CF58A9D16DA6EE252C274DD0F18E7307C048EE85FE61DFFC251D7324CD2B85D0',
       rtc: null,
       roomData: {
-        desc: ''
+        desc: '直播间标题',
+        name: '教师姓名',
+        user: {
+          id: '',
+          name: '',
+          role: 'talker',
+          rommid: ''
+        },
+        max_users: 1,
+        allow_chat: true,
+        allow_audio: true,
+        allow_speak: true
       },
-      loadedNumber: 0
+      loadedNumber: 0,
+      speakData: {},
+      roomContext: {}
     };
   },
   watch: {
     loadedNumber(newValue) {
-      if (newValue === 3) {
+      if (newValue === 5) {
         this.initSDK();
+        this.$loading().close();
       }
     }
   },
@@ -48,22 +88,42 @@ export default {
   methods: {
     // 加载直播所需 SDK,加载完成后才能初始化
     downloadWebSDK() {
+      this.$loading({
+        text: '加载直播所需SDK中...',
+        background: '#fff'
+      });
       let script = this.createScript('https://class.csslcloud.net/static/dist/js/websdk_4.0.js');
+      let link = this.createLink('https://class.csslcloud.net/static/SDK/docSDK/draw.css');
+
+      link.onload = () => {
+        this.loadedNumber += 1;
+      };
 
       script.onload = () => {
-        this.loadedNumber = this.loadedNumber + 1;
         let scriptArray = [
           'https://class.csslcloud.net/static/dist/js/classMode.js',
-          'https://class.csslcloud.net/static/dist/js/classUpdateChat.js'
+          'https://class.csslcloud.net/static/dist/js/classUpdateChat.js',
+          'https://image.csslcloud.net/js/dpc.js'
         ];
         for (let i = 0; i < scriptArray.length; i++) {
           let classMode = this.createScript(scriptArray[i]);
           classMode.onload = () => {
-            this.loadedNumber = this.loadedNumber + 1;
+            this.loadedNumber += 1;
           };
         }
       };
+
+      let jq = this.createScript('https://class.csslcloud.net/static/js/jquery/jquery.min.js');
+      jq.onload = () => {
+        let classMode = this.createScript(
+          'https://class.csslcloud.net/static/SDK/docSDK/drawSdk_3.0.js'
+        );
+        classMode.onload = () => {
+          this.loadedNumber += 1;
+        };
+      };
     },
+
     createScript(url) {
       let script = document.createElement('script');
       script.type = 'text/javascript';
@@ -71,6 +131,15 @@ export default {
       document.getElementsByTagName('body')[0].appendChild(script);
       return script;
     },
+
+    createLink(url) {
+      let link = document.createElement('link');
+      link.rel = 'stylesheet';
+      link.href = url;
+      document.getElementsByTagName('body')[0].appendChild(link);
+      return link;
+    },
+
     initSDK() {
       this.rtc = common.initSDK({
         userid: this.userid,
@@ -81,9 +150,22 @@ export default {
       common.initListener(that); // 注册监听事件
     },
 
-    // 结束直播
     stopLive() {
       common.stopLive();
+    },
+
+    // 推送桌面共享
+    publishShareStream() {
+      common.publishShareStream();
+    },
+
+    // 关闭桌面共享
+    unPubShareStream() {
+      this.rtc.unPubShareStream();
+    },
+
+    invite(uid) {
+      common.invite(uid);
     }
   }
 };
@@ -101,22 +183,49 @@ export default {
   &-desc {
     margin: 17px 0 8px;
   }
+  &-info {
+    display: flex;
+    justify-content: space-between;
+  }
+  &-name {
+    opacity: 0.4;
+    line-height: 30px;
+  }
 
-  &-left-container {
-    width: 661px;
+  // 主要容器
+  &-container {
+    display: flex;
+    justify-content: left;
     margin-top: 17px;
 
-    #live {
-      width: 100%;
-      height: 331px;
-      margin-bottom: 14px;
+    &-left {
+      width: 661px;
+      margin-right: 18px;
+
+      #draw-parent {
+        width: 100%;
+        height: 331px;
+        margin-bottom: 14px;
+        border: 1px solid #ccc;
+      }
+      .button-group {
+        display: flex;
+        justify-content: space-between;
+      }
     }
 
-    .button-group {
-      button {
-        margin-right: 20px;
+    &-right {
+      #live {
+        width: 321px;
+        height: 91px;
       }
     }
   }
+
+  .el-button {
+    background-color: #ececec;
+    border-radius: 8px;
+    padding: 7px 12px;
+  }
 }
 </style>

+ 124 - 34
src/views/live/live.js

@@ -1,3 +1,5 @@
+import { Message } from 'element-ui';
+
 /**
  * @description WebSDK 实例化对象
  */
@@ -15,22 +17,6 @@ export function initSDK(data) {
 }
 
 /**
- * @method startLive
- * @description 开启直播
- */
-export function startLive() {
-  rtc.startLive({
-    success(data) {
-      console.log(data);
-      alert('开启直播成功');
-    },
-    fail(data) {
-      alert(`开启直播失败:${data}`);
-    }
-  });
-}
-
-/**
  * @method publishStream
  * @description 推送本地流
  */
@@ -39,17 +25,17 @@ export function publishStream() {
     streamName: 'main',
     // 推流成功,更新上麦结果
     success: function (stream) {
-      console.log(stream);
-      // rtc.updateMcResult({
-      //   pid: 1,
-      //   stid: stream.id(),
-      //   success: function (data) {
-      //     alert('更新上麦结果请求成功,此处可处理应用层逻辑' + JSON.stringify(data));
-      //   },
-      //   fail: function (data) {
-      //     alert('更新上麦结果请求失败,此处可处理应用层逻辑' + JSON.stringify(data));
-      //   }
-      // });
+      console.log('推流成功', stream);
+      rtc.updateMcResult({
+        pid: 1,
+        stid: stream.id(),
+        success: function (data) {
+          console.log('更新上麦结果请求成功,此处可处理应用层逻辑', data);
+        },
+        fail: function (data) {
+          alert('更新上麦结果请求失败:' + JSON.stringify(data));
+        }
+      });
     },
     fail: function (str) {
       // 推流失败,更新上麦结果
@@ -59,6 +45,29 @@ export function publishStream() {
 }
 
 /**
+ * @method startLive
+ * @description 开启直播
+ */
+export function startLive() {
+  rtc.startLive({
+    success(data) {
+      console.log(data);
+      publishStream(); // 如果需要立即推流,执行 publish 方法
+      Message({
+        message: '开启直播成功',
+        type: 'success'
+      });
+    },
+    fail(data) {
+      Message({
+        message: `开启直播失败:${data}`,
+        type: 'warning'
+      });
+    }
+  });
+}
+
+/**
  * @method createLocalStram
  * @description 创建本地流
  */
@@ -75,7 +84,6 @@ export function createLocalStream() {
       // 创建本地流成功,将流展示到id为 live 的dom元素盒子中
       stream.show('live');
       startLive();
-      publishStream(stream); // 如果需要立即推流,执行 publish 方法
     },
     fail: function (data) {
       // 创建本地流失败,应用层处理
@@ -92,12 +100,30 @@ export function createLocalStream() {
 export function initListener(vue) {
   rtc.on('login_success', data => {
     console.log('登录成功', data);
+    Message({
+      message: '登录成功',
+      type: 'success'
+    });
     vue.roomData = data;
+    let canvasInitData = {
+      allowDraw: true, // 是否具有书写画笔权限(讲师权限) true / false
+      id: 'draw-parent',
+      pptDisplay: 0 // 文档展示方式。默认0,按窗口  1, 按宽度
+    };
+    // 如果直播已经开始,需将直播id传入sdk中,
+    if (data.live.status === 1) {
+      canvasInitData.liveId = data.live.id;
+    }
+    // 初始化画板
+    rtc.canvasInit(canvasInitData);
   });
 
   rtc.on('login_failed', data => {
     console.log('登录失败', data);
-    alert('登录失败:' + JSON.stringify(data));
+    Message({
+      message: '登录失败:' + JSON.stringify(data),
+      type: 'warning'
+    });
   });
 
   // 必须在加入房间成功的“conference_join”事件回调里创建本地流
@@ -113,15 +139,24 @@ export function initListener(vue) {
 
   // 房间全量信息事件
   rtc.on('room_context', roomData => {
-    console.log(JSON.parse(roomData));
+    vue.roomContext = JSON.parse(roomData);
+    console.log('房间全量信息事件', JSON.parse(roomData));
   });
 
   rtc.on('publish_stream', str => {
     console.log('直播已开启', str);
+    Message({
+      message: '直播已开启',
+      type: 'success'
+    });
   });
 
   rtc.on('end_stream', str => {
     console.log('直播已关闭', str);
+    Message({
+      message: '直播已关闭',
+      type: 'success'
+    });
   });
 
   rtc.on('switch_user_settings', settingData => {
@@ -129,8 +164,9 @@ export function initListener(vue) {
     console.log(settingData);
   });
 
+  // 人员列表事件(人员麦序变化时广播)
   rtc.on('speak_context', speakData => {
-    console.log(speakData); // 人员列表事件(人员麦序变化时广播)
+    vue.speakData = JSON.parse(speakData);
   });
 
   rtc.on('switch_settings', data => {
@@ -138,7 +174,7 @@ export function initListener(vue) {
   });
 
   rtc.on('allow_sub', stream => {
-    alert('监听到有流');
+    console.log('监听到有流');
     rtc.trySubscribeStream({
       tryStream: stream,
       success: function success(stream) {
@@ -289,6 +325,20 @@ export function getLiveStat() {
 }
 
 /**
+ * @description 推送桌面共享
+ */
+export function publishShareStream() {
+  rtc.publishShareStream({
+    success: function (stream) {
+      console.log('推送桌面共享成功', stream);
+    },
+    fail: function (str) {
+      console.log(str);
+    }
+  });
+}
+
+/**
  * @description 开启、结束、暂停、恢复录制
  * @param { String } status: 'start' 开启, 'end' 结束, 'pause' 暂停, 'resume' 恢复
  */
@@ -304,6 +354,42 @@ export function liveRecord(status) {
   });
 }
 
+// 排麦
+
+/**
+ * @description 老师端发起邀请,邀请学生上麦。(举手模式)
+ * @param {String} uid 被邀请用户id
+ */
+export function invite(uid) {
+  rtc.invite({
+    uid: uid,
+    success: function (str) {
+      console.log('邀请上麦成功', str);
+    },
+    fail: function (data) {
+      console.log(data);
+      Message({
+        type: 'error',
+        message: `邀请上麦失败:${data.errorMsg}`
+      });
+    }
+  });
+}
+
+/**
+ * @description 学生端接受老师的上麦邀请,同意上麦
+ */
+export function inviteAccept() {
+  rtc.inviteAccept({
+    success: function (str) {
+      console.log('接受邀请成功', str);
+    },
+    fail: function (data) {
+      console.log('接受邀请失败', data);
+    }
+  });
+}
+
 // 聊天组件
 
 /**
@@ -314,6 +400,10 @@ export function sendMsg(msg) {
   rtc.sendMsg(msg);
 }
 
-export function roomUpdate() {
-  rtc.roomUpdate();
+/**
+ * @description 房间配置项更新
+ * @param {Object} option 房间配置项 (具体看2.0 https://doc.bokecc.com/class/developer/web/chat.html),以键值对的形式传
+ */
+export function roomUpdate(option) {
+  rtc.roomUpdate(option);
 }