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
e342e91f
authored
Nov 09, 2024
by
puhui999
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【功能完善】商城: 客服会话缓存
parent
1c3be2b9
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
99 additions
and
31 deletions
+99
-31
src/api/mall/promotion/kefu/conversation/index.ts
+5
-1
src/store/modules/mall/kefu.ts
+72
-5
src/views/mall/promotion/kefu/components/KeFuConversationList.vue
+8
-13
src/views/mall/promotion/kefu/components/KeFuMessageList.vue
+4
-0
src/views/mall/promotion/kefu/index.vue
+10
-12
No files found.
src/api/mall/promotion/kefu/conversation/index.ts
View file @
e342e91f
...
...
@@ -21,6 +21,10 @@ export const KeFuConversationApi = {
getConversationList
:
async
()
=>
{
return
await
request
.
get
({
url
:
'/promotion/kefu-conversation/list'
})
},
// 获得客服会话
getConversation
:
async
(
id
:
number
)
=>
{
return
await
request
.
get
({
url
:
`/promotion/kefu-conversation/get?id=`
+
id
})
},
// 客服会话置顶
updateConversationPinned
:
async
(
data
:
any
)
=>
{
return
await
request
.
put
({
...
...
@@ -30,6 +34,6 @@ export const KeFuConversationApi = {
},
// 删除客服会话
deleteConversation
:
async
(
id
:
number
)
=>
{
return
await
request
.
delete
({
url
:
`/promotion/kefu-conversation/delete?id=
${
id
}
`
})
return
await
request
.
delete
({
url
:
`/promotion/kefu-conversation/delete?id=
${
id
}
`
})
}
}
src/store/modules/mall/kefu.ts
View file @
e342e91f
...
...
@@ -2,6 +2,7 @@ import { store } from '@/store'
import
{
defineStore
}
from
'pinia'
import
{
KeFuConversationApi
,
KeFuConversationRespVO
}
from
'@/api/mall/promotion/kefu/conversation'
import
{
KeFuMessageRespVO
}
from
'@/api/mall/promotion/kefu/message'
import
{
isEmpty
}
from
'@/utils/is'
// TODO puhui999: 待优化完善
interface
MallKefuInfoVO
{
...
...
@@ -23,15 +24,81 @@ export const useMallKefuStore = defineStore('mall-kefu', {
}
},
actions
:
{
/** 加载会话缓存列表 */
async
setConversationList
()
{
const
list
=
await
KeFuConversationApi
.
getConversationList
()
list
.
sort
((
a
:
KeFuConversationRespVO
,
_
)
=>
(
a
.
adminPinned
?
-
1
:
1
))
this
.
conversationList
=
list
this
.
conversationList
=
await
KeFuConversationApi
.
getConversationList
()
this
.
conversationSort
()
},
/** 更新会话缓存已读 */
async
updateConversationStatus
(
conversationId
:
number
)
{
if
(
isEmpty
(
this
.
conversationList
))
{
return
}
const
conversation
=
this
.
conversationList
.
find
((
item
)
=>
item
.
id
===
conversationId
)
conversation
&&
(
conversation
.
adminUnreadMessageCount
=
0
)
},
/** 更新会话缓存 */
async
updateConversation
(
conversationId
:
number
)
{
if
(
isEmpty
(
this
.
conversationList
))
{
return
}
const
conversation
=
await
KeFuConversationApi
.
getConversation
(
conversationId
)
this
.
deleteConversation
(
conversationId
)
conversation
&&
this
.
conversationList
.
push
(
conversation
)
this
.
conversationSort
()
},
/** 删除会话缓存 */
deleteConversation
(
conversationId
:
number
)
{
const
index
=
this
.
conversationList
.
findIndex
((
item
)
=>
item
.
id
===
conversationId
)
// 存在则删除
if
(
index
>
-
1
)
{
this
.
conversationList
.
splice
(
index
,
1
)
}
},
conversationSort
()
{
this
.
conversationList
.
sort
((
obj1
,
obj2
)
=>
{
// 如果 obj1.adminPinned 为 true,obj2.adminPinned 为 false,obj1 应该排在前面
if
(
obj1
.
adminPinned
&&
!
obj2
.
adminPinned
)
return
-
1
// 如果 obj1.adminPinned 为 false,obj2.adminPinned 为 true,obj2 应该排在前面
if
(
!
obj1
.
adminPinned
&&
obj2
.
adminPinned
)
return
1
// 如果 obj1.adminPinned 和 obj2.adminPinned 都为 true,比较 adminUnreadMessageCount 的值
if
(
obj1
.
adminPinned
&&
obj2
.
adminPinned
)
{
return
obj1
.
adminUnreadMessageCount
-
obj2
.
adminUnreadMessageCount
}
// 如果 obj1.adminPinned 和 obj2.adminPinned 都为 false,比较 adminUnreadMessageCount 的值
if
(
!
obj1
.
adminPinned
&&
!
obj2
.
adminPinned
)
{
return
obj1
.
adminUnreadMessageCount
-
obj2
.
adminUnreadMessageCount
}
// 如果 obj1.adminPinned 为 true,obj2.adminPinned 为 true,且 b 都大于 0,比较 adminUnreadMessageCount 的值
if
(
obj1
.
adminPinned
&&
obj2
.
adminPinned
&&
obj1
.
adminUnreadMessageCount
>
0
&&
obj2
.
adminUnreadMessageCount
>
0
)
{
return
obj1
.
adminUnreadMessageCount
-
obj2
.
adminUnreadMessageCount
}
// 如果 obj1.adminPinned 为 false,obj2.adminPinned 为 false,且 b 都大于 0,比较 adminUnreadMessageCount 的值
if
(
!
obj1
.
adminPinned
&&
!
obj2
.
adminPinned
&&
obj1
.
adminUnreadMessageCount
>
0
&&
obj2
.
adminUnreadMessageCount
>
0
)
{
return
obj1
.
adminUnreadMessageCount
-
obj2
.
adminUnreadMessageCount
}
return
0
})
}
// async setConversationMessageList(conversationId: number) {}
}
})
export
const
use
User
StoreWithOut
=
()
=>
{
export
const
use
MallKefu
StoreWithOut
=
()
=>
{
return
useMallKefuStore
(
store
)
}
src/views/mall/promotion/kefu/components/KeFuConversationList.vue
View file @
e342e91f
<
template
>
<el-aside
class=
"kefu p-5px h-100%"
width=
"260px"
>
<div
class=
"color-[#999] font-bold my-10px"
>
会话记录(
{{
conversationList
.
length
}}
)
</div>
<div
class=
"color-[#999] font-bold my-10px"
>
会话记录(
{{
kefuStore
.
getConversationList
.
length
}}
)
</div>
<div
v-for=
"item in
c
onversationList"
v-for=
"item in
kefuStore.getC
onversationList"
:key=
"item.id"
:class=
"
{ active: item.id === activeConversationId, pinned: item.adminPinned }"
class="kefu-conversation flex items-center"
...
...
@@ -75,24 +77,17 @@ import { useEmoji } from './tools/emoji'
import
{
formatPast
}
from
'@/utils/formatTime'
import
{
KeFuMessageContentTypeEnum
}
from
'./tools/constants'
import
{
useAppStore
}
from
'@/store/modules/app'
import
{
useMallKefuStore
}
from
'@/store/modules/mall/kefu'
defineOptions
({
name
:
'KeFuConversationList'
})
const
message
=
useMessage
()
// 消息弹窗
const
appStore
=
useAppStore
()
const
kefuStore
=
useMallKefuStore
()
// 客服缓存
const
{
replaceEmoji
}
=
useEmoji
()
const
conversationList
=
ref
<
KeFuConversationRespVO
[]
>
([])
// 会话列表
const
activeConversationId
=
ref
(
-
1
)
// 选中的会话
const
collapse
=
computed
(()
=>
appStore
.
getCollapse
)
// 折叠菜单
/** 加载会话列表 */
const
getConversationList
=
async
()
=>
{
const
list
=
await
KeFuConversationApi
.
getConversationList
()
list
.
sort
((
a
:
KeFuConversationRespVO
,
_
)
=>
(
a
.
adminPinned
?
-
1
:
1
))
conversationList
.
value
=
list
}
defineExpose
({
getConversationList
})
/** 打开右侧的消息列表 */
const
emits
=
defineEmits
<
{
(
e
:
'change'
,
v
:
KeFuConversationRespVO
):
void
...
...
@@ -156,7 +151,7 @@ const updateConversationPinned = async (adminPinned: boolean) => {
message
.
notifySuccess
(
adminPinned
?
'置顶成功'
:
'取消置顶成功'
)
// 2. 关闭右键菜单,更新会话列表
closeRightMenu
()
await
getConversationList
(
)
await
kefuStore
.
updateConversation
(
rightClickConversation
.
value
.
id
)
}
/** 删除会话 */
...
...
@@ -166,7 +161,7 @@ const deleteConversation = async () => {
await
KeFuConversationApi
.
deleteConversation
(
rightClickConversation
.
value
.
id
)
// 2. 关闭右键菜单,更新会话列表
closeRightMenu
()
await
getConversationList
(
)
kefuStore
.
deleteConversation
(
rightClickConversation
.
value
.
id
)
}
/** 监听右键菜单的显示状态,添加点击事件监听器 */
...
...
src/views/mall/promotion/kefu/components/KeFuMessageList.vue
View file @
e342e91f
...
...
@@ -152,6 +152,7 @@ import dayjs from 'dayjs'
import
relativeTime
from
'dayjs/plugin/relativeTime'
import
{
debounce
}
from
'lodash-es'
import
{
jsonParse
}
from
'@/utils'
import
{
useMallKefuStore
}
from
'@/store/modules/mall/kefu'
dayjs
.
extend
(
relativeTime
)
...
...
@@ -169,6 +170,7 @@ const queryParams = reactive({
})
const
total
=
ref
(
0
)
// 消息总条数
const
refreshContent
=
ref
(
false
)
// 内容刷新,主要解决会话消息页面高度不一致导致的滚动功能精度失效
const
kefuStore
=
useMallKefuStore
()
// 客服缓存
/** 获悉消息内容 */
const
getMessageContent
=
computed
(()
=>
(
item
:
any
)
=>
jsonParse
(
item
.
content
))
...
...
@@ -297,6 +299,8 @@ const sendMessage = async (msg: any) => {
message
.
value
=
''
// 加载消息列表
await
refreshMessageList
()
// 异步刷新
kefuStore
.
updateConversation
(
conversation
.
value
.
id
)
}
/** 滚动到底部 */
...
...
src/views/mall/promotion/kefu/index.vue
View file @
e342e91f
...
...
@@ -3,7 +3,7 @@
<!-- 会话列表 -->
<KeFuConversationList
ref=
"keFuConversationRef"
@
change=
"handleChange"
/>
<!-- 会话详情(选中会话的消息列表) -->
<KeFuMessageList
ref=
"keFuChatBoxRef"
@
change=
"getConversationList"
/>
<KeFuMessageList
ref=
"keFuChatBoxRef"
/>
<!-- 会员信息(选中会话的会员信息) -->
<MemberInfo
ref=
"memberInfoRef"
/>
</el-container>
...
...
@@ -15,10 +15,12 @@ import { WebSocketMessageTypeConstants } from './components/tools/constants'
import
{
KeFuConversationRespVO
}
from
'@/api/mall/promotion/kefu/conversation'
import
{
getRefreshToken
}
from
'@/utils/auth'
import
{
useWebSocket
}
from
'@vueuse/core'
import
{
useMallKefuStore
}
from
'@/store/modules/mall/kefu'
defineOptions
({
name
:
'KeFu'
})
const
message
=
useMessage
()
// 消息弹窗
const
kefuStore
=
useMallKefuStore
()
// 客服缓存
// ======================= WebSocket start =======================
const
server
=
ref
(
...
...
@@ -53,29 +55,24 @@ watchEffect(() => {
}
// 2.2 消息类型:KEFU_MESSAGE_TYPE
if
(
type
===
WebSocketMessageTypeConstants
.
KEFU_MESSAGE_TYPE
)
{
const
message
=
JSON
.
parse
(
jsonMessage
.
content
)
// 刷新会话列表
// TODO @puhui999:不应该刷新列表,而是根据消息,本地 update 列表的数据;
getConversationList
(
)
kefuStore
.
updateConversation
(
message
.
conversationId
)
// 刷新消息列表
keFuChatBoxRef
.
value
?.
refreshMessageList
(
JSON
.
parse
(
jsonMessage
.
content
)
)
keFuChatBoxRef
.
value
?.
refreshMessageList
(
message
)
return
}
// 2.3 消息类型:KEFU_MESSAGE_ADMIN_READ
if
(
type
===
WebSocketMessageTypeConstants
.
KEFU_MESSAGE_ADMIN_READ
)
{
// 刷新会话列表
// TODO @puhui999:不应该刷新列表,而是根据消息,本地 update 列表的数据;
getConversationList
()
// 更新会话已读
kefuStore
.
updateConversationStatus
(
JSON
.
parse
(
jsonMessage
.
content
)?.
id
)
}
}
catch
(
error
)
{
console
.
error
(
error
)
}
})
// ======================= WebSocket end =======================
/** 加载会话列表 */
const
keFuConversationRef
=
ref
<
InstanceType
<
typeof
KeFuConversationList
>>
()
const
getConversationList
=
()
=>
{
keFuConversationRef
.
value
?.
getConversationList
()
}
/** 加载指定会话的消息列表 */
const
keFuChatBoxRef
=
ref
<
InstanceType
<
typeof
KeFuMessageList
>>
()
...
...
@@ -87,7 +84,8 @@ const handleChange = (conversation: KeFuConversationRespVO) => {
/** 初始化 */
onMounted
(()
=>
{
getConversationList
()
/** 加载会话列表 */
kefuStore
.
setConversationList
()
// 打开 websocket 连接
open
()
})
...
...
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