WGShare.Client.Wx/pages/meeting/index.ts

857 lines
25 KiB
TypeScript

import { GetRoomInfo, GetRoomUser, GetShowUser, GetApplySpeak, PostMuteAll, PostOpenMicr, PostOpenCamera, DeleteRoomManager } from '../../api/meeting/index'
import { agora } from '../../utils/agora'
import { onInvoke, onSignalr } from '../../utils/singlr'
import { role, getStorage } from '../../utils/utils'
import { Message } from 'tdesign-miniprogram';
import dayjs from 'dayjs';
const computedBehavior = require('miniprogram-computed').behavior;
Page({
behaviors: [computedBehavior],
data: {
footerList: [
{
title: '关闭听筒',
titleActive: '开启听筒',
active: true,
icon: '/assets/icon1.png',
iconActive: '/assets/icon1-active.png',
show: false,
},
{
title: '静音',
titleActive: '解除静音',
active: false,
icon: '/assets/icon2.png',
iconActive: '/assets/icon2-active.png',
show: true,
},
{
title: '关闭视频',
titleActive: '打开视频',
active: false,
icon: '/assets/icon3.png',
iconActive: '/assets/icon3-active.png',
show: true,
},
{
title: '翻转',
titleActive: '翻转',
active: true,
icon: '/assets/icon4.png',
iconActive: '/assets/icon4.png',
show: false,
},
{
title: '聊天',
titleActive: '聊天',
active: true,
icon: '/assets/icon5.png',
iconActive: '/assets/icon5.png',
show: true,
},
{
title: '成员',
titleActive: '成员',
active: true,
icon: '/assets/icon6.png',
iconActive: '/assets/icon6.png',
show: true,
},
{
title: '申请发言',
titleActive: '结束发言',
active: true,
icon: '/assets/icon7.png',
iconActive: '/assets/icon7-active.png',
show: true,
},
],
channelId: '',
roomInfo: '',
roomUserList: [],
audioList: [],
userVolume: 0,
chatList: [],
isAdmin: 0,
currentUid: '',
currentUser: '',
userNumer: 0,
scrollTop: 0,
noViewChatList: 0,
applySpeakDialog: false,
leaveDialog: false,
userPopupVisible: false,
chatPopupVisible: false,
isFullscreen: false,
muted: false,
currentRequestSpeakType: '',
user: '',
messageStr: '',
commonlyChatList: [
'能听到我说话吗?',
'听得到',
'听不到',
'我要发言',
]
},
watch: {
'roomUserList.**': function (roomUserList) {
this.setData({
isAdmin: roomUserList.filter((item: any) => (role.ID.includes(item.roleId) || item.isRoomManager) && item.isRoom).length,
userNumer: roomUserList.filter((item: any) => item.isRoom).length,
audioList: roomUserList.map(item => {
return {
volume: 0,
uid: item.uid,
}
})
})
this.scroll()
},
'footerList.**': function (footerList) {
const footerListTemplate = [...footerList];
footerListTemplate[3].show = footerListTemplate[2].active
this.setData({
footerList: footerListTemplate
})
},
'isClicked': function (isClicked) {
if (isClicked) {
let timer = setTimeout(() => {
this.setData({
isClicked: false,
})
clearTimeout(timer)
}, 10000);
}
},
'currentUid': function (currentUid) {
this.data.roomUserList.forEach(item => {
if (item.src) {
if (item.uid == currentUid) {
agora.setRemoteVideoStreamType(Number(item.uid), 0)
} else {
agora.setRemoteVideoStreamType(Number(item.uid), 1)
}
}
});
},
},
async onLoad(option) {
wx.enableAlertBeforeUnload({
message: "确定要离开房间吗?"
})
this.setData({
channelId: option.roomNum,
user: await getStorage('user')
})
await this.joinChannel()
await this.getRoomUser()
await this.getShowUser()
this.startClientEvent()
this.startSignalr()
await this.getRoomInfo()
const that = this;
wx.getStorage({
key: 'historicalList',
success(res: any) {
const list = [...res.data]
if (list.length >= 3) {
list.splice(0, 1)
}
list.push({
nickName: option.nickName,
roomNum: option.roomNum,
roomName: that.data.roomInfo.roomName
})
wx.setStorage({
key: "historicalList",
data: list
})
},
fail() {
wx.setStorage({
key: "historicalList",
data: [{
nickName: option.nickName,
roomNum: option.roomNum,
roomName: that.data.roomInfo.roomName
}]
})
}
})
},
onReady() {
wx.onNetworkStatusChange(this.listener)
},
onUnload() {
wx.offNetworkStatusChange(this.listener)
},
startSignalr() {
onSignalr(async (item) => {
const userInfo: any = await getStorage('user')
switch (item.key) {
// 聊天
case 'ReceiveMessage':
if (!this.data.chatPopupVisible) {
this.setData({
noViewChatList: this.data.noViewChatList += 1
})
}
item.timestamp = dayjs(item.timestamp).format('HH:mm:ss')
this.setData({
chatList: [...this.data.chatList, item]
})
this.scrollToBottom()
break;
// 扩展操作
case 'Operation':
// 4:屏幕共享
break;
// 全员离开房间
case 'AllLeave':
this.message('管理员已结束会议!').success()
wx.disableAlertBeforeUnload({
complete: () => {
wx.navigateBack()
}
})
break;
// 移出会议
case 'ForceExitRoom':
this.message('管理员已将你移出会议!').success()
wx.disableAlertBeforeUnload({
complete: () => {
wx.navigateBack()
}
})
break;
// 更新视图模式
case 'RefreshView':
break;
// 全员看他
case 'ShowUser':
if (item.operUid && item.operUserName) {
if (item.operUid !== userInfo.uid) {
if (item.uid === userInfo.uid) {
this.message(`${item.operUserName}设置全员看你`).success()
} else {
this.message(`${item.operUserName}设置全员看${item.uname}`).success()
}
}
}
this.getShowUser()
break;
// 用户加入频道回调
case 'UserJoined':
this.setAllUserListData('UserJoined', item)
break;
// 用户退出频道回调
case 'UserLeave':
this.setAllUserListData('UserLeave', item)
break;
// 所有用户开闭麦
case 'OperAllMicr':
this.setAllUserListData('OperAllMicr', item)
break;
// 用户关闭开启麦克风
case 'OperMicr':
if (item.operUid !== userInfo.uid) {
if (item.user.uid === userInfo.uid) {
this.message(item.user.enableMicr ? '管理员已取消你的静音' : '你已被管理员静音').success()
}
}
this.setAllUserListData('OperMicr', item)
break;
// 用户开启关闭摄像头
case 'OperCamera':
if (item.operUid !== userInfo.uid) {
if (item.user.uid === userInfo.uid) {
this.message(item.user.enableCamera ? '管理员已开启你的摄像头' : '管理员已关闭你摄像头').success()
}
}
this.setAllUserListData('OperCamera', item)
break;
// 发言人用户信息刷新
case 'ManagerRefresh':
this.setAllUserListData('ManagerRefresh', item, async () => {
if (item.user.uid === item.uid) {
if (item.user.uid === userInfo.uid) {
// await agora.allLeaveChannelEx()
this.message(`操作成功`).success()
await agora.setRole(item.user.isRoomManager, (url: string) => {
const roomUserListTemp = [...this.data.roomUserList]
const itemUser = roomUserListTemp.find(row => row.uid == userInfo.uid)
itemUser.src = url
this.setData({
roomUserList: roomUserListTemp,
})
})
await this.postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false)
await this.postOpenCameraApi(false, userInfo.uid) // 不管身份如何改变都关闭摄像头
} else {
this.message(`${item.user.userName}已结束发言`).success()
}
} else {
if (item.user.uid === userInfo.uid) {
if (item.user.isRoomManager) {
// await agora.allLeaveChannelEx()
}
this.message(`管理员${item.user.isRoomManager ? '设置' : '取消'}您为发言人`).success()
await agora.setRole(item.user.isRoomManager, (url: string) => {
const roomUserListTemp = [...this.data.roomUserList]
const itemUser = roomUserListTemp.find(row => row.uid == userInfo.uid)
itemUser.src = url
this.setData({
roomUserList: roomUserListTemp,
})
})
if (this.data.currentRequestSpeakType === 'video') {
await this.postOpenCameraApi(item.user.isRoomManager, userInfo.uid)
} else if (this.data.currentRequestSpeakType === 'audio') {
await this.postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false)
} else {
await this.postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false)
await this.postOpenCameraApi(false, userInfo.uid)
}
this.setData({
currentRequestSpeakType: ''
})
} else {
this.message(`管理员${item.user.isRoomManager ? '设置' : '取消'}${item.user.userName}为发言人`).success()
}
}
})
break;
// 申请发言
case 'ApplyToSpeak':
break;
// 管理员查看随机用户
case 'Watch':
if (!role.ID.includes(userInfo.roleId)) {
let userId = item.watchUids.find((uid: any) => uid === userInfo.uid)
if (userId) {
// await agora.allJoinChannelEx()
} else {
// await agora.allLeaveChannelEx()
}
}
break;
// 设备列表
case 'DriverList':
break;
// 设置设备
case 'SaveDriver':
break;
// 显示设备列表
case 'ShowDriverList':
break;
}
})
},
startClientEvent() {
agora.clientEvent({
streamAdded: async (url: string, uid: number | string) => {
const roomUserListTemp = [...this.data.roomUserList]
const item = roomUserListTemp.find(row => row.uid == uid || row.screenShareId == uid)
if (item) {
if (String(uid).length === 9) {
item.shareSrc = url
} else {
item.src = url
}
}
this.setData({
roomUserList: roomUserListTemp,
currentUser: item,
})
},
streamRemoved: (uid) => {
const roomUserListTemp = [...this.data.roomUserList]
uid.forEach(id => {
if (String(id).length === 9) {
const item = roomUserListTemp.find(row => row.uid == id || row.screenShareId == id)
item.shareSrc = ''
this.setData({
roomUserList: roomUserListTemp,
currentUser: item,
})
}
});
}
})
},
async getRoomUser(): Promise<void> {
await GetRoomUser(this.data.channelId).then(res => {
if (res.code === 200) {
res.data.forEach((item) => {
item.isRoom = true;
item.isAdmin = role.ID.includes(item.roleId) || item.isRoomManager
item.avatarName = item.userName?.slice(-2)
})
this.setData({
roomUserList: res.data
})
}
})
},
async getShowUser(): Promise<void> {
await GetShowUser(this.data.channelId).then(async (res) => {
if (res.code === 200 && res.data) {
const currentUser = this.data.roomUserList.find(row => row.uid == res.data || row.screenShareId == res.data)
this.setData({
currentUid: currentUser.uid,
currentUser,
})
}
})
},
async getRoomInfo(): Promise<void> {
await GetRoomInfo(this.data.channelId).then(async (res) => {
if (res.code === 200) {
this.setData({
roomInfo: res.data,
})
}
})
},
async joinChannel(): Promise<void> {
await onInvoke('joinChannel', {
roomNum: this.data.channelId,
enableMicr: this.data.footerList[1].active,
enableCamera: this.data.footerList[2].active,
})
await agora.joinChannel()
},
async setAllUserListData(key: string, item: any, callBack?: Function): Promise<void> {
const { roomUserList } = this.data;
const userInfo: any = await getStorage('user')
switch (key) {
case 'OperMicr':
case 'OperCamera':
case 'ManagerRefresh':
let userItem = roomUserList.find((row: any) => row.uid === item.user.uid)
if (userItem) {
for (const keys in item.user) {
if (keys !== 'enableCamera' && keys !== 'enableMicr') {
userItem[keys] = item.user[keys];
}
}
if (key === 'OperCamera') {
userItem.enableCamera = item.user.enableCamera;
if (userItem.uid === userInfo.uid) {
// userItem.enableCamera ? agora.startCameraCapture() : agora.stopCameraCapture()
}
}
if (key === 'OperMicr') {
userItem.enableMicr = item.user.enableMicr;
}
userItem.isAdmin = role.ID.includes(item.user.roleId) || item.user.isRoomManager;
this.setData({
roomUserList
})
}
if (key === 'ManagerRefresh') {
callBack && callBack()
}
break;
case 'UserJoined':
let userJoinedItem = roomUserList.find((row: any) => row.uid === item.user.uid)
if (userJoinedItem) {
for (const key in item.user) {
userJoinedItem[key] = item.user[key];
}
userJoinedItem.isRoom = true;
userJoinedItem.isAdmin = role.ID.includes(item.user.roleId) || item.user.isRoomManager;
this.setData({
roomUserList
})
} else {
item.user.isRoom = true;
item.user.isAdmin = role.ID.includes(item.user.roleId) || item.user.isRoomManager;
item.user.avatarName = item.user.userName?.slice(-2)
this.setData({
roomUserList: [...roomUserList, item.user]
})
}
break;
case 'UserLeave':
let userLeaveItem = roomUserList.find((row: any) => row.uid === item.uid)
if (userLeaveItem) {
userLeaveItem.isRoom = false
userLeaveItem.isAdmin = false
this.setData({
roomUserList
})
}
break;
case 'OperAllMicr':
roomUserList.forEach((row: any) => {
if (row.uid !== item.uid) {
row.enableMicr = item.enableMicr
}
})
this.setData({
roomUserList
})
break;
}
if (item.user && (item.user.uid === this.data.currentUid)) {
this.setData({
currentUser: roomUserList.find(row => row.uid == this.data.currentUid || row.screenShareId == this.data.currentUid)
})
}
this.changeAgoraDevice()
},
async changeFooterList(e): Promise<void> {
const userInfo: any = await getStorage('user')
const { index } = e.currentTarget.dataset;
const { footerList } = this.data;
const footerListTemplate = [...footerList]
const item = footerListTemplate[index];
let title = item.active ? item.title : item.titleActive;
switch (title) {
case '关闭听筒':
case '开启听筒':
break;
case '解除静音':
case '静音':
if (item.active) {
// 静音
await this.postOpenMicrApi(false, userInfo.uid, false, true)
} else {
// 解除静音
await this.getUserRoomInfo().then(async (res) => {
if (res) {
await this.postOpenMicrApi(true, userInfo.uid, false, true)
} else {
if (!this.data.isClicked) {
this.setData({
applySpeakDialog: true,
currentRequestSpeakType: 'audio'
})
} else {
this.message('申请太频繁了,请稍后重试!').error();
}
}
})
}
break;
case '关闭视频':
case '打开视频':
if (item.active) {
// 关闭视频
await this.postOpenCameraApi(false, userInfo.uid, true)
} else {
// 打开视频
await this.getUserRoomInfo().then(async (res) => {
if (res) {
await this.postOpenCameraApi(true, userInfo.uid, true)
} else {
if (!this.data.isClicked) {
this.setData({
applySpeakDialog: true,
currentRequestSpeakType: 'video'
})
} else {
this.message('申请太频繁了,请稍后重试!').error();
}
}
})
}
break;
case '申请发言':
case '结束发言':
if (item.active) {
// 申请发言
if (!this.data.isClicked) {
this.setData({
applySpeakDialog: true,
currentRequestSpeakType: ''
})
} else {
this.message('申请太频繁了,请稍后重试!').error();
}
} else {
// 结束发言
DeleteRoomManager({
roomId: this.data.roomInfo.id,
roomNum: this.data.channelId,
userId: userInfo.uid
})
}
break;
case '翻转':
await this.getUserRoomInfo().then(async (res) => {
if (res) {
wx.createLivePusherContext().switchCamera()
} else {
this.message('暂无权限').error();
}
})
break;
case '聊天':
this.setData({
chatPopupVisible: true,
noViewChatList: 0
})
this.scrollToBottom()
break;
case '成员':
this.setData({
userPopupVisible: true
})
break;
}
},
async postOpenMicrApi(enableMicr: boolean, uid: string, isAll: boolean, isMessage: boolean = false): Promise<void> {
if (isAll) {
await PostMuteAll({
roomNum: this.data.channelId,
enableMicr
})
} else {
await PostOpenMicr({
roomNum: this.data.channelId,
uid,
enableMicr
})
}
if (isMessage) {
this.message('操作成功').success()
}
},
async postOpenCameraApi(enableCamera: boolean, uid: string, isMessage: boolean = false): Promise<void> {
if (enableCamera) {
// await agora.startCameraCapture()
} else {
// await agora.stopCameraCapture();
}
await PostOpenCamera({
roomNum: this.data.channelId,
uid,
enableCamera
})
if (isMessage) {
this.message('操作成功').success()
}
},
async closeDialog(e) {
const { type } = e.currentTarget.dataset;
switch (e.type) {
case "confirm":
switch (type) {
case "applySpeakDialog":
await GetApplySpeak(this.data.channelId).then(res => {
if (res.code === 200) {
this.setData({
isClicked: true,
[type]: false,
})
this.message('申请发言成功').success()
}
})
break;
case "leaveDialog":
wx.disableAlertBeforeUnload({
complete: () => {
wx.navigateBack()
}
})
break;
}
break;
case "cancel":
this.setData({
[type]: false
})
break;
}
},
playerStateChange(e) {
},
recorderStateChange(e) {
},
playerAudioVolumenotify(e) {
const { uid } = e.currentTarget.dataset;
const { volume } = e.detail;
const audioListTemp = [...this.data.audioList]
const percentage = (volume / 100) * 100
const item = audioListTemp.find(row => row.uid == uid)
if (item) {
item.volume = Math.floor(percentage) + '%'
}
this.setData({
audioList: audioListTemp,
userVolume: audioListTemp.find(row => row.uid == this.data.user.uid).volume
})
},
clickChangeVideo(e) {
const { item } = e.currentTarget.dataset;
this.setData({
currentUser: item,
currentUid: item.uid
})
},
message(content: string) {
return {
success: () => {
Message.success({
context: this,
offset: [20, 32],
duration: 2000,
content,
});
},
error: () => {
Message.error({
context: this,
offset: [20, 32],
duration: 2000,
content,
});
}
}
},
async getUserRoomInfo(): Promise<any> {
const userInfo: any = await getStorage('user')
return new Promise((resolve, _reject) => {
let userItem = this.data.roomUserList.find((item: any) => item.uid === userInfo.uid)
if (userItem && (role.ID.includes(userItem.roleId) || userItem.isRoomManager)) {
resolve(userItem)
} else {
resolve('')
}
})
},
async changeAgoraDevice(): Promise<any> {
const userInfo: any = await getStorage('user')
this.data.roomUserList.forEach(async (item: any) => {
if (item.uid == userInfo.uid) {
const footerListTemplate = [...this.data.footerList]
footerListTemplate[1].active = item.enableMicr
footerListTemplate[2].active = item.enableCamera
item.enableMicr ? await agora.unmuteLocal('audio') : await agora.muteLocal('audio')
item.enableCamera ? await agora.unmuteLocal('video') : await agora.muteLocal('video')
if (!role.ID.includes(userInfo.roleId)) {
footerListTemplate[6].active = !item.isRoomManager;
}
this.setData({
footerList: footerListTemplate
})
}
});
},
async back() {
this.setData({
leaveDialog: true
})
},
onVisibleChange() {
this.setData({
userPopupVisible: false,
chatPopupVisible: false,
})
},
changeMessageStr(e) {
this.setData({
messageStr: e.detail.value
})
},
async sendMeg(e) {
if (this.data.messageStr || e.target.dataset.item) {
await onInvoke('sendChannelMsg', {
roomNum: this.data.channelId,
msg: e.target.dataset.item || this.data.messageStr
})
this.setData({
chatList: [...this.data.chatList, {
userName: this.data.user.userName,
message: e.target.dataset.item || this.data.messageStr,
timestamp: dayjs(+new Date()).format('HH:mm:ss'),
me: true
}],
messageStr: ''
})
this.scrollToBottom()
} else {
this.message('请输入文字!').error()
}
},
changeFullscreen() {
this.setData({
isFullscreen: !this.data.isFullscreen
})
},
scrollToBottom() {
wx.createSelectorQuery()
.select('#chatView')
.node()
.exec((res) => {
const scrollView = res[0].node;
scrollView.scrollTo({
top: 10000000000000
})
})
},
async listener(res) {
if (res.isConnected && (res.networkType !== 'none' || res.networkType !== 'unknown')) {
} else {
wx.setStorage({
key: "isConnected",
data: true
})
wx.disableAlertBeforeUnload({
complete: () => {
wx.navigateBack()
}
})
}
},
scroll(e) {
const query = wx.createSelectorQuery().in(this);
query.select('#meeting-content-smallvideo').boundingClientRect()
query.selectAll('.meeting-content-smallvideo-box').boundingClientRect()
query.exec((res) => {
const listItemRects = res[1];
listItemRects.forEach(rect => {
if (rect.dataset.item.src && rect.dataset.item.enableCamera) {
if (rect.top < res[0].height && rect.top + rect.height > 0) {
agora.unmute(Number(rect.dataset.item.uid), 'video')
} else {
if (rect.dataset.item.uid != this.data.currentUid) {
agora.mute(Number(rect.dataset.item.uid), 'video')
}
}
}
});
})
},
scrollUp() {
const query = wx.createSelectorQuery()
query.select('#meeting-content-smallvideo').scrollOffset((res => {
this.setData({
scrollTop: res.scrollTop - 50
})
}))
query.exec()
},
scrollDown() {
const query = wx.createSelectorQuery()
query.select('#meeting-content-smallvideo').scrollOffset((res => {
this.setData({
scrollTop: res.scrollTop + 50
})
}))
query.exec()
},
})