<template>
|
<div>
|
<div style="display: flex; flex-direction: row;">
|
<div id="meet" ref="meet" style="flex-grow: 1;">
|
</div>
|
<div style="padding-top: 5px; padding-left: 5px;right: 15px">
|
<el-button type="success" size="small" @click="hiddenStudent">{{ getShowText() }}</el-button>
|
<el-row v-show="showStudent">
|
<el-row :gutter="5">
|
<el-col :span="12">
|
<el-input placeholder="搜索学员" size="small" clearable @input="getStudentList" @clear="getStudentList"
|
v-model="searchForm.keyword"/>
|
</el-col>
|
<el-col :span="2">
|
<el-button type="primary" size="small" @click="getStudentList">搜索</el-button>
|
</el-col>
|
</el-row>
|
<el-tabs v-model="searchForm.onlineStatus" @tab-click="handleTabChange" style="margin-left: 3px">
|
<el-tab-pane label="在线学员" name="1"></el-tab-pane>
|
<el-tab-pane label="离线学员" name="0"></el-tab-pane>
|
</el-tabs>
|
<el-table :data="showStudentList" style="width: 100%">
|
<el-table-column prop="realName" label="学员姓名"></el-table-column>
|
<el-table-column prop="id" label="操作" width="80px;">
|
<template slot-scope="scope">
|
<el-dropdown trigger="click" @command="handleCommand">
|
<i class="el-icon-more-outline" id="more"></i>
|
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-item :command="{ command: 'openCamera', id: scope.row.id }">打开/关闭摄像头</el-dropdown-item>
|
<el-dropdown-item :command="{ command: 'mute', id: scope.row.id }">静音/取消静音</el-dropdown-item>
|
<el-dropdown-item :command="{ command: 'kickOut', id: scope.row.id }">踢出</el-dropdown-item>
|
</el-dropdown-menu>
|
</el-dropdown>
|
</template>
|
</el-table-column>
|
<el-table-column prop="onlineStatus" label="状态" width="80px;">
|
<template slot-scope="scope">
|
<div :class="{ online: scope.row.onlineStatus === 1, outline: scope.row.onlineStatus === 0 }">
|
{{ getStatus(scope.row.onlineStatus) }}
|
</div>
|
</template>
|
</el-table-column>
|
</el-table>
|
<el-button class="link-left" type="primary" size="small" @click="muteEveryone">全体静音</el-button>
|
<el-button class="link-left" type="primary" size="small" @click="videoEveryone">全体关闭摄像头</el-button>
|
</el-row>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import { getStudentList } from '@/api/meet'
|
import Cookies from 'js-cookie'
|
|
export default {
|
data () {
|
return {
|
ws: null,
|
jitsiApi: null,
|
width: 0,
|
height: 0,
|
showStudent: true,
|
intervalId: null,
|
meetId: null,
|
roomName: '',
|
joinList: [],
|
searchForm: {
|
keyword: '',
|
// 0 未在线、 1 在线
|
onlineStatus: 0
|
},
|
studentList: [],
|
showStudentList: []
|
}
|
},
|
beforeDestroy () {
|
if (this.ws) {
|
this.ws.close()
|
}
|
},
|
methods: {
|
muteEveryone () {
|
this.jitsiApi.executeCommand('muteEveryone', 'audio')
|
const h = this.$createElement;
|
|
this.$notify({
|
title: '提示',
|
message: h('i', { style: 'color: teal'}, '已全体禁音')
|
});
|
},
|
videoEveryone () {
|
this.jitsiApi.executeCommand('muteEveryone', 'video')
|
const h = this.$createElement;
|
|
this.$notify({
|
title: '提示',
|
message: h('i', { style: 'color: teal'}, '已关闭全体视频')
|
});
|
},
|
handleCommand (command) {
|
this.sendMessage(JSON.stringify(command))
|
},
|
initWebSocket () {
|
this.ws = new WebSocket('wss://www.kgmeet.com:18080/websocket/' + JSON.parse(Cookies.get('adminUserInfo')).id)
|
let ws = this.ws
|
ws.onopen = () => {
|
console.log('WebSocket 连接成功')
|
// 发送心跳数据
|
ws.send('ping')
|
}
|
ws.onmessage = (event) => {
|
console.log('收到服务器消息:', event.data)
|
// 处理服务器发来的消息
|
}
|
ws.onerror = (error) => {
|
console.error('WebSocket 连接出错:', error)
|
}
|
ws.onclose = () => {
|
console.log('WebSocket 连接已关闭')
|
// 可以在这里尝试重新连接
|
}
|
|
// 组件销毁时断开 WebSocket 连接
|
this.$once('hook:beforeDestroy', () => {
|
ws.close()
|
})
|
},
|
sendMessage (message) {
|
if (this.ws.readyState === WebSocket.OPEN) {
|
this.ws.send(message)
|
} else {
|
console.error('WebSocket 连接未打开')
|
}
|
},
|
hiddenStudent () {
|
this.showStudent = !this.showStudent
|
},
|
changeJitsiWindowSize (width, height) {
|
this.jitsiApi.resizeLargeVideo(width, height)
|
},
|
getShowText () {
|
if (this.showStudent) {
|
return '隐藏'
|
} else {
|
return '显示'
|
}
|
},
|
getStatus (status) {
|
if (status === 1) {
|
return '在线'
|
} else if (status === 0) {
|
return '离线'
|
}
|
},
|
handleTabChange (tab) {
|
let status = parseInt(tab.name)
|
this.showStudentList = this.studentList.filter(student => {
|
return student.onlineStatus === status
|
})
|
},
|
getStudentList () {
|
let params = {
|
keyword: this.searchForm.keyword
|
}
|
getStudentList(this.meetId, params).then(res => {
|
this.studentList = res.data.data
|
this.showStudentList = this.studentList.filter(student => {
|
return student.onlineStatus === this.searchForm.onlineStatus
|
})
|
})
|
},
|
getRoomInfo () {
|
this.jitsiApi.getRoomsInfo().then(rooms => {
|
rooms.rooms.forEach(room => {
|
// 房间的id是一个子域名,且@符前的会议名称是经过URL编码的
|
let encodedPart = room.id.split('@')[0]
|
let decodedPart = decodeURIComponent(encodedPart)
|
if (this.roomName === decodedPart) {
|
room.participants.forEach(user => {
|
// 使用'_'作为分隔符分割字符串,获取到userId
|
const parts = user.displayName.split('_')
|
let userId = null
|
if (parts.length > 1) {
|
userId = parseInt(parts[1])
|
// 设置学员状态为在线
|
this.studentList.forEach(student => {
|
console.log(student.id === userId)
|
if (student.id === userId) {
|
student.onlineStatus = 1
|
}
|
})
|
}
|
})
|
}
|
})
|
this.showStudentList = this.studentList.filter(student => {
|
return student.onlineStatus === parseInt(this.searchForm.onlineStatus)
|
})
|
})
|
}
|
},
|
mounted () {
|
this.height = window.innerHeight
|
this.meetId = this.$route.query.meetId
|
this.getStudentList()
|
const domain = this.$route.query.domain
|
const roomName = this.$route.query.roomName
|
this.roomName = roomName
|
const userInfoStr = this.$route.query.userInfoStr
|
const userInfo = userInfoStr ? JSON.parse(userInfoStr) : null
|
const options = {
|
roomName: roomName,
|
height: this.height,
|
parentNode: this.$refs.meet,
|
lang: 'zh_CN',
|
userInfo: userInfo,
|
configOverwrite: {
|
prejoinConfig: {
|
enabled: false
|
},
|
// 禁用邀请
|
disableInviteFunctions: true,
|
// 禁用邮箱
|
gravatar: {
|
disabled: true
|
},
|
// 禁用改名
|
readOnlyName: true,
|
// 自定义按钮
|
toolbarButtons: [
|
// 摄像头
|
'camera',
|
// 聊天
|
'chat',
|
// 共享
|
'desktop',
|
'download',
|
'fullscreen',
|
'hangup',
|
// 'help',
|
'highlight',
|
// 'invite',
|
'linktosalesforce',
|
'livestreaming',
|
'microphone',
|
'noisesuppression',
|
'recording',
|
'select-background',
|
'settings',
|
'shareaudio',
|
'sharedvideo',
|
'shortcuts',
|
'stats',
|
'tileview',
|
'toggle-camera',
|
'whiteboard',
|
|
// 'closedcaptions',
|
// 'embedmeeting',
|
// 'etherpad',
|
// 'feedback',
|
// 'filmstrip',
|
'participants-pane',
|
// 'profile',
|
'raisehand',
|
// 'security',
|
'videoquality',
|
],
|
whiteboard: {
|
enabled: true
|
}
|
}
|
}
|
|
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options)
|
|
this.jitsiApi.addListener('readyToClose', () => {
|
window.close()
|
})
|
// 初始化
|
this.initWebSocket()
|
// 每三秒更学员在线状态
|
this.intervalId = setInterval(() => {
|
this.getRoomInfo()
|
// 发送心跳数据
|
this.ws.send('ping')
|
}, 2500)
|
|
},
|
beforeDestroy () {
|
// 清除定时器,避免内存泄漏
|
if (this.intervalId) {
|
clearInterval(this.intervalId)
|
this.intervalId = null
|
}
|
}
|
}
|
|
</script>
|
|
<style lang="scss" scoped>
|
/deep/ thead {
|
display: none;
|
}
|
|
#more:hover {
|
cursor: pointer;
|
}
|
|
#meet {
|
height: 100%;
|
}
|
|
.online {
|
color: #42b983;
|
}
|
|
.outline {
|
color: #aa1111;
|
}
|
|
.studentWarp {
|
display: flex;
|
flex-direction: row;
|
}
|
|
.student-row {
|
margin-top: 8px;
|
padding-left: 3px;
|
color: #565b5e;
|
}
|
</style>
|