2023-11-10 18:57:18 +08:00
|
|
|
<template>
|
2024-01-18 10:46:33 +08:00
|
|
|
<div class="page">
|
|
|
|
|
<div class="roompage" @mouseover="mouseHover" v-if="modileFlag">
|
|
|
|
|
<div class="txtContent">
|
|
|
|
|
<el-tag type="danger" @click="txtContent">会议内容</el-tag>
|
|
|
|
|
</div>
|
|
|
|
|
<div :class="userClass" :style="{ height: userHeight }" id="localStream">
|
|
|
|
|
<div class="userName">{{ userId }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div :class="userClass" :style="{ height: userHeight }" v-for="(item, index) in userList" :key="index"
|
|
|
|
|
:id="item">
|
|
|
|
|
<div class="userName">{{ item }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="footer" v-show="showFlag">
|
|
|
|
|
<roomFooter @exitRoom="exitRoom" :roomId="roomId"></roomFooter>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="roomPhone" v-if="!modileFlag">
|
|
|
|
|
<div class="header">
|
|
|
|
|
<roomFooterPhone @exitRoom="exitRoom"></roomFooterPhone>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="bodyVideo">
|
|
|
|
|
<div :class="userClassPhone" id="localStream">
|
|
|
|
|
<div class="userNamePhone">{{ userId }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div :class="userClassPhone" v-for="(item, index) in userList" :key="index" :id="item">
|
|
|
|
|
<div class="userNamePhone">{{ item }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- 语音转文字弹窗 -->
|
|
|
|
|
<el-drawer title="会议内容" :visible.sync="textVisible" :modal="false">
|
|
|
|
|
<quill-editor ref="myQuillEditor" v-model="contentValue" :options="editorOption" @blur="onEditorBlur($event)"
|
|
|
|
|
@focus="onEditorFocus($event)" @ready="onEditorReady($event)"></quill-editor>
|
|
|
|
|
<el-button class="updataBtn" @click="updataClick" type="primary" :disabled="!updataFlag">确认修改内容</el-button>
|
|
|
|
|
</el-drawer>
|
2023-11-10 18:57:18 +08:00
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
2024-01-18 10:46:33 +08:00
|
|
|
import { getUsersig, reserveConferenceList } from '@/api/home';
|
|
|
|
|
import { secretaryRoleByUserId, htmlToPDF } from '@/api/room'
|
|
|
|
|
import { getWidth, getHeight, getWidthPhone, getModile } from "@/utils/utils";
|
|
|
|
|
import roomFooter from './components/roomFooter.vue';
|
|
|
|
|
import roomFooterPhone from "./components/footerPhone.vue";
|
|
|
|
|
import ASR from '../utils/asr.esm.js'
|
|
|
|
|
import TRTC from 'trtc-sdk-v5';
|
|
|
|
|
let trtc = null;
|
|
|
|
|
import 'quill/dist/quill.core.css'
|
|
|
|
|
import 'quill/dist/quill.snow.css'
|
|
|
|
|
import 'quill/dist/quill.bubble.css'
|
|
|
|
|
import { quillEditor } from 'vue-quill-editor'
|
2023-11-10 18:57:18 +08:00
|
|
|
export default {
|
2024-01-18 10:46:33 +08:00
|
|
|
name: 'App',
|
|
|
|
|
components: {
|
|
|
|
|
roomFooter,
|
|
|
|
|
roomFooterPhone,
|
|
|
|
|
quillEditor
|
|
|
|
|
},
|
2023-11-10 18:57:18 +08:00
|
|
|
data() {
|
|
|
|
|
return {
|
2024-01-18 10:46:33 +08:00
|
|
|
userClass: "userVideo5",
|
|
|
|
|
userClassPhone: "userVideoPhone",
|
|
|
|
|
userList: [],
|
|
|
|
|
userHeight: '100%',
|
|
|
|
|
userPhoneHeight: '92%',
|
|
|
|
|
userSign: "",
|
|
|
|
|
roomId: "",
|
|
|
|
|
userId: null,
|
|
|
|
|
id: null,
|
|
|
|
|
showFlag: false,
|
|
|
|
|
modileFlag: false,
|
|
|
|
|
localStreamAsr: null,
|
|
|
|
|
contentValue: '',
|
|
|
|
|
textVisible: false,
|
|
|
|
|
editorOption: {
|
|
|
|
|
// Some Quill options...
|
|
|
|
|
},
|
|
|
|
|
asrList: {},
|
|
|
|
|
updataFlag: true,
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
// 点击提交修改后的内容
|
|
|
|
|
updataClick() {
|
|
|
|
|
this.contentValue = this.contentValue.replace(/<br>/g,"");
|
|
|
|
|
htmlToPDF({
|
|
|
|
|
caseId: this.caseId,
|
|
|
|
|
htmlContent: this.contentValue
|
|
|
|
|
}).then(res => {
|
|
|
|
|
if (res.code == 200) {
|
|
|
|
|
this.$message({
|
|
|
|
|
message: "提交修改成功",
|
|
|
|
|
type: 'success'
|
|
|
|
|
})
|
|
|
|
|
}else{
|
|
|
|
|
this.$message({
|
|
|
|
|
message: res.msg,
|
|
|
|
|
type: 'error'
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
onEditorBlur(quill) {
|
|
|
|
|
console.log('editor blur!', this.content, quill)
|
|
|
|
|
},
|
|
|
|
|
onEditorFocus(quill) {
|
|
|
|
|
if (!this.updataFlag) {
|
|
|
|
|
quill.enable(false)
|
|
|
|
|
} else {
|
|
|
|
|
quill.enable(true)
|
|
|
|
|
}
|
|
|
|
|
console.log('editor focus!', quill)
|
|
|
|
|
},
|
|
|
|
|
onEditorReady(quill) {
|
|
|
|
|
console.log('editor ready!', quill)
|
|
|
|
|
},
|
|
|
|
|
onEditorChange({ quill, html, text }) {
|
|
|
|
|
console.log('editor change!', quill, html, text)
|
|
|
|
|
this.content = html
|
|
|
|
|
},
|
|
|
|
|
// 点击显示修改的文本框
|
|
|
|
|
txtContent() {
|
|
|
|
|
this.textVisible = true;
|
|
|
|
|
},
|
|
|
|
|
// 鼠标滑过显示操作栏
|
|
|
|
|
mouseHover() {
|
|
|
|
|
this.showFlag = true;
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.showFlag = false;
|
|
|
|
|
}, 4000)
|
|
|
|
|
},
|
|
|
|
|
async exitRoom() {
|
|
|
|
|
// // 关闭识别
|
|
|
|
|
Object.keys(this.asrList).forEach(key => {
|
|
|
|
|
this.asrList[key].stop();
|
|
|
|
|
})
|
|
|
|
|
this.localStreamAsr.stop();
|
|
|
|
|
await trtc.exitRoom();
|
|
|
|
|
await trtc.updateLocalVideo({ publish: false });
|
|
|
|
|
await trtc.updateLocalAudio({ publish: false });
|
|
|
|
|
await trtc.destroy();
|
|
|
|
|
this.$router.push({
|
|
|
|
|
name: "Home"
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 获取拉流信息
|
|
|
|
|
getPushVideo() {
|
|
|
|
|
trtc.on(TRTC.EVENT.REMOTE_VIDEO_AVAILABLE, event => {
|
|
|
|
|
const userId = event.userId;
|
|
|
|
|
const streamType = event.streamType;
|
|
|
|
|
this.userList.push(userId);
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
let aoido = trtc.getAudioTrack(userId)
|
|
|
|
|
this.asrList[this.userList[this.userList.length - 1]] = new ASR({
|
|
|
|
|
secretKey: 'INDrIXcT8YmomZBcsy0oNirnU0LTN4X7',
|
|
|
|
|
secretId: 'AKID3xfHgroY4MQHvLXUXMwIQL1UjmbBX1Tv',
|
|
|
|
|
appId: 1304001529,
|
|
|
|
|
engine_model_type: '16k_zh',
|
|
|
|
|
voice_format: 1,
|
|
|
|
|
needvad: 1,
|
|
|
|
|
audioTrack: aoido,
|
|
|
|
|
})
|
|
|
|
|
this.asrList[this.userList[this.userList.length - 1]].start();
|
|
|
|
|
// 开始识别
|
|
|
|
|
this.asrList[this.userList[this.userList.length - 1]].OnRecognitionStart = (res) => {
|
|
|
|
|
console.log('远端流:开始识别', res);
|
|
|
|
|
};
|
|
|
|
|
this.asrList[this.userList[this.userList.length - 1]].OnError = (res) => {
|
|
|
|
|
console.log('远端流:识别失败', res);
|
|
|
|
|
};
|
|
|
|
|
// 一句话结束
|
|
|
|
|
this.asrList[this.userList[this.userList.length - 1]].OnSentenceEnd = (res) => {
|
|
|
|
|
console.log('远端流:一句话结束', res);
|
|
|
|
|
this.contentValue = this.contentValue + `<h2>${userId}</h2>` + `<span>${res.result.voice_text_str}</span>`;
|
|
|
|
|
};
|
|
|
|
|
}, 2000);
|
|
|
|
|
|
|
|
|
|
if (this.modileFlag) {
|
|
|
|
|
this.userClass = getWidth(this.userList);
|
|
|
|
|
this.userHeight = getHeight(this.userList);
|
|
|
|
|
} else {
|
|
|
|
|
this.userClassPhone = getWidthPhone(this.userList);
|
|
|
|
|
}
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
trtc.startRemoteVideo({ userId, streamType, view: `${userId}` })
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// })
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 删除退出会议人员列表
|
|
|
|
|
deletePushVideo() {
|
|
|
|
|
trtc.on(TRTC.EVENT.REMOTE_VIDEO_UNAVAILABLE, event => {
|
|
|
|
|
const userId = event.userId;
|
|
|
|
|
if (this.hostId == userId) {
|
|
|
|
|
alert('主持人已经解散会议')
|
|
|
|
|
this.$router.push({
|
|
|
|
|
name: 'Home'
|
|
|
|
|
})
|
|
|
|
|
this.userList = [];
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
let deleteIndex = this.userList.indexOf(userId);
|
|
|
|
|
this.userList = this.userList.filter(item => item !== userId);
|
|
|
|
|
if (deleteIndex !== -1) {
|
|
|
|
|
this.userList.splice(deleteIndex, 1)
|
|
|
|
|
}
|
|
|
|
|
if (this.modileFlag) {
|
|
|
|
|
this.userClass = getWidth(this.userList);
|
|
|
|
|
this.userHeight = getHeight(this.userList);
|
|
|
|
|
} else {
|
|
|
|
|
this.userClassPhone = getWidthPhone(this.userList);
|
|
|
|
|
}
|
|
|
|
|
Object.keys(this.asrList).forEach(key => {
|
|
|
|
|
this.asrList[userId].stop();
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 根据caseId查询房间相关信息
|
|
|
|
|
reserveConferenceListFn(data) {
|
|
|
|
|
reserveConferenceList(data).then(res => {
|
|
|
|
|
this.hostId = res.data[0].userName;
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 根据userid查询是否是秘书角色
|
|
|
|
|
secretaryRoleByUserIdFn(data) {
|
|
|
|
|
secretaryRoleByUserId(data).then(res => {
|
|
|
|
|
console.log(res.data.isSecretaryRole, 'kkkkkkkkkkkkkkk');
|
|
|
|
|
this.updataFlag = res.data.isSecretaryRole;
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
computed: {
|
|
|
|
|
editor() {
|
|
|
|
|
return this.$refs.myQuillEditor.quill
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
async mounted() {
|
|
|
|
|
// 判断设备类型
|
|
|
|
|
this.modileFlag = getModile();
|
|
|
|
|
let roomId = this.$route.query.roomId;
|
|
|
|
|
this.roomId = this.$route.query.roomId;
|
|
|
|
|
let userId = this.$route.query.userId;
|
|
|
|
|
this.userId = this.$route.query.userId;
|
|
|
|
|
this.caseId = this.$route.query.caseId;
|
|
|
|
|
this.id = this.$route.query.id;
|
|
|
|
|
this.secretaryRoleByUserIdFn(this.id)
|
|
|
|
|
// 获取主持人的userId
|
|
|
|
|
this.reserveConferenceListFn(this.caseId)
|
|
|
|
|
const sdkAppId = 1600011167;
|
|
|
|
|
// 获取usersign
|
|
|
|
|
await getUsersig(userId).then(res => {
|
|
|
|
|
this.userSign = res.msg;
|
|
|
|
|
})
|
|
|
|
|
this.getPushVideo();
|
|
|
|
|
this.deletePushVideo();
|
|
|
|
|
try {
|
|
|
|
|
await trtc.enterRoom({ roomId: Number(roomId), scene: 'rtc', sdkAppId, userId, userSig: this.userSign });
|
|
|
|
|
await trtc.startLocalVideo({
|
|
|
|
|
view: document.getElementById('localStream'), // 在 DOM 中的 elementId 为 localStream 的标签上预览视频。
|
|
|
|
|
});
|
|
|
|
|
await trtc.startLocalAudio();
|
|
|
|
|
console.log('进房成功');
|
|
|
|
|
this.$message({
|
|
|
|
|
message: "进房成功",
|
|
|
|
|
type: 'success'
|
|
|
|
|
})
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('进房失败 ' + error);
|
|
|
|
|
this.$message({
|
|
|
|
|
message: "进房失败",
|
|
|
|
|
type: 'error'
|
|
|
|
|
});
|
2024-01-20 17:32:07 +08:00
|
|
|
// this.$router.push({
|
|
|
|
|
// name: 'Home'
|
|
|
|
|
// })
|
2024-01-18 10:46:33 +08:00
|
|
|
}
|
|
|
|
|
this.localStreamAsr = new ASR({
|
|
|
|
|
secretKey: 'INDrIXcT8YmomZBcsy0oNirnU0LTN4X7',
|
|
|
|
|
secretId: 'AKID3xfHgroY4MQHvLXUXMwIQL1UjmbBX1Tv',
|
|
|
|
|
appId: 1304001529,
|
|
|
|
|
engine_model_type: '16k_zh',
|
|
|
|
|
voice_format: 1,
|
|
|
|
|
needvad: 1,
|
|
|
|
|
audioTrack: trtc.getAudioTrack(),
|
|
|
|
|
});
|
|
|
|
|
this.localStreamAsr.start();
|
|
|
|
|
// 开始识别
|
|
|
|
|
this.localStreamAsr.OnRecognitionStart = (res) => {
|
|
|
|
|
console.log('本地流:开始识别', res);
|
|
|
|
|
};
|
|
|
|
|
this.localStreamAsr.OnError = (res) => {
|
|
|
|
|
console.log('本地流:识别失败', res);
|
|
|
|
|
};
|
|
|
|
|
// 一句话结束
|
|
|
|
|
this.localStreamAsr.OnSentenceEnd = (res) => {
|
|
|
|
|
console.log('本地流:一句话结束', res);
|
|
|
|
|
// this.contentValue = `<h2>${this.userId}</h2>` + `<span>${res.result.voice_text_str}</span>`;
|
|
|
|
|
this.contentValue = this.contentValue + `<h2>${this.userId}</h2>` + `<span>${res.result.voice_text_str}</span>`;
|
2023-11-10 18:57:18 +08:00
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
created() {
|
2024-01-18 10:46:33 +08:00
|
|
|
trtc = TRTC.create();
|
2023-11-10 18:57:18 +08:00
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
</script>
|
|
|
|
|
|
2024-01-18 10:46:33 +08:00
|
|
|
<style scoped>
|
|
|
|
|
.roompage {
|
2023-11-10 18:57:18 +08:00
|
|
|
width: 100%;
|
2024-01-18 10:46:33 +08:00
|
|
|
height: 100vh;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: space-around;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
position: relative;
|
2023-11-10 18:57:18 +08:00
|
|
|
}
|
|
|
|
|
|
2024-01-18 10:46:33 +08:00
|
|
|
.txtContent {
|
|
|
|
|
width: 100px;
|
|
|
|
|
height: 50px;
|
|
|
|
|
position: absolute;
|
|
|
|
|
right: 5px;
|
|
|
|
|
top: 20px;
|
|
|
|
|
z-index: 10;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.userVideo,
|
|
|
|
|
.userVideo1,
|
|
|
|
|
.userVideo2,
|
|
|
|
|
.userVideo3,
|
|
|
|
|
.userVideo4,
|
|
|
|
|
.userVideo5 {
|
|
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.userVideo5 {
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.userVideo {
|
|
|
|
|
width: 48%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.userVideo1 {
|
|
|
|
|
width: 33%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.userVideo2 {
|
|
|
|
|
width: 33%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.userVideo3 {
|
|
|
|
|
width: 33%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.userVideo4 {
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.footer {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 10%;
|
|
|
|
|
background: rgb(46 43 43 / 90%);
|
|
|
|
|
position: absolute;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
z-index: 10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.userName {
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
width: 90px;
|
|
|
|
|
height: 40px;
|
|
|
|
|
text-align: center;
|
|
|
|
|
line-height: 40px;
|
|
|
|
|
background-color: black;
|
|
|
|
|
position: absolute;
|
|
|
|
|
right: 0;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
z-index: 9;
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.userNamePhone {
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
min-width: 20%;
|
|
|
|
|
height: 30px;
|
|
|
|
|
line-height: 30px;
|
|
|
|
|
text-align: center;
|
|
|
|
|
background-color: black;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
position: absolute;
|
|
|
|
|
right: 0;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
z-index: 9;
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.header {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 8%;
|
|
|
|
|
background-color: #716c6c;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: row-reverse;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.roomPhone {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100vh;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.bodyVideo {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 92%;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
/* justify-content: space-between; */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.userVideoPhone {
|
2023-11-10 18:57:18 +08:00
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
2024-01-18 10:46:33 +08:00
|
|
|
background-color: yellow;
|
|
|
|
|
position: relative;
|
2023-11-10 18:57:18 +08:00
|
|
|
}
|
2024-01-18 10:46:33 +08:00
|
|
|
|
|
|
|
|
.userVideoPhone1 {
|
|
|
|
|
width: 50%;
|
|
|
|
|
flex-basis: calc(33.333% - 3px);
|
|
|
|
|
max-width: calc(33.333% - 3px);
|
|
|
|
|
height: 200px;
|
|
|
|
|
/* height: 0; */
|
|
|
|
|
/* padding-bottom: calc(33.333% - 3px); */
|
|
|
|
|
margin-bottom: 3px;
|
|
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.quill-editor {
|
|
|
|
|
height: 70%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.updataBtn {
|
|
|
|
|
width: 100%;
|
|
|
|
|
position: absolute;
|
|
|
|
|
bottom: 8px;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|