聊天室调整

This commit is contained in:
fan 2022-12-02 17:22:51 +08:00
parent fe5ce61325
commit 42d8e9fe60
4 changed files with 513 additions and 3 deletions

View File

@ -116,7 +116,8 @@ const socket = {
nextStationName: '',
endStationName: ''
},
simulationWorkParam: {}
simulationWorkParam: {},
conversationMessage: {}
},
getters: {
},
@ -381,6 +382,9 @@ const socket = {
},
setSimulationWorkParam: (state, data) => {
state.simulationWorkParam = data;
},
setConversationMessage: (state, message) => {
state.conversationMessage = message;
}
},
@ -604,6 +608,9 @@ const socket = {
},
setSimulationWorkParam: ({ commit }, data) => {
commit('setSimulationWorkParam', data);
},
setConversationMessage: ({ commit }, message) => {
commit('setConversationMessage', message);
}
}
};

View File

@ -68,7 +68,7 @@ function handle(data) {
handleSimulationInfo(msg);
break;
case 'Simulation_Conversation_Operation': // 仿真-用户交互消息(聊天/命令)-新
handleSimulationInfo({id: msg.id, message: msg, messageType: 'MESSAGE'});
store.dispatch('socket/setConversationMessage', msg);
break;
case 'Simulation_ApplyHandle': // 请求处理消息(旧版可能在用,新版地图不用这个)
store.dispatch('socket/handlePushMsgQueue', msg);

View File

@ -27,7 +27,7 @@ import TrainingTip from './trainingList/trainingTip';
import TrainingPositionTip from './trainingList/trainingPositionTip.vue';
import TrainingMenu from './trainingList/trainingMenu';
import TrainingDesign from './trainingDesign/designPane.vue';
import VoiceChatBox from './voiceChatBox';
import VoiceChatBox from './voiceChatBox/chatBox';
import DesignTrainingMenu from './trainingList/designTrainingMenu';
export default {
name: 'DisplayDraft',

View File

@ -0,0 +1,503 @@
<template>
<div v-quickMenuDrag class="voice-chat-box">
<div v-if="min" :id="sideButtonDom.domId" @click="clickBtn">
<el-button circle style="color: #0C161A;" icon="el-icon-mic" />
</div>
<div v-show="!min" class="chat-box-main">
<div class="chat-box-header">
<div style="margin-right: 10px;cursor: pointer;">
<i class="el-icon-minus" style="color: #000;" @click="minimize" />
</div>
</div>
<div class="chat-box-content">
<div v-for="(content,index) in messageList" :key="index" style="width: 100%;height: 65px;">
<div :class="content.memberId == myMemberId?'rightUser':'leftUser'">
<div class="userHeader">
<div class="userName">{{ covertName(content.memberId) }}</div>
<div :class="content.memberId == myMemberId?'userChatTime textRight':'userChatTime'">{{ content.time }}</div>
</div>
<div v-if="content.type === 'Text'" class="userBubble">
<div class="userMessage">
<span class="messageText">{{ content.content }}</span>
</div>
</div>
<div v-else class="userBubble" style="height: 30px;width: 140px;" @click="playAudio(content.audioPath, content)">
<div class="userMessage">
<div class="wifi-symbol">
<div class="wifi-circle first" />
<div class="wifi-circle second" :class="{'second-amit': content.activeAuto}" />
<div class="wifi-circle third" :class="{'third-amit': content.activeAuto}" />
</div>
</div>
</div>
</div>
</div>
</div>
<div class="chat-box-footer">
<el-input v-model="textContent" size="small" placeholder="请输入会话文字点击T发送" style="flex: 1; margin-left: 5px;" :rows="1" />
<el-button :id="sendTextId" size="mini" class="chat-box-footer-create" :disabled="contentSend" @click="sendText">T</el-button>
<el-button class="chat-box-footer-create chat-box-footer-send" :class="{'active': recordSending}" :disabled="audioPlay" size="mini" type="primary" @click="startRecording()">
<el-progress id="voice_progress_bar" type="circle" :show-text="false" :percentage="100/60*seconds" :width="40" :stroke-width="2" status="success" />
<i v-if="recordSending" class="el-icon-close close_icon" @click.stop="cancelRecording()" />
<span class="iconfont icon-yuyin">&#xe62b;</span>
</el-button>
</div>
</div>
<audio id="audioPlay" style="display:none" />
</div>
</template>
<script>
import RecordRTC from 'recordrtc';
import {sendChatAudioBase64, getAllConversition} from '@/api/chat';
import { OperationEvent } from '@/scripts/cmdPlugin/OperationHandler';
import {menuOperate, commitOperate} from '@/jmapNew/theme/components/utils/menuOperate';
import {UserOperationType} from '@/scripts/ConstDic';
export default {
name: 'ChatBox',
data() {
return {
recordSending:false,
seconds:0,
inter:null,
recorders: null,
microphone:null,
audioPlay:false,
textContent: '',
min: true,
messageList: [], //
currentAudioList:[],
currentMessage: {}
};
},
computed:{
group() {
return this.$route.query.group;
},
contentSend() {
return !this.textContent;
},
myMemberId() {
return this.$store.state.training.myMemberId;
},
userId() {
return this.$store.state.user.id;
},
sendTextId() {
return OperationEvent.Conversation.Chat.menu.domId;
},
sideButtonDom() {
return OperationEvent.Conversation.Chat.sideButton;
}
},
watch: {
'$store.state.socket.simulationReset': function () { // 仿
this.messageList = [];
},
'$store.state.socket.conversationMessage':function (val) { // 仿
this.messageList.push(val);
if (val.memberId != this.myMemberId) {
this.currentAudioList.push(val);
if (!this.isPlay) {
this.playAllAudio();
}
}
this.scrollTop();
}
},
mounted() {
this.initConversationData();
},
methods: {
scrollTop() {
},
initConversationData() {
getAllConversition(this.group).then(resp => {
if (resp.data && resp.data.length) {
const conversation = resp.data.find(con => con.id === 'chat_room_key');
this.messageList = conversation ? conversation.messageList : [];
} else {
this.messageList = [];
}
});
},
playAllAudio() {
this.$nextTick(function() {
this.currentMessage = this.currentAudioList.shift();
document.querySelector('#audioPlay').src = this.currentMessage.audioPath;
document.querySelector('#audioPlay').play();
this.$set(this.currentMessage, 'activeAuto', true);
this.play = true;
document.querySelector('#audioPlay').onended = () => {
if (!this.currentAudioList || !this.currentAudioList.length) {
this.play = false;
}
this.$set(this.currentMessage, 'activeAuto', false);
this.playAllAudio();
};
});
},
playAudio(audioPath, data) {
this.$set(this.currentMessage, 'activeAuto', false);
this.currentAudioList = [];
this.currentMessage = data;
this.play = true;
document.querySelector('#audioPlay').src = audioPath;
document.querySelector('#audioPlay').play();
this.$set(this.currentMessage, 'activeAuto', true);
document.querySelector('#audioPlay').onended = () => { this.play = false; this.$set(this.currentMessage, 'activeAuto', false); };
},
covertName(memberId) {
let name = '';
const member = this.$store.state.training.memberData[memberId];
if (member && member.userId) {
const user = this.$store.state.training.simulationUserList.find(user => user.userId == member.userId);
name = member.labelName + '(' + user.nickName + ')';
} else if (member) {
name = member.labelName;
}
return name;
},
clickBtn() {
const operate = {
operation: this.sideButtonDom.operation,
param: { min: this.min },
userOperationType: UserOperationType.LEFTCLICK
};
this.min = false;
this.$store.dispatch('trainingNew/next', operate);
},
minimize() {
this.min = true;
},
sendText() {
commitOperate(menuOperate.Conversation.Chat, {content: this.textContent}, 3).then(({valid})=>{
if (valid) {
this.textContent = '';
}
}).catch((error) => {
this.$message.error('发送会话文字失败:' + error.message);
});
},
cancelRecording() {
if (this.microphone) {
clearInterval(this.inter);
this.seconds = 0;
this.microphone.stop();
this.microphone = null;
this.recordSending = false;
this.recorders = null;
}
},
//
stopRecording() {
this.audioPlay = true;
clearInterval(this.inter);
this.seconds = 0;
const that = this;
this.recorders.stopRecording(function(blobURL) {
that.recorders.getDataURL(function(BaseURL) {
sendChatAudioBase64(that.group, {fileBase64Str: BaseURL})
.then((data) => {
that.textContent = '';
that.audioPlay = false;
})
.catch(error => {
console.log(error);
that.$message.error('语音发送失败: ' + error.message);
that.audioPlay = false;
});
if (that.microphone) {
that.microphone.stop();
that.microphone = null;
that.recordSending = false;
that.recorders = null;
}
});
});
},
//
startRecording() {
this.audioPlay = true;
const that = this;
if (!this.recordSending) {
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',
recorderType: StereoAudioRecorder,
numberOfAudioChannels: 1,
bitsPerSecond:256000,
desiredSampRate: 16000
});
that.recorders.startRecording();
that.recordSending = true;
that.audioPlay = false;
that.inter = setInterval(() => {
if (that.seconds < 60) {
that.seconds++;
} else {
clearInterval(that.inter);
that.stopRecording();
}
}, 1000);
}, function (error) {
that.audioPlay = false;
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;
}
}
);
}
} else {
this.stopRecording(); //
}
}
}
};
</script>
<style lang="scss" scoped>
.voice-chat-box {
position: absolute;
left: 20px;
bottom: 50%;
height: 1px;
width: 1px;
z-index: 2000;
}
.chat-box-header{
width: 100%;
height: 40px;
border-bottom: 1px #dedede solid;
display: flex;
align-items: center;
justify-content: right;
padding: 0 10px;
}
.chat-box-content{
height: 250px;
position: relative;
border-top: 1px #9a9a9a solid;
margin-top: 8px;
display: block;
overflow-y: auto;
}
// safariqq360
//
.chat-box-content::-webkit-scrollbar {
width: 6px;
height: 6px;
// height: 110px;
background-color: #FFFFFF;
}
/*定义滚动条轨道 内阴影+圆角*/
.chat-box-content::-webkit-scrollbar-track {
// box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
border-radius: 10px;
background-color: #FFFFFF;;
}
/*定义滑块 内阴影+圆角*/
.chat-box-content::-webkit-scrollbar-thumb {
border-radius: 10px;
// box-shadow: inset 0 0 6px rgba(0,0,0,.3);
background-color: #cacaca;
}
/*滑块效果*/
.chat-box-content::-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);
}
.chat-box-footer{
display: flex;
align-items: center;
width: 100%;
height: 55px;
border-top: 1px solid #afafaf;
}
.chat-box-main{
position: absolute;
left: 0;
height: 350px;
width: 503px;
top: 0;
border-right: 1px #dedede solid;
z-index: 4;
background: #fff;
border-radius: 5px;
}
.chat-box-footer-create{
font-size: 16px;
color: #fff;
margin-left: 5px;
margin-right: 5px;
cursor: pointer;
width: 40px;
height: 40px;
border-radius: 50%;
background: green;
border: none;
display: flex;
justify-content: center;
align-items: center;
}
.chat-box-footer-send{
position: relative;
background: #F2F2F2;
cursor: pointer;
.icon-yuyin{
color: #333;
font-size: 24px;
margin: 0;
}
&.active{
.icon-yuyin{
color: green;
}
}
.close_icon{
position: absolute;
top: -15px;
left: 11px;
font-size: 16px;
color: #333;
font-weight: 600;
}
}
#voice_progress_bar{
width: 40px;
height: 40px;
position: absolute;
left: 0;
top: 0;
border-radius: 50%;
}
.chat-box-footer-send.disbled{
cursor: no-drop;
}
.leftUser{
float: left;
margin-left: 10px;
margin-top: 10px;
display: inline-block;
max-width: 80%;
}
.rightUser{
float: right;
margin-right: 10px;
margin-top: 10px;
display: inline-block;
max-width: 80%;
}
.userHeader{margin-bottom: 2px;}
.userName{font-size: 12px;display:inline-block;margin-right:10px;}
.userChatTime{font-size: 12px;display:inline-block;}
.textRight{text-align: right;}
.userBubble{
font-size: 12px;
padding: 5px 10px 6px 10px;
min-width: 140px;
background: #ccc;
border-radius: 5px;
cursor: pointer;
display:inline-block;
}
.userMessage{
position: relative;
}
.messageText{
line-height: 20px;
word-break: break-all;
}
.wifi-symbol {
width: 48px;
height: 48px;
box-sizing: border-box;
overflow: hidden;
transform: rotate(135deg);
position: absolute;
left: 5px;
top: -13px;
}
.wifi-circle {
border: 1px solid #000000;
border-radius: 50%;
position: absolute;
}
.first {
width: 9px;
height: 9px;
background: #cccccc;
top: 45px;
left: 45px;
border: 2px solid #000;
}
.second {
width: 20px;
height: 20px;
top: 40px;
left: 40px;
&.second-amit{
animation: fadeInOut 1s infinite 0.2s;
}
}
.third {
width: 26px;
height: 26px;
top: 36px;
left: 36px;
&.third-amit{
animation: fadeInOut 1s infinite 0.4s;
}
}
@keyframes fadeInOut {
0% {
opacity: 0; /*初始状态 透明度为0*/
}
100% {
opacity: 1; /*结尾状态 透明度为1*/
}
}
</style>