会话群调整
This commit is contained in:
parent
baaa8e4bbb
commit
3b21f72e38
@ -419,6 +419,12 @@ const socket = {
|
||||
if (state.conversationGroup[message.messageType] !== undefined) {
|
||||
state.conversationGroup[message.messageType] = message;
|
||||
}
|
||||
},
|
||||
resetConversationGroup: (state) => {
|
||||
const arr = ['JOIN', 'UPDATE_NAME', 'UPDATE_MEMBER', 'EXIT', 'MESSAGE', 'MESSAGE_STATUS'];
|
||||
arr.forEach(key => {
|
||||
state.conversationGroup[key] = {};
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@ -660,6 +666,9 @@ const socket = {
|
||||
},
|
||||
setConversationGroup: ({ commit }, message) => {
|
||||
commit('setConversationGroup', message);
|
||||
},
|
||||
resetConversationGroup: ({ commit }) => {
|
||||
commit('resetConversationGroup');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
490
src/views/newMap/display/newChat/chatContent.vue
Normal file
490
src/views/newMap/display/newChat/chatContent.vue
Normal file
@ -0,0 +1,490 @@
|
||||
<template>
|
||||
<div class="voice-chat-box">
|
||||
<div class="chat-box-main">
|
||||
<div class="chat-box-content">
|
||||
<div v-for="(content,index) in messageList" :key="index" class="eachChatContent">
|
||||
<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 :id="recordVoice" class="chat-box-footer-create chat-box-footer-send" :class="{'active': recordSending}" :disabled="audioPlay || (trainingDesign && !trainingSwitch)" 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"></span>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<audio id="audioPlay" style="display:none" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RecordRTC from 'recordrtc';
|
||||
import { sendText } from '@/api/newChat';
|
||||
import { OperationEvent } from '@/scripts/cmdPlugin/OperationHandler';
|
||||
import {UserOperationType} from '@/scripts/ConstDic';
|
||||
import CMD from '@/scripts/cmdPlugin/CommandEnum';
|
||||
export default {
|
||||
name: 'ChatBox',
|
||||
props:{
|
||||
messageList:{
|
||||
type:Array,
|
||||
required:true
|
||||
},
|
||||
id:{
|
||||
type:Number,
|
||||
required:true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
recordSending:false,
|
||||
seconds:0,
|
||||
inter:null,
|
||||
recorders: null,
|
||||
microphone:null,
|
||||
audioPlay:false,
|
||||
textContent: '',
|
||||
currentAudioList:[],
|
||||
currentMessage: {},
|
||||
trainingDesign: false
|
||||
};
|
||||
},
|
||||
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;
|
||||
},
|
||||
recordVoice() {
|
||||
return OperationEvent.Conversation.Chat.record.domId;
|
||||
},
|
||||
sideButtonDom() {
|
||||
return OperationEvent.Conversation.Chat.sideButton;
|
||||
},
|
||||
trainingSwitch() {
|
||||
return this.$store.state.trainingNew.trainingSwitch;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$store.state.training.domConfig': function(val) {
|
||||
this.trainingDesign = val.trainingDesign;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.trainingDesign = this.$store.state.training.domConfig ? this.$store.state.training.domConfig.trainingDesign : false;
|
||||
this.scrollTop();
|
||||
},
|
||||
methods: {
|
||||
scrollTop() {
|
||||
this.$nextTick(() => {
|
||||
const scrollTop = this.messageList.length * 62;
|
||||
document.querySelector('.chat-box-content').scrollTop = scrollTop;
|
||||
});
|
||||
},
|
||||
playAllAudio() {
|
||||
this.$nextTick(function() {
|
||||
this.currentMessage = this.currentAudioList.shift();
|
||||
if (this.currentMessage.type === 'Text') {
|
||||
return;
|
||||
}
|
||||
document.querySelector('#audioPlay').src = this.currentMessage.audioPath;
|
||||
document.querySelector('#audioPlay').play();
|
||||
this.$set(this.currentMessage, 'activeAuto', true);
|
||||
this.play = true;
|
||||
document.querySelector('#audioPlay').onended = () => {
|
||||
this.$set(this.currentMessage, 'activeAuto', false);
|
||||
if (!this.currentAudioList || !this.currentAudioList.length) {
|
||||
this.play = false;
|
||||
} else {
|
||||
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;
|
||||
},
|
||||
sendText() {
|
||||
sendText(this.group, {id: this.id, content:this.textContent}).then(res => {
|
||||
console.log(res, '--res--');
|
||||
this.textContent = '';
|
||||
}).catch(err => {
|
||||
console.log(err, '--err--');
|
||||
this.$message.error('发送会话文字失败:' + err.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) {
|
||||
const operate = {
|
||||
over: true,
|
||||
cmdType: CMD.Conversation.CMD_Conversation_Chat_Audio_Base64,
|
||||
operation: OperationEvent.Conversation.Chat.record.operation,
|
||||
userOperationType: UserOperationType.LEFTCLICK,
|
||||
param: {
|
||||
fileBase64Str: BaseURL
|
||||
}
|
||||
};
|
||||
that.$store.dispatch('trainingNew/next', operate).then(({ valid }) => {
|
||||
if (valid) {
|
||||
that.textContent = '';
|
||||
that.audioPlay = false;
|
||||
}
|
||||
}).catch(error => {
|
||||
that.$message.error('发送会话语音失败:' + error.message);
|
||||
that.audioPlay = false;
|
||||
});
|
||||
if (that.microphone) {
|
||||
that.microphone.stop();
|
||||
that.microphone = null;
|
||||
that.recordSending = false;
|
||||
that.recorders = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
tipErrorMessage(error) {
|
||||
switch (error.code || error.name) {
|
||||
case 'PERMISSION_DENIED':
|
||||
case 'PermissionDeniedError':
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '用户拒绝提供信息',
|
||||
type: 'error'
|
||||
});
|
||||
break;
|
||||
case 'NOT_SUPPORTED_ERROR':
|
||||
case 'NotSupportedError':
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '浏览器不支持硬件设备',
|
||||
type: 'error'
|
||||
});
|
||||
break;
|
||||
case 'MANDATORY_UNSATISFIED_ERROR':
|
||||
case 'MandatoryUnsatisfiedError':
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '无法发现指定的硬件设备',
|
||||
type: 'error'
|
||||
});
|
||||
break;
|
||||
default:
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '无法打开麦克风',
|
||||
type: 'error'
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
mediaSuccessCallback(stream) {
|
||||
const StereoAudioRecorder = RecordRTC.StereoAudioRecorder;
|
||||
this.microphone = stream;
|
||||
this.recorders = new RecordRTC(this.microphone, {
|
||||
type: 'audio',
|
||||
recorderType: StereoAudioRecorder,
|
||||
numberOfAudioChannels: 1,
|
||||
bitsPerSecond:256000,
|
||||
desiredSampRate: 16000
|
||||
});
|
||||
this.recorders.startRecording();
|
||||
this.recordSending = true;
|
||||
this.audioPlay = false;
|
||||
this.inter = setInterval(() => {
|
||||
if (this.seconds < 60) {
|
||||
this.seconds++;
|
||||
} else {
|
||||
clearInterval(this.inter);
|
||||
this.stopRecording();
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
// 语音录制开始
|
||||
startRecording() {
|
||||
if (!this.recordSending) {
|
||||
const operate = {
|
||||
operation: OperationEvent.Conversation.Chat.record.operation,
|
||||
userOperationType: UserOperationType.LEFTCLICK
|
||||
};
|
||||
this.$store.dispatch('trainingNew/next', operate).then(({ valid }) => {
|
||||
if (valid) {
|
||||
this.audioPlay = true;
|
||||
const that = this;
|
||||
if (!this.recordSending && !this.recorders && !this.microphone) {
|
||||
navigator.getUserMedia(
|
||||
{ audio: true } // 只启用音频
|
||||
, function (stream) {
|
||||
that.mediaSuccessCallback(stream);
|
||||
}, function (error) {
|
||||
that.audioPlay = false;
|
||||
that.tipErrorMessage(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}).catch(() => { console.error('操作失败!'); });
|
||||
} else {
|
||||
this.stopRecording(); // 发送语音
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.voice-chat-box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.chat-box-content{
|
||||
height: calc(100% - 55px);
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
padding: 5px;
|
||||
}
|
||||
// 谷歌、safari、qq浏览器、360浏览器滚动条样式
|
||||
// 定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸
|
||||
.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{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-left: 1px solid #dedede;
|
||||
background: #fff;
|
||||
}
|
||||
.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%;
|
||||
}
|
||||
.eachChatContent{width: 100%;min-height: 65px;display:inline-block;}
|
||||
.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%;
|
||||
text-align: right;
|
||||
}
|
||||
.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;
|
||||
text-align: left;
|
||||
}
|
||||
.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>
|
||||
|
@ -53,12 +53,13 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div v-for="(item, index) in activeMessageList" :key="index">
|
||||
<!-- <div v-for="(item, index) in activeMessageList" :key="index">
|
||||
<span>{{ item.time }}</span>
|
||||
<span>{{ item.content }}</span>
|
||||
</div>
|
||||
<el-input v-model="inputMsg" />
|
||||
<el-button @click="sendMsg">发送</el-button>
|
||||
<el-button @click="sendMsg">发送</el-button> -->
|
||||
<chat-content :id="id" :message-list="activeMessageList" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="tabActive==1">文档</div>
|
||||
@ -72,10 +73,11 @@
|
||||
import {mapGetters} from 'vuex';
|
||||
import { getGroupList, sendText } from '@/api/newChat';
|
||||
import { timestampFormat } from '@/utils/date';
|
||||
import ChatContent from './chatContent';
|
||||
export default {
|
||||
name: '',
|
||||
components: {
|
||||
|
||||
ChatContent
|
||||
},
|
||||
props: {
|
||||
|
||||
@ -112,6 +114,9 @@ export default {
|
||||
groupId() {
|
||||
return this.$route.query.group;
|
||||
},
|
||||
myMemberId() {
|
||||
return this.$store.state.training.myMemberId;
|
||||
},
|
||||
activeMessageList() {
|
||||
let list = [];
|
||||
const find = this.groupList.find(item => {
|
||||
@ -124,6 +129,11 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$store.state.socket.simulationReset': function (val) { // 仿真重置
|
||||
if (val) {
|
||||
this.$store.dispatch('socket/resetConversationGroup');
|
||||
}
|
||||
},
|
||||
'$store.state.socket.conversationGroup.MESSAGE': function(val) {
|
||||
const find = this.groupList.find(item => {
|
||||
return item.id == val.id;
|
||||
@ -148,6 +158,9 @@ export default {
|
||||
find.messageList.splice(index, 1, obj);
|
||||
}
|
||||
}
|
||||
},
|
||||
myMemberId() {
|
||||
this.getGroupList();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@ -180,9 +193,9 @@ export default {
|
||||
if (list.length) {
|
||||
time = list[list.length - 1].time;
|
||||
}
|
||||
return this.timestampFormat(time);
|
||||
return this.timeFormat(time);
|
||||
},
|
||||
timestampFormat(time) {
|
||||
timeFormat(time) {
|
||||
let timeStr = '';
|
||||
if (time) {
|
||||
const t = new Date(time).getTime();
|
||||
@ -205,7 +218,7 @@ export default {
|
||||
getGroupList(this.groupId).then(res => {
|
||||
console.log(res, '---res--');
|
||||
this.groupList = res.data;
|
||||
if (this.groupList && this.groupList[0].id) {
|
||||
if (this.groupList && this.groupList[0]) {
|
||||
this.id = this.groupList[0].id;
|
||||
}
|
||||
}).catch(err => {
|
||||
|
Loading…
Reference in New Issue
Block a user