Skip to content

Commit ec61670

Browse files
committed
【代码评审】Mall:客服的会话列表
1 parent 6550983 commit ec61670

File tree

9 files changed

+72
-26
lines changed

9 files changed

+72
-26
lines changed

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

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
<template>
22
<el-container v-if="showChatBox" class="kefu">
33
<el-header>
4+
<!-- TODO @puhui999:keFuConversation => conversation -->
45
<div class="kefu-title">{{ keFuConversation.userNickname }}</div>
56
</el-header>
7+
<!-- TODO @puhui999:unocss -->
68
<el-main class="kefu-content" style="overflow: visible">
9+
<!-- 加载历史消息 -->
710
<div
811
v-show="loadingMore"
912
class="loadingMore flex justify-center items-center cursor-pointer"
@@ -13,6 +16,7 @@
1316
</div>
1417
<el-scrollbar ref="scrollbarRef" always height="calc(100vh - 495px)" @scroll="handleScroll">
1518
<div ref="innerRef" class="w-[100%] pb-3px">
19+
<!-- 消息列表 -->
1620
<div v-for="(item, index) in getMessageList0" :key="item.id" class="w-[100%]">
1721
<div class="flex justify-center items-center mb-20px">
1822
<!-- 日期 -->
@@ -118,8 +122,10 @@ import relativeTime from 'dayjs/plugin/relativeTime'
118122
dayjs.extend(relativeTime)
119123
120124
defineOptions({ name: 'KeFuMessageBox' })
125+
126+
const message = ref('') // 消息弹窗
127+
121128
const messageTool = useMessage()
122-
const message = ref('') // 消息
123129
const messageList = ref<KeFuMessageRespVO[]>([]) // 消息列表
124130
const keFuConversation = ref<KeFuConversationRespVO>({} as KeFuConversationRespVO) // 用户会话
125131
const showNewMessageTip = ref(false) // 显示有新消息提示
@@ -128,7 +134,8 @@ const queryParams = reactive({
128134
conversationId: 0
129135
})
130136
const total = ref(0) // 消息总条数
131-
// 获得消息
137+
138+
/** 获得消息列表 */
132139
const getMessageList = async (conversation: KeFuConversationRespVO) => {
133140
keFuConversation.value = conversation
134141
queryParams.conversationId = conversation.id
@@ -146,12 +153,14 @@ const getMessageList = async (conversation: KeFuConversationRespVO) => {
146153
}
147154
await scrollToBottom()
148155
}
156+
157+
/** 按照时间倒序,获取消息列表 */
149158
const getMessageList0 = computed(() => {
150159
messageList.value.sort((a: any, b: any) => a.createTime - b.createTime)
151160
return messageList.value
152161
})
153162
154-
// 刷新消息列表
163+
/** 刷新消息列表 */
155164
const refreshMessageList = async () => {
156165
if (!keFuConversation.value) {
157166
return
@@ -164,14 +173,16 @@ const refreshMessageList = async () => {
164173
showNewMessageTip.value = true
165174
}
166175
}
176+
167177
defineExpose({ getMessageList, refreshMessageList })
168-
// 是否显示聊天区域
169-
const showChatBox = computed(() => !isEmpty(keFuConversation.value))
170-
// 处理表情选择
178+
const showChatBox = computed(() => !isEmpty(keFuConversation.value)) // 是否显示聊天区域
179+
180+
/** 处理表情选择 */
171181
const handleEmojiSelect = (item: Emoji) => {
172182
message.value += item.name
173183
}
174-
// 处理图片发送
184+
185+
/** 处理图片发送 */
175186
const handleSendPicture = async (picUrl: string) => {
176187
// 组织发送消息
177188
const msg = {
@@ -181,7 +192,8 @@ const handleSendPicture = async (picUrl: string) => {
181192
}
182193
await sendMessage(msg)
183194
}
184-
// 发送消息
195+
196+
/** 发送文本消息 */
185197
const handleSendMessage = async () => {
186198
// 1. 校验消息是否为空
187199
if (isEmpty(unref(message.value))) {
@@ -197,7 +209,7 @@ const handleSendMessage = async () => {
197209
await sendMessage(msg)
198210
}
199211
200-
// 发送消息 【共用】
212+
/** 真正发送消息 【共用】*/
201213
const sendMessage = async (msg: any) => {
202214
// 发送消息
203215
await KeFuMessageApi.sendKeFuMessage(msg)
@@ -208,9 +220,9 @@ const sendMessage = async (msg: any) => {
208220
await scrollToBottom()
209221
}
210222
223+
/** 滚动到底部 */
211224
const innerRef = ref<HTMLDivElement>()
212225
const scrollbarRef = ref<InstanceType<typeof ElScrollbarType>>()
213-
// 滚动到底部
214226
const scrollToBottom = async () => {
215227
// 1. 首次加载时滚动到最新消息,如果加载的是历史消息则不滚动
216228
if (loadHistory.value) {
@@ -223,12 +235,14 @@ const scrollToBottom = async () => {
223235
// 2.2 消息已读
224236
await KeFuMessageApi.updateKeFuMessageReadStatus(keFuConversation.value.id)
225237
}
226-
// 查看新消息
238+
239+
/** 查看新消息 */
227240
const handleToNewMessage = async () => {
228241
loadHistory.value = false
229242
await scrollToBottom()
230243
}
231244
245+
/** 加载历史消息 */
232246
const loadingMore = ref(false) // 滚动到顶部加载更多
233247
const loadHistory = ref(false) // 加载历史消息
234248
const handleScroll = async ({ scrollTop }) => {
@@ -247,8 +261,10 @@ const handleOldMessage = async () => {
247261
loadingMore.value = false
248262
// TODO puhui999: 等页面加载完后,获得上一页最后一条消息的位置,控制滚动到它所在位置
249263
}
264+
250265
/**
251266
* 是否显示时间
267+
*
252268
* @param {*} item - 数据
253269
* @param {*} index - 索引
254270
*/

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<template>
22
<div class="kefu">
3-
<!-- TODO @puhui999:item => conversation 会不会更容易理解 -->
43
<div
54
v-for="(item, index) in conversationList"
65
:key="item.id"

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
: ''
1111
]"
1212
>
13+
<!-- TODO @puhui999:unocss -->
1314
<el-image
1415
:src="message.content"
1516
fit="contain"
@@ -30,6 +31,7 @@ defineOptions({ name: 'ImageMessageItem' })
3031
defineProps<{
3132
message: KeFuMessageRespVO
3233
}>()
34+
3335
/** 图预览 */
3436
const imagePreview = (imgUrl: string) => {
3537
createImageViewer({

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
</div>
1919
</div>
2020
<div v-for="item in getMessageContent.items" :key="item.id" class="border-bottom">
21+
<!-- TODO @puhui999:要不把 img => picUrl 类似这种,搞的更匹配一点 -->
2122
<ProductItem
2223
:img="item.picUrl"
2324
:num="item.count"
@@ -29,10 +30,10 @@
2930
<div class="pay-box mt-30px flex justify-end pr-20px">
3031
<div class="flex items-center">
3132
<div class="discounts-title pay-color"
32-
>共 {{ getMessageContent.productCount }} 件商品,总金额:
33+
>共 {{ getMessageContent?.productCount }} 件商品,总金额:
3334
</div>
3435
<div class="discounts-money pay-color">
35-
¥{{ fenToYuan(getMessageContent.payPrice) }}
36+
¥{{ fenToYuan(getMessageContent?.payPrice) }}
3637
</div>
3738
</div>
3839
</div>

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ const props = defineProps({
9090
default: ''
9191
}
9292
})
93+
94+
/** SKU 展示字符串 */
9395
const skuString = computed(() => {
9496
if (!props.skuText) {
9597
return ''
@@ -99,6 +101,8 @@ const skuString = computed(() => {
99101
}
100102
return props.skuText
101103
})
104+
105+
// TODO @puhui999:可以使用 preview-teleported
102106
/** 图预览 */
103107
const imagePrediv = (imgUrl: string) => {
104108
createImageViewer({

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,7 @@ defineOptions({ name: 'ProductMessageItem' })
3232
const props = defineProps<{
3333
message: KeFuMessageRespVO
3434
}>()
35+
36+
/** 获悉消息内容 */
3537
const getMessageContent = computed(() => JSON.parse(props.message.content))
3638
</script>

src/views/mall/promotion/kefu/components/tools/EmojiSelectPopover.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
class="icon-item mr-2 mt-1 w-1/10 flex cursor-pointer items-center justify-center border border-solid p-2"
1818
@click="handleSelect(item)"
1919
>
20+
<!-- TODO @puhui999:换成 unocss -->
2021
<img :src="item.url" style="width: 24px; height: 24px" />
2122
</li>
2223
</ul>
@@ -31,6 +32,7 @@ import { Emoji, useEmoji } from './emoji'
3132
const { getEmojiList } = useEmoji()
3233
const emojiList = computed(() => getEmojiList())
3334
35+
/** 选择 emoji 表情 */
3436
const emits = defineEmits<{
3537
(e: 'select-emoji', v: Emoji)
3638
}>()

src/views/mall/promotion/kefu/components/tools/PictureSelectUpload.vue

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
1+
<!-- 图片选择 -->
12
<template>
23
<div>
4+
<!-- TODO @puhui999:unocss -->
35
<img :src="Picture" style="width: 35px; height: 35px" @click="selectAndUpload" />
46
</div>
57
</template>
68

79
<script lang="ts" setup>
10+
// TODO @puhui999:images 换成 asserts
811
import Picture from '@/views/mall/promotion/kefu/components/images/picture.svg'
912
import * as FileApi from '@/api/infra/file'
1013
1114
defineOptions({ name: 'PictureSelectUpload' })
12-
const message = useMessage()
15+
16+
const message = useMessage() // 消息弹窗
17+
18+
/** 选择并上传文件 */
1319
const emits = defineEmits<{
1420
(e: 'send-picture', v: string): void
1521
}>()
16-
// 选择并上传文件
1722
const selectAndUpload = async () => {
1823
const files: any = await getFiles()
1924
message.success('图片发送中请稍等。。。')
@@ -23,6 +28,7 @@ const selectAndUpload = async () => {
2328
2429
/**
2530
* 唤起文件选择窗口,并获取选择的文件
31+
*
2632
* @param {Object} options - 配置选项
2733
* @param {boolean} [options.multiple=true] - 是否支持多选
2834
* @param {string} [options.accept=''] - 文件上传格式限制
@@ -54,7 +60,7 @@ async function getFiles(options = {}) {
5460
5561
// 等待文件选择元素的 change 事件
5662
try {
57-
const files = await new Promise((resolve, reject) => {
63+
return await new Promise((resolve, reject) => {
5864
input.addEventListener('change', (event: any) => {
5965
const filesArray = Array.from(event?.target?.files || [])
6066
@@ -68,9 +74,9 @@ async function getFiles(options = {}) {
6874
}
6975
7076
// 判断是否超出上传文件大小限制
71-
const oversizedFiles = filesArray.filter((file: File) => file.size / 1024 ** 2 > fileSize)
72-
if (oversizedFiles.length > 0) {
73-
reject({ errorType: 'fileSize', files: oversizedFiles })
77+
const overSizedFiles = filesArray.filter((file: File) => file.size / 1024 ** 2 > fileSize)
78+
if (overSizedFiles.length > 0) {
79+
reject({ errorType: 'fileSize', files: overSizedFiles })
7480
return
7581
}
7682
@@ -79,8 +85,6 @@ async function getFiles(options = {}) {
7985
resolve(fileList)
8086
})
8187
})
82-
83-
return files
8488
} catch (error) {
8589
console.error('选择文件出错:', error)
8690
throw error

src/views/mall/promotion/kefu/components/tools/emoji.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,11 @@ export interface Emoji {
5858

5959
export const useEmoji = () => {
6060
const emojiPathList = ref<any[]>([])
61-
// 加载本地图片
61+
62+
// TODO @puhui999:initStaticEmoji 会不会更好
63+
/** 加载本地图片 */
6264
const getStaticEmojiPath = async () => {
65+
// TODO @puhui999:images 改成 asserts 更合适哈。
6366
const pathList = import.meta.glob(
6467
'@/views/mall/promotion/kefu/components/images/*.{png,jpg,jpeg,svg}'
6568
)
@@ -68,17 +71,25 @@ export const useEmoji = () => {
6871
emojiPathList.value.push(imageModule.default)
6972
}
7073
}
71-
// 初始化
74+
75+
/** 初始化 */
7276
onMounted(async () => {
7377
if (isEmpty(emojiPathList.value)) {
7478
await getStaticEmojiPath()
7579
}
7680
})
7781

78-
// 处理表情
82+
// TODO @puhui999:建议 function 都改成 const 这种来定义哈。保持统一风格
83+
/**
84+
* 将文本中的表情替换成图片
85+
*
86+
* @param data 文本 TODO @puhui999:data => content
87+
* @return 替换后的文本
88+
*/
7989
function replaceEmoji(data: string) {
8090
let newData = data
8191
if (typeof newData !== 'object') {
92+
// TODO @puhui999: \] 是不是可以简化成 ]。我看 idea 提示了哈
8293
const reg = /\[(.+?)\]/g // [] 中括号
8394
const zhEmojiName = newData.match(reg)
8495
if (zhEmojiName) {
@@ -94,14 +105,19 @@ export const useEmoji = () => {
94105
return newData
95106
}
96107

97-
// 获得所有表情
108+
/**
109+
* 获得所有表情
110+
*
111+
* @return 表情列表
112+
*/
98113
function getEmojiList(): Emoji[] {
99114
return emojiList.map((item) => ({
100115
url: selEmojiFile(item.name),
101116
name: item.name
102117
})) as Emoji[]
103118
}
104119

120+
// TODO @puhui999:getEmojiFileByName 会不会更容易理解哈
105121
function selEmojiFile(name: string) {
106122
for (const emoji of emojiList) {
107123
if (emoji.name === name) {

0 commit comments

Comments
 (0)