Skip to content

Commit 18c7693

Browse files
YunaiVgitee-org
authored andcommitted
!584 【功能完善】商城: 客服
Merge pull request !584 from puhui999/dev
2 parents 8b0778c + 5e7afae commit 18c7693

File tree

11 files changed

+236
-237
lines changed

11 files changed

+236
-237
lines changed

src/store/modules/mall/kefu.ts

Lines changed: 7 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -63,48 +63,14 @@ export const useMallKefuStore = defineStore('mall-kefu', {
6363
}
6464
},
6565
conversationSort() {
66-
// TODO @puhui999:1)逻辑上,先按照置顶、再按照最后消息时间;2)感觉写的有一丢丢小复杂,发给大模型,看看有没可能简化哈。
67-
this.conversationList.sort((obj1, obj2) => {
68-
// 如果 obj1.adminPinned 为 true,obj2.adminPinned 为 false,obj1 应该排在前面
69-
if (obj1.adminPinned && !obj2.adminPinned) {
70-
return -1
66+
// 按置顶属性和最后消息时间排序
67+
this.conversationList.sort((a, b) => {
68+
// 按照置顶排序,置顶的会在前面
69+
if (a.adminPinned !== b.adminPinned) {
70+
return a.adminPinned ? -1 : 1
7171
}
72-
// 如果 obj1.adminPinned 为 false,obj2.adminPinned 为 true,obj2 应该排在前面
73-
if (!obj1.adminPinned && obj2.adminPinned) {
74-
return 1
75-
}
76-
77-
// 如果 obj1.adminPinned 和 obj2.adminPinned 都为 true,比较 adminUnreadMessageCount 的值
78-
if (obj1.adminPinned && obj2.adminPinned) {
79-
return obj1.adminUnreadMessageCount - obj2.adminUnreadMessageCount
80-
}
81-
82-
// 如果 obj1.adminPinned 和 obj2.adminPinned 都为 false,比较 adminUnreadMessageCount 的值
83-
if (!obj1.adminPinned && !obj2.adminPinned) {
84-
return obj1.adminUnreadMessageCount - obj2.adminUnreadMessageCount
85-
}
86-
87-
// 如果 obj1.adminPinned 为 true,obj2.adminPinned 为 true,且 b 都大于 0,比较 adminUnreadMessageCount 的值
88-
if (
89-
obj1.adminPinned &&
90-
obj2.adminPinned &&
91-
obj1.adminUnreadMessageCount > 0 &&
92-
obj2.adminUnreadMessageCount > 0
93-
) {
94-
return obj1.adminUnreadMessageCount - obj2.adminUnreadMessageCount
95-
}
96-
97-
// 如果 obj1.adminPinned 为 false,obj2.adminPinned 为 false,且 b 都大于 0,比较 adminUnreadMessageCount 的值
98-
if (
99-
!obj1.adminPinned &&
100-
!obj2.adminPinned &&
101-
obj1.adminUnreadMessageCount > 0 &&
102-
obj2.adminUnreadMessageCount > 0
103-
) {
104-
return obj1.adminUnreadMessageCount - obj2.adminUnreadMessageCount
105-
}
106-
107-
return 0
72+
// 按照最后消息时间排序,最近的会在前面
73+
return (b.lastMessageTime as unknown as number) - (a.lastMessageTime as unknown as number)
10874
})
10975
}
11076
}

src/utils/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { toNumber } from 'lodash-es'
1+
import {toNumber} from 'lodash-es'
22

33
/**
44
*

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<el-aside class="kefu p-5px h-100%" width="260px">
3-
<div class="color-[#999] font-bold my-10px"
4-
>会话记录({{ kefuStore.getConversationList.length }})
3+
<div class="color-[#999] font-bold my-10px">
4+
会话记录({{ kefuStore.getConversationList.length }})
55
</div>
66
<div
77
v-for="item in kefuStore.getConversationList"
@@ -78,6 +78,7 @@ import { formatPast } from '@/utils/formatTime'
7878
import { KeFuMessageContentTypeEnum } from './tools/constants'
7979
import { useAppStore } from '@/store/modules/app'
8080
import { useMallKefuStore } from '@/store/modules/mall/kefu'
81+
import { jsonParse } from '@/utils'
8182
8283
defineOptions({ name: 'KeFuConversationList' })
8384
@@ -118,7 +119,7 @@ const getConversationDisplayText = computed(
118119
case KeFuMessageContentTypeEnum.VOICE:
119120
return '[语音消息]'
120121
case KeFuMessageContentTypeEnum.TEXT:
121-
return replaceEmoji(lastMessageContent)
122+
return replaceEmoji(jsonParse(lastMessageContent).text || lastMessageContent)
122123
default:
123124
return ''
124125
}

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
<MessageItem :message="item">
5353
<template v-if="KeFuMessageContentTypeEnum.TEXT === item.contentType">
5454
<div
55-
v-dompurify-html="replaceEmoji(item.content)"
55+
v-dompurify-html="replaceEmoji(getMessageContent(item).text || item.content)"
5656
class="flex items-center"
5757
></div>
5858
</template>
@@ -62,8 +62,8 @@
6262
<el-image
6363
v-if="KeFuMessageContentTypeEnum.IMAGE === item.contentType"
6464
:initial-index="0"
65-
:preview-src-list="[item.content]"
66-
:src="item.content"
65+
:preview-src-list="[getMessageContent(item).picUrl || item.content]"
66+
:src="getMessageContent(item).picUrl || item.content"
6767
class="w-200px"
6868
fit="contain"
6969
preview-teleported
@@ -75,12 +75,11 @@
7575
v-if="KeFuMessageContentTypeEnum.PRODUCT === item.contentType"
7676
:picUrl="getMessageContent(item).picUrl"
7777
:price="getMessageContent(item).price"
78-
:skuText="getMessageContent(item).introduction"
78+
:sales-count="getMessageContent(item).salesCount"
7979
:spuId="getMessageContent(item).spuId"
80+
:stock="getMessageContent(item).stock"
8081
:title="getMessageContent(item).spuName"
81-
:titleWidth="400"
82-
class="max-w-70%"
83-
priceColor="#FF3000"
82+
class="max-w-300px"
8483
/>
8584
</MessageItem>
8685
<!-- 订单消息 -->
@@ -245,6 +244,7 @@ const getNewMessageList = async (val: KeFuConversationRespVO) => {
245244
total.value = messageList.value.length || 0
246245
loadHistory.value = false
247246
refreshContent.value = false
247+
skipGetMessageList.value = false
248248
// 2.2 设置会话相关属性
249249
conversation.value = val
250250
queryParams.conversationId = val.id
@@ -268,7 +268,7 @@ const handleSendPicture = async (picUrl: string) => {
268268
const msg = {
269269
conversationId: conversation.value.id,
270270
contentType: KeFuMessageContentTypeEnum.IMAGE,
271-
content: picUrl
271+
content: JSON.stringify({ picUrl })
272272
}
273273
await sendMessage(msg)
274274
}
@@ -288,7 +288,7 @@ const handleSendMessage = async (event: any) => {
288288
const msg = {
289289
conversationId: conversation.value.id,
290290
contentType: KeFuMessageContentTypeEnum.TEXT,
291-
content: message.value
291+
content: JSON.stringify({ text: message.value })
292292
}
293293
await sendMessage(msg)
294294
}
@@ -392,7 +392,7 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
392392
393393
&-content {
394394
margin: 0;
395-
padding: 0;
395+
padding: 10px;
396396
position: relative;
397397
height: 100%;
398398
width: 100%;

src/views/mall/promotion/kefu/components/member/MemberInfo.vue

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,22 @@
2424
交易订单
2525
</div>
2626
</el-header>
27-
<el-main class="kefu-content">
27+
<el-main class="kefu-content p-10px!">
28+
<div v-if="!isEmpty(conversation)" v-loading="loading">
29+
<!-- 基本信息 -->
30+
<UserBasicInfo v-if="activeTab === '会员信息'" :user="user" mode="kefu">
31+
<template #header>
32+
<CardTitle title="基本信息" />
33+
</template>
34+
</UserBasicInfo>
35+
<!-- 账户信息 -->
36+
<el-card v-if="activeTab === '会员信息'" class="h-full mt-10px" shadow="never">
37+
<template #header>
38+
<CardTitle title="账户信息" />
39+
</template>
40+
<UserAccountInfo :column="1" :user="user" :wallet="wallet" />
41+
</el-card>
42+
</div>
2843
<div v-show="!isEmpty(conversation)">
2944
<el-scrollbar ref="scrollbarRef" always @scroll="handleScroll">
3045
<!-- 最近浏览 -->
@@ -45,11 +60,17 @@ import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation'
4560
import { isEmpty } from '@/utils/is'
4661
import { debounce } from 'lodash-es'
4762
import { ElScrollbar as ElScrollbarType } from 'element-plus/es/components/scrollbar/index'
63+
import { CardTitle } from '@/components/Card'
64+
import UserBasicInfo from '@/views/member/user/detail/UserBasicInfo.vue'
65+
import UserAccountInfo from '@/views/member/user/detail/UserAccountInfo.vue'
66+
import * as UserApi from '@/api/member/user'
67+
import * as WalletApi from '@/api/pay/wallet/balance'
4868
4969
defineOptions({ name: 'MemberBrowsingHistory' })
5070
5171
const activeTab = ref('会员信息')
5272
const tabActivation = computed(() => (tab: string) => activeTab.value === tab)
73+
5374
/** tab 切换 */
5475
const productBrowsingHistoryRef = ref<InstanceType<typeof ProductBrowsingHistory>>()
5576
const orderBrowsingHistoryRef = ref<InstanceType<typeof OrderBrowsingHistory>>()
@@ -63,6 +84,8 @@ const handleClick = async (tab: string) => {
6384
const getHistoryList = async () => {
6485
switch (activeTab.value) {
6586
case '会员信息':
87+
await getUserData()
88+
await getUserWallet()
6689
break
6790
case '最近浏览':
6891
await productBrowsingHistoryRef.value?.getHistoryList(conversation.value)
@@ -110,6 +133,37 @@ const handleScroll = debounce(() => {
110133
loadMore()
111134
}
112135
}, 200)
136+
137+
/* 用户钱包相关信息 */
138+
const WALLET_INIT_DATA = {
139+
balance: 0,
140+
totalExpense: 0,
141+
totalRecharge: 0
142+
} as WalletApi.WalletVO // 钱包初始化数据
143+
const wallet = ref<WalletApi.WalletVO>(WALLET_INIT_DATA) // 钱包信息
144+
145+
/** 查询用户钱包信息 */
146+
const getUserWallet = async () => {
147+
if (!conversation.value.userId) {
148+
wallet.value = WALLET_INIT_DATA
149+
return
150+
}
151+
const params = { userId: conversation.value.userId }
152+
wallet.value = (await WalletApi.getWallet(params)) || WALLET_INIT_DATA
153+
}
154+
155+
const loading = ref(true) // 加载中
156+
const user = ref<UserApi.UserVO>({} as UserApi.UserVO)
157+
158+
/** 获得用户 */
159+
const getUserData = async () => {
160+
loading.value = true
161+
try {
162+
user.value = await UserApi.getUser(conversation.value.userId)
163+
} finally {
164+
loading.value = false
165+
}
166+
}
113167
</script>
114168

115169
<style lang="scss" scoped>

src/views/mall/promotion/kefu/components/member/ProductBrowsingHistory.vue

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
<template>
22
<ProductItem
33
v-for="item in list"
4-
:spu-id="item.spuId"
54
:key="item.id"
65
:picUrl="item.picUrl"
76
:price="item.price"
8-
:skuText="item.introduction"
7+
:sales-count="item.salesCount"
8+
:spu-id="item.spuId"
9+
:stock="item.stock"
910
:title="item.spuName"
10-
:titleWidth="400"
1111
class="mb-10px"
12-
priceColor="#FF3000"
1312
/>
1413
</template>
1514

src/views/mall/promotion/kefu/components/message/OrderItem.vue

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
</div>
1515
<div v-for="item in getMessageContent.items" :key="item.id" class="border-bottom">
1616
<ProductItem
17-
:spu-id="item.spuId"
1817
:num="item.count"
1918
:picUrl="item.picUrl"
2019
:price="item.price"
2120
:skuText="item.properties.map((property: any) => property.valueName).join(' ')"
21+
:spu-id="item.spuId"
2222
:title="item.spuName"
2323
/>
2424
</div>
@@ -112,14 +112,14 @@ function formatOrderStatus(order: any) {
112112
border-radius: 10px;
113113
padding: 10px;
114114
border: 1px var(--el-border-color) solid;
115-
background-color: var(--app-content-bg-color);
115+
background-color: rgba(128, 128, 128, 0.5); // 透明色,暗黑模式下也能体现
116116
117117
.order-card-header {
118118
height: 28px;
119+
font-weight: bold;
119120
120121
.order-no {
121-
font-size: 12px;
122-
font-weight: 500;
122+
font-size: 13px;
123123
124124
span {
125125
&:hover {
@@ -128,27 +128,30 @@ function formatOrderStatus(order: any) {
128128
}
129129
}
130130
}
131+
132+
.order-state {
133+
font-size: 13px;
134+
}
131135
}
132136
133137
.pay-box {
134138
padding-top: 10px;
139+
color: #fff;
140+
font-weight: bold;
135141
136142
.discounts-title {
137143
font-size: 16px;
138144
line-height: normal;
139-
color: #999999;
140145
}
141146
142147
.discounts-money {
143148
font-size: 16px;
144149
line-height: normal;
145-
color: #999;
146150
font-family: OPPOSANS;
147151
}
148152
149153
.pay-color {
150154
font-size: 13px;
151-
color: var(--left-menu-text-color);
152155
}
153156
}
154157
}

0 commit comments

Comments
 (0)