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
9ab367e4
authored
Jul 05, 2024
by
puhui999
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【新增】:mall 客服会话未读消息展示和消息已读处理
parent
2b329d33
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
73 additions
and
110 deletions
+73
-110
src/api/mall/promotion/kefu/conversation/index.ts
+12
-49
src/api/mall/promotion/kefu/message/index.ts
+13
-47
src/views/mall/promotion/kefu/components/KeFuChatBox.vue
+7
-3
src/views/mall/promotion/kefu/components/KeFuConversationBox.vue
+31
-2
src/views/mall/promotion/kefu/components/index.ts
+1
-2
src/views/mall/promotion/kefu/index.vue
+9
-7
No files found.
src/api/mall/promotion/kefu/conversation/index.ts
View file @
9ab367e4
import
request
from
'@/config/axios'
import
request
from
'@/config/axios'
// TODO @puhui999:注释要不放在属性后面,避免太长哈
export
interface
KeFuConversationRespVO
{
export
interface
KeFuConversationRespVO
{
/**
id
:
number
// 编号
* 编号
userId
:
number
// 会话所属用户
*/
userAvatar
:
string
// 会话所属用户头像
id
:
number
userNickname
:
string
// 会话所属用户昵称
/**
lastMessageTime
:
Date
// 最后聊天时间
* 会话所属用户
lastMessageContent
:
string
// 最后聊天内容
*/
lastMessageContentType
:
number
// 最后发送的消息类型
userId
:
number
adminPinned
:
boolean
// 管理端置顶
/**
userDeleted
:
boolean
// 用户是否可见
* 会话所属用户头像
adminDeleted
:
boolean
// 管理员是否可见
*/
adminUnreadMessageCount
:
number
// 管理员未读消息数
userAvatar
:
string
createTime
?:
string
// 创建时间
/**
* 会话所属用户昵称
*/
userNickname
:
string
/**
* 最后聊天时间
*/
lastMessageTime
:
Date
/**
* 最后聊天内容
*/
lastMessageContent
:
string
/**
* 最后发送的消息类型
*/
lastMessageContentType
:
number
/**
* 管理端置顶
*/
adminPinned
:
boolean
/**
* 用户是否可见
*/
userDeleted
:
boolean
/**
* 管理员是否可见
*/
adminDeleted
:
boolean
/**
* 管理员未读消息数
*/
adminUnreadMessageCount
:
number
/**
* 创建时间
*/
createTime
?:
string
}
}
// 客服会话 API
// 客服会话 API
...
...
src/api/mall/promotion/kefu/message/index.ts
View file @
9ab367e4
import
request
from
'@/config/axios'
import
request
from
'@/config/axios'
export
interface
KeFuMessageRespVO
{
export
interface
KeFuMessageRespVO
{
/**
id
:
number
// 编号
* 编号
conversationId
:
number
// 会话编号
*/
senderId
:
number
// 发送人编号
id
:
number
senderAvatar
:
string
// 发送人头像
/**
senderType
:
number
// 发送人类型
* 会话编号
receiverId
:
number
// 接收人编号
*/
receiverType
:
number
// 接收人类型
conversationId
:
number
contentType
:
number
// 消息类型
/**
content
:
string
// 消息
* 发送人编号
readStatus
:
boolean
// 是否已读
*/
createTime
:
Date
// 创建时间
senderId
:
number
/**
* 发送人头像
*/
senderAvatar
:
string
/**
* 发送人类型
*/
senderType
:
number
/**
* 接收人编号
*/
receiverId
:
number
/**
* 接收人类型
*/
receiverType
:
number
/**
* 消息类型
*/
contentType
:
number
/**
* 消息
*/
content
:
string
/**
* 是否已读
*/
readStatus
:
boolean
/**
* 创建时间
*/
createTime
:
Date
}
}
// 客服会话 API
// 客服会话 API
...
@@ -57,10 +24,9 @@ export const KeFuMessageApi = {
...
@@ -57,10 +24,9 @@ export const KeFuMessageApi = {
})
})
},
},
// 更新客服消息已读状态
// 更新客服消息已读状态
updateKeFuMessageReadStatus
:
async
(
data
:
any
)
=>
{
updateKeFuMessageReadStatus
:
async
(
conversationId
:
number
)
=>
{
return
await
request
.
put
({
return
await
request
.
put
({
url
:
'/promotion/kefu-message/update-read-status'
,
url
:
'/promotion/kefu-message/update-read-status?conversationId='
+
conversationId
data
})
})
},
},
// 获得消息分页数据
// 获得消息分页数据
...
...
src/views/mall/promotion/kefu/components/KeFuChatBox.vue
View file @
9ab367e4
...
@@ -18,12 +18,12 @@
...
@@ -18,12 +18,12 @@
{{
formatDate
(
item
.
createTime
)
}}
{{
formatDate
(
item
.
createTime
)
}}
</div>
</div>
<!-- 系统消息 -->
<!-- 系统消息 -->
<
view
<
div
v-if=
"item.contentType === KeFuMessageContentTypeEnum.SYSTEM"
v-if=
"item.contentType === KeFuMessageContentTypeEnum.SYSTEM"
class=
"system-message"
class=
"system-message"
>
>
{{
item
.
content
}}
{{
item
.
content
}}
</
view
>
</
div
>
</div>
</div>
<div
<div
:class=
"[
:class=
"[
...
@@ -154,9 +154,10 @@ const handleSendMessage = async () => {
...
@@ -154,9 +154,10 @@ const handleSendMessage = async () => {
// 发送消息 【共用】
// 发送消息 【共用】
const
sendMessage
=
async
(
msg
:
any
)
=>
{
const
sendMessage
=
async
(
msg
:
any
)
=>
{
// 发送消息
await
KeFuMessageApi
.
sendKeFuMessage
(
msg
)
await
KeFuMessageApi
.
sendKeFuMessage
(
msg
)
message
.
value
=
''
message
.
value
=
''
//
3.
加载消息列表
// 加载消息列表
await
getMessageList
(
keFuConversation
.
value
)
await
getMessageList
(
keFuConversation
.
value
)
// 滚动到最新消息处
// 滚动到最新消息处
await
scrollToBottom
()
await
scrollToBottom
()
...
@@ -166,8 +167,11 @@ const innerRef = ref<HTMLDivElement>()
...
@@ -166,8 +167,11 @@ const innerRef = ref<HTMLDivElement>()
const
scrollbarRef
=
ref
<
InstanceType
<
typeof
ElScrollbarType
>>
()
const
scrollbarRef
=
ref
<
InstanceType
<
typeof
ElScrollbarType
>>
()
// 滚动到底部
// 滚动到底部
const
scrollToBottom
=
async
()
=>
{
const
scrollToBottom
=
async
()
=>
{
// 1. 滚动到最新消息
await
nextTick
()
await
nextTick
()
scrollbarRef
.
value
!
.
setScrollTop
(
innerRef
.
value
!
.
clientHeight
)
scrollbarRef
.
value
!
.
setScrollTop
(
innerRef
.
value
!
.
clientHeight
)
// 2. 消息已读
await
KeFuMessageApi
.
updateKeFuMessageReadStatus
(
keFuConversation
.
value
.
id
)
}
}
/**
/**
* 是否显示时间
* 是否显示时间
...
...
src/views/mall/promotion/kefu/components/KeFuConversationBox.vue
View file @
9ab367e4
...
@@ -8,7 +8,15 @@
...
@@ -8,7 +8,15 @@
@click="openRightMessage(item, index)"
@click="openRightMessage(item, index)"
>
>
<div
class=
"flex justify-center items-center w-100%"
>
<div
class=
"flex justify-center items-center w-100%"
>
<div
class=
"flex justify-center items-center"
style=
"width: 50px; height: 50px"
>
<el-badge
:hidden=
"item.adminUnreadMessageCount === 0"
:max=
"99"
:value=
"item.adminUnreadMessageCount"
>
<el-avatar
:src=
"item.userAvatar"
alt=
"avatar"
/>
<el-avatar
:src=
"item.userAvatar"
alt=
"avatar"
/>
</el-badge>
</div>
<div
class=
"ml-10px w-100%"
>
<div
class=
"ml-10px w-100%"
>
<div
class=
"flex justify-between items-center w-100%"
>
<div
class=
"flex justify-between items-center w-100%"
>
<span>
{{
item
.
userNickname
}}
</span>
<span>
{{
item
.
userNickname
}}
</span>
...
@@ -24,8 +32,10 @@
...
@@ -24,8 +32,10 @@
></div>
></div>
</
template
>
</
template
>
<!-- 图片消息 -->
<!-- 图片消息 -->
<
template
v-if=
"KeFuMessageContentTypeEnum.IMAGE === item.lastMessageContentType"
>
<
template
v-else
>
<div
class=
"last-message flex items-center color-[#989EA6]"
>
【图片消息】
</div>
<div
class=
"last-message flex items-center color-[#989EA6]"
>
{{
getContentType
(
item
.
lastMessageContentType
)
}}
</div>
</
template
>
</
template
>
</div>
</div>
</div>
</div>
...
@@ -55,6 +65,25 @@ const openRightMessage = (item: KeFuConversationRespVO, index: number) => {
...
@@ -55,6 +65,25 @@ const openRightMessage = (item: KeFuConversationRespVO, index: number) => {
activeConversationIndex
.
value
=
index
activeConversationIndex
.
value
=
index
emits
(
'change'
,
item
)
emits
(
'change'
,
item
)
}
}
// 获得消息类型
const
getContentType
=
computed
(()
=>
(
lastMessageContentType
:
number
)
=>
{
switch
(
lastMessageContentType
)
{
case
KeFuMessageContentTypeEnum
.
SYSTEM
:
return
'[系统消息]'
case
KeFuMessageContentTypeEnum
.
VIDEO
:
return
'[视频消息]'
case
KeFuMessageContentTypeEnum
.
IMAGE
:
return
'[图片消息]'
case
KeFuMessageContentTypeEnum
.
PRODUCT
:
return
'[商品消息]'
case
KeFuMessageContentTypeEnum
.
ORDER
:
return
'[订单消息]'
case
KeFuMessageContentTypeEnum
.
VOICE
:
return
'[语音消息]'
default
:
return
''
}
})
</
script
>
</
script
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
...
...
src/views/mall/promotion/kefu/components/index.ts
View file @
9ab367e4
import
KeFuConversationBox
from
'./KeFuConversationBox.vue'
import
KeFuConversationBox
from
'./KeFuConversationBox.vue'
import
KeFuChatBox
from
'./KeFuChatBox.vue'
import
KeFuChatBox
from
'./KeFuChatBox.vue'
import
*
as
Constants
from
'./tools/constants'
export
{
KeFuConversationBox
,
KeFuChatBox
,
Constants
}
export
{
KeFuConversationBox
,
KeFuChatBox
}
src/views/mall/promotion/kefu/index.vue
View file @
9ab367e4
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
</el-col>
</el-col>
<el-col
:span=
"16"
>
<el-col
:span=
"16"
>
<ContentWrap>
<ContentWrap>
<KeFuChatBox
ref=
"keFuChatBoxRef"
/>
<KeFuChatBox
ref=
"keFuChatBoxRef"
@
change=
"getConversationList"
/>
</ContentWrap>
</ContentWrap>
</el-col>
</el-col>
</el-row>
</el-row>
...
@@ -15,13 +15,14 @@
...
@@ -15,13 +15,14 @@
<
script
lang=
"ts"
setup
>
<
script
lang=
"ts"
setup
>
import
{
KeFuChatBox
,
KeFuConversationBox
}
from
'./components'
import
{
KeFuChatBox
,
KeFuConversationBox
}
from
'./components'
import
{
WebSocketMessageTypeConstants
}
from
'./components/tools/constants'
import
{
KeFuConversationRespVO
}
from
'@/api/mall/promotion/kefu/conversation'
import
{
KeFuConversationRespVO
}
from
'@/api/mall/promotion/kefu/conversation'
import
{
getAccessToken
}
from
'@/utils/auth'
import
{
getAccessToken
}
from
'@/utils/auth'
import
{
useWebSocket
}
from
'@vueuse/core'
import
{
useWebSocket
}
from
'@vueuse/core'
import
{
WebSocketMessageTypeConstants
}
from
'@/views/mall/promotion/kefu/components/tools/constants'
defineOptions
({
name
:
'KeFu'
})
defineOptions
({
name
:
'KeFu'
})
const
message
=
useMessage
()
const
message
=
useMessage
()
// 加载消息
// 加载消息
const
keFuChatBoxRef
=
ref
<
InstanceType
<
typeof
KeFuChatBox
>>
()
const
keFuChatBoxRef
=
ref
<
InstanceType
<
typeof
KeFuChatBox
>>
()
const
handleChange
=
(
conversation
:
KeFuConversationRespVO
)
=>
{
const
handleChange
=
(
conversation
:
KeFuConversationRespVO
)
=>
{
...
@@ -47,10 +48,6 @@ watchEffect(() => {
...
@@ -47,10 +48,6 @@ watchEffect(() => {
try
{
try
{
// 1. 收到心跳
// 1. 收到心跳
if
(
data
.
value
===
'pong'
)
{
if
(
data
.
value
===
'pong'
)
{
// state.recordList.push({
// text: '【心跳】',
// time: new Date().getTime()
// })
return
return
}
}
...
@@ -63,12 +60,17 @@ watchEffect(() => {
...
@@ -63,12 +60,17 @@ watchEffect(() => {
}
}
// 2.2 消息类型:KEFU_MESSAGE_TYPE
// 2.2 消息类型:KEFU_MESSAGE_TYPE
if
(
type
===
WebSocketMessageTypeConstants
.
KEFU_MESSAGE_TYPE
)
{
if
(
type
===
WebSocketMessageTypeConstants
.
KEFU_MESSAGE_TYPE
)
{
// 刷新列表
// 刷新
会话
列表
getConversationList
()
getConversationList
()
// 刷新消息列表
// 刷新消息列表
keFuChatBoxRef
.
value
?.
refreshMessageList
()
keFuChatBoxRef
.
value
?.
refreshMessageList
()
return
return
}
}
// 2.3 消息类型:KEFU_MESSAGE_ADMIN_READ
if
(
type
===
WebSocketMessageTypeConstants
.
KEFU_MESSAGE_ADMIN_READ
)
{
// 刷新会话列表
getConversationList
()
}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
error
)
console
.
error
(
error
)
}
}
...
...
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