Skip to content

Commit 2b329d3

Browse files
author
puhui999
committed
【新增】:mall 客服接入 websocket 实现消息实时拉取
1 parent 893cd5d commit 2b329d3

File tree

4 files changed

+74
-33
lines changed

4 files changed

+74
-33
lines changed

src/views/mall/promotion/kefu/components/KeFuChatBox.vue

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ const messageTool = useMessage()
101101
const message = ref('') // 消息
102102
const messageList = ref<KeFuMessageRespVO[]>([]) // 消息列表
103103
const keFuConversation = ref<KeFuConversationRespVO>({} as KeFuConversationRespVO) // 用户会话
104-
const poller = ref<any>(null) // TODO puhui999: 轮训定时器,暂时模拟 websocket
105104
// 获得消息 TODO puhui999: 先不考虑下拉加载历史消息
106105
const getMessageList = async (conversation: KeFuConversationRespVO) => {
107106
keFuConversation.value = conversation
@@ -112,14 +111,15 @@ const getMessageList = async (conversation: KeFuConversationRespVO) => {
112111
messageList.value = list.reverse()
113112
// TODO puhui999: 首次加载时滚动到最新消息,如果加载的是历史消息则不滚动
114113
await scrollToBottom()
115-
// TODO puhui999: 轮训相关,功能完善后移除
116-
if (!poller.value) {
117-
poller.value = setInterval(() => {
118-
getMessageList(conversation)
119-
}, 2000)
114+
}
115+
// 刷新消息列表
116+
const refreshMessageList = () => {
117+
if (!keFuConversation.value) {
118+
return
120119
}
120+
getMessageList(keFuConversation.value)
121121
}
122-
defineExpose({ getMessageList })
122+
defineExpose({ getMessageList, refreshMessageList })
123123
// 是否显示聊天区域
124124
const showChatBox = computed(() => !isEmpty(keFuConversation.value))
125125
// 处理表情选择
@@ -181,13 +181,6 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
181181
}
182182
return false
183183
})
184-
// TODO puhui999: 轮训相关,功能完善后移除
185-
onBeforeUnmount(() => {
186-
if (!poller.value) {
187-
return
188-
}
189-
clearInterval(poller.value)
190-
})
191184
</script>
192185

193186
<style lang="scss" scoped>

src/views/mall/promotion/kefu/components/KeFuConversationBox.vue

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,6 @@ const openRightMessage = (item: KeFuConversationRespVO, index: number) => {
5555
activeConversationIndex.value = index
5656
emits('change', item)
5757
}
58-
const poller = ref<any>(null) // TODO puhui999: 轮训定时器,暂时模拟 websocket
59-
onMounted(() => {
60-
// TODO puhui999: 轮训相关,功能完善后移除
61-
if (!poller.value) {
62-
poller.value = setInterval(() => {
63-
getConversationList()
64-
}, 1000)
65-
}
66-
})
67-
// TODO puhui999: 轮训相关,功能完善后移除
68-
onBeforeUnmount(() => {
69-
if (!poller.value) {
70-
return
71-
}
72-
clearInterval(poller.value)
73-
})
7458
</script>
7559

7660
<style lang="scss" scoped>

src/views/mall/promotion/kefu/components/tools/constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// 客服消息类型枚举类
12
export const KeFuMessageContentTypeEnum = {
23
TEXT: 1, // 文本消息
34
IMAGE: 2, // 图片消息
@@ -8,3 +9,8 @@ export const KeFuMessageContentTypeEnum = {
89
PRODUCT: 10, // 商品消息
910
ORDER: 11 // 订单消息"
1011
}
12+
// Promotion 的 WebSocket 消息类型枚举类
13+
export const WebSocketMessageTypeConstants = {
14+
KEFU_MESSAGE_TYPE: 'kefu_message_type', // 客服消息类型
15+
KEFU_MESSAGE_ADMIN_READ: 'kefu_message_read_status_change' // 客服消息管理员已读
16+
}

src/views/mall/promotion/kefu/index.vue

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,77 @@
1616
<script lang="ts" setup>
1717
import { KeFuChatBox, KeFuConversationBox } from './components'
1818
import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation'
19+
import { getAccessToken } from '@/utils/auth'
20+
import { useWebSocket } from '@vueuse/core'
21+
import { WebSocketMessageTypeConstants } from '@/views/mall/promotion/kefu/components/tools/constants'
1922
2023
defineOptions({ name: 'KeFu' })
21-
24+
const message = useMessage()
2225
// 加载消息
2326
const keFuChatBoxRef = ref<InstanceType<typeof KeFuChatBox>>()
2427
const handleChange = (conversation: KeFuConversationRespVO) => {
2528
keFuChatBoxRef.value?.getMessageList(conversation)
2629
}
2730
28-
// 加载会话
31+
//======================= websocket start=======================
32+
const server = ref(
33+
(import.meta.env.VITE_BASE_URL + '/infra/ws/').replace('http', 'ws') +
34+
'?token=' +
35+
getAccessToken()
36+
) // WebSocket 服务地址
37+
38+
/** 发起 WebSocket 连接 */
39+
const { data, close, open } = useWebSocket(server.value, {
40+
autoReconnect: false,
41+
heartbeat: true
42+
})
43+
watchEffect(() => {
44+
if (!data.value) {
45+
return
46+
}
47+
try {
48+
// 1. 收到心跳
49+
if (data.value === 'pong') {
50+
// state.recordList.push({
51+
// text: '【心跳】',
52+
// time: new Date().getTime()
53+
// })
54+
return
55+
}
56+
57+
// 2.1 解析 type 消息类型
58+
const jsonMessage = JSON.parse(data.value)
59+
const type = jsonMessage.type
60+
if (!type) {
61+
message.error('未知的消息类型:' + data.value)
62+
return
63+
}
64+
// 2.2 消息类型:KEFU_MESSAGE_TYPE
65+
if (type === WebSocketMessageTypeConstants.KEFU_MESSAGE_TYPE) {
66+
// 刷新列表
67+
getConversationList()
68+
// 刷新消息列表
69+
keFuChatBoxRef.value?.refreshMessageList()
70+
return
71+
}
72+
} catch (error) {
73+
console.error(error)
74+
}
75+
})
76+
//======================= websocket end=======================
77+
// 加载会话列表
2978
const keFuConversationRef = ref<InstanceType<typeof KeFuConversationBox>>()
30-
onMounted(() => {
79+
const getConversationList = () => {
3180
keFuConversationRef.value?.getConversationList()
81+
}
82+
onMounted(() => {
83+
getConversationList()
84+
// 打开 websocket 连接
85+
open()
86+
})
87+
onBeforeUnmount(() => {
88+
// 关闭 websocket 连接
89+
close()
3290
})
3391
</script>
3492

0 commit comments

Comments
 (0)