Ver código fonte

完善 分组讨论

dusenyao 4 anos atrás
pai
commit
f6c0990098

+ 6 - 2
src/router/index.js

@@ -117,12 +117,16 @@ const routes = [
         component: () => import('@/views/live/teacher')
       },
       {
+        path: '/live/teacher/group',
+        component: () => import('@/views/live/teacher/group.vue')
+      },
+      {
         path: '/live/student',
         component: () => import('@/views/live/student')
       },
       {
-        path: '/live/group',
-        component: () => import('@/views/live/group')
+        path: '/live/student/group',
+        component: () => import('@/views/live/student/group.vue')
       }
     ]
   },

+ 4 - 0
src/styles/index.scss

@@ -26,6 +26,10 @@ body {
   height: 100%;
 }
 
+ul {
+  padding-inline-start: 0;
+}
+
 #app {
   height: 100%;
 }

+ 1 - 3
src/views/live/group/group.js → src/views/live/student/group.js

@@ -13,13 +13,12 @@ export {
 /**
  * 取消订阅远程流
  */
-function unSubscribeStream(stream) {
+export function unSubscribeStream(stream) {
   rtc.unSubscribeStream({
     unSubStream: stream,
     success: function (str) {
       console.log('取消订阅流成功', str);
     },
-
     fail: function (str) {
       console.log(str);
     }
@@ -103,7 +102,6 @@ export function initListener(vue) {
   // 房间全量信息事件(人员进出时广播)
   rtc.on('room_context', roomData => {
     vue.roomContext = JSON.parse(roomData);
-    vue.getLiveRoomStudentList();
     console.log('房间全量信息事件(人员进出时广播)', JSON.parse(roomData));
   });
 

+ 32 - 50
src/views/live/group/index.vue → src/views/live/student/group.vue

@@ -6,7 +6,6 @@
         <div class="live-title-name">{{ roomInfo.cs_item_name }} {{ roomInfo.task_name }}</div>
         <div>
           <el-button @click="exitRoom">退出房间</el-button>
-          <el-button @click="getLiveStat">getLiveStat</el-button>
         </div>
       </div>
       <div class="live-course-name">{{ roomInfo.course_name }}</div>
@@ -67,7 +66,9 @@
           @mouseover="liveMenuShow = true"
           @mouseout="liveMenuShow = false"
         >
-          <div id="live"></div>
+          <div id="live">
+            <el-image v-if="!teacherExist" :src="roomInfo.teacher_image_url" fit="contain" />
+          </div>
           <div :style="{ bottom: liveMenuShow ? '0' : '-40px' }" class="live-wrapper">
             <div>
               {{ roomInfo.teacher_name }}
@@ -76,7 +77,7 @@
           </div>
         </div>
         <div class="student-list">
-          <div class="student-list-title">学生列表</div>
+          <div class="student-list-title">小组成员</div>
           <ul>
             <li v-for="item in student_list" :key="item.room_user_id">
               <div class="student-list-left">
@@ -93,7 +94,6 @@
 
 <script>
 import {
-  GetLiveRoomStudentList,
   StudentExitLiveRoom,
   GetLiveRoomInfo,
   IsEnableGroup,
@@ -106,9 +106,9 @@ export default {
     return {
       task_id: this.$route.query.task_id,
       room_user_id: this.$route.query.live_room_sys_user_id,
+      teacherExist: false,
       // 定时器
       timer: null,
-      timer_group: null,
       rtc: null,
       streamList: [],
       roomData: {
@@ -174,27 +174,20 @@ export default {
     }
   },
   created() {
-    this.getLiveRoomStudentList();
     this.getLiveRoomInfo();
+    this.getMyGroupInfo_Student();
   },
   mounted() {
-    // const { live_room_sys_user_id, room_id, sessionid } = this.$route.query;
-    // this.rtc = common.initSDK({
-    //   userid: live_room_sys_user_id,
-    //   roomid: room_id,
-    //   sessionid
-    // });
-    // common.initListener(this); // 注册监听事件
-    // this.getLiveStat();
     common.downloadWebSDK(this);
-    this.getLiveRoomStudentListPolling();
     this.isEnableGroup();
   },
   beforeDestroy() {
     clearInterval(this.timer);
-    clearInterval(this.timer_group);
     StudentExitLiveRoom({ task_id: this.task_id, room_user_id: this.room_user_id });
     common.closeVideo('picture');
+    this.streamList.forEach(item => {
+      common.unSubscribeStream(item);
+    });
   },
   methods: {
     getLiveRoomInfo() {
@@ -251,30 +244,30 @@ export default {
       common.getDevice();
     },
 
-    getLiveRoomStudentList() {
-      GetLiveRoomStudentList({ task_id: this.task_id }).then(({ student_list }) => {
-        this.student_list = student_list;
-      });
-    },
-
-    getLiveRoomStudentListPolling() {
-      this.timer = setInterval(() => {
-        this.getLiveRoomStudentList();
-      }, 5000);
-    },
-
     // 分组讨论
     isEnableGroup() {
-      this.timer_group = setInterval(() => {
+      this.timer = setInterval(() => {
         IsEnableGroup({ task_id: this.task_id })
           .then(({ is_enable_group }) => {
-            if (is_enable_group === 'true') {
-              clearInterval(this.timer_group);
-              this.getMyGroupInfo_Student();
+            if (is_enable_group === 'false') {
+              clearInterval(this.timer);
+              const {
+                room_info: { live_room_sys_user_id, room_id, session_id, room_user_id }
+              } = this.$route.query;
+              this.$router.push({
+                path: '/live/student',
+                query: {
+                  live_room_sys_user_id,
+                  room_id,
+                  session_id,
+                  task_id: this.task_id,
+                  room_user_id
+                }
+              });
             }
           })
           .catch(() => {
-            clearInterval(this.timer_group);
+            clearInterval(this.timer);
           });
       }, 5000);
     },
@@ -283,10 +276,7 @@ export default {
       GetMyGroupInfo_Student({
         task_id: this.task_id
       }).then(({ student_list }) => {
-        let data = student_list.find(el => {
-          return el.is_self === 'true';
-        });
-        console.log(data);
+        this.student_list = student_list;
       });
     }
   }
@@ -458,6 +448,11 @@ $live-bc: #3d3938;
           width: 352px;
           height: 198px;
           background-color: $live-bc;
+
+          .el-image {
+            width: 100%;
+            height: 100%;
+          }
         }
 
         .live-wrapper {
@@ -491,24 +486,11 @@ $live-bc: #3d3938;
           margin-bottom: 16px;
 
           .student-list-left {
-            flex: 7;
-
             .name {
               vertical-align: super;
               margin-left: 8px;
             }
           }
-
-          .student-list-right {
-            flex: 3;
-
-            .svg-icon {
-              font-size: 18px;
-              cursor: pointer;
-              margin-top: 7px;
-              margin-right: 8px;
-            }
-          }
         }
       }
     }

+ 9 - 2
src/views/live/student/index.vue

@@ -373,13 +373,20 @@ export default {
         let data = student_list.find(el => {
           return el.is_self === 'true';
         });
+        const query = this.$route.query;
         this.$router.push({
-          path: '/live/group',
+          path: '/live/student/group',
           query: {
             task_id: this.task_id,
             live_room_sys_user_id,
             room_id,
-            sessionid: data.session_id
+            sessionid: data.session_id,
+            room_info: {
+              live_room_sys_user_id: query.live_room_sys_user_id,
+              room_id: query.room_id,
+              session_id: query.session_id,
+              room_user_id: query.room_user_id
+            }
           }
         });
       });

+ 233 - 0
src/views/live/teacher/group.js

@@ -0,0 +1,233 @@
+import { Message } from 'element-ui';
+import { rtc, updateMcResult } from '@/views/live/common';
+export {
+  initSDK,
+  downloadWebSDK,
+  sendMsg,
+  getDevice,
+  sendPublishMessage,
+  closeVideo
+} from '@/views/live/common';
+
+/**
+ * 推送本地流
+ */
+function publishStream(streamName) {
+  rtc.publish({
+    streamName,
+    // 推流成功,更新上麦结果
+    success: stream => {
+      console.log('推流成功', stream);
+      updateMcResult(stream.id(), 1);
+    },
+    fail: str => {
+      // 推流失败,更新上麦结果
+      console.log('推流失败,更新上麦结果', str);
+      updateMcResult('', 0);
+    }
+  });
+}
+
+/**
+ * 创建本地流
+ */
+function createLocalStream() {
+  const createData = {
+    video: true,
+    audio: true
+  };
+  rtc.createLocalStream({
+    streamName: 'main',
+    createData,
+    success: function (stream) {
+      console.log('创建本地流成功', stream);
+      // 创建本地流成功,将流展示到id为 live 的 dom 元素盒子中
+      stream.show('live');
+      publishStream('main'); // 如果需要立即推流,执行 publish 方法
+    },
+    fail: function (data) {
+      // 创建本地流失败,应用层处理
+      Message({
+        type: 'error',
+        message: '创建本地流失败:' + data
+      });
+    }
+  });
+}
+
+/**
+ * 初始化监听事件
+ */
+export function initListener(vue) {
+  rtc.on('login_success', data => {
+    console.log('登录成功', data);
+    Message({
+      message: '登录成功',
+      type: 'success'
+    });
+    vue.roomData = data;
+  });
+
+  rtc.on('login_failed', data => {
+    console.log('登录失败', data);
+    Message({
+      message: '登录失败:' + JSON.stringify(data),
+      type: 'warning'
+    });
+  });
+
+  // 教师 必须在加入房间成功的事件回调里创建本地流
+  rtc.on('conference_join', () => {
+    console.log('加入房间成功');
+    createLocalStream();
+  });
+
+  rtc.on('conference_join_failed', err => {
+    // 加入房间失败  err为错误原因
+    console.log('加入房间失败', err);
+  });
+
+  // 新增订阅流事件
+  rtc.on('allow_sub', function (stream) {
+    if (stream.isMixed()) {
+      console.log('是混合流,不订阅');
+    } else {
+      // 订阅远程流
+      rtc.trySubscribeStream({
+        tryStream: stream,
+        success: function (stream) {
+          // 订阅流成功
+          let streamType = stream.streamType();
+          console.log('订阅流成功', streamType);
+          stream.show('student', 'contain'); // 将流显示到指定 id 的盒子中
+        },
+        fail: function (err) {
+          console.log('订阅流失败', err);
+        }
+      });
+    }
+  });
+
+  // 直播未开始,不能推流
+  rtc.on('not_live', function () {
+    console.log('直播未开始,不能推流');
+    Message({
+      message: '直播未开始,不能推流',
+      type: 'warning'
+    });
+  });
+
+  // 推流前查询直播状态失败,导致没有推流
+  rtc.on('local_stream_publish_failed', function () {
+    console.log('推流前查询直播状态失败,导致没有推流');
+    Message({
+      message: '推流前查询直播状态失败,导致没有推流',
+      type: 'warning'
+    });
+  });
+
+  // 房间全量信息事件(人员进出时广播)
+  rtc.on('room_context', roomData => {
+    vue.roomContext = JSON.parse(roomData);
+    console.log('房间全量信息事件(人员进出时广播)', JSON.parse(roomData));
+  });
+
+  rtc.on('publish_stream', str => {
+    console.log('直播已开启', str);
+    vue.liveStat = true;
+  });
+
+  rtc.on('end_stream', str => {
+    console.log('直播已关闭', str);
+    vue.liveStat = false;
+  });
+
+  rtc.on('switch_user_settings', settingData => {
+    // 单个用户配置监听
+    console.log(settingData);
+  });
+
+  // 人员列表事件(人员麦序变化时广播)
+  rtc.on('speak_context', speakData => {
+    vue.speakData = JSON.parse(speakData);
+    console.log('人员列表事件(人员麦序变化时广播)', JSON.parse(speakData));
+  });
+
+  rtc.on('switch_settings', data => {
+    console.log('房间设置事件', data); // 房间设置事件
+  });
+
+  rtc.on('publishStreamErr', data => {
+    console.log('推流意外终止:' + data.streamName);
+    // 直播开启状态下,尝试重推这条流
+  });
+
+  // 视频无法自动播放
+  rtc.on('playError', data => {
+    console.log('视频无法自动播放', data);
+  });
+
+  // 监听通知移除流事件
+  rtc.on('stream_removed', stream => {
+    console.log('监听通知移除流事件');
+  });
+
+  // 停止订阅流
+  rtc.on('unSub', function (stream) {
+    console.log('停止订阅流', stream);
+    rtc.unSubscribeStream({
+      unSubStream: stream,
+      success: function (stream) {
+        console.log('取消订阅流成功', stream.id());
+      },
+
+      fail: function (str) {
+        console.log(str);
+      }
+    });
+  });
+
+  // 用户退出房间通知其他人员事件
+  rtc.on('exit_room_user', function (data) {
+    console.log('用户退出房间通知其他人员事件', data);
+  });
+
+  /**
+   * 排麦监听事件
+   */
+
+  // 监听自己被邀请事件
+  rtc.on('inviteUp', uid => {
+    console.log('监听自己被邀请事件', uid);
+    rtc.inviteAccept({
+      success: function (str) {
+        console.log('接受邀请成功', str);
+      },
+      fail: function (data) {
+        console.log('接受邀请失败', data);
+      }
+    });
+  });
+
+  /**
+   * 监听聊天事件
+   */
+  rtc.on('chat_message', data => {
+    let dat = JSON.parse(data);
+    console.log(dat);
+    // 敏感词过滤:如果发送的聊天消息被系统判定包含敏感词,则只有发送者能收到本条消息,房间内其他人都不会收到这条聊天消息。
+    // 如果返回消息中有 isFilterChat 字段(消息不包含敏感词返回数据中无isFilterChat字段),且isFilterChat的值为1,则说明该消息包含敏感字,除发送者外其他人不会收到这条消息。
+    if (dat.isFilterChat && dat.isFilterChat === 1) {
+      return;
+    }
+    vue.chatList.push(dat);
+  });
+
+  rtc.on('allowChatChange', function (data) {
+    let msg = data.settings.allow_chat ? '开言' : '禁言';
+    Message({
+      type: 'success',
+      message: `全体${msg}成功`
+    });
+  });
+}

+ 506 - 0
src/views/live/teacher/group.vue

@@ -0,0 +1,506 @@
+<template>
+  <div class="live">
+    <!--顶部-->
+    <div class="live-top">
+      <div class="live-title">
+        <div class="live-title-name">{{ roomInfo.cs_item_name }} {{ roomInfo.task_name }}</div>
+        <div>
+          <el-button @click="stopGroup">结束群组讨论</el-button>
+        </div>
+      </div>
+      <div class="live-course-name">{{ roomInfo.course_name }}</div>
+      <div class="live-teacher">
+        <span class="live-teacher-name">
+          <svg-icon icon-class="person" />{{ roomInfo.teacher_name }}
+        </span>
+        <span><svg-icon icon-class="people" />{{ roomInfo.student_count }}</span>
+      </div>
+    </div>
+    <!-- 主容器 -->
+    <div class="live-container">
+      <!-- 左侧 -->
+      <div class="live-container-left">
+        <div class="group">
+          <template v-for="(item, i) in group_list">
+            <div :key="item.room_id" class="group-list">
+              <div class="group-serial">{{ i + 1 }}</div>
+              <div class="group-list-avatar">
+                <el-avatar
+                  v-for="li in item.student_list"
+                  :key="li.student_id"
+                  icon="el-icon-user"
+                  :src="li.student_image_url"
+                />
+              </div>
+            </div>
+          </template>
+        </div>
+        <div class="button-group">
+          <div class="button-group-left">
+            <span class="stop-group" @click="stopGroup">结束群组讨论</span>
+          </div>
+          <div class="button-group-right"></div>
+        </div>
+        <div class="live-container-left-chat">
+          <div class="chat-top">
+            <span>聊天</span>
+            <!-- <label @click="chatBans">
+              <input v-model="roomData.allow_chat" type="checkbox" class="allow-chat" />
+              <span>禁言</span>
+            </label> -->
+          </div>
+          <div class="chat-window">
+            <ul class="chat-window-ul">
+              <li v-for="(item, i) in chatList" :key="i">
+                <div class="msg-normal">
+                  <span>{{ item.username }}: </span>
+                  <span>{{ item.msg }}</span>
+                </div>
+              </li>
+            </ul>
+          </div>
+          <div class="chat-speak">
+            <el-input
+              v-model="msg"
+              placeholder="输入发言"
+              maxlength="400"
+              @keydown.enter.native="sendMsg"
+            >
+              <el-button slot="append" @click="sendMsg">发送</el-button>
+            </el-input>
+          </div>
+        </div>
+      </div>
+      <!-- 右侧 -->
+      <div class="live-container-right">
+        <div
+          class="live-teacher-lens"
+          @mouseover="liveMenuShow = true"
+          @mouseout="liveMenuShow = false"
+        >
+          <div id="live"></div>
+          <div :style="{ bottom: liveMenuShow ? '0' : '-40px' }" class="live-wrapper">
+            <div>
+              {{ roomInfo.teacher_name }}
+            </div>
+            <div></div>
+          </div>
+        </div>
+        <div class="student-list">
+          <div class="student-list-title">小组列表</div>
+          <ul>
+            <template v-for="item in group_list">
+              <li v-for="el in item.student_list" :key="el.student_id">
+                <div class="student-list-left">
+                  <el-avatar icon="el-icon-user" size="small" :src="el.student_image_url" />
+                  <span class="name">{{ el.student_name }}</span>
+                </div>
+                <div class="student-list-right"></div>
+              </li>
+            </template>
+          </ul>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { GetLiveRoomInfo, StudentExitLiveRoom, StopGroup, GetGroupInfo_Teacher } from '@/api/live';
+import * as common from './live';
+
+export default {
+  data() {
+    return {
+      task_id: this.$route.query.task_id,
+      // 定时器
+      timer: null,
+      rtc: null,
+      roomData: {
+        desc: '直播间标题',
+        name: '姓名',
+        user: {
+          id: '',
+          name: '',
+          role: 'talker',
+          rommid: ''
+        },
+        max_users: 1,
+        allow_chat: true,
+        allow_audio: true,
+        allow_speak: true
+      },
+      roomInfo: {
+        room_id: '',
+        video_mode: 1,
+        task_name: '',
+        cs_item_name: '',
+        course_name: '',
+        teacher_name: '',
+        student_count: 0
+      },
+      loadedNumber: 0,
+      speakData: {},
+      roomContext: {},
+      msg: '',
+      chatList: [],
+      // 小组列表
+      group_list: [],
+      live_room_sys_user_id: '',
+      // 直播状态
+      liveStat: false,
+      liveMenuShow: false
+    };
+  },
+  watch: {
+    loadedNumber(newVal) {
+      if (newVal === 5) {
+        common.createScript(
+          'https://class.csslcloud.net/static/SDK/docSDK/drawSdk_3.0.js'
+        ).onload = () => {
+          const { room_id, session_id } = this.$route.query;
+          this.rtc = common.initSDK({
+            userid: this.live_room_sys_user_id,
+            roomid: room_id,
+            sessionid: session_id
+          });
+          common.initListener(this); // 注册监听事件
+          this.$loading().close();
+        };
+      }
+    }
+  },
+  created() {
+    // common.downloadWebSDK(this);
+    this.getLiveRoomInfo();
+    GetGroupInfo_Teacher({ task_id: this.task_id }).then(
+      ({ live_room_sys_user_id, group_list }) => {
+        this.group_list = group_list;
+        this.live_room_sys_user_id = live_room_sys_user_id;
+      }
+    );
+  },
+  beforeDestroy() {
+    clearInterval(this.timer);
+    common.closeVideo('main');
+  },
+  methods: {
+    getLiveRoomInfo() {
+      GetLiveRoomInfo({ task_id: this.task_id }).then(
+        ({
+          room_id,
+          video_mode,
+          task_name,
+          cs_item_name,
+          course_name,
+          teacher_name,
+          student_count
+        }) => {
+          this.roomInfo = {
+            room_id,
+            video_mode,
+            task_name,
+            cs_item_name,
+            course_name,
+            teacher_name,
+            student_count
+          };
+        }
+      );
+    },
+
+    // 发消息
+    sendMsg() {
+      common.sendMsg(this.msg);
+      this.msg = '';
+    },
+
+    chatBans() {
+      common.roomUpdate({
+        allow_chat: !this.roomData.allow_chat,
+        roomUpdateSuccess: function (data) {
+          console.log(data, '房间模板配置更新请求成功!');
+        },
+        roomUpdateFailed: function (data) {
+          console.log(data, '房间模板配置更新请求失败! 请稍后再试!');
+        }
+      });
+    },
+
+    studentExitLiveRoom(room_user_id) {
+      StudentExitLiveRoom({ task_id: this.task_id, room_user_id });
+    },
+
+    // 分组讨论
+    stopGroup() {
+      StopGroup({ task_id: this.task_id }).then(() => {
+        this.$message.success('结束分组讨论成功');
+        const {
+          room_info: { live_room_sys_user_id, room_id, session_id, room_user_id }
+        } = this.$route.query;
+        this.$router.push({
+          path: '/live/teacher',
+          query: {
+            live_room_sys_user_id,
+            room_id,
+            session_id,
+            task_id: this.task_id,
+            room_user_id
+          }
+        });
+      });
+    }
+  }
+};
+</script>
+
+<style lang="scss">
+@import '~@/styles/mixin.scss';
+$live-bc: #3d3938;
+
+.live {
+  @include container;
+
+  // 顶部
+  &-top {
+    background-color: #fff;
+    padding: 24px 32px;
+    border-top-left-radius: 8px;
+    border-top-right-radius: 8px;
+
+    .live-title {
+      display: flex;
+      justify-content: space-between;
+
+      &-name {
+        font-size: 22px;
+      }
+
+      .el-button {
+        border-radius: 4px;
+        padding: 7px 12px;
+      }
+    }
+
+    .live-course-name {
+      font-size: 14px;
+      color: #737373;
+      line-height: 30px;
+    }
+
+    .live-teacher {
+      margin-top: 12px;
+
+      .svg-icon {
+        margin-right: 8px;
+      }
+
+      &-name {
+        margin-right: 60px;
+      }
+    }
+  }
+
+  // 主容器
+  &-container {
+    display: flex;
+    justify-content: left;
+
+    &-left {
+      width: 832px;
+      background-color: #fff;
+      border-radius: 8px;
+
+      .group {
+        width: 100%;
+        height: 468px;
+        display: flex;
+        flex-wrap: wrap;
+        background-color: #4d4d4d;
+        overflow: hidden;
+        padding: 10px 24px;
+
+        &-list {
+          background-color: #646464;
+          position: relative;
+          padding: 24px;
+          width: 253px;
+          height: 144px;
+          margin-right: 8px;
+
+          &-avatar {
+            display: flex;
+            flex-wrap: wrap;
+            justify-content: space-around;
+            align-items: center;
+            margin-top: 24px;
+          }
+
+          .group-serial {
+            position: absolute;
+            display: inline-block;
+            top: 0;
+            left: 0;
+            height: 24px;
+            width: 24px;
+            color: #fff;
+            background-color: #3d3d3d;
+            text-align: center;
+            line-height: 24px;
+          }
+        }
+      }
+
+      .button-group {
+        display: flex;
+        justify-content: space-between;
+        height: 48px;
+        background-color: #4d4d4d;
+        padding: 0 15px;
+        border-bottom-left-radius: 5px;
+
+        .svg-icon {
+          font-size: 20px;
+        }
+
+        &-left {
+          .stop-group {
+            color: #fff;
+          }
+
+          > span {
+            display: inline-block;
+            height: 100%;
+            padding: 14px 16px;
+            cursor: pointer;
+
+            &:active,
+            &:hover {
+              background-color: #3d3d3d;
+            }
+          }
+        }
+      }
+
+      // 聊天窗口
+      &-chat {
+        height: 278px;
+        border: 1px solid #ccc;
+        border-bottom-left-radius: 8px;
+        display: flex;
+        flex-direction: column;
+        justify-content: space-between;
+
+        .chat-top {
+          display: flex;
+          justify-content: space-between;
+          padding: 15px 15px 10px;
+          border-bottom: 1px solid #e6e6e6;
+          color: #959595;
+
+          label {
+            cursor: pointer;
+          }
+
+          .allow-chat {
+            margin-right: 12px;
+          }
+        }
+
+        .chat-window {
+          position: relative;
+          width: 100%;
+          height: 100%;
+          overflow: hidden;
+
+          &-ul {
+            position: absolute;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 100%;
+            overflow: auto;
+
+            .msg-normal {
+              padding: 7px 16px;
+            }
+          }
+        }
+
+        .chat-speak {
+          padding: 16px;
+        }
+      }
+    }
+
+    &-right {
+      padding: 8px;
+      background-color: #2c2c2c;
+      border-end-end-radius: 8px;
+
+      .live-teacher-lens {
+        position: relative;
+        overflow: hidden;
+
+        #live {
+          width: 352px;
+          height: 198px;
+          background-color: $live-bc;
+        }
+
+        .live-wrapper {
+          position: absolute;
+          height: 40px;
+          width: 100%;
+          background-color: #000;
+          opacity: 0.7;
+          color: #fff;
+          line-height: 40px;
+          padding: 0 16px;
+          transition: all 300ms ease-in 0s;
+        }
+      }
+
+      // 学员列表
+      .student-list {
+        width: 100%;
+        padding: 24px 16px;
+        margin-top: 2px;
+        height: calc(100% - 200px);
+        background-color: #2c2c2c;
+        font-size: 14px;
+        color: #fff;
+
+        &-title {
+          margin-bottom: 16px;
+        }
+
+        li {
+          display: flex;
+          margin-bottom: 16px;
+
+          .student-list-left {
+            flex: 8;
+
+            .name {
+              vertical-align: super;
+              margin-left: 8px;
+            }
+          }
+
+          .student-list-right {
+            flex: 2;
+
+            .svg-icon {
+              font-size: 18px;
+              cursor: pointer;
+              margin-top: 7px;
+              margin-right: 8px;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 84 - 62
src/views/live/teacher/index.vue

@@ -75,26 +75,20 @@
             </span>
           </div>
         </div>
-        <div v-show="isGroup" class="group"></div>
         <div class="button-group">
           <div class="button-group-left">
-            <template v-if="isGroup">
-              <span class="stop-group" @click="stopGroup">结束群组讨论</span>
-            </template>
-            <template v-else>
-              <span @click="publishShareStream">
-                <svg-icon icon-class="share" />
-              </span>
-              <span @click="showDrawSetting">
-                <svg-icon icon-class="draw" />
-              </span>
-              <span @click="startGroup">
-                <svg-icon icon-class="group" />
-              </span>
-              <span @click="dialogVisible = true">
-                <svg-icon icon-class="push" />
-              </span>
-            </template>
+            <span @click="publishShareStream">
+              <svg-icon icon-class="share" />
+            </span>
+            <span @click="showDrawSetting">
+              <svg-icon icon-class="draw" />
+            </span>
+            <span @click="startGroup">
+              <svg-icon icon-class="group" />
+            </span>
+            <span @click="dialogVisible = true">
+              <svg-icon icon-class="push" />
+            </span>
           </div>
           <div class="button-group-right"></div>
         </div>
@@ -175,6 +169,22 @@
       :dialog-visible-complete="dialogVisibleComplete"
       @dialogCompleteClose="dialogCompleteClose"
     />
+
+    <el-dialog
+      title="分组讨论组数"
+      top="30vh"
+      width="300px"
+      :visible.sync="dialogVisibleGroup"
+      :close-on-click-modal="false"
+    >
+      <el-select v-model="group_count">
+        <el-option v-for="i in groupNumList" :key="i" :label="i" :value="i" />
+      </el-select>
+      <span slot="footer" class="dialog-footer">
+        <el-button size="small" @click="closeGroup">取 消</el-button>
+        <el-button size="small" type="primary" @click="dialogGroup">确 定</el-button>
+      </span>
+    </el-dialog>
   </div>
 </template>
 
@@ -185,8 +195,6 @@ import {
   GetLiveRoomInfo,
   StudentExitLiveRoom,
   StartGroup,
-  StopGroup,
-  GetGroupInfo_Teacher,
   IsEnableGroup
 } from '@/api/live';
 import SelectMaterial from '@/components/live/SelectMaterial.vue';
@@ -213,7 +221,6 @@ export default {
       // 定时器
       timer: null,
       remoteStreamType: -1,
-      isGroup: false,
       rtc: null,
       roomData: {
         desc: '直播间标题',
@@ -250,13 +257,17 @@ export default {
       student_list: [],
       // 直播状态
       liveStat: false,
-      liveMenuShow: false
+      liveMenuShow: false,
+      // 分组讨论
+      groupNumList: [],
+      group_count: 2,
+      dialogVisibleGroup: false
     };
   },
   computed: {
     // 画板模式
     isDraw() {
-      return !this.connect && !this.callLoading && !this.isGroup;
+      return !this.connect && !this.callLoading;
     }
   },
   watch: {
@@ -272,13 +283,24 @@ export default {
     }
   },
   created() {
-    this.$loading({
-      text: '加载直播所需SDK中...',
-      background: '#fff'
+    IsEnableGroup({ task_id: this.task_id }).then(({ is_enable_group }) => {
+      if (is_enable_group === 'true') {
+        this.$router.push({
+          path: '/live/teacher/group',
+          query: {
+            task_id: this.task_id
+          }
+        });
+      } else {
+        this.$loading({
+          text: '加载直播所需SDK中...',
+          background: '#fff'
+        });
+        common.downloadWebSDK(this);
+        this.getLiveRoomStudentList();
+        this.getLiveRoomInfo();
+      }
     });
-    common.downloadWebSDK(this);
-    this.getLiveRoomStudentList();
-    this.getLiveRoomInfo();
   },
   mounted() {
     document.addEventListener(
@@ -303,14 +325,8 @@ export default {
       true
     );
     this.getLiveRoomStudentListPolling();
-    this.isEnableGroup();
   },
   beforeDestroy() {
-    // 清除所有定时器
-    // let end = setInterval(() => {}, 1000);
-    // for (let i = 1; i <= end; i++) {
-    //   clearInterval(i);
-    // }
     clearInterval(this.timer);
     common.closeVideo('main');
   },
@@ -513,32 +529,41 @@ export default {
 
     // 分组讨论
     startGroup() {
-      StartGroup({ task_id: this.task_id, group_count: 2 })
-        .then(() => {
-          this.isGroup = true;
-          return GetGroupInfo_Teacher({ task_id: this.task_id });
-        })
-        .then(({ group_list, live_room_sys_user_id }) => {
-          console.log(group_list, live_room_sys_user_id);
-        });
+      let num = Math.ceil(this.student_list.length / 2);
+      num = num < 2 ? 2 : num;
+      for (let i = 2; i <= num; i++) {
+        this.groupNumList.push(i);
+      }
+      this.dialogVisibleGroup = true;
     },
 
-    stopGroup() {
-      StopGroup({ task_id: this.task_id }).then(() => {
-        this.isGroup = false;
-        this.$message.success('结束分组讨论成功');
+    // 弹出框方法
+    dialogGroup() {
+      // 开始分组讨论
+      StartGroup({ task_id: this.task_id, group_count: this.group_count }).then(() => {
+        this.$message.success('开启分组讨论成功');
+        let query = this.$route.query;
+        this.$router.push({
+          path: '/live/teacher/group',
+          query: {
+            task_id: this.task_id,
+            room_info: {
+              live_room_sys_user_id: query.live_room_sys_user_id,
+              room_id: query.room_id,
+              session_id: query.session_id,
+              room_user_id: query.room_user_id
+            }
+          }
+        });
       });
     },
 
-    isEnableGroup() {
-      IsEnableGroup({ task_id: this.task_id }).then(({ is_enable_group }) => {
-        if (is_enable_group === 'true') {
-          this.isGroup = true;
-        }
-      });
+    closeGroup() {
+      this.dialogVisibleGroup = false;
+      this.groupNumList = [];
+      this.group_count = 2;
     },
 
-    // 弹出框方法
     dialogClose() {
       this.dialogVisible = false;
     },
@@ -561,6 +586,11 @@ $live-bc: #3d3938;
 
 .live {
   @include container;
+  @include dialog;
+
+  .el-dialog__body {
+    height: 65px;
+  }
 
   // 顶部
   &-top {
@@ -686,14 +716,6 @@ $live-bc: #3d3938;
         }
       }
 
-      .group {
-        width: 100%;
-        height: 468px;
-        position: relative;
-        background-color: $live-bc;
-        overflow: hidden;
-      }
-
       #draw-parent {
         width: 100%;
         height: 468px;