Commit 18cb1194 authored by yaya's avatar yaya

添加消息发送功能

parent 618cc34e
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WebPackConfiguration">
<option name="mode" value="DISABLED" />
</component>
</project>
\ No newline at end of file
......@@ -15,3 +15,11 @@ export function getUserList(params) {
})
}
export function sendChatMsg(params) {
return request({
url: '/sysIM/sendChatMsg',
method: 'post',
data: params
})
}
......@@ -8,13 +8,13 @@
<el-container v-loading="loading" style="width: 100%;height: 100%; border: 1px solid #eee">
<el-aside style="width: 25%;background-color: white;padding: 0">
<el-tabs style="width: 100%; padding: 10px 10px 0" @tab-click="handleClick">
<el-tab-pane v-for="item in chatList" :key="item.code" :label="item.name" />
<el-tab-pane v-for="item in customerList" :key="item.code" :label="item.name" />
</el-tabs>
<div class="conversation">
<div
v-for="item in conversationList"
:key="item.conversationID"
:class="{'conversation-item-active': currentChatItem.conversationID === item.conversationID}"
:class="{'conversation-item-active': currentConversationItem.conversationID === item.conversationID}"
class="conversation-item flex f-ai-c"
@click="handleSelectChat(item)">
<div class="conversation-item-image">
......@@ -34,23 +34,33 @@
<el-main style="background-color: rgb(238, 241, 246); padding: 0; border: 1px solid #eee">
<div class="chat-message">
<div class="chat-message-top flex f-jc-sb">
<div class="chat-message-top__title">账号昵称</div>
<el-button type="text">人工介入</el-button>
<div class="chat-message-top__title">{{ currentConversationItem && currentConversationItem.nick }}</div>
<el-button type="text" @click="handleService">{{ serviceTip }}</el-button>
</div>
<div class="chat-message-list" style="overflow:auto">
<div
v-if="!isCompleted && currentConversationItem.conversationID"
class="chat-message-list__more"
@click="handleGetHistory(false)">点击获取更多历史消息
</div>
<ul
class="chat-message-list__content"
infinite-scroll-disabled="disabled"
style="margin: 0; padding: 0">
<div v-for="messageItem in messageList" :key="messageItem.id" class="chat-message-list__content__item">
<div
v-for="(messageItem, index) in messageList"
:key="messageItem.id"
:class="`chat-message-list__content__item_${index}`"
class="chat-message-list__content__item">
<ChatMessageItem :chat-message-item="messageItem" />
</div>
</ul>
<div class="hash" />
</div>
<div class="chat-message-input">
<el-input v-model="messageContent" :rows="4" type="textarea" placeholder="请输入聊天内容" style="border: none"/>
<el-input v-model="messageContent" :rows="4" type="textarea" placeholder="请输入聊天内容" style="border: none" />
<div class="chat-message-input__send">
<el-button :disabled="sendDisabled" type="primary">发送</el-button>
<el-button :disabled="sendDisabled" type="primary" @click="sendMessage">发送</el-button>
</div>
</div>
</div>
......@@ -67,54 +77,98 @@
<script>
import { getUserSig, getUserList } from '@/api/business/chat'
import { getUserSig, getUserList, sendChatMsg } from '@/api/business/chat'
import chat from '@/utils/chat'
import { formatTime } from '@/utils/index'
import TencentCloudChat from '@tencentcloud/chat'
import ChatMessageItem from './components/chatMessageItem'
import store from '../../store'
export default {
name: 'ChatDetail',
components: { ChatMessageItem },
data() {
return {
currentChatItem: {}, // 当前聊天
chatList: [],
customerList: [], // 客服列表
currentCustomerIndex: -1, // 当前客服
loading: true,
conversationList: [],
messageContent: '',
count: 10,
currentChatIndex: -1, // 当前聊天
nextReqMessageID: '', // 历史消息下一页
isCompleted: false,
envText: 'cjxc-applet-dev_',
messageList: [] // 历史消息
conversationList: [], // 会话列表
currentConversationItem: {}, // 当前聊天
messageList: [], // 历史消息
isRealPersonal: false, // 是否人工介入
userId: ''
}
},
computed: {
sendDisabled() {
return !this.messageContent || this.messageContent.length === 0
return !this.messageContent || this.messageContent.length === 0 || !this.isRealPersonal || !this.currentConversationItem.conversationID
},
serviceTip() {
return this.isRealPersonal ? '结束人工' : '人工介入'
}
},
mounted() {
},
created() {
chat.on(TencentCloudChat.EVENT.SDK_READY, this.onSdkReady)
this.handleGetUserInfo()
this.handleGetChatList()
},
methods: {
handleGetUserInfo() {
store.dispatch('GetUserInfo').then(res => { // 拉取user_info
this.userId = res.data.data.id // note: perms must be a array! such as: ['GET /aaa','POST /bbb']
}).catch((err) => {
console.log('====userInfo=', err)
})
},
handleSelect(key, keyPath) {
console.log(key, keyPath)
},
/**
* 是否人工介入
* */
handleService() {
if (this.isRealPersonal) {
this.isRealPersonal = false
} else {
this.isRealPersonal = true
}
const object = {
messageContent: this.isRealPersonal ? '人工接管聊天' : '退出人工聊天',
msgType: this.isRealPersonal ? 3 : 4
}
this.messageList.push(object)
this.scrollToBottom(true)
},
/**
* 选择客服
**/
handleClick(tab, event) {
console.log('====tab=', tab.index, event)
if (this.currentChatIndex === tab.index) {
if (this.currentCustomerIndex === tab.index) {
return
}
this.currentChatIndex = tab.index
this.handleClear()
this.currentCustomerIndex = tab.index
this.handleBeforeLogin()
},
/**
* 切换客服清空数据
* */
handleClear() {
this.currentConversationItem = {}
this.conversationList = []
this.isRealPersonal = false
this.nextReqMessageID = ''
this.messageList = []
this.messageContent = ''
},
/**
* 获取客服列表
**/
......@@ -122,9 +176,9 @@ export default {
const params = {}
getUserList(params).then(response => {
if (response && response.data && response.data.data) {
this.chatList = response.data.data
this.customerList = response.data.data
}
if (this.chatList.length > 0) {
if (this.customerList.length > 0) {
this.handleBeforeLogin()
}
console.log('===list ===', response.data.data)
......@@ -135,19 +189,23 @@ export default {
})
})
},
/**
* 切换客服
* */
handleBeforeLogin() {
this.showLoading()
if (this.currentChatIndex === -1) {
const chatItem = this.chatList[0]
this.currentChatIndex = 0
if (this.currentCustomerIndex === -1) {
const chatItem = this.customerList[0]
this.currentCustomerIndex = 0
this.handleGetUserSign(chatItem.code)
} else {
const promise = chat.logout()
promise.then((imResponse) => {
// console.log('==登出成功=', imResponse.data, this.chatList) // 登出成功
const chatItem = this.chatList[this.currentChatIndex]
// console.log('==登出成功=', imResponse.data, this.conversationList) // 登出成功
const chatItem = this.customerList[this.currentCustomerIndex]
this.handleGetUserSign(chatItem.code)
}).catch(function(imError) {
this.closeLoading()
console.warn('====登出失败:', imError) // 登录失败的相关信息
})
}
......@@ -175,12 +233,11 @@ export default {
*/
handleImLoin(userId, userSign) {
console.log('====用户信息===', userId, userSign) // 登录成功
this.closeLoading()
const promise = chat.login({ userID: this.envText + userId, userSig: userSign })
promise.then((imResponse) => {
this.closeLoading()
console.log('====登录成功===', imResponse.data) // 登录成功
chat.on(TencentCloudChat.EVENT.CONVERSATION_LIST_UPDATED, this.onConversationListUpdated)
chat.on(TencentCloudChat.EVENT.MESSAGE_RECEIVED, this.onMessageReceived)
this.handleGetConversationList()
......@@ -195,14 +252,36 @@ export default {
},
onSdkReady(event) {
console.log('====SDK ready===', event) // 登录成功
this.handleGetConversationList()
},
/**
* 接受消息
* */
onMessageReceived(event) {
const receivedList = event.data
receivedList.forEach((message) => {
if (message.type === TencentCloudChat.TYPES.MSG_TEXT) {
console.log('=====新消息=', message)
if (message.conversationID !== this.currentConversationItem.conversationID) {
return
}
const userID = this.customerList[this.currentCustomerIndex].code
if (this.isRealPersonal && message.from === this.envText + userID) {
return
}
const object = {
id: message.ID,
messageContent: message.payload.text,
fromUserId: message.from,
toAccount: message.to,
avatar: message.avatar,
msgType: this.isRealPersonal && message.from === this.envText + userID ? 1 : 2
}
this.messageList.push(object)
this.scrollToBottom(true)
// 文本消息 - https://web.sdk.qcloud.com/im/doc/v3/zh-cn/Message.html#.TextPayload
}/* else if (message.type === TencentCloudChat.TYPES.MSG_IMAGE) {
// 图片消息 - https://web.sdk.qcloud.com/im/doc/v3/zh-cn/Message.html#.ImagePayload
......@@ -226,6 +305,9 @@ export default {
})
},
/**
* 获取会话列表
* */
handleGetConversationList() {
const promise = chat.getConversationList()
promise.then((imResponse) => {
......@@ -270,18 +352,22 @@ export default {
* */
handleSelectChat(item) {
this.messageList = []
if (this.currentChatItem !== item) {
this.currentChatItem = item
if (this.currentConversationItem && this.currentConversationItem.conversationID !== item.conversationID) {
this.currentConversationItem = item
this.nextReqMessageID = ''
this.isRealPersonal = false
this.handleGetHistory()
}
},
handleGetHistory() {
const userID = this.chatList[this.currentChatIndex].code
if (this.currentChatItem) {
/**
* 获取历史消息
* */
handleGetHistory(scrollEnd = true) {
const userID = this.customerList[this.currentCustomerIndex].code
if (this.currentConversationItem) {
const promise = chat.getMessageList({
conversationID: this.currentChatItem.conversationID,
conversationID: this.currentConversationItem.conversationID,
nextReqMessageID: this.nextReqMessageID
})
promise.then((imResponse) => {
......@@ -308,12 +394,61 @@ export default {
}
console.log('====messageList', this.messageList, topList)
this.messageList = topList.concat(this.messageList)
this.scrollToBottom(scrollEnd, topList.length)
console.log('====历史消息', this.messageList)
}).catch((err) => {
console.log('====err--历史消息', err)
})
}
},
scrollToBottom(scrollToEnd, listLength) {
if (scrollToEnd) {
setTimeout(() => {
const hashElements = document.getElementsByClassName('hash')
if (hashElements && hashElements.length > 0) {
hashElements[0].scrollIntoView(true)
}
}, 250) // 延长触发时间,避免在App.vue的afterEnter之前执行
} else {
setTimeout(() => {
const hashElements = document.getElementsByClassName(`chat-message-list__content__item_${listLength - 1}`)
if (hashElements && hashElements.length > 0) {
hashElements[0].scrollIntoView(true)
}
}, 250)
}
},
/**
* 发送消息
* */
sendMessage() {
const params = {
fromAccount: this.customerList[this.currentCustomerIndex].code,
toAccount: this.currentConversationItem.fromAccount,
isRealPersonAnswer: 1,
msgType: 1,
realPersonId: this.userId,
msgContent: this.messageContent
}
sendChatMsg(params).then(response => {
const object = {
messageContent: this.messageContent,
fromUserId: this.customerList[this.currentCustomerIndex].code,
toAccount: this.currentConversationItem.conversationID,
avatar: this.customerList[this.currentCustomerIndex].avatar,
msgType: 1
}
this.messageList.push(object)
this.messageContent = ''
this.scrollToBottom(true)
}).catch(response => {
this.$notify.error({
title: '失败',
message: response.data.errmsg || '请求失败'
})
})
},
/**
* 打开加载
......@@ -335,9 +470,11 @@ export default {
/deep/ .main {
padding: 0;
}
/deep/ .el-textarea__inner {
border: none;
}
/deep/ .ul {
padding-inline-start: 0;
}
......@@ -387,6 +524,7 @@ export default {
.conversation-item-info {
width: 100%;
.conversation-item-info__nick {
height: 20px;
font-size: 13px;
......@@ -398,6 +536,7 @@ export default {
.conversation-item-info__message {
width: 100%;
.conversation-item-info__message__profile {
flex: 1;
height: 16px;
......@@ -426,6 +565,7 @@ export default {
}
}
}
.conversation-item-active {
background: rgb(238, 241, 246);
}
......@@ -434,28 +574,44 @@ export default {
.chat-message {
display: flex;
flex-direction: column;
height:100%;
height: 100%;
.chat-message-top {
background: white;
padding: 8px;
}
.chat-message-list {
width: 100%;
flex: 1;
padding-top: 10px;
.chat-message-list__more {
width: 100%;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #989CA8;
line-height: 40px;
text-align: center;
}
.chat-message-list__content {
width: 100%;
.chat-message-list__content__item {
width: 100%;
margin-bottom: 20px;
}
}
}
.chat-message-input {
border: 1px solid #DCDFE6;
border-radius: 4px;
background-color: #FFFFFF;
padding: 12px 0;
.chat-message-input__send {
text-align: end;
margin: 12px 12px 0 0;
......
<template>
<div class="message_components">
<!--自己发送的消息-->
<div v-if="chatMessageItem.msgType === 1" class="message-self">
<div class="message-self_content">{{ chatMessageItem.messageContent }}</div>
<img :src="chatMessageItem.avatar" class="message-self__avatar">
</div>
<!--其他人发送的消息-->
<div v-if="chatMessageItem.msgType === 2" class="message-other">
<img :src="chatMessageItem.avatar" class="message-other__avatar">
<div class="message-other_content">
{{ chatMessageItem.messageContent }}
</div>
</div>
<!--人工接管聊天-->
<div v-if="chatMessageItem.msgType === 3" class="message-enter">{{ chatMessageItem.messageContent }}</div>
<!--人工退出聊天-->
<div v-if="chatMessageItem.msgType === 4" class="message-enter">{{ chatMessageItem.messageContent }}</div>
</div>
</template>
......@@ -60,7 +66,7 @@ export default {
width: fit-content;
max-width: 60%;
background: #FFFFFF;
border-radius: 11px 11px 0px 11px;
border-radius: 11px 11px 11px 0;
padding: 10px 12px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
......@@ -74,6 +80,15 @@ export default {
margin: 0 10px;
}
}
.message-enter {
width: 100%;
text-align: center;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #989CA8;
line-height: 20px;
}
}
</style>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment