综合演练 语音聊天接口调整

剧本预览 代码调整
This commit is contained in:
joylink_cuiweidong 2020-05-14 14:36:15 +08:00
parent 352becd47b
commit 70f06409df
17 changed files with 1176 additions and 198 deletions

View File

@ -49,7 +49,7 @@ export function chatWithText(data, group) {
});
}
// 文字聊天 发送文字
// 文字聊天 发送语音
export function chatWithAudio(file, group) {
return request({
url: `/api/jointTraining/chatWithAudio?group=${group}`,
@ -58,6 +58,15 @@ export function chatWithAudio(file, group) {
});
}
// 文字聊天 发送语音(新版)
export function chatWithAudioNew(file, group) {
return request({
url: `/api/v1/jointTraining/chatWithAudio?group=${group}`,
method: 'post',
data: file
});
}
// 生成分发二维码
export function getJoinTrainCode(data, group) {
return request({

View File

@ -118,7 +118,7 @@ function handleRecordList(state, data) {
value: data.message,
self: isSelf,
voice: data.isAudio,
src: data.isAudio ? `${process.env.process.env.VUE_VOICE_API}/jlcloud/audio/${data.audioPath}` : '',
src: data.isAudio ? `/jlcloud/audio/${data.audioPath}` : '',
other: !isSelf,
userName: data.member.nickName,
chatTime: data.chatTime,

View File

@ -0,0 +1,422 @@
<template>
<!-- v-quickMenuDrag -->
<div class="chatBox">
<div v-show="!minimize" class="chat-box">
<chat-member-list ref="chatMemberList" :group="group" @addCoversition="addCoversition" />
<div class="chat-box-main">
<chat-coversition-list ref="chatCoversitionList" @setCurrentCoversition="setCurrentCoversition" @setHeadTitle="setHeadTitle" />
<div class="chat-window">
<div class="chat-box-header">
<div class="chat-box-header-title">{{ headerTitle }}</div>
<div class="minimality" @click="handleMinimality('min')">
<i class="el-icon-remove" />
</div>
<div v-show="currentCoversition.group==undefined?true:currentCoversition.group" class="showMembers" @click="handleMembers()">
<i class="el-icon-user-solid" />
</div>
<div class="chat-setting" @click="handleSetting()">
<i class="el-icon-s-tools" />
</div>
</div>
<div class="chat-box-content">
<chat-content ref="chatContent" :current-coversition="currentCoversition" />
<div v-if="recordSending" class="chat_record_tip">
<div id="record_progress_bar" :style="'width:'+100/60*seconds+'%'" />
<div class="record_icon" />
<div class="record_tip_text">正在录音...</div>
<div class="record_tip_confirm" @click="stopRecording()">确定</div>
<div class="record_tip_cancle" @click="cancleRecording()">取消</div>
</div>
</div>
<div class="chat-box-footer">
<div class="chat-box-footer-tool" />
<div class="chat-box-footer-send" @click="startRecording()">发送语音</div>
</div>
</div>
</div>
</div>
<div v-show="minimize" class="reminder-drag minimize-box">
<div class="chat-title">聊天窗口</div>
<div class="minimality" @click="handleMinimality('max')">
<i class="el-icon-circle-plus" />
</div>
</div>
<chat-setting ref="chatSetting" :form="form" @setSetting="setSetting" />
</div>
</template>
<script>
import ChatSetting from './chatSetting';
import ChatContent from './chatContent';
import ChatMemberList from './chatMemberList';
import ChatCoversitionList from './chatCoversitionList';
import RecordRTC from 'recordrtc';
import {uploadAudioFileNew} from '@/api/chat';
export default {
name: 'ChatBox',
components:{
ChatSetting,
ChatContent,
ChatMemberList,
ChatCoversitionList
},
props: {
group: {
type: String,
required: true
}
},
data() {
return {
minimize:false,
recordSending:false,
currentCoversition:{},
seconds:0,
inter:null,
recorders: null,
microphone:null,
form:{
language:'zh',
sex:'1'
},
headerTitle:'所有人'
};
},
watch: {
'$store.state.socket.simulationRoleList': function (val) {
if (val && val.length) {
this.$nextTick(() => {
this.$refs.chatMemberList.setMemberStatus(val);
this.$refs.chatCoversitionList.setCoversitionStatus(val);
});
}
}
},
mounted() {
this.initPage();
},
methods:{
async initPage() {
},
handleMinimality(data) {
if (data == 'min') {
this.minimize = true;
this.$refs.chatSetting.doClose();
} else {
this.minimize = false;
}
},
setSetting(data) {
this.form = data;
},
setCurrentCoversition(coversition) {
this.currentCoversition = coversition;
},
setHeadTitle(headerTitle) {
this.headerTitle = headerTitle;
},
addCoversition({data, headerTitle}) {
this.$refs.chatCoversitionList.addCoversition(data);
this.currentCoversition = {id:data.id, group:data.group};
this.headerTitle = headerTitle;
},
//
startRecording() {
const that = this;
if (!this.recordSending && !this.recorders && !this.microphone) {
this.$refs.chatSetting.doClose();
const StereoAudioRecorder = RecordRTC.StereoAudioRecorder;
navigator.getUserMedia(
{ audio: true } //
, function (stream) {
that.microphone = stream;
that.recorders = new RecordRTC(that.microphone, {
type: 'audio',
recorderType: StereoAudioRecorder,
numberOfAudioChannels: 1,
bitsPerSecond:256000,
desiredSampRate: 16000
});
that.recorders.startRecording();
that.recordSending = true;
that.inter = setInterval(() => {
if (that.seconds < 60) {
that.seconds++;
} else {
clearInterval(that.inter);
}
}, 1000);
}, function (error) {
switch (error.code || error.name) {
case 'PERMISSION_DENIED':
case 'PermissionDeniedError':
that.$message({
showClose: true,
message: '用户拒绝提供信息',
type: 'error'
});
break;
case 'NOT_SUPPORTED_ERROR':
case 'NotSupportedError':
that.$message({
showClose: true,
message: '浏览器不支持硬件设备',
type: 'error'
});
break;
case 'MANDATORY_UNSATISFIED_ERROR':
case 'MandatoryUnsatisfiedError':
that.$message({
showClose: true,
message: '无法发现指定的硬件设备',
type: 'error'
});
break;
default:
that.$message({
showClose: true,
message: '无法打开麦克风',
type: 'error'
});
break;
}
}
);
}
},
cancleRecording() {
if (this.microphone) {
clearInterval(this.inter);
this.seconds = 0;
this.microphone.stop();
this.microphone = null;
this.recordSending = false;
this.recorders = null;
}
},
//
stopRecording() {
const that = this;
this.recorders.stopRecording(function(blobURL) {
const data = URL.createObjectURL(that.recorders.getBlob());
console.log('--------', data);
clearInterval(that.inter);
that.seconds = 0;
const blob = that.recorders.getBlob();
const fd = new FormData();
fd.append('file', blob);
uploadAudioFileNew(that.group, that.form.language, that.form.sex, that.currentCoversition.id, fd)
.then((data) => {
})
.catch(error => {
console.log(error);
});
if (that.microphone) {
that.microphone.stop();
that.microphone = null;
that.recordSending = false;
that.recorders = null;
}
});
},
handleSetting() {
this.$refs.chatSetting.doShow();
},
handleMembers() {
this.$refs.chatSetting.doClose();
this.$refs.chatMemberList.doShow();
}
}
};
</script>
<style lang="scss" scoped>
.chatBox{
width: 503px;
height: 400px;
position: absolute;
padding-left:5px;
left: 0;
bottom:28px;
z-index:22;
}
.chat-box{
width: 100%;
height: 100%;
}
.chat-box-header{
width: 100%;
height: 40px;
border-bottom: 1px #dedede solid;
}
.chat-box-header-title{
font-size: 15px;
margin-left: 15px;
display: inline-block;
margin-top: 10px;
}
.chat-box-content{
width: 100%;
height: 300px;
border-bottom: 1px #dedede solid;
position: relative;
}
.chat-box-contentTip{
}
.chat-box-footer{
display: inline-block;
width: 100%;
}
.chat-window{
display: inline-block;
width: 400px;
}
.chat-setting{
float: right;
line-height: 40px;
margin-right: 10px;
cursor: pointer;
font-size: 16px;
}
.chat-box-footer-tool{
width: 100%;
height: 30px;
}
.chat-box-footer-send{
background: #36a2fd;
width: 65px;
font-size: 12px;
padding: 5px 0px 4px 0px;
text-align: center;
border-radius: 3px;
color: #fff;
float: right;
margin-right: 10px;
margin-bottom: 10px;
cursor: pointer;
}
.minimality {
float: right;
line-height: 40px;
margin-right: 10px;
cursor: pointer;
font-size:16px;
}
.chat-box-main{
position: absolute;
width: 100%;
left: 0;
height: 100%;
top: 0;
border-right: 1px #dedede solid;
z-index: 4;
background: #fff;
border-radius: 5px;
left:5px;
font-size:0;
}
.chat-coversition{
}
.coversition-list{
}
.showMembers{
float: right;
line-height: 40px;
margin-right: 10px;
cursor: pointer;
font-size: 17px;
}
#record_progress_bar{
height: 100%;
position: absolute;
background: #bbe5f5;
}
.chat_record_tip{
height: 28px;
display: inline-block;
background: #dfe6ee;
width: 100%;
font-size: 13px;
border-top: 1px #d8dce5 solid;
position: absolute;
bottom: 0;
right: 0;
}
.record_icon{
display: inline-block;
width: 8px;
height: 8px;
background: #25d825;
border-radius: 10px;
left: 7px;
margin-right: 0px;
box-shadow: -1px 0px 3px #6d6d6d;
border: 1px #28d228 solid;
position: absolute;
top: 10px;
}
.record_tip_text{
display: inline-block;
font-size: 12px;
margin-left: 3px;
// padding: 8px 0px 6px 0px;
position: absolute;
top: 8px;
left:20px
}
.record_tip_confirm{
position: absolute;
right: 63px;
padding: 3px 0px 2px 0px;
border: 1px #a2a5aa solid;
border-radius: 5px;
width: 45px;
text-align: center;
font-size: 12px;
top: 4px;
background: #eeeeee;
cursor: pointer;
}
.record_tip_cancle{
position: absolute;
right: 10px;
padding: 3px 0px 2px 0px;
border: 1px #a2a5aa solid;
border-radius: 5px;
width: 45px;
text-align: center;
font-size: 12px;
top: 4px;
background: #eeeeee;
cursor: pointer;
}
.minimize-box {
width: 97.5%;
height: 40px;
position: absolute;
left: 5px;
bottom: 0;
z-index: 222;
background: #fff;
border-radius: 5px;
.chat-title {
float: left;
font-size: 15px;
margin-left: 10px;
line-height: 40px;
}
.minimality {
float: right;
height: 40px;
line-height: 40px;
margin-right: 10px;
cursor: pointer;
}
}
</style>

View File

@ -0,0 +1,199 @@
<template>
<div class="chatcontentIn">
<div v-for="(chatContent,index) in chatContentList" :key="index" class="chatContentInClass">
<div :class="chatContent.self?'rightUser':'leftUser'">
<div class="userHeader">
<div v-if="chatContent.group&& !chatContent.self" class="userName">{{ covertName(chatContent.member) }}</div>
<div :class="chatContent.self?'userChatTime textRight':'userChatTime'">{{ formatTime(chatContent.chatTime) }}</div>
</div>
<div class="userBubble" @click="playAudio('audio'+index)">
<div class="userMessage">
<span v-if="chatContent.group||!chatContent.member.robot">@{{ covertName(chatContent.targetName) }}</span>
<span class="el-icon-video-play playicon" />
<span class="messageText">{{ chatContent.message }}</span>
<audio :id="'audio'+index" :src="baseUrl+chatContent.src" style="display:none" />
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {getSimulationContextListNew} from '@/api/chat';
import ConstConfig from '@/scripts/ConstConfig';
import Cookies from 'js-cookie';
export default {
props:{
currentCoversition:{
type:Object,
required:true
}
},
data() {
return {
chatContentList:[],
coversition:{},
baseUrl:process.env.VUE_APP_VOICE_API
};
},
watch:{
'$store.state.socket.simulationText':function (val, old) { // 仿
if (this.currentCoversition.id == val.conversationId) {
const simulationText = this.$store.state.socket.simulationText;
this.chatContentList.push(simulationText);
}
},
$route() {
this.inintData();
},
currentCoversition:function (val, old) {
if (val) {
this.chatContentList = [];
this.coversition = this.currentCoversition;
this.inintData();
}
}
},
mounted() {
// this.coversition = this.currentCoversition;
// this.inintData();
},
methods:{
inintData() {
getSimulationContextListNew(this.$route.query.group, this.coversition.id).then(res=>{
const userId = this.$store.state.user.id;
const coversitionList = res.data.map(coversition=>{
coversition.self = false;
if (coversition.member.userId == userId) {
coversition.self = true;
}
coversition.src = coversition.isAudio ? `/jlcloud/audio/${coversition.audioPath}` : '';
coversition.memberName = coversition.member.name;
coversition.targetName = coversition.targetMember ? coversition.targetMember : 'All';
coversition.memberRole = coversition.member.role;
return coversition;
});
this.chatContentList = coversitionList;
});
// const coversitionListAll = Object.assign({}, this.$store.state.socket.coversitionList);
// const coversitionList = coversitionListAll[this.coversition.id] || [];
// // console.log('inintData---coversitionList' + JSON.stringify(this.$store.state.socket.coversitionList[this.coversition.id]));
// this.chatContentList = coversitionList;
},
formatTime(time) {
return /\d{2}:\d{2}:\d{2}/.exec(time)[0] || time;
},
covertName(data) {
if (data != 'All') {
const roleTypeList = ConstConfig.ConstSelect.roleTypeNew;
roleTypeList.forEach(function(element) {
const rolename = element.value;
if (Cookies.get('user_lang') == 'en') {
if (rolename == data.role) {
data.role = element.enLabel;
}
} else {
if (rolename == data.role) {
data.role = element.label;
}
}
});
const deviceName = data.deviceName ? '-' + data.deviceName : '';
const memberName = data.name ? '-' + data.name : '';
return data.role + deviceName + memberName;
} else {
return 'All';
}
},
playAudio(id) {
document.querySelector('#' + id).play();
}
// reloadData(currentCoversition) {
// this.chatContentList = [];
// this.coversition = currentCoversition;
// this.inintData();
// }
}
};
</script>
<style lang="scss" scoped>
.chatcontentIn{
height: 100%;
width: 100%;
display: inline-block;
overflow: auto;
padding-bottom: 20px;
cursor:auto;
}
.leftUser{
float: left;
margin-left: 10px;
margin-top: 10px;
display: inline-block;
}
.rightUser{
float: right;
margin-right: 10px;
margin-top: 10px;
display: inline-block;
}
.userHeader{margin-bottom: 2px;}
.userName{font-size: 12px;display:inline-block;}
.userChatTime{font-size: 12px;display:inline-block;}
.userBubble{
max-width: 200px;
font-size: 12px;
padding: 10px;
background: #ccc;
border-radius: 5px;
cursor: pointer;
}
.playicon{
font-size: 20px;
vertical-align: top;
}
.textRight{text-align: right;width: 100%;}
.userMessage{}
.messageText{line-height: 20px;}
.chatContentInClass{
display: inline-block;
width: 100%;
}
// safariqq360
//
.chatcontentIn::-webkit-scrollbar {
width: 6px;
height: 6px;
// height: 110px;
background-color: #FFFFFF;
}
/*定义滚动条轨道 内阴影+圆角*/
.chatcontentIn::-webkit-scrollbar-track {
// box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
border-radius: 10px;
background-color: #FFFFFF;;
}
/*定义滑块 内阴影+圆角*/
.chatcontentIn::-webkit-scrollbar-thumb {
border-radius: 10px;
// box-shadow: inset 0 0 6px rgba(0,0,0,.3);
background-color: #cacaca;
}
/*滑块效果*/
.chatcontentIn::-webkit-scrollbar-thumb:hover {
border-radius: 5px;
// box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
background: rgba(0,0,0,0.4);
}
/*IE滚动条颜色*/
html {
scrollbar-face-color:#bfbfbf;/*滚动条颜色*/
scrollbar-highlight-color:#000;
scrollbar-3dlight-color:#000;
scrollbar-darkshadow-color:#000;
scrollbar-Shadow-color:#adadad;/*滑块边色*/
scrollbar-arrow-color:rgba(0,0,0,0.4);/*箭头颜色*/
scrollbar-track-color:#eeeeee;/*背景颜色*/
}
</style>

View File

@ -0,0 +1,168 @@
<template>
<div class="chat-coversition">
<div id="coversition-list-name" />
<div class="coversition-list">
<div
v-for="coversition in coversitionList"
:key="coversition.id"
:class="coversition.id==currentCoversition.id?'coversition-active each-coversition':'each-coversition'"
@click="changeCoversition(coversition)"
>{{ coversition.coverName }}</div>
</div>
</div>
</template>
<script>
import ConstConfig from '@/scripts/ConstConfig';
import Cookies from 'js-cookie';
import {getSimulationConversationListNew} from '@/api/chat';
export default {
name:'ChatCoversitionList',
data() {
return {
coversitionList:[],
currentCoversition:{}
};
},
mounted() {
this.initPage(true);
},
methods:{
initPage(status) {
getSimulationConversationListNew(this.$route.query.group).then(resp=>{
if (resp.data) {
const data = resp.data;
data.map(coversition=>{
const objectCover = this.handleMemberName(coversition);
coversition.coverName = objectCover.coversitionName;
coversition.isOnline = objectCover.isOnline;
return coversition;
});
this.coversitionList = data;
if (resp.data && resp.data.length && resp.data.length > 0 && status) {
this.currentCoversition = data[0];
this.$emit('setCurrentCoversition', resp.data[0]);
}
}
});
},
addCoversition(data) {
const index = this.coversitionList.findIndex(item=>{ return item.id == data.id; });
if (index < 0) {
const objectCover = this.handleMemberName(data);
data.coverName = objectCover.coversitionName;
data.isOnline = objectCover.isOnline;
this.coversitionList.push(data);
this.currentCoversition = data;
}
},
changeCoversition(coversition) {
this.$emit('setHeadTitle', !coversition.isOnline ? coversition.coverName + ' (离线)' : coversition.coverName);
this.currentCoversition = {id:coversition.id, group:coversition.group};
this.$emit('setCurrentCoversition', coversition);
// this.$refs.chatContent.reloadData(this.currentCoversition);
},
handleMemberName(conversition) {
if (conversition.group) {
return {coversitionName:conversition.name, isOnline:true};
} else {
let coversitionName = '';
let isOnline = true;
if (conversition.memberList) {
conversition.memberList.forEach(member=>{
if (member.userId != this.$store.state.user.id) {
const roleTypeList = ConstConfig.ConstSelect.roleTypeNew;
let data = member.role;
roleTypeList.forEach(function(element) {
const rolename = element.value;
if (Cookies.get('user_lang') == 'en') {
data = data.replace(rolename, element.enLabel);
} else {
data = data.replace(rolename, element.label);
}
});
const deviceName = member.deviceName ? '-' + member.deviceName : '';
const memberName = member.name ? '-' + member.name : '';
isOnline = member.online;
coversitionName = data + deviceName + memberName;
}
});
} else {
coversitionName = conversition.name;
}
return {coversitionName:coversitionName, isOnline:isOnline};
}
},
setCoversitionStatus(data) {
this.initPage(false);
this.$emit('setHeadTitle', !this.currentCoversition.isOnline ? this.currentCoversition.coverName + ' (离线)' : this.currentCoversition.coverName);
// this.changeCoversition(this.currentCoversition);
}
}
};
</script>
<style lang="scss" scoped>
.chat-coversition{
width: 100px;
display: inline-block;
border-right: 1px #dedede solid;
height: 100%;
vertical-align: top;
background: #f9f9f9;
border-radius: 5px 0px 0px 5px;
}
.coversition-list{
padding: 3px 0px 10px 0px;
height: 355px;
overflow: auto;
margin-top:40px;
}
.each-coversition{
font-size: 14px;
padding: 10px 7px 10px 10px;
border-bottom: 1px #dedede solid;
cursor: pointer;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.coversition-active{
background: #e0e0e0;
}
// safariqq360
//
.coversition-list::-webkit-scrollbar {
width: 6px;
height: 6px;
// height: 110px;
background-color: #FFFFFF;
}
/*定义滚动条轨道 内阴影+圆角*/
.coversition-list::-webkit-scrollbar-track {
// box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
border-radius: 10px;
background-color: #FFFFFF;;
}
/*定义滑块 内阴影+圆角*/
.coversition-list::-webkit-scrollbar-thumb {
border-radius: 10px;
// box-shadow: inset 0 0 6px rgba(0,0,0,.3);
background-color: #cacaca;
}
/*滑块效果*/
.coversition-list::-webkit-scrollbar-thumb:hover {
border-radius: 5px;
// box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
background: rgba(0,0,0,0.4);
}
/*IE滚动条颜色*/
html {
scrollbar-face-color:#bfbfbf;/*滚动条颜色*/
scrollbar-highlight-color:#000;
scrollbar-3dlight-color:#000;
scrollbar-darkshadow-color:#000;
scrollbar-Shadow-color:#adadad;/*滑块边色*/
scrollbar-arrow-color:rgba(0,0,0,0.4);/*箭头颜色*/
scrollbar-track-color:#eeeeee;/*背景颜色*/
}
</style>

View File

@ -0,0 +1,154 @@
<template>
<div :class="showMembers?'memberAnimate chat-box-members':'chat-box-members'">
<div class="chat-member-title">成员列表</div>
<div class="chat-member-list">
<div
v-for="member in memberList"
:key="member.id"
:class="member.online?'each-chat-member':'each-chat-member each-chat-member-outline'"
>{{ member.memberName }}</div>
</div>
</div>
</template>
<script>
import {getSimulationMembersNew} from '@/api/chat';
import ConstConfig from '@/scripts/ConstConfig';
import Cookies from 'js-cookie';
export default {
name: 'ChatMemberList',
props: {
group: {
type: String,
required: true
}
},
data() {
return {
showMembers:false,
memberList:[]
};
},
mounted() {
this.getSimulationMembers();
},
methods:{
setMemberStatus(memberInfo) {
this.getSimulationMembers();
// memberInfo.forEach(member=>{
// if (this.coversitionList) {
// this.coversitionList.forEach(item=>{
// if (item.id == member.id) {
// item.online = member.online;
// }
// });
// }
// });
},
getSimulationMembers() {
getSimulationMembersNew(this.$route.query.group).then(resp => {
let lastData = JSON.stringify(resp.data);
const roleTypeList = ConstConfig.ConstSelect.roleTypeNew;
roleTypeList.forEach(function(element) {
const rolename = element.value;
if (Cookies.get('user_lang') == 'en') {
lastData = lastData.replace(new RegExp(rolename, 'g'), element.enLabel);
} else {
lastData = lastData.replace(new RegExp(rolename, 'g'), element.label);
}
});
lastData = JSON.parse(lastData);
lastData.map(member=>{
const deviceName = member.deviceName ? '-' + member.deviceName : '';
const memberName = member.name ? '-' + member.name : '';
member.memberName = member.role + deviceName + memberName;
return member;
});
this.memberList = lastData;
});
},
doShow() {
if (this.showMembers) {
this.showMembers = false;
} else {
this.showMembers = true;
this.getSimulationMembers();
}
}
}
};
</script>
<style lang="scss" scoped>
.memberAnimate{
transform: translateX(97%);
}
.chat-box-members{
position: absolute;
width: 140px;
right: 0;
height: 100%;
background: #fff;
border-right: 1px #dedede solid;
border-radius: 0px 5px 5px 0px;
z-index: 2;
transition: transform 1s;
padding: 12px 2px 10px 16px;
font-size: 14px;
}
.chat-member-title{
}
.chat-member-list{
margin-top: 13px;
font-size: 12px;
margin-left: 2px;
height: 350px;
overflow-y: auto;
}
.each-chat-member{
margin-bottom: 10px;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
}
.each-chat-member-outline{
color: #ccc;
}
// safariqq360
//
.chat-member-list::-webkit-scrollbar {
width: 6px;
height: 6px;
// height: 110px;
background-color: #FFFFFF;
}
/*定义滚动条轨道 内阴影+圆角*/
.chat-member-list::-webkit-scrollbar-track {
// box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
border-radius: 10px;
background-color: #FFFFFF;;
}
/*定义滑块 内阴影+圆角*/
.chat-member-list::-webkit-scrollbar-thumb {
border-radius: 10px;
// box-shadow: inset 0 0 6px rgba(0,0,0,.3);
background-color: #cacaca;
}
/*滑块效果*/
.chat-member-list::-webkit-scrollbar-thumb:hover {
border-radius: 5px;
// box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
background: rgba(0,0,0,0.4);
}
/*IE滚动条颜色*/
html {
scrollbar-face-color:#bfbfbf;/*滚动条颜色*/
scrollbar-highlight-color:#000;
scrollbar-3dlight-color:#000;
scrollbar-darkshadow-color:#000;
scrollbar-Shadow-color:#adadad;/*滑块边色*/
scrollbar-arrow-color:rgba(0,0,0,0.4);/*箭头颜色*/
scrollbar-track-color:#eeeeee;/*背景颜色*/
}
</style>

View File

@ -0,0 +1,126 @@
<template>
<div v-show="dialogVisible" class="chat-popup">
<div class="chat-setting-header">
<div class="chat-setting-title">设置</div>
<div class="chat-setting-close">
<i class="el-icon-close" @click="dialogVisible=false" />
</div>
</div>
<div class="chat-setting-content">
<div class="chat-setting-language">
<div class="setting-language-title">语言: </div>
<el-switch
v-model="form.language"
class="setting-language-select"
active-color="#409EFF"
inactive-color="#ff4949"
active-text="中"
inactive-text="En"
active-value="zh"
inactive-value="en"
@change="changeLanguage()"
/>
</div>
<div class="chat-setting-sex">
<div class="setting-sex-title">性别: </div>
<el-switch
v-model="form.sex"
class="setting-sex-select"
active-color="#409EFF"
inactive-color="#ff4949"
active-icon-class="el-icon-male"
inactive-icon-class="el-icon-female"
active-value="1"
inactive-value="0"
@change="changeSex()"
/>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ChatSetting',
props:{
form:{
type:Object,
required:true
}
},
data() {
return {
dialogVisible: false,
loading:false
};
},
methods:{
doShow() {
this.dialogVisible = true;
},
doClose() {
this.dialogVisible = false;
},
changeLanguage() {
this.$emit('setSetting', this.form);
},
changeSex() {
this.$emit('setSetting', this.form);
}
}
};
</script>
<style lang="scss" scoped>
.chat-popup{
position: absolute;
width: 54%;
height: 143px;
border: 1px #dedede solid;
left: 33%;
top: 24%;
z-index: 7;
border-radius: 4px;
-webkit-box-shadow: 3px 3px 3px #dedede;
box-shadow: 3px 3px 3px #dedede;
background: #fff;
}
.chat-setting-header{
padding-left: 10px;
padding-top: 6px;
font-size: 14px;
border-bottom: 1px #dedede solid;
padding-bottom: 6px;
}
.chat-setting-title{
display: inline-block;
}
.chat-setting-close{
float: right;
display: inline-block;
margin-right: 5px;
font-size: 16px;
cursor: pointer;
}
.chat-setting-content{
}
.chat-setting-language,.chat-setting-sex{
display: inline-block;
margin-top: 20px;
}
.setting-language-title,.setting-sex-title{
display: inline-block;
font-size: 14px;
margin-left: 20px;
vertical-align: top;
margin-top: 3px;
}
.setting-language-select,.setting-sex-select{
display: inline-block;
vertical-align: top;
}
</style>
<style lang="scss">
.setting-sex-select .el-icon-male,.setting-sex-select .el-icon-female{
font-size:18px !important;
}
</style>

View File

@ -5,8 +5,6 @@
<map-system-draft ref="mapCanvas" @back="back" />
</transition>
<menu-lesson v-if="isLesson" ref="lessonMenu" :offset="offset" :group="group" :training-obj="trainingObj" />
<menu-demon
v-if="isDemon"
ref="menuDemon"
@ -20,10 +18,8 @@
@showScheduling="showScheduling"
/>
<menu-script v-if="isScript" ref="menuScript" :offset="offset" :group="group" />
<menu-schema
v-if="isDemon || isScript "
v-if="isDemon"
ref="menuSchema"
:offset="offset"
:offset-bottom="offsetBottom"
@ -42,7 +38,6 @@
<run-plan-Load ref="runPlanLoad" :group="group" />
<run-plan-view ref="runPlanView" :group="group" />
<add-quest ref="addQuest" @selectQuest="selectQuest" />
<scheduling v-if="isShowScheduling" ref="scheduling" :group="group" />
</div>
</template>
@ -54,9 +49,7 @@ import MapSystemDraft from '@/views/newMap/mapsystemNew/index';
import MenuDemon from '@/views/newMap/displayNew/menuDemon';
import MenuSchema from '@/views/newMap/displayNew/menuSchema';
import MenuSystemTime from '@/views/newMap/displayNew/menuSystemTime';
import MenuScript from '@/views/newMap/displayNew/menuScript';
import AddQuest from './demon/addQuest';
import Scheduling from './demon/scheduling';
import { mapGetters } from 'vuex';
import { setGoodsTryUse } from '@/api/management/goods';
import { clearSimulation, getSimulationInfoNew } from '@/api/simulation';
@ -80,12 +73,10 @@ export default {
AddQuest,
MapSystemDraft,
MenuDemon,
MenuScript,
MenuSchema,
MenuSystemTime,
// Jl3dSimulation,
Jl3dDrive,
Scheduling
Jl3dDrive
// Scheduling
},
props: {
size: {
@ -119,8 +110,7 @@ export default {
'04': '02', // =>
'05': '' // => null
},
isDrive: this.prdType == '04',
isShowScheduling: this.prdType == '05'
isDrive: this.prdType == '04'
};
},
computed: {
@ -146,9 +136,6 @@ export default {
right() {
return this.$store.state.config.width / 2 - 55;
},
trainingId() {
return this.$route.query.trainingId;
},
mapId() {
return this.$route.query.mapId;
},
@ -156,24 +143,12 @@ export default {
// return this.$route.query.prdType;
return this.$store.state.training.prdType;
},
skinCode() {
return this.$route.query.skinCode;
},
isLesson() {
return this.mode === 'teach' || this.mode === 'manage';
},
isDemon() {
return this.mode === 'demon';
},
isScript() {
return this.mode === 'script';
}
// isDrive() {
// return this.prdType == '04';
// },
// isShowScheduling() {
// return this.prdType == '05';
// }
},
watch: {
'$store.state.config.menuBarLoadedCount': function (val) {
@ -183,19 +158,12 @@ export default {
this.mapBoxP = document.getElementById(this.canvasId).children[0];
this.mapBoxP.style.cursor = '';
},
'$store.state.training.prdType': function(val) {
// this.prdType=val;
this.isDrive = (val == '04');
this.isShowScheduling = (val == '05');
},
'$store.state.socket.permissionOver': function () {
this.$alert('用户权限已被收回', '提示', {
confirmButtonText: '确定',
callback: action => {
this.back();
}
});
},
// '$store.state.training.prdType': function(val) {
// debugger;
// // this.prdType=val;
// this.isDrive = (val == '04');
// this.isShowScheduling = (val == '05');
// },
'$store.state.app.windowSizeCount': function() {
this.setWindowSize();
},
@ -322,8 +290,6 @@ export default {
await this.loadSimulationInfo();
if (this.isDemon) {
await this.initLoadDemonData();
} else if (this.isScript) {
await this.initLoadTaskData();
}
this.checkLoginLineTimer();
this.checkMouseStatusTimer();
@ -344,18 +310,6 @@ export default {
this.endViewLoading();
}
},
//
async initLoadTaskData() {
this.$store.dispatch('training/end', TrainingMode.NORMAL);
this.$store.dispatch('training/changeOperateMode', { mode: OperateMode.NORMAL }); //
this.switchMode('01');
if (this.group) {
await this.loadNewMapDataByGroup(this.group);
} else {
this.endViewLoading();
}
},
//
async runQuestLoadShow() {
this.$refs.addQuest.doShow();
@ -435,12 +389,8 @@ export default {
},
// 仿退
async back() {
if (this.isLesson) {
await this.$refs.lessonMenu.back();
} else if (this.isDemon) {
if (this.isDemon) {
await this.$refs.menuDemon.back();
} else if (this.isScript) {
await this.$refs.menuScript.back();
}
},
// 使
@ -491,9 +441,7 @@ export default {
this.$nextTick(() => {
const width = this.size ? this.size.width : this.width;
const height = this.size ? this.size.height : this.height;
this.$store.dispatch('config/resize', { width, height });
this.$store.dispatch('training/updateOffsetStationCode', { offsetStationCode: this.offsetStationCode });
});
}

View File

@ -1,5 +1,6 @@
<template>
<div>
<chat-box :group="group" />
<div class="display-card" :style="{top: offset+'px'}">
<el-row>
<span v-if="countTime" class="display-score">{{ $t('display.demon.trialTime') }} {{ countTime }}</span>
@ -32,6 +33,7 @@
<!-- 单人仿真 -->
<script>
import SetTime from './demon/setTime';
import ChatBox from './chatView/chatBox';
import { Notification } from 'element-ui';
import { getGoodsTryUse } from '@/api/management/goods';
import { ranAsPlan, exitRunPlan, clearSimulation } from '@/api/simulation';
@ -42,7 +44,8 @@ import { quitScript, quitScriptNew } from '@/api/simulation';
export default {
name: 'MenuDemon',
components: {
SetTime
SetTime,
ChatBox
},
props: {
group: {

View File

@ -117,7 +117,6 @@ export default {
addCoversition({data, headerTitle}) {
this.$refs.chatCoversitionList.addCoversition(data);
this.currentCoversition = {id:data.id, group:data.group};
this.$refs.chatCoversitionList.setCurrentCoversition(this.currentCoversition);
this.headerTitle = headerTitle;
},
//
@ -198,8 +197,6 @@ export default {
stopRecording() {
const that = this;
this.recorders.stopRecording(function(blobURL) {
const data = URL.createObjectURL(that.recorders.getBlob());
console.log('--------', data);
clearInterval(that.inter);
that.seconds = 0;
const blob = that.recorders.getBlob();
@ -211,7 +208,6 @@ export default {
.catch(error => {
console.log(error);
});
//
if (that.microphone) {
that.microphone.stop();
that.microphone = null;

View File

@ -39,7 +39,7 @@ export default {
});
this.coversitionList = data;
if (resp.data && resp.data.length && resp.data.length > 0 && status) {
this.currentCoversition = resp.data[0];
this.currentCoversition = data[0];
this.$emit('setCurrentCoversition', resp.data[0]);
}
}
@ -52,11 +52,9 @@ export default {
data.coverName = objectCover.coversitionName;
data.isOnline = objectCover.isOnline;
this.coversitionList.push(data);
this.currentCoversition = data;
}
},
setCurrentCoversition(data) {
this.currentCoversition = data;
},
changeCoversition(coversition) {
this.$emit('setHeadTitle', !coversition.isOnline ? coversition.coverName + ' (离线)' : coversition.coverName);
this.currentCoversition = {id:coversition.id, group:coversition.group};
@ -96,6 +94,7 @@ export default {
},
setCoversitionStatus(data) {
this.initPage(false);
this.$emit('setHeadTitle', !this.currentCoversition.isOnline ? this.currentCoversition.coverName + ' (离线)' : this.currentCoversition.coverName);
// this.changeCoversition(this.currentCoversition);
}
}

View File

@ -66,6 +66,12 @@ export default {
}
};
},
computed:{
drawWay() {
const drawWay = this.$route.query.drawWay;
return drawWay && JSON.parse(drawWay);
}
},
watch: {
'$store.state.scriptRecord.bgSet': function (val) {
this.backDisabled = val;
@ -103,7 +109,7 @@ export default {
}
},
pauseScript() {
if (this.$route.query.drawWay == 'true') {
if (this.drawWay) {
simulationPause(this.group).then(resp => {
this.$store.dispatch('scriptRecord/updateSimulationPause', true);
}).catch(() => {
@ -119,7 +125,7 @@ export default {
},
executePlayScript() {
if (this.$route.query.drawWay == 'true') {
if (this.drawWay) {
executeScriptNew(this.group).then(resp => {
this.$store.dispatch('scriptRecord/updateSimulationPause', false);
}).catch(() => {
@ -138,7 +144,7 @@ export default {
const data = Vue.prototype.$jlmap.$options;
const group = this.$route.query.group;
const dataZoom = {scale: data.scaleRate, x: data.offsetX, y: data.offsetY};
if (this.$route.query.drawWay == 'true') {
if (this.drawWay) {
saveScriptScenesNew(this.group).then(resp => {
updateMapLocationNew(group, dataZoom).then(response=>{
this.$store.dispatch('scriptRecord/updateBgSet', true);
@ -165,8 +171,7 @@ export default {
},
saveScenesData() {
this.isSavingScript = true;
if (this.$route.query.drawWay == 'true') {
if (this.drawWay) {
saveScriptDataNew(this.group).then(resp => {
this.$message.success(this.$t('scriptRecord.saveDataSucess'));
this.isSavingScript = false;
@ -204,7 +209,7 @@ export default {
cancelButtonText: this.$t('global.cancel'),
type: 'warning'
}).then(() => {
if (this.$route.query.drawWay == 'true') {
if (this.drawWay) {
dumpScriptDataNew(group).then(resp => {
this.$parent.$refs['display'].$refs['menuScript'].resetBeginTime();
this.$refs['getAction'].loadInitData();

View File

@ -30,7 +30,7 @@
</el-form-item>
</el-form>
</el-card>
<el-card v-if="this.$route.query.drawWay != 'true'" class="commandCard">
<el-card v-if="!drawWay" class="commandCard">
<div class="addCommand">{{ $t('scriptRecord.addCommand') }}</div>
<el-form ref="commandData" size="mini" :model="commandData" :rules="commandRules" label-width="120px" class="actionInfo" label-position="right">
<el-form-item :label="$t('scriptRecord.executor')" class="conditionVO" prop="action.memberId">
@ -181,6 +181,12 @@ export default {
}
};
},
computed:{
drawWay() {
const drawWay = this.$route.query.drawWay;
return drawWay && JSON.parse(drawWay);
}
},
watch:{
'$store.state.map.mapViewLoadedCount': function (val) {
Vue.prototype.$jlmap.setOptions(this.$store.state.scriptRecord.mapLocation);
@ -191,7 +197,7 @@ export default {
this.isPause = !(this.$store.state.scriptRecord.simulationPause);
this.$parent.$parent.$parent.setIsParse(this.isPause);
this.$refs['modalData'].clearValidate();
if (this.$route.query.drawWay == 'true') {
if (this.drawWay) {
this.$refs['commandDataNew'].clearValidate();
if (!val) {
this.initActionData();
@ -224,7 +230,7 @@ export default {
initData() {
this.buttonName = this.$t('scriptRecord.addConversitionButton');
this.operateType = 'add';
if (this.$route.query.drawWay == 'true') {
if (this.drawWay) {
getScriptPlayMemberNew(this.group).then(resp => {
this.orginMemberList = resp.data;
this.memberList = resp.data;
@ -385,7 +391,7 @@ export default {
const data = this.modalData.actionVO;
this.modifying = true;
if (this.operateType == 'add') {
if (this.$route.query.drawWay == 'true') {
if (this.drawWay) {
addScriptActionNew(group, data).then(response=>{
this.modifying = false;
this.$message.success(this.$t('scriptRecord.addConversitionSuccess'));
@ -512,7 +518,7 @@ export default {
}
},
resetData() {
if (this.$route.query.drawWay != 'true') {
if (!this.drawWay) {
this.$refs.command.resetData();
}
}

View File

@ -30,6 +30,12 @@ export default {
sexGroup: this.$t('scriptRecord.roleSexMale')
};
},
computed:{
drawWay() {
const drawWay = this.$route.query.drawWay;
return drawWay && JSON.parse(drawWay);
}
},
watch: {
'$store.state.socket.simulationStart': function (val) {
if (val) {
@ -43,7 +49,7 @@ export default {
methods: {
initData() {
const group = this.$props.group;
if (this.$route.query.drawWay == 'true') {
if (this.drawWay) {
getScriptMemberDataNew(group).then(response=>{
let lastData = JSON.stringify(response.data);
lastData = lastData.replace(new RegExp('id', 'g'), 'key');
@ -100,7 +106,7 @@ export default {
case 'right': {
const group = this.$props.group;
const data = movedKeys;
if (this.$route.query.drawWay == 'true') {
if (this.drawWay) {
selectScriptMembersNew(group, data).then(response=>{
this.$message.success(this.$t('scriptRecord.selectScriptActorSuccess'));
this.$emit('refresh');
@ -123,7 +129,7 @@ export default {
case 'left': {
const group = this.$props.group;
const data = movedKeys;
if (this.$route.query.drawWay == 'true') {
if (this.drawWay) {
cancleScriptMembersNew(group, data).then(response=>{
this.$emit('refresh');
this.$message.success(this.$t('scriptRecord.cancleScriptActorSuccess'));
@ -149,10 +155,9 @@ export default {
const data = {'gender': event};
modifyScriptMemberSex(group, id, data).then(response=>{
this.$message.success(this.$t('scriptRecord.modifyScriptActorSexSuccess'));
})
.catch(error => {
this.$messageBox(`${this.$t('scriptRecord.modifyScriptActorSexFail')}: ${error.message}`);
});
}).catch(error => {
this.$messageBox(`${this.$t('scriptRecord.modifyScriptActorSexFail')}: ${error.message}`);
});
}
}
};

View File

@ -62,6 +62,12 @@ export default {
signalName:''
};
},
computed:{
drawWay() {
const drawWay = this.$route.query.drawWay;
return drawWay && JSON.parse(drawWay);
}
},
watch: {
'$store.state.menuOperation.selectedCount':function(em) {
const device = this.$store.state.menuOperation.selected;
@ -77,7 +83,7 @@ export default {
getDeviceCode() {
const params = {deviceType:'StationStand'};
const group = this.$route.query.group;
if (this.$route.query.drawWay != 'true') {
if (!this.drawWay) {
getDeviceCodeByDeviceType(group, params).then(response =>{
let resultData = response.data;
resultData = JSON.parse(JSON.stringify(response.data).replace(/groupNumber/g, 'name'));

View File

@ -55,6 +55,12 @@ export default {
memberName: ''
};
},
computed:{
drawWay() {
const drawWay = this.$route.query.drawWay;
return drawWay && JSON.parse(drawWay);
}
},
watch: {
actionInfoList: function(val) {
this.$nextTick(function() {
@ -70,7 +76,7 @@ export default {
loadInitData() {
// const group=this.$route.query.group;
const data = {role: 'Driver'};
if (this.$route.query.drawWay != 'true') {
if (!this.drawWay) {
getAvailableDeviceCommand(data).then(response=>{
this.deviceCommandList = response.data;
this.loadOtherData(this.$route.query);
@ -81,7 +87,7 @@ export default {
},
loadOtherData(obj) {
const group = obj.group;
if (this.$route.query.drawWay == 'true') {
if (this.drawWay) {
getScriptPlayMemberNew(this.group).then(response => {
const memberVOList = response.data;
getScriptAllAction(group).then(resp=>{
@ -174,7 +180,7 @@ export default {
},
deleteAction(row) {
const group = this.$props.group;
if (this.$route.query.drawWay != 'true') {
if (!this.drawWay) {
deleteScriptAction(group, row).then(resp => {
this.reloadTable();
this.$message.success('删除行为动作成功');
@ -187,7 +193,7 @@ export default {
this.loadInitData();
},
modifyAction(row) {
if (this.$route.query.drawWay != 'true') {
if (!this.drawWay) {
this.$emit('setAction', row);
}
}

View File

@ -38,6 +38,7 @@
<div class="record_tip_cancle" @click="cancleRecording()">取消</div>
</div>
</div>
<audio ref="audio" />
<div class="chat__footer">
<div class="chat_tool">
<div class="microphoneBtn" @click="startRecording()">
@ -53,7 +54,7 @@
<script>
// import HZRecorder from '@/utils/HZRecorder';
import RecordRTC from 'recordrtc';
import { chatWithText, chatWithAudio } from '@/api/chat';
import { chatWithText, chatWithAudio, chatWithAudioNew } from '@/api/chat';
import { chatWithTextNew } from '@/api/jointTraining';
export default {
@ -81,7 +82,8 @@ export default {
recorders: null,
sending: false,
disabled:true,
microphone:null
microphone:null,
baseUrl:process.env.VUE_APP_VOICE_API
};
},
computed: {
@ -95,7 +97,8 @@ export default {
return this.$store.state.user ? this.$store.state.user.id : '';
},
drawWay() {
return this.$route.query.drawWay + '';
const drawWay = this.$route.query.drawWay;
return drawWay && JSON.parse(drawWay);
}
},
watch: {
@ -119,7 +122,7 @@ export default {
async handleSendText() {
try {
if (this.text.trim()) {
if (this.drawWay === 'true') {
if (this.drawWay) {
await chatWithTextNew(this.text, this.group);
} else {
await chatWithText(this.text, this.group);
@ -150,13 +153,17 @@ export default {
startRecording() {
const that = this;
if (!this.recordSending && !this.recorders && !this.microphone) {
const StereoAudioRecorder = RecordRTC.StereoAudioRecorder;
navigator.getUserMedia(
{ audio: true } //
, function (stream) {
that.microphone = stream;
that.recorders = new RecordRTC(that.microphone, {
type: 'audio',
checkForInactiveTracks: true
recorderType: StereoAudioRecorder,
numberOfAudioChannels: 1,
bitsPerSecond:256000,
desiredSampRate: 16000
});
that.recorders.startRecording();
that.recordSending = true;
@ -203,63 +210,33 @@ export default {
}
}
);
// HZRecorder.init.get(rec => {
// if (typeof rec == 'object') {
// this.recorders = rec;
// this.recorders.start();
// this.recordSending = true;
// }
// });
}
},
//
stopRecording() {
const that = this;
this.recorders.stopRecording(function(blobURL) {
const data = URL.createObjectURL(that.recorders.getBlob());
console.log('--------', data);
clearInterval(that.inter);
that.seconds = 0;
const blob = that.recorders.getBlob();
const fd = new FormData();
fd.append('file', blob);
chatWithAudio(fd, that.$route.query.group).then((res)=>{
this.recordSending = false;
that.$message({
showClose: true,
message: '语音发送成功',
type: 'success'
});
}).catch(error => {
// this.sending = false;
that.recordSending = false;
const message = JSON.parse(error.message);
if (message.err_no == 3301) {
that.$message({
showClose: true,
message: '音频质量有问题',
type: 'error'
if (that.drawWay) {
chatWithAudioNew(fd, that.group)
.then((data) => {
})
.catch(error => {
console.log(error);
});
} else if (message.err_no == 3308) {
that.$message({
showClose: true,
message: '音频过长,建议60s以下',
type: 'error'
} else {
chatWithAudio(fd, that.group)
.then((data) => {
})
.catch(error => {
console.log(error);
});
} else if (message.err_no == 3314) {
that.$message({
showClose: true,
message: '音频太短,建议重录',
type: 'error'
});
} else {
that.$message({
showClose: true,
message: '网络问题,请重试',
type: 'error'
});
}
});
}
if (that.microphone) {
that.microphone.stop();
that.microphone = null;
@ -267,57 +244,6 @@ export default {
that.recorders = null;
}
});
// this.sending = true;
// if (this.recorders) {
// this.recorders.stop();
// var fd = new FormData();
// fd.append('file', this.recorders.getBlob());
// chatWithAudio(fd, this.$route.query.group).then((res)=>{
// this.recordSending = false;
// this.$message({
// showClose: true,
// message: '',
// type: 'success'
// });
// }).catch(error => {
// // this.sending = false;
// this.recordSending = false;
// const message = JSON.parse(error.message);
// if (message.err_no == 3301) {
// this.$message({
// showClose: true,
// message: '',
// type: 'error'
// });
// } else if (message.err_no == 3308) {
// this.$message({
// showClose: true,
// message: ',60s',
// type: 'error'
// });
// } else if (message.err_no == 3314) {
// this.$message({
// showClose: true,
// message: ',',
// type: 'error'
// });
// } else {
// this.$message({
// showClose: true,
// message: '',
// type: 'error'
// });
// }
// });
// this.recorders = null;
// } else {
// // this.sending = false;
// this.$message({
// showClose: true,
// message: ',',
// type: 'error'
// });
// }
},
cancleRecording() {
if (this.microphone) {
@ -330,7 +256,7 @@ export default {
}
},
playAudio(nor) {
this.$refs.audio.src = nor.src;
this.$refs.audio.src = this.baseUrl + nor.src;
this.$refs.audio.play();
}
}