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
bfddd674
authored
Jul 19, 2024
by
xiaohong
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev' of
https://gitee.com/yudaocode/yudao-ui-admin-vue3
into dev
parents
21c7c17e
e8a0eb08
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
435 additions
and
246 deletions
+435
-246
src/api/mall/product/history.ts
+9
-0
src/views/ai/image/square/index.vue
+37
-16
src/views/mall/promotion/kefu/components/KeFuConversationList.vue
+13
-3
src/views/mall/promotion/kefu/components/KeFuMessageList.vue
+102
-39
src/views/mall/promotion/kefu/components/history/MemberBrowsingHistory.vue
+97
-0
src/views/mall/promotion/kefu/components/history/OrderBrowsingHistory.vue
+44
-0
src/views/mall/promotion/kefu/components/history/ProductBrowsingHistory.vue
+57
-0
src/views/mall/promotion/kefu/components/index.ts
+2
-1
src/views/mall/promotion/kefu/components/message/MessageItem.vue
+13
-23
src/views/mall/promotion/kefu/components/message/OrderItem.vue
+38
-74
src/views/mall/promotion/kefu/components/message/ProductItem.vue
+10
-18
src/views/mall/promotion/kefu/components/message/ProductMessageItem.vue
+0
-38
src/views/mall/promotion/kefu/components/message/TextMessageItem.vue
+0
-29
src/views/mall/promotion/kefu/index.vue
+13
-5
No files found.
src/api/mall/product/history.ts
0 → 100644
View file @
bfddd674
import
request
from
'@/config/axios'
/**
* 获得商品浏览记录分页
* @param params 请求参数
*/
export
const
getBrowseHistoryPage
=
(
params
:
any
)
=>
{
return
request
.
get
({
url
:
'/product/browse-history/page'
,
params
})
}
src/views/ai/image/square/index.vue
View file @
bfddd674
<
template
>
<div
class=
"
card-list
"
>
<div
v-for=
"item in publicList"
:key=
"item
.id"
class=
"card
"
>
<img
:src=
"item.picUrl"
class=
"img"
/>
<div
class=
"
gallery
"
>
<div
v-for=
"item in publicList"
:key=
"item
"
class=
"gallery-item
"
>
<img
:src=
"item.picUrl"
class=
"img"
/>
</div>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
ImageApi
,
ImageVO
}
from
'@/api/ai/image'
import
{
ImageApi
,
ImageVO
,
ImageMidjourneyButtonsVO
}
from
'@/api/ai/image'
/** 属性 */
// TODO @fan:queryParams 里面搞分页哈。
const
pageNo
=
ref
<
number
>
(
1
)
const
pageSize
=
ref
<
number
>
(
20
)
const
publicList
=
ref
<
ImageVO
[]
>
([])
/** 获取数据 */
const
getListData
=
async
()
=>
{
const
res
=
await
ImageApi
.
getImagePagePublic
({
pageNo
:
pageNo
.
value
,
pageSize
:
pageSize
.
value
})
publicList
.
value
=
res
.
list
as
ImageVO
[]
const
res
=
await
ImageApi
.
getImagePagePublic
({
pageNo
:
pageNo
.
value
,
pageSize
:
pageSize
.
value
});
publicList
.
value
=
res
.
list
as
ImageVO
[]
;
console
.
log
(
'publicList.value'
,
publicList
.
value
)
}
...
...
@@ -26,16 +25,38 @@ onMounted(async () => {
})
</
script
>
<
style
scoped
lang=
"scss"
>
.card-list
{
//
display
:
flex
;
//
flex-direction
:
column
;
column-count
:
4
;
column-gap
:
3px
;
.gallery
{
display
:
grid
;
grid-template-columns
:
repeat
(
auto-fill
,
minmax
(
200px
,
1
fr
));
gap
:
10px
;
//
max-width
:
1000px
;
padding
:
20px
;
background-color
:
#fff
;
box-shadow
:
0
0
10px
rgba
(
0
,
0
,
0
,
0.1
);
}
.gallery-item
{
position
:
relative
;
overflow
:
hidden
;
background
:
#f0f0f0
;
cursor
:
pointer
;
transition
:
transform
0.3s
;
}
.gallery-item
img
{
width
:
100%
;
height
:
auto
;
display
:
block
;
transition
:
transform
0.3s
;
}
.gallery-item
:hover
img
{
transform
:
scale
(
1.1
);
}
.card
{
.img
{
width
:
50%
;
}
.gallery-item
:hover
{
transform
:
scale
(
1.05
);
}
</
style
>
src/views/mall/promotion/kefu/components/KeFuConversationList.vue
View file @
bfddd674
...
...
@@ -21,9 +21,9 @@
</div>
<div
class=
"ml-10px w-100%"
>
<div
class=
"flex justify-between items-center w-100%"
>
<span>
{{
item
.
userNickname
}}
</span>
<span
class=
"username"
>
{{
item
.
userNickname
}}
</span>
<span
class=
"color-[#989EA6]"
>
{{
format
Date
(
item
.
lastMessageTime
)
}}
{{
format
Past
(
item
.
lastMessageTime
,
'YYYY-mm-dd'
)
}}
</span>
</div>
<!-- 最后聊天内容 -->
...
...
@@ -70,7 +70,7 @@
<
script
lang=
"ts"
setup
>
import
{
KeFuConversationApi
,
KeFuConversationRespVO
}
from
'@/api/mall/promotion/kefu/conversation'
import
{
useEmoji
}
from
'./tools/emoji'
import
{
format
Date
}
from
'@/utils/formatTime'
import
{
format
Past
}
from
'@/utils/formatTime'
import
{
KeFuMessageContentTypeEnum
}
from
'./tools/constants'
import
{
useAppStore
}
from
'@/store/modules/app'
...
...
@@ -185,6 +185,16 @@ watch(showRightMenu, (val) => {
background-color
:
#fff
;
transition
:
border-left
0.05s
ease-in-out
;
/* 设置过渡效果 */
.username
{
min-width
:
0
;
max-width
:
60%
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
display
:
-webkit-box
;
-webkit-box-orient
:
vertical
;
-webkit-line-clamp
:
1
;
}
.last-message
{
width
:
200px
;
overflow
:
hidden
;
//
隐藏超出的文本
...
...
src/views/mall/promotion/kefu/components/KeFuMessageList.vue
View file @
bfddd674
...
...
@@ -40,19 +40,54 @@
v-if=
"item.senderType === UserTypeEnum.MEMBER"
:src=
"conversation.userAvatar"
alt=
"avatar"
class=
"w-60px h-60px"
/>
<div
:class=
"
{ 'kefu-message': KeFuMessageContentTypeEnum.TEXT === item.contentType }"
class="p-10px"
>
<!-- 文本消息 -->
<TextMessageItem
:message=
"item"
/>
<MessageItem
:message=
"item"
>
<template
v-if=
"KeFuMessageContentTypeEnum.TEXT === item.contentType"
>
<div
v-dompurify-html=
"replaceEmoji(item.content)"
class=
"flex items-center"
></div>
</
template
>
</MessageItem>
<!-- 图片消息 -->
<ImageMessageItem
:message=
"item"
/>
<MessageItem
:message=
"item"
>
<el-image
v-if=
"KeFuMessageContentTypeEnum.IMAGE === item.contentType"
:initial-index=
"0"
:preview-src-list=
"[item.content]"
:src=
"item.content"
class=
"w-200px"
fit=
"contain"
preview-teleported
/>
</MessageItem>
<!-- 商品消息 -->
<ProductMessageItem
:message=
"item"
/>
<MessageItem
:message=
"item"
>
<ProductItem
v-if=
"KeFuMessageContentTypeEnum.PRODUCT === item.contentType"
:picUrl=
"getMessageContent(item).picUrl"
:price=
"getMessageContent(item).price"
:skuText=
"getMessageContent(item).introduction"
:title=
"getMessageContent(item).spuName"
:titleWidth=
"400"
class=
"max-w-70%"
priceColor=
"#FF3000"
/>
</MessageItem>
<!-- 订单消息 -->
<OrderMessageItem
:message=
"item"
/>
<MessageItem
:message=
"item"
>
<OrderItem
v-if=
"KeFuMessageContentTypeEnum.ORDER === item.contentType"
:message=
"item"
class=
"max-w-70%"
/>
</MessageItem>
</div>
<el-avatar
v-if=
"item.senderType === UserTypeEnum.ADMIN"
...
...
@@ -97,24 +132,24 @@ import { KeFuMessageApi, KeFuMessageRespVO } from '@/api/mall/promotion/kefu/mes
import
{
KeFuConversationRespVO
}
from
'@/api/mall/promotion/kefu/conversation'
import
EmojiSelectPopover
from
'./tools/EmojiSelectPopover.vue'
import
PictureSelectUpload
from
'./tools/PictureSelectUpload.vue'
import
TextMessageItem
from
'./message/TextMessageItem.vue'
import
ImageMessageItem
from
'./message/ImageMessageItem.vue'
import
ProductMessageItem
from
'./message/ProductMessageItem.vue'
import
OrderMessageItem
from
'./message/OrderMessageItem.vue'
import
{
Emoji
}
from
'./tools/emoji'
import
ProductItem
from
'./message/ProductItem.vue'
import
OrderItem
from
'./message/OrderItem.vue'
import
{
Emoji
,
useEmoji
}
from
'./tools/emoji'
import
{
KeFuMessageContentTypeEnum
}
from
'./tools/constants'
import
{
isEmpty
}
from
'@/utils/is'
import
{
UserTypeEnum
}
from
'@/utils/constants'
import
{
formatDate
}
from
'@/utils/formatTime'
import
dayjs
from
'dayjs'
import
relativeTime
from
'dayjs/plugin/relativeTime'
import
{
debounce
}
from
'lodash-es'
import
{
jsonParse
}
from
'@/utils'
dayjs
.
extend
(
relativeTime
)
defineOptions
({
name
:
'KeFuMessageList'
})
const
message
=
ref
(
''
)
// 消息弹窗
const
{
replaceEmoji
}
=
useEmoji
()
const
messageTool
=
useMessage
()
const
messageList
=
ref
<
KeFuMessageRespVO
[]
>
([])
// 消息列表
const
conversation
=
ref
<
KeFuConversationRespVO
>
({}
as
KeFuConversationRespVO
)
// 用户会话
...
...
@@ -126,18 +161,11 @@ const queryParams = reactive({
})
const
total
=
ref
(
0
)
// 消息总条数
const
refreshContent
=
ref
(
false
)
// 内容刷新,主要解决会话消息页面高度不一致导致的滚动功能精度失效
/** 获悉消息内容 */
const
getMessageContent
=
computed
(()
=>
(
item
:
any
)
=>
jsonParse
(
item
.
content
))
/** 获得消息列表 */
const
getMessageList
=
async
(
val
:
KeFuConversationRespVO
,
conversationChange
:
boolean
)
=>
{
// 会话切换,重置相关参数
if
(
conversationChange
)
{
queryParams
.
pageNo
=
1
messageList
.
value
=
[]
total
.
value
=
0
loadHistory
.
value
=
false
refreshContent
.
value
=
false
}
conversation
.
value
=
val
queryParams
.
conversationId
=
val
.
id
const
getMessageList
=
async
()
=>
{
const
res
=
await
KeFuMessageApi
.
getKeFuMessagePage
(
queryParams
)
total
.
value
=
res
.
total
// 情况一:加载最新消息
...
...
@@ -146,14 +174,18 @@ const getMessageList = async (val: KeFuConversationRespVO, conversationChange: b
}
else
{
// 情况二:加载历史消息
for
(
const
item
of
res
.
list
)
{
if
(
messageList
.
value
.
some
((
val
)
=>
val
.
id
===
item
.
id
))
{
continue
}
messageList
.
value
.
push
(
item
)
pushMessage
(
item
)
}
}
refreshContent
.
value
=
true
await
scrollToBottom
()
}
/** 添加消息 */
const
pushMessage
=
(
message
:
any
)
=>
{
if
(
messageList
.
value
.
some
((
val
)
=>
val
.
id
===
message
.
id
))
{
return
}
messageList
.
value
.
push
(
message
)
}
/** 按照时间倒序,获取消息列表 */
...
...
@@ -163,20 +195,46 @@ const getMessageList0 = computed(() => {
})
/** 刷新消息列表 */
const
refreshMessageList
=
async
()
=>
{
const
refreshMessageList
=
async
(
message
?:
any
)
=>
{
if
(
!
conversation
.
value
)
{
return
}
queryParams
.
pageNo
=
1
await
getMessageList
(
conversation
.
value
,
false
)
if
(
typeof
message
!==
'undefined'
)
{
// 当前查询会话与消息所属会话不一致则不做处理
if
(
message
.
conversationId
!==
conversation
.
value
.
id
)
{
return
}
pushMessage
(
message
)
}
else
{
queryParams
.
pageNo
=
1
await
getMessageList
()
}
if
(
loadHistory
.
value
)
{
// 右下角显示有新消息提示
showNewMessageTip
.
value
=
true
}
else
{
// 滚动到最新消息处
await
handleToNewMessage
()
}
}
defineExpose
({
getMessageList
,
refreshMessageList
})
const
getNewMessageList
=
async
(
val
:
KeFuConversationRespVO
)
=>
{
// 会话切换,重置相关参数
queryParams
.
pageNo
=
1
messageList
.
value
=
[]
total
.
value
=
0
loadHistory
.
value
=
false
refreshContent
.
value
=
false
// 设置会话相关属性
conversation
.
value
=
val
queryParams
.
conversationId
=
val
.
id
// 获取消息
await
refreshMessageList
()
}
defineExpose
({
getNewMessageList
,
refreshMessageList
})
const
showKeFuMessageList
=
computed
(()
=>
!
isEmpty
(
conversation
.
value
))
// 是否显示聊天区域
const
skipGetMessageList
=
computed
(()
=>
{
// 已加载到最后一页的话则不触发新的消息获取
...
...
@@ -221,9 +279,7 @@ const sendMessage = async (msg: any) => {
await
KeFuMessageApi
.
sendKeFuMessage
(
msg
)
message
.
value
=
''
// 加载消息列表
await
getMessageList
(
conversation
.
value
,
false
)
// 滚动到最新消息处
await
scrollToBottom
()
await
refreshMessageList
()
}
/** 滚动到底部 */
...
...
@@ -248,17 +304,24 @@ const handleToNewMessage = async () => {
await
scrollToBottom
()
}
/** 加载历史消息 */
const
loadHistory
=
ref
(
false
)
// 加载历史消息
const
handleScroll
=
async
({
scrollTop
})
=>
{
/** 处理消息列表滚动事件(debounce 限流) */
const
handleScroll
=
debounce
(({
scrollTop
})
=>
{
if
(
skipGetMessageList
.
value
)
{
return
}
// 触顶自动加载下一页数据
if
(
scrollTop
===
0
)
{
await
handleOldMessage
()
if
(
Math
.
floor
(
scrollTop
)
===
0
)
{
handleOldMessage
()
}
}
const
wrap
=
scrollbarRef
.
value
?.
wrapRef
// 触底重置
if
(
Math
.
abs
(
wrap
!
.
scrollHeight
-
wrap
!
.
clientHeight
-
wrap
!
.
scrollTop
)
<
1
)
{
loadHistory
.
value
=
false
refreshMessageList
()
}
},
200
)
/** 加载历史消息 */
const
handleOldMessage
=
async
()
=>
{
// 记录已有页面高度
const
oldPageHeight
=
innerRef
.
value
?.
clientHeight
...
...
@@ -268,7 +331,7 @@ const handleOldMessage = async () => {
loadHistory
.
value
=
true
// 加载消息列表
queryParams
.
pageNo
+=
1
await
getMessageList
(
conversation
.
value
,
false
)
await
getMessageList
()
// 等页面加载完后,获得上一页最后一条消息的位置,控制滚动到它所在位置
scrollbarRef
.
value
!
.
setScrollTop
(
innerRef
.
value
!
.
clientHeight
-
oldPageHeight
)
}
...
...
src/views/mall/promotion/kefu/components/history/MemberBrowsingHistory.vue
0 → 100644
View file @
bfddd674
<!-- 目录是不是叫 member 好点。然后这个组件是 MemberInfo,里面有浏览足迹 -->
<
template
>
<div
v-show=
"!isEmpty(conversation)"
class=
"kefu"
>
<div
class=
"header-title h-60px flex justify-center items-center"
>
他的足迹
</div>
<el-tabs
v-model=
"activeName"
class=
"demo-tabs"
@
tab-click=
"handleClick"
>
<el-tab-pane
label=
"最近浏览"
name=
"a"
/>
<el-tab-pane
label=
"订单列表"
name=
"b"
/>
</el-tabs>
<div>
<el-scrollbar
ref=
"scrollbarRef"
always
height=
"calc(100vh - 400px)"
@
scroll=
"handleScroll"
>
<!-- 最近浏览 -->
<ProductBrowsingHistory
v-if=
"activeName === 'a'"
ref=
"productBrowsingHistoryRef"
/>
<!-- 订单列表 -->
<OrderBrowsingHistory
v-if=
"activeName === 'b'"
ref=
"orderBrowsingHistoryRef"
/>
</el-scrollbar>
</div>
</div>
<el-empty
v-show=
"isEmpty(conversation)"
description=
"请选择左侧的一个会话后开始"
/>
</
template
>
<
script
lang=
"ts"
setup
>
import
type
{
TabsPaneContext
}
from
'element-plus'
import
ProductBrowsingHistory
from
'./ProductBrowsingHistory.vue'
import
OrderBrowsingHistory
from
'./OrderBrowsingHistory.vue'
import
{
KeFuConversationRespVO
}
from
'@/api/mall/promotion/kefu/conversation'
import
{
isEmpty
}
from
'@/utils/is'
import
{
debounce
}
from
'lodash-es'
import
{
ElScrollbar
as
ElScrollbarType
}
from
'element-plus/es/components/scrollbar'
defineOptions
({
name
:
'MemberBrowsingHistory'
})
const
activeName
=
ref
(
'a'
)
/** tab 切换 */
const
productBrowsingHistoryRef
=
ref
<
InstanceType
<
typeof
ProductBrowsingHistory
>>
()
const
orderBrowsingHistoryRef
=
ref
<
InstanceType
<
typeof
OrderBrowsingHistory
>>
()
const
handleClick
=
async
(
tab
:
TabsPaneContext
)
=>
{
activeName
.
value
=
tab
.
paneName
as
string
await
nextTick
()
await
getHistoryList
()
}
/** 获得历史数据 */
// TODO @puhui:不要用 a、b 哈。就订单列表、浏览列表这种噶
const
getHistoryList
=
async
()
=>
{
switch
(
activeName
.
value
)
{
case
'a'
:
await
productBrowsingHistoryRef
.
value
?.
getHistoryList
(
conversation
.
value
)
break
case
'b'
:
await
orderBrowsingHistoryRef
.
value
?.
getHistoryList
(
conversation
.
value
)
break
default
:
break
}
}
/** 加载下一页数据 */
const
loadMore
=
async
()
=>
{
switch
(
activeName
.
value
)
{
case
'a'
:
await
productBrowsingHistoryRef
.
value
?.
loadMore
()
break
case
'b'
:
await
orderBrowsingHistoryRef
.
value
?.
loadMore
()
break
default
:
break
}
}
/** 浏览历史初始化 */
const
conversation
=
ref
<
KeFuConversationRespVO
>
({}
as
KeFuConversationRespVO
)
// 用户会话
const
initHistory
=
async
(
val
:
KeFuConversationRespVO
)
=>
{
activeName
.
value
=
'a'
conversation
.
value
=
val
await
nextTick
()
await
getHistoryList
()
}
defineExpose
({
initHistory
})
/** 处理消息列表滚动事件(debounce 限流) */
const
scrollbarRef
=
ref
<
InstanceType
<
typeof
ElScrollbarType
>>
()
const
handleScroll
=
debounce
(()
=>
{
const
wrap
=
scrollbarRef
.
value
?.
wrapRef
// 触底重置
if
(
Math
.
abs
(
wrap
!
.
scrollHeight
-
wrap
!
.
clientHeight
-
wrap
!
.
scrollTop
)
<
1
)
{
loadMore
()
}
},
200
)
</
script
>
<
style
lang=
"scss"
scoped
>
.header-title
{
border-bottom
:
#e4e0e0
solid
1px
;
}
</
style
>
src/views/mall/promotion/kefu/components/history/OrderBrowsingHistory.vue
0 → 100644
View file @
bfddd674
<
template
>
<OrderItem
v-for=
"item in list"
:key=
"item.id"
:order=
"item"
class=
"mb-10px"
/>
</
template
>
<
script
lang=
"ts"
setup
>
import
OrderItem
from
'@/views/mall/promotion/kefu/components/message/OrderItem.vue'
import
{
KeFuConversationRespVO
}
from
'@/api/mall/promotion/kefu/conversation'
import
{
getOrderPage
}
from
'@/api/mall/trade/order'
import
{
concat
}
from
'lodash-es'
defineOptions
({
name
:
'OrderBrowsingHistory'
})
const
list
=
ref
<
any
>
([])
// 列表
const
total
=
ref
(
0
)
// 总数
const
queryParams
=
reactive
({
pageNo
:
1
,
pageSize
:
10
,
userId
:
0
})
const
skipGetMessageList
=
computed
(()
=>
{
// 已加载到最后一页的话则不触发新的消息获取
return
total
.
value
>
0
&&
Math
.
ceil
(
total
.
value
/
queryParams
.
pageSize
)
===
queryParams
.
pageNo
})
// 跳过消息获取
/** 获得浏览记录 */
const
getHistoryList
=
async
(
val
:
KeFuConversationRespVO
)
=>
{
queryParams
.
userId
=
val
.
userId
const
res
=
await
getOrderPage
(
queryParams
)
total
.
value
=
res
.
total
list
.
value
=
res
.
list
}
/** 加载下一页数据 */
const
loadMore
=
async
()
=>
{
if
(
skipGetMessageList
.
value
)
{
return
}
queryParams
.
pageNo
+=
1
const
res
=
await
getOrderPage
(
queryParams
)
total
.
value
=
res
.
total
concat
(
list
.
value
,
res
.
list
)
}
defineExpose
({
getHistoryList
,
loadMore
})
</
script
>
src/views/mall/promotion/kefu/components/history/ProductBrowsingHistory.vue
0 → 100644
View file @
bfddd674
<
template
>
<ProductItem
v-for=
"item in list"
:key=
"item.id"
:picUrl=
"item.picUrl"
:price=
"item.price"
:skuText=
"item.introduction"
:title=
"item.spuName"
:titleWidth=
"400"
class=
"mb-10px"
priceColor=
"#FF3000"
/>
</
template
>
<
script
lang=
"ts"
setup
>
import
{
getBrowseHistoryPage
}
from
'@/api/mall/product/history'
import
ProductItem
from
'@/views/mall/promotion/kefu/components/message/ProductItem.vue'
import
{
KeFuConversationRespVO
}
from
'@/api/mall/promotion/kefu/conversation'
import
{
concat
}
from
'lodash-es'
defineOptions
({
name
:
'ProductBrowsingHistory'
})
const
list
=
ref
<
any
>
([])
// 列表
const
total
=
ref
(
0
)
// 总数
const
queryParams
=
reactive
({
pageNo
:
1
,
pageSize
:
10
,
userId
:
0
,
userDeleted
:
false
})
const
skipGetMessageList
=
computed
(()
=>
{
// 已加载到最后一页的话则不触发新的消息获取
return
total
.
value
>
0
&&
Math
.
ceil
(
total
.
value
/
queryParams
.
pageSize
)
===
queryParams
.
pageNo
})
// 跳过消息获取
/** 获得浏览记录 */
const
getHistoryList
=
async
(
val
:
KeFuConversationRespVO
)
=>
{
queryParams
.
userId
=
val
.
userId
const
res
=
await
getBrowseHistoryPage
(
queryParams
)
total
.
value
=
res
.
total
list
.
value
=
res
.
list
}
/** 加载下一页数据 */
const
loadMore
=
async
()
=>
{
if
(
skipGetMessageList
.
value
)
{
return
}
queryParams
.
pageNo
+=
1
const
res
=
await
getBrowseHistoryPage
(
queryParams
)
total
.
value
=
res
.
total
concat
(
list
.
value
,
res
.
list
)
}
defineExpose
({
getHistoryList
,
loadMore
})
</
script
>
<
style
lang=
"scss"
scoped
></
style
>
src/views/mall/promotion/kefu/components/index.ts
View file @
bfddd674
import
KeFuConversationList
from
'./KeFuConversationList.vue'
import
KeFuMessageList
from
'./KeFuMessageList.vue'
import
MemberBrowsingHistory
from
'./history/MemberBrowsingHistory.vue'
export
{
KeFuConversationList
,
KeFuMessageList
}
export
{
KeFuConversationList
,
KeFuMessageList
,
MemberBrowsingHistory
}
src/views/mall/promotion/kefu/components/message/
Image
MessageItem.vue
→
src/views/mall/promotion/kefu/components/message/MessageItem.vue
View file @
bfddd674
<
template
>
<!-- 图片消息 -->
<template
v-if=
"KeFuMessageContentTypeEnum.IMAGE === message.contentType"
>
<div
:class=
"[
message.senderType === UserTypeEnum.MEMBER
? `ml-10px`
: message.senderType === UserTypeEnum.ADMIN
? `mr-10px`
: ''
]"
>
<el-image
:initial-index=
"0"
:preview-src-list=
"[message.content]"
:src=
"message.content"
class=
"w-200px"
fit=
"contain"
preview-teleported
/>
</div>
</
template
>
<!-- 消息组件 -->
<div
:class=
"[
message.senderType === UserTypeEnum.MEMBER
? `ml-10px`
: message.senderType === UserTypeEnum.ADMIN
? `mr-10px`
: ''
]"
>
<slot></slot>
</div>
</
template
>
<
script
lang=
"ts"
setup
>
import
{
KeFuMessageContentTypeEnum
}
from
'../tools/constants'
import
{
UserTypeEnum
}
from
'@/utils/constants'
import
{
KeFuMessageRespVO
}
from
'@/api/mall/promotion/kefu/message'
defineOptions
({
name
:
'
Image
MessageItem'
})
defineOptions
({
name
:
'MessageItem'
})
defineProps
<
{
message
:
KeFuMessageRespVO
}
>
()
...
...
src/views/mall/promotion/kefu/components/message/Order
Message
Item.vue
→
src/views/mall/promotion/kefu/components/message/OrderItem.vue
View file @
bfddd674
<
template
>
<!-- 图片消息 -->
<template
v-if=
"KeFuMessageContentTypeEnum.ORDER === message.contentType"
>
<div
:class=
"[
message.senderType === UserTypeEnum.MEMBER
? `ml-10px`
: message.senderType === UserTypeEnum.ADMIN
? `mr-10px`
: ''
]"
>
<div
:key=
"getMessageContent.id"
class=
"order-list-card-box mt-14px"
>
<div
class=
"order-card-header flex items-center justify-between p-x-20px"
>
<div
class=
"order-no"
>
订单号:
{{
getMessageContent
.
no
}}
</div>
<div
:class=
"formatOrderColor(getMessageContent)"
class=
"order-state font-26"
>
{{
formatOrderStatus
(
getMessageContent
)
}}
</div>
</div>
<div
v-for=
"item in getMessageContent.items"
:key=
"item.id"
class=
"border-bottom"
>
<ProductItem
:num=
"item.count"
:picUrl=
"item.picUrl"
:price=
"item.price"
:skuText=
"item.properties.map((property: any) => property.valueName).join(' ')"
:title=
"item.spuName"
/>
<div
v-if=
"isObject(getMessageContent)"
>
<div
:key=
"getMessageContent.id"
class=
"order-list-card-box mt-14px"
>
<div
class=
"order-card-header flex items-center justify-between p-x-20px"
>
<div
class=
"order-no"
>
订单号:
{{
getMessageContent
.
no
}}
</div>
<div
:class=
"formatOrderColor(getMessageContent)"
class=
"order-state font-16"
>
{{
formatOrderStatus
(
getMessageContent
)
}}
</div>
<div
class=
"pay-box mt-30px flex justify-end pr-20px"
>
<div
class=
"flex items-center"
>
<div
class=
"discounts-title pay-color"
>
共
{{
getMessageContent
?.
productCount
}}
件商品,总金额:
</div>
<div
class=
"discounts-money pay-color"
>
¥
{{
fenToYuan
(
getMessageContent
?.
payPrice
)
}}
</div>
</div>
<div
v-for=
"item in getMessageContent.items"
:key=
"item.id"
class=
"border-bottom"
>
<ProductItem
:num=
"item.count"
:picUrl=
"item.picUrl"
:price=
"item.price"
:skuText=
"item.properties.map((property: any) => property.valueName).join(' ')"
:title=
"item.spuName"
/>
</div>
<div
class=
"pay-box flex justify-end pr-20px"
>
<div
class=
"flex items-center"
>
<div
class=
"discounts-title pay-color"
>
共
{{
getMessageContent
?.
productCount
}}
件商品,总金额:
</div>
<div
class=
"discounts-money pay-color"
>
¥
{{
fenToYuan
(
getMessageContent
?.
payPrice
)
}}
</div>
</div>
</div>
</div>
</
template
>
</
div
>
</
template
>
<
script
lang=
"ts"
setup
>
import
{
KeFuMessageContentTypeEnum
}
from
'../tools/constants'
import
ProductItem
from
'./ProductItem.vue'
import
{
UserTypeEnum
}
from
'@/utils/constants'
import
{
fenToYuan
,
jsonParse
}
from
'@/utils'
import
{
KeFuMessageRespVO
}
from
'@/api/mall/promotion/kefu/message'
import
{
fenToYuan
}
from
'@/utils'
import
{
isObject
}
from
'@/utils/is'
import
ProductItem
from
'@/views/mall/promotion/kefu/components/message/ProductItem.vue'
defineOptions
({
name
:
'Order
Message
Item'
})
defineOptions
({
name
:
'OrderItem'
})
const
props
=
defineProps
<
{
message
:
KeFuMessageRespVO
message
?:
KeFuMessageRespVO
order
?:
any
}
>
()
const
getMessageContent
=
computed
(()
=>
JSON
.
parse
(
props
.
message
.
content
))
const
getMessageContent
=
computed
(()
=>
typeof
props
.
message
!==
'undefined'
?
jsonParse
(
props
!
.
message
!
.
content
)
:
props
.
order
)
/**
* 格式化订单状态的颜色
...
...
@@ -108,23 +100,23 @@ function formatOrderStatus(order: any) {
background-color
:
#e2e2e2
;
.order-card-header
{
height
:
80
px
;
height
:
28
px
;
.order-no
{
font-size
:
2
6px
;
font-size
:
1
6px
;
font-weight
:
500
;
}
}
.pay-box
{
.discounts-title
{
font-size
:
24
px
;
font-size
:
16
px
;
line-height
:
normal
;
color
:
#999999
;
}
.discounts-money
{
font-size
:
24
px
;
font-size
:
16
px
;
line-height
:
normal
;
color
:
#999
;
font-family
:
OPPOSANS
;
...
...
@@ -134,34 +126,6 @@ function formatOrderStatus(order: any) {
color
:
#333
;
}
}
.order-card-footer
{
height
:
100px
;
.more-item-box
{
padding
:
20px
;
.more-item
{
height
:
60px
;
.title
{
font-size
:
26px
;
}
}
}
.more-btn
{
color
:
#999999
;
font-size
:
24px
;
}
.content
{
width
:
154px
;
color
:
#333333
;
font-size
:
26px
;
font-weight
:
500
;
}
}
}
.warning-color
{
...
...
src/views/mall/promotion/kefu/components/message/ProductItem.vue
View file @
bfddd674
...
...
@@ -110,33 +110,25 @@ const skuString = computed(() => {
</
script
>
<
style
lang=
"scss"
scoped
>
.score-img
{
width
:
36px
;
height
:
36px
;
margin
:
0
4px
;
}
.ss-order-card-warp
{
padding
:
20px
;
border-radius
:
10px
;
background-color
:
#e2e2e2
;
.img-box
{
width
:
164
px
;
height
:
164
px
;
width
:
80
px
;
height
:
80
px
;
border-radius
:
10px
;
overflow
:
hidden
;
.order-img
{
width
:
164
px
;
height
:
164
px
;
width
:
80
px
;
height
:
80
px
;
}
}
.box-right
{
flex
:
1
;
//
width
:
500px
;
//
height
:
164px
;
position
:
relative
;
.tool-box
{
...
...
@@ -147,13 +139,13 @@ const skuString = computed(() => {
}
.title-text
{
font-size
:
28
px
;
font-size
:
16
px
;
font-weight
:
500
;
line-height
:
4
0px
;
line-height
:
2
0px
;
}
.spec-text
{
font-size
:
24
px
;
font-size
:
16
px
;
font-weight
:
400
;
color
:
#999999
;
min-width
:
0
;
...
...
@@ -165,15 +157,15 @@ const skuString = computed(() => {
}
.price-text
{
font-size
:
24
px
;
font-size
:
16
px
;
font-weight
:
500
;
font-family
:
OPPOSANS
;
}
.total-text
{
font-size
:
24
px
;
font-size
:
16
px
;
font-weight
:
400
;
line-height
:
24
px
;
line-height
:
16
px
;
color
:
#999999
;
margin-left
:
8px
;
}
...
...
src/views/mall/promotion/kefu/components/message/ProductMessageItem.vue
deleted
100644 → 0
View file @
21c7c17e
<
template
>
<!-- 图片消息 -->
<template
v-if=
"KeFuMessageContentTypeEnum.PRODUCT === message.contentType"
>
<div
:class=
"[
message.senderType === UserTypeEnum.MEMBER
? `ml-10px`
: message.senderType === UserTypeEnum.ADMIN
? `mr-10px`
: ''
]"
>
<ProductItem
:picUrl=
"getMessageContent.picUrl"
:price=
"getMessageContent.price"
:skuText=
"getMessageContent.introduction"
:title=
"getMessageContent.spuName"
:titleWidth=
"400"
priceColor=
"#FF3000"
/>
</div>
</
template
>
</template>
<
script
lang=
"ts"
setup
>
import
{
KeFuMessageContentTypeEnum
}
from
'../tools/constants'
import
ProductItem
from
'./ProductItem.vue'
import
{
UserTypeEnum
}
from
'@/utils/constants'
import
{
KeFuMessageRespVO
}
from
'@/api/mall/promotion/kefu/message'
defineOptions
({
name
:
'ProductMessageItem'
})
const
props
=
defineProps
<
{
message
:
KeFuMessageRespVO
}
>
()
/** 获悉消息内容 */
const
getMessageContent
=
computed
(()
=>
JSON
.
parse
(
props
.
message
.
content
))
</
script
>
src/views/mall/promotion/kefu/components/message/TextMessageItem.vue
deleted
100644 → 0
View file @
21c7c17e
<
template
>
<!-- 文本消息 -->
<template
v-if=
"KeFuMessageContentTypeEnum.TEXT === message.contentType"
>
<div
v-dompurify-html=
"replaceEmoji(message.content)"
:class=
"[
message.senderType === UserTypeEnum.MEMBER
? `ml-10px`
: message.senderType === UserTypeEnum.ADMIN
? `mr-10px`
: ''
]"
class=
"flex items-center"
></div>
</
template
>
</template>
<
script
lang=
"ts"
setup
>
import
{
KeFuMessageContentTypeEnum
}
from
'../tools/constants'
import
{
UserTypeEnum
}
from
'@/utils/constants'
import
{
useEmoji
}
from
'../tools/emoji'
import
{
KeFuMessageRespVO
}
from
'@/api/mall/promotion/kefu/message'
defineOptions
({
name
:
'TextMessageItem'
})
defineProps
<
{
message
:
KeFuMessageRespVO
}
>
()
const
{
replaceEmoji
}
=
useEmoji
()
</
script
>
src/views/mall/promotion/kefu/index.vue
View file @
bfddd674
<
template
>
<el-row
:gutter=
"10"
>
<!-- 会话列表 -->
<el-col
:span=
"
8
"
>
<el-col
:span=
"
6
"
>
<ContentWrap>
<KeFuConversationList
ref=
"keFuConversationRef"
@
change=
"handleChange"
/>
</ContentWrap>
</el-col>
<!-- 会话详情(选中会话的消息列表) -->
<el-col
:span=
"1
6
"
>
<el-col
:span=
"1
2
"
>
<ContentWrap>
<KeFuMessageList
ref=
"keFuChatBoxRef"
@
change=
"getConversationList"
/>
</ContentWrap>
</el-col>
<!-- 会员足迹(选中会话的会员足迹) -->
<el-col
:span=
"6"
>
<ContentWrap>
<MemberBrowsingHistory
ref=
"memberBrowsingHistoryRef"
/>
</ContentWrap>
</el-col>
</el-row>
</
template
>
<
script
lang=
"ts"
setup
>
import
{
KeFuConversationList
,
KeFuMessageList
}
from
'./components'
import
{
KeFuConversationList
,
KeFuMessageList
,
MemberBrowsingHistory
}
from
'./components'
import
{
WebSocketMessageTypeConstants
}
from
'./components/tools/constants'
import
{
KeFuConversationRespVO
}
from
'@/api/mall/promotion/kefu/conversation'
import
{
getAccessToken
}
from
'@/utils/auth'
...
...
@@ -60,7 +66,7 @@ watchEffect(() => {
// 刷新会话列表
getConversationList
()
// 刷新消息列表
keFuChatBoxRef
.
value
?.
refreshMessageList
()
keFuChatBoxRef
.
value
?.
refreshMessageList
(
JSON
.
parse
(
jsonMessage
.
content
)
)
return
}
// 2.3 消息类型:KEFU_MESSAGE_ADMIN_READ
...
...
@@ -81,8 +87,10 @@ const getConversationList = () => {
/** 加载指定会话的消息列表 */
const
keFuChatBoxRef
=
ref
<
InstanceType
<
typeof
KeFuMessageList
>>
()
const
memberBrowsingHistoryRef
=
ref
<
InstanceType
<
typeof
MemberBrowsingHistory
>>
()
const
handleChange
=
(
conversation
:
KeFuConversationRespVO
)
=>
{
keFuChatBoxRef
.
value
?.
getMessageList
(
conversation
,
true
)
keFuChatBoxRef
.
value
?.
getNewMessageList
(
conversation
)
memberBrowsingHistoryRef
.
value
?.
initHistory
(
conversation
)
}
/** 初始化 */
...
...
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