Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
2b329d33
authored
Jul 04, 2024
by
puhui999
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【新增】:mall 客服接入 websocket 实现消息实时拉取
parent
893cd5d8
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
74 additions
and
33 deletions
+74
-33
src/views/mall/promotion/kefu/components/KeFuChatBox.vue
+7
-14
src/views/mall/promotion/kefu/components/KeFuConversationBox.vue
+0
-16
src/views/mall/promotion/kefu/components/tools/constants.ts
+6
-0
src/views/mall/promotion/kefu/index.vue
+61
-3
No files found.
src/views/mall/promotion/kefu/components/KeFuChatBox.vue
View file @
2b329d33
...
...
@@ -101,7 +101,6 @@ const messageTool = useMessage()
const
message
=
ref
(
''
)
// 消息
const
messageList
=
ref
<
KeFuMessageRespVO
[]
>
([])
// 消息列表
const
keFuConversation
=
ref
<
KeFuConversationRespVO
>
({}
as
KeFuConversationRespVO
)
// 用户会话
const
poller
=
ref
<
any
>
(
null
)
// TODO puhui999: 轮训定时器,暂时模拟 websocket
// 获得消息 TODO puhui999: 先不考虑下拉加载历史消息
const
getMessageList
=
async
(
conversation
:
KeFuConversationRespVO
)
=>
{
keFuConversation
.
value
=
conversation
...
...
@@ -112,14 +111,15 @@ const getMessageList = async (conversation: KeFuConversationRespVO) => {
messageList
.
value
=
list
.
reverse
()
// TODO puhui999: 首次加载时滚动到最新消息,如果加载的是历史消息则不滚动
await
scrollToBottom
()
// TODO puhui999: 轮训相关,功能完善后移除
if
(
!
poller
.
value
)
{
poller
.
value
=
setInterval
(
()
=>
{
getMessageList
(
conversation
)
},
2000
)
}
// 刷新消息列表
const
refreshMessageList
=
()
=>
{
if
(
!
keFuConversation
.
value
)
{
return
}
getMessageList
(
keFuConversation
.
value
)
}
defineExpose
({
getMessageList
})
defineExpose
({
getMessageList
,
refreshMessageList
})
// 是否显示聊天区域
const
showChatBox
=
computed
(()
=>
!
isEmpty
(
keFuConversation
.
value
))
// 处理表情选择
...
...
@@ -181,13 +181,6 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
}
return
false
})
// TODO puhui999: 轮训相关,功能完善后移除
onBeforeUnmount
(()
=>
{
if
(
!
poller
.
value
)
{
return
}
clearInterval
(
poller
.
value
)
})
</
script
>
<
style
lang=
"scss"
scoped
>
...
...
src/views/mall/promotion/kefu/components/KeFuConversationBox.vue
View file @
2b329d33
...
...
@@ -55,22 +55,6 @@ const openRightMessage = (item: KeFuConversationRespVO, index: number) => {
activeConversationIndex
.
value
=
index
emits
(
'change'
,
item
)
}
const
poller
=
ref
<
any
>
(
null
)
// TODO puhui999: 轮训定时器,暂时模拟 websocket
onMounted
(()
=>
{
// TODO puhui999: 轮训相关,功能完善后移除
if
(
!
poller
.
value
)
{
poller
.
value
=
setInterval
(()
=>
{
getConversationList
()
},
1000
)
}
})
// TODO puhui999: 轮训相关,功能完善后移除
onBeforeUnmount
(()
=>
{
if
(
!
poller
.
value
)
{
return
}
clearInterval
(
poller
.
value
)
})
</
script
>
<
style
lang=
"scss"
scoped
>
...
...
src/views/mall/promotion/kefu/components/tools/constants.ts
View file @
2b329d33
// 客服消息类型枚举类
export
const
KeFuMessageContentTypeEnum
=
{
TEXT
:
1
,
// 文本消息
IMAGE
:
2
,
// 图片消息
...
...
@@ -8,3 +9,8 @@ export const KeFuMessageContentTypeEnum = {
PRODUCT
:
10
,
// 商品消息
ORDER
:
11
// 订单消息"
}
// Promotion 的 WebSocket 消息类型枚举类
export
const
WebSocketMessageTypeConstants
=
{
KEFU_MESSAGE_TYPE
:
'kefu_message_type'
,
// 客服消息类型
KEFU_MESSAGE_ADMIN_READ
:
'kefu_message_read_status_change'
// 客服消息管理员已读
}
src/views/mall/promotion/kefu/index.vue
View file @
2b329d33
...
...
@@ -16,19 +16,77 @@
<
script
lang=
"ts"
setup
>
import
{
KeFuChatBox
,
KeFuConversationBox
}
from
'./components'
import
{
KeFuConversationRespVO
}
from
'@/api/mall/promotion/kefu/conversation'
import
{
getAccessToken
}
from
'@/utils/auth'
import
{
useWebSocket
}
from
'@vueuse/core'
import
{
WebSocketMessageTypeConstants
}
from
'@/views/mall/promotion/kefu/components/tools/constants'
defineOptions
({
name
:
'KeFu'
})
const
message
=
useMessage
()
// 加载消息
const
keFuChatBoxRef
=
ref
<
InstanceType
<
typeof
KeFuChatBox
>>
()
const
handleChange
=
(
conversation
:
KeFuConversationRespVO
)
=>
{
keFuChatBoxRef
.
value
?.
getMessageList
(
conversation
)
}
// 加载会话
//======================= websocket start=======================
const
server
=
ref
(
(
import
.
meta
.
env
.
VITE_BASE_URL
+
'/infra/ws/'
).
replace
(
'http'
,
'ws'
)
+
'?token='
+
getAccessToken
()
)
// WebSocket 服务地址
/** 发起 WebSocket 连接 */
const
{
data
,
close
,
open
}
=
useWebSocket
(
server
.
value
,
{
autoReconnect
:
false
,
heartbeat
:
true
})
watchEffect
(()
=>
{
if
(
!
data
.
value
)
{
return
}
try
{
// 1. 收到心跳
if
(
data
.
value
===
'pong'
)
{
// state.recordList.push({
// text: '【心跳】',
// time: new Date().getTime()
// })
return
}
// 2.1 解析 type 消息类型
const
jsonMessage
=
JSON
.
parse
(
data
.
value
)
const
type
=
jsonMessage
.
type
if
(
!
type
)
{
message
.
error
(
'未知的消息类型:'
+
data
.
value
)
return
}
// 2.2 消息类型:KEFU_MESSAGE_TYPE
if
(
type
===
WebSocketMessageTypeConstants
.
KEFU_MESSAGE_TYPE
)
{
// 刷新列表
getConversationList
()
// 刷新消息列表
keFuChatBoxRef
.
value
?.
refreshMessageList
()
return
}
}
catch
(
error
)
{
console
.
error
(
error
)
}
})
//======================= websocket end=======================
// 加载会话列表
const
keFuConversationRef
=
ref
<
InstanceType
<
typeof
KeFuConversationBox
>>
()
onMounted
(
()
=>
{
const
getConversationList
=
()
=>
{
keFuConversationRef
.
value
?.
getConversationList
()
}
onMounted
(()
=>
{
getConversationList
()
// 打开 websocket 连接
open
()
})
onBeforeUnmount
(()
=>
{
// 关闭 websocket 连接
close
()
})
</
script
>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment