<template>
<div class="main">
<div class="row">
<div class="left" :style="obj">
<!-- top -->
<div class="top">
<span>频道号:2066909 <i>无直播</i> </span>
<span>经典儿童言语康复案例解析</span>
<span>
<i>网络延时:10ms</i>
<i style="padding: 0 2px;">丢包率:{{videoPacketsLostRate}}%</i>
<i> <span></span><span class="span"></span><span></span>网络状态</i>
</span>
</div>
<!-- bottom -->
<div class="bottom">
<div class="bottom_l">
<div class="t">
<!-- tab -->
<div class="baiban">
<i class="el-icon-edit-outline" style="font-size:24px;"></i>
<p>白板</p>
</div>
<div class="baiban">
<i class="el-icon-document" style="font-size:24px;"></i>
<p>课件</p>
</div>
<div class="baiban">
<i class="el-icon-video-camera" style="font-size:24px;"></i>
<p>多媒体</p>
</div>
<div class="baiban">
<i class="el-icon-monitor" style="font-size:24px;"></i>
<p>屏幕共享</p>
</div>
<div class="baiban yingyong" @mouseenter="onMousehoverYing($event)" @mouseleave="onMouseleaveYing($event)">
<i class="el-icon-copy-document" style="font-size:24px;"></i>
<p>应用</p>
</div>
</div>
<div class="b">
<span>
<el-button class="oneBtn" type="primary" @click="startPublishingStream" circle>开始</el-button>
</span>
<span>
<el-button type="primary" class="btn two" size="small" icon="el-icon-share" circle></el-button>
</span>
<span>
<el-button type="primary" class="btn" size="small" icon="el-icon-setting" circle></el-button>
</span>
</div>
</div>
<div class="ar-main" style="width:100%;height: 100%;">
<div class="bottom_r ar-video_wrap" ref="canvasWrap">
<!-- 应用bar -->
<div class="bar" v-show="showBar" @mouseenter="onMousehoverYing($event)" @mouseleave="onMouseleaveYing($event)" style="display: none;">
<!-- tab -->
<div class="baiban">
<i class="el-icon-location-outline" style="font-size:24px;"></i>
<p>签到</p>
</div>
<div class="baiban">
<i class="el-icon-date" style="font-size:24px;"></i>
<p>公告</p>
</div>
<div class="baiban">
<i class="el-icon-document-copy" style="font-size:24px;"></i>
<p>问卷</p>
</div>
<div class="baiban">
<i class="el-icon-document-checked" style="font-size:24px;"></i>
<p>答题卡</p>
</div>
<div class="baiban">
<i class="el-icon-trophy" style="font-size:24px;"></i>
<p>抽奖</p>
</div>
</div>
<!-- 白板区域 -->
<div id="myCanvas" ref="canvas" class="canvas"></div>
<!-- 上一页、下一页 -->
<ul class="ar-block">
<li>
<el-button type="warning" size="mini" @click="boardPrePage">上一页</el-button>
</li>
<li class="gray" style="margin:0 15px;">
<el-button type="text">
{{nBgIndex}} / {{nBgTotal}}
</el-button>
</li>
<li>
<el-button type="danger" size="mini" @click="boardNextPage">下一页</el-button>
</li>
</ul>
<!-- tools -->
<div class="tools">
<div class="board-tools-menu">
<!-- 画笔 -->
<el-tooltip class="item" effect="dark" content="画笔" placement="left">
<div class="itemtools">
<i class="el-icon-edit" style="font-size:18px" @click="setBrushModel(1)"></i>
</div>
</el-tooltip>
<!-- 箭头 -->
<el-tooltip class="item" effect="dark" content="箭头" placement="left">
<div class="itemtools">
<i class="el-icon-top-left" style="font-size:18px" @click="setBrushModel(2)"></i>
</div>
</el-tooltip>
<!-- 直线 -->
<el-tooltip class="item" effect="dark" content="直线" placement="left">
<div class="itemtools">
<i class="el-icon-minus" style="font-size:18px" @click="setBrushModel(3)"></i>
</div>
</el-tooltip>
<!-- 矩形 -->
<el-tooltip class="item" effect="dark" content="矩形" placement="left">
<div class="itemtools">
<i class="el-icon-full-screen" style="font-size:18px" @click="setBrushModel(4)"></i>
</div>
</el-tooltip>
<div class="itemtools">
<i class="el-icon-rank" style="font-size:18px"></i>
</div>
<!-- 颜色 -->
<el-tooltip class="item" effect="dark" content="颜色" placement="left">
<div class="itemtools">
<el-color-picker v-model="color1" size="mini" @change='setBrushColor' @active-change='activesetBrushColor'></el-color-picker>
</div>
</el-tooltip>
<!-- 撤销 -->
<el-tooltip class="item" effect="dark" content="撤销" placement="left">
<div class="itemtools">
<i class="el-icon-refresh-left" style="font-size:18px" @click="undo"></i>
</div>
</el-tooltip>
<!-- <div class="itemtools">
<i class="el-icon-refresh-right" style="font-size:18px"></i>
</div> -->
<el-tooltip class="item" effect="dark" content="清除画板" placement="left">
<div class="itemtools">
<i class="el-icon-error" style="font-size:18px" @click="clearBoard"></i>
</div>
</el-tooltip>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="right" :style="obj">
<!-- avatar -->
<div class="avatar" id="local_stream" @mouseenter="onMousehoverEnv($event)" @mouseleave="onMouseleaveEnv($event)">
<!-- toobar -->
<div class="toobar" style="display: none;">
<span>
<img :src="getItemIcon1()" alt="" v-show='showTagVideo' @click="closeVideo" class="imgIcon" width="30">
<img :src="getItemIcon2()" alt="" v-show='!showTagVideo' @click="openVideo" class="imgIcon" width="30">
</span>
<span style="margin:0 15px;">
<img :src="getItemIcon3()" class="imgIcon" alt="" width="30">
</span>
<span>
<img :src="getItemIcon4()" class="imgIcon" alt="" width="30">
</span>
</div>
<!-- 底部状态栏 -->
<div class="b_toobar">
<span>(我)2076282</span>
<span>
<i class="el-icon-bell" style="font-size:20px;margin-right:5px;"></i>
<i class="el-icon-microphone" style="font-size:20px;"></i>
</span>
</div>
<!-- avatar_live.png -->
<div class="live" v-show="!showTagVideo">
<img src="http://erkong.ybc365.com/b4576202012231731231009.png" alt="">
</div>
<!-- 视频区域 -->
<video v-show="showTagVideo" autoplay muted id='video' :src-object.prop="stream" width="100%" height="100%"></video>
</div>
<!-- tabs -->
<ul class="tabs">
<li class="li-tab" v-for="(item,index) in tabsParam" @click="toggleTabs(index)" :class="{active:index==nowIndex}">
{{item =='成员'?item+`(${index})`:item}}</li>
</ul>
<div class="divTab1" v-show="nowIndex===0">
<div class="content" ref="logView">
<div class="ar-rtcp_log" ref="logList">
<div :class="['ar-rtcp_log_item', {'error': log.type === 'error'}]" v-for="(log, n) in logs" :key="n">{{log.content}}</div>
</div>
</div>
<div class="send">
<div class="check">
<span>
<i class="el-icon-picture-outline-round biaoqingicon"></i>
</span>
<span>
<el-checkbox v-model="checked">屏蔽打赏</el-checkbox>
</span>
</div>
<div class="input">
<el-input class="textarea" type="textarea" placeholder="我也来参与一下互动" v-model="textarea" maxlength="200" show-word-limit rows="3"
resize='none'>
</el-input>
<div class="sendBtn">
<div>聊天室已开启</div>
<div>
<span style="margin-right:15px;">0/200</span>
<span class="senBtntxt">
发送
</span>
</div>
</div>
</div>
</div>
</div>
<div class="divTab2" v-show="nowIndex===1">
22
</div>
</div>
</div>
</div>
</template>
<script>
// import { ZegoExpressEngine } from 'zego-express-engine-webrtc'
import { ZegoExpressEngine } from 'zego-express-whiteboard-web'
import ArWhiteBoard from 'ar-whiteboard';
import 'ar-whiteboard/lib/index.css';
import config from "../config.js";
// AppID:1974122008
// AppSign: 52db995b730066c45a659f8f4217676eb56346d621f98f97b50dca32882cd98a
const controlBtnList = [
{
name: 'camera',
cnName: '摄像头',
imgSrc: {
open: require('../assets/icons/room/mumber_camer.svg'),
close: require('../assets/icons/room/mumber_camer_close.svg')
}
},
{
name: 'mic',
cnName: '麦克风',
imgSrc: {
open: require('../assets/icons/room/mumber_micophone.svg'),
close: require('../assets/icons/room/mumber_micophone_close.svg')
}
},
]
export default {
data() {
return {
showTagVideo: true,
showBar: false,
checked: false,
textarea: "",
tabsParam: ['聊天', '成员'],
nowIndex: 0,//默认第一个tab为激活状态
obj: {
height: (document.documentElement.clientHeight || document.body.clientHeight) + 'px',
},
controlBtnList,
userID: '888',
AppID: 1974122008,
AppSign: '52db995b730066c45a659f8f4217676eb56346d621f98f97b50dca32882cd98a',
zg: {},
token1: "",
stream: {},
videoPacketsLostRate: 0,
backgroundList: [//画板背景图,第一次初始化后生效(调用注销画板API后将会清空)
{
board_background: 'https://convertcdn.netless.link/staticConvert/c2753d604fcf11ebafaa5169bd346aaa/1.png',
board_number: 1
},
{
board_background: 'https://convertcdn.netless.link/staticConvert/ffd4d0c04fee11ebb53249a29571d554/8.png',
board_number: 2
},
{
board_background: 'https://convertcdn.netless.link/staticConvert/c2753d604fcf11ebafaa5169bd346aaa/1.png',
board_number: 3
},
{
board_background: 'https://convertcdn.netless.link/staticConvert/c2753d604fcf11ebafaa5169bd346aaa/1.png',
board_number: 4
},
{
board_background: 'https://convertcdn.netless.link/staticConvert/c2753d604fcf11ebafaa5169bd346aaa/1.png',
board_number: 5
},
{
board_background: 'https://convertcdn.netless.link/staticConvert/c2753d604fcf11ebafaa5169bd346aaa/1.png',
board_number: 6
},
{
board_background: 'https://convertcdn.netless.link/staticConvert/c2753d604fcf11ebafaa5169bd346aaa/1.png',
board_number: 7
},
{
board_background: 'https://convertcdn.netless.link/staticConvert/c2753d604fcf11ebafaa5169bd346aaa/1.png',
board_number: 8
},
{
board_background: 'https://convertcdn.netless.link/staticConvert/c2753d604fcf11ebafaa5169bd346aaa/1.png',
board_number: 9
},
{
board_background: 'https://convertcdn.netless.link/staticConvert/c2753d604fcf11ebafaa5169bd346aaa/1.png',
board_number: 10
}
],
roomId: "",
Board: null,
userId: `${parseInt(Math.random() * 1000000)}`,
roomId: '',
fileId: '77777',
logs: [],
nBgIndex: 1,
nBgTotal: 1,
color1: "#ff000"
}
},
methods: {
getItemIcon1() {
return this.controlBtnList[0].imgSrc.open
},
getItemIcon2() {
return this.controlBtnList[0].imgSrc.close
},
getItemIcon3() {
return this.controlBtnList[1].imgSrc.open
},
getItemIcon4() {
return this.controlBtnList[1].imgSrc.close
},
onMousehoverEnv(e) {
e.target.parentElement.querySelector(".toobar").style.display = "block"
},
onMouseleaveEnv(e) {
e.target.parentElement.querySelector(".toobar").style.display = "none"
},
onMousehoverYing(e) {
this.showBar = true
},
onMouseleaveYing(e) {
this.showBar = false
},
toggleTabs(index) {
this.nowIndex = index;
},
// 关闭摄像头
closeVideo() {
this.showTagVideo = !this.showTagVideo
this.$message.error('摄像头已关闭,观众将看不到您的画面')
},
// 启用摄像头
openVideo() {
this.showTagVideo = !this.showTagVideo
this.$message.success('摄像头已打开')
},
// 获取token的方法
getTokenFun(appID, userID) {
return new Promise((resolve, reject) => {
const xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = e => {
if (xmlhttp.readyState == 4) {
if (xmlhttp.status == 200) {
resolve(xmlhttp.response);
} else {
reject(e);
}
}
};
xmlhttp.open(
"GET",
`https://wsliveroom-alpha.zego.im:8282/token?app_id=${appID}&id_name=${userID}`,
true
);
xmlhttp.send(null);
});
},
// 获取token
async getToken() {
this.token1 = await this.getTokenFun(this.AppID, this.userID)
this.loginRoom()
},
// 登陆房间
async loginRoom() {
const result = await this.zg.loginRoom('666', this.token1, { userID: this.userID, userName: 'aaa' });
this.createStr()
},
// 创建流和渲染
async createStr() {
this.stream = await this.zg.createStream();
},
// 开始推流、开始直播
startPublishingStream() {
this.zg.startPublishingStream('123', this.stream)
},
addLog(type, strLog) {
this.logs.push({
type: type,
content: strLog
});
this.$nextTick(() => {
let logView = this.$refs.logView.getBoundingClientRect();
let logList = this.$refs.logList.getBoundingClientRect();
if (logList.height > logView.height) {
this.$refs.logView.scrollTop = (logList.height - logView.height);
}
});
},
//改变窗口大小
handleResize(e) {
let that = this;
let w = that.$refs.canvasWrap.offsetWidth;
let h = that.$refs.canvasWrap.offsetHeight;
let Width = '';
let Height = '';
if (w / (16 / 9) > h) {
Height = h;
Width = h * (16 / 9);
} else {
Width = w;
Height = w / (16 / 9);
}
that.$refs.canvas.style.width = Width + 'px';
that.$refs.canvas.style.height = Height + 'px';
that.Board && that.Board.setCanvasSize(Width, Height);
},
//清除白板
clearBoard() {
this.Board.clearCurrentDraw();
},
//上一页
boardPrePage() {
this.Board.prePage(true);
},
//下一页
boardNextPage() {
this.Board.nextPage(true);
},
// 设置画笔类型
setBrushModel(type) {
this.Board.setBrushModel(type);
},
// 撤销
undo() {
this.Board.undo();
},
//设置画笔的颜色
setBrushColor() {
this.Board.setBrushColor(this.color1);
},
activesetBrushColor(e) {
this.Board.setBrushColor(e);
}
},
mounted() {
window.onresize = () => {
return (() => {
this.obj.height = (document.documentElement.clientHeight
|| document.body.clientHeight) + 'px'
})()
}
// 初始化实例
this.zg = new ZegoExpressEngine(this.AppID, 'wss://webliveroom-test.zego.im/ws')
// this.zegoExpressDocs = new ZegoExpressDocs({appID, token, userID, isTestEnv});
// 获取token执行登陆房间操作
// this.getToken()
// 监听zg连接状态
this.zg.on('roomStateUpdate', (roomID, state, errorCode, extendedData) => {
if (state == 'DISCONNECTED') {
// 与房间断开了连接
console.log('与房间断开了连接');
}
if (state == 'CONNECTING') {
// 与房间尝试连接中
console.log('与房间尝试连接中');
}
if (state == 'CONNECTED') {
// 与房间连接成功
this.$message.success('登陆成功')
}
})
// 监听推流状态
this.zg.on('publisherStateUpdate', result => {
// 推流状态变更通知
this.$message.success('推流成功')
})
this.zg.on('publishQualityUpdate', (streamID, stats) => {
// 推流质量
console.log(stats);
this.videoPacketsLostRate = (stats.video.videoTransferFPS).toFixed(2)
})
// --------------------------------------------------------- //
// 白板相关
this.roomId = '1115009980';
this.$nextTick(() => {
this.Board = new ArWhiteBoard("myCanvas");
this.addLog('info', `方法:initEngineWithARInfo,画板初始化`);
//配置私有云白板服务器,如果使用公有云请忽略
config.whiteBoardServeUrl && this.Board.configServerUrl(config.whiteBoardServeUrl);
this.Board.initEngineWithARInfo(config.appid, config.apptoken).then(res => {
if (res.code === 0) {
this.Board.initWithRoomID(this.roomId, this.fileId, this.userId, this.backgroundList).then(res => {
if (res.code === 0) {
let data = res.data;
this.addLog('info', `方法:initWithRoomID成功`);
this.addLog('info', `方法:setBrushModel,设置画笔类型`);
//type Number 画笔的类型 0不可编辑1涂鸦(默认)2箭头3直线4矩形
this.Board.setBrushModel(1);
//console.log(this.Board.getBrushModel())//获取画笔的类型
//设置画笔的粗细
this.addLog('info', `方法:setBrushWidth,设置画笔的粗细`);
this.Board.setBrushWidth(4);
// 设置画笔的颜色
this.addLog('info', `方法:setBrushColor,设置画笔的颜色`);
this.Board.setBrushColor('#ff0000');
this.nBgIndex = data.currPageIndex;
this.nBgTotal = data.maxPageIndex;
// this.backgroundList = data.backgroundList;
}
}).catch(err => {
console.log("initWithRoomID err", err);
});
}
}).catch(err => {
console.log(err);
});
//监听离开
this.Board.on("onBoardDestroy", () => {
console.log("onBoardDestroy");
});
//监听错误
this.Board.on("onBoardError", (code) => {
console.log(code);
});
//监听画板变化
this.Board.on("onBoardPageChange", (currentPage, totalPage, backgroundUrl) => {
this.nBgIndex = currentPage;
this.nBgTotal = totalPage;
});
})
this.$nextTick(() => {
this.handleResize();
})
window.addEventListener('resize', this.handleResize, false);
},
watch: {
showBar() {
if (this.showBar) {
document.querySelector(".yingyong").style.color = "#3595fb"
document.querySelector(".yingyong").style.background = "#363644"
} else {
document.querySelector(".yingyong").style.color = ""
document.querySelector(".yingyong").style.background = ""
}
}
}
}
</script>
<style lang="scss" scoped>
.main {
.row {
display: flex;
.left {
background: #eee;
min-height: 650px;
flex: 1;
min-width: 1000px;
.top {
height: 49px;
background: #191a1c;
display: flex;
justify-content: space-between;
align-items: center;
color: #adadc0;
font-size: 14px;
padding: 0 15px;
span {
&:first-child {
i {
font-style: normal;
border: 1px solid #adadc0;
border-radius: 2px;
padding: 0 8px;
margin-left: 16px;
color: #fff;
}
}
&:nth-child(2) {
color: #fff;
font-size: 16px;
}
&:nth-child(3) {
i {
font-style: normal;
&:nth-child(2) {
margin: 0 12px;
}
&:nth-child(3) {
span {
display: inline-block;
width: 1px;
background: #5fb430;
&:first-child {
height: 4px;
}
&:nth-child(2) {
height: 7px;
}
&:nth-child(3) {
height: 10px;
margin-right: 5px;
}
}
.span {
margin: 0 3px;
}
}
}
}
}
}
.bottom {
display: flex;
height: calc(100% - 49px);
width: 100%;
font-size: 13.5px;
.bottom_l {
background: #191a1c;
height: 100%;
width: 80px;
color: #adadc0;
display: flex;
flex-direction: column;
justify-content: space-between;
text-align: center;
.t {
width: 100%;
height: 50%;
p {
margin: 0;
}
.baiban {
width: 100%;
height: 75px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
p {
margin-top: 6px;
}
&:hover {
background: #363644;
cursor: pointer;
color: #3595fb;
}
}
}
.b {
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-around;
padding: 15px 0;
.oneBtn {
width: 55px;
height: 55px;
}
.btn {
background: #26272e;
border-color: #26272e;
font-size: 16px;
}
.two {
margin: 15px 0;
}
}
}
.bottom_r {
flex: 1;
background: #f5f7ff;
height: 100%;
position: relative;
.bar {
width: 80px;
background: #363644;
height: 100%;
color: #adadc0;
position: absolute;
top: 0px;
z-index: 1;
p {
margin: 0;
}
.baiban {
width: 100%;
height: 75px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
p {
margin-top: 6px;
}
&:hover {
background: #363644;
cursor: pointer;
color: #fff;
}
}
}
}
}
}
.right {
background: #191a1c;
min-height: 650px;
min-width: 256px;
width: 256px;
.avatar {
width: 100%;
height: 168px;
background: #363636;
color: #fff;
position: relative;
box-shadow: inset 0px -6px 18px -10px #000;
.toobar {
position: absolute;
bottom: 0;
top: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.5);
text-align: center;
line-height: 150px;
z-index: 99;
.imgIcon {
cursor: pointer;
}
}
.b_toobar {
width: 100%;
position: absolute;
bottom: 0;
font-size: 12px;
padding: 2px 4px;
display: flex;
align-items: center;
justify-content: space-between;
z-index: 98;
}
.live {
position: absolute;
bottom: 0;
top: 25%;
left: 0;
right: 0;
text-align: center;
img {
width: 66px;
}
}
}
.tabs {
padding: 0;
margin: 0;
width: 100%;
display: flex;
justify-content: space-around;
background: #363644;
color: #fff;
font-size: 13px;
.li-tab {
height: 100%;
display: inline-block;
text-align: center;
padding: 10px 0 5px 0;
&:hover {
cursor: pointer;
}
}
.active {
border-bottom: 2px solid #fff;
}
}
.divTab1 {
color: #fff;
font-size: 12px;
height: calc(100% - 341px);
.content {
padding: 10px 10px 0 10px;
height: 100%;
overflow: auto;
}
.send {
height: 142px;
// background: red;
.check {
height: 30px;
background: #363644;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 10px;
.biaoqingicon {
cursor: pointer;
font-size: 20px;
}
::v-deep .el-checkbox__input.is-checked + .el-checkbox__label {
color: #fff;
}
::v-deep .el-checkbox {
color: #fff;
}
::v-deep .el-checkbox__label {
margin-top: 1px;
}
}
.input {
height: calc(100% - 30px);
position: relative;
.textarea {
height: 85%;
::v-deep .el-textarea__inner {
border: none;
background-color: transparent;
color: #fff;
font-size: 12px;
&::placeholder {
font-size: 12px;
}
}
}
.sendBtn {
position: absolute;
bottom: 0;
background: #333;
width: 100%;
padding: 12px 10px;
display: flex;
justify-content: space-between;
align-items: center;
.senBtntxt {
background: #3595fb;
padding: 4px 14px;
border-radius: 30px;
cursor: pointer;
}
}
}
}
}
}
#video {
object-fit: cover;
}
.canvas {
height: 100% !important;
position: relative;
z-index: 0;
}
.ar-block {
display: flex;
position: absolute;
bottom: 0;
right: 8px;
align-items: center;
li {
list-style: none;
}
}
.tools {
position: absolute;
right: 0px;
top: 50px;
width: 55px;
z-index: 2;
.board-tools-menu {
padding: 2px 0;
display: flex;
flex-direction: column;
width: 46px;
min-height: 46px;
border-radius: 6px;
background-color: rgba(51, 51, 51, 0.4);
justify-content: center;
align-items: center;
pointer-events: all;
.itemtools {
width: 38px;
height: 38px;
background: #565656;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
border-radius: 4px;
color: #fff;
margin-bottom: 6px;
&:first-child {
margin-top: 3px;
}
&:last-child {
margin-bottom: 3px;
}
&:hover {
background: #141414;
border: 1px solid #eee;
}
::v-deep .el-color-picker__trigger {
border: none;
}
}
}
}
}
}
</style>
网友评论