Skip to content

Commit bfddd67

Browse files
author
xiaohong
committed
2 parents 21c7c17 + e8a0eb0 commit bfddd67

16 files changed

+554
-365
lines changed

src/api/mall/product/history.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import request from '@/config/axios'
2+
3+
/**
4+
* 获得商品浏览记录分页
5+
* @param params 请求参数
6+
*/
7+
export const getBrowseHistoryPage = (params: any) => {
8+
return request.get({ url: '/product/browse-history/page', params })
9+
}

src/views/ai/image/square/index.vue

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
<template>
2-
<div class="card-list">
3-
<div v-for="item in publicList" :key="item.id" class="card">
4-
<img :src="item.picUrl" class="img" />
2+
<div class="gallery">
3+
<div v-for="item in publicList" :key="item" class="gallery-item">
4+
<img :src="item.picUrl" class="img"/>
55
</div>
66
</div>
77
</template>
88
<script setup lang="ts">
9-
import { ImageApi, ImageVO } from '@/api/ai/image'
9+
import { ImageApi, ImageVO, ImageMidjourneyButtonsVO } from '@/api/ai/image'
1010
1111
/** 属性 */
12-
// TODO @fan:queryParams 里面搞分页哈。
1312
const pageNo = ref<number>(1)
1413
const pageSize = ref<number>(20)
1514
const publicList = ref<ImageVO[]>([])
1615
1716
/** 获取数据 */
1817
const getListData = async () => {
19-
const res = await ImageApi.getImagePagePublic({ pageNo: pageNo.value, pageSize: pageSize.value })
20-
publicList.value = res.list as ImageVO[]
18+
const res = await ImageApi.getImagePagePublic({pageNo: pageNo.value, pageSize: pageSize.value});
19+
publicList.value = res.list as ImageVO[];
2120
console.log('publicList.value', publicList.value)
2221
}
2322
@@ -26,16 +25,38 @@ onMounted(async () => {
2625
})
2726
</script>
2827
<style scoped lang="scss">
29-
.card-list {
30-
//display: flex;
31-
//flex-direction: column;
32-
column-count: 4;
33-
column-gap: 3px;
28+
29+
.gallery {
30+
display: grid;
31+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
32+
gap: 10px;
33+
//max-width: 1000px;
34+
padding: 20px;
35+
background-color: #fff;
36+
box-shadow: 0 0 10px rgba(0,0,0,0.1);
37+
}
38+
39+
.gallery-item {
40+
position: relative;
41+
overflow: hidden;
42+
background: #f0f0f0;
43+
cursor: pointer;
44+
transition: transform 0.3s;
45+
}
46+
47+
.gallery-item img {
48+
width: 100%;
49+
height: auto;
50+
display: block;
51+
transition: transform 0.3s;
52+
}
53+
54+
.gallery-item:hover img {
55+
transform: scale(1.1);
3456
}
3557
36-
.card {
37-
.img {
38-
width: 50%;
39-
}
58+
.gallery-item:hover {
59+
transform: scale(1.05);
4060
}
61+
4162
</style>

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
</div>
2222
<div class="ml-10px w-100%">
2323
<div class="flex justify-between items-center w-100%">
24-
<span>{{ item.userNickname }}</span>
24+
<span class="username">{{ item.userNickname }}</span>
2525
<span class="color-[#989EA6]">
26-
{{ formatDate(item.lastMessageTime) }}
26+
{{ formatPast(item.lastMessageTime, 'YYYY-mm-dd') }}
2727
</span>
2828
</div>
2929
<!-- 最后聊天内容 -->
@@ -70,7 +70,7 @@
7070
<script lang="ts" setup>
7171
import { KeFuConversationApi, KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation'
7272
import { useEmoji } from './tools/emoji'
73-
import { formatDate } from '@/utils/formatTime'
73+
import { formatPast } from '@/utils/formatTime'
7474
import { KeFuMessageContentTypeEnum } from './tools/constants'
7575
import { useAppStore } from '@/store/modules/app'
7676
@@ -185,6 +185,16 @@ watch(showRightMenu, (val) => {
185185
background-color: #fff;
186186
transition: border-left 0.05s ease-in-out; /* 设置过渡效果 */
187187
188+
.username {
189+
min-width: 0;
190+
max-width: 60%;
191+
overflow: hidden;
192+
text-overflow: ellipsis;
193+
display: -webkit-box;
194+
-webkit-box-orient: vertical;
195+
-webkit-line-clamp: 1;
196+
}
197+
188198
.last-message {
189199
width: 200px;
190200
overflow: hidden; // 隐藏超出的文本

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

Lines changed: 102 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,54 @@
4040
v-if="item.senderType === UserTypeEnum.MEMBER"
4141
:src="conversation.userAvatar"
4242
alt="avatar"
43+
class="w-60px h-60px"
4344
/>
4445
<div
4546
:class="{ 'kefu-message': KeFuMessageContentTypeEnum.TEXT === item.contentType }"
4647
class="p-10px"
4748
>
4849
<!-- 文本消息 -->
49-
<TextMessageItem :message="item" />
50+
<MessageItem :message="item">
51+
<template v-if="KeFuMessageContentTypeEnum.TEXT === item.contentType">
52+
<div
53+
v-dompurify-html="replaceEmoji(item.content)"
54+
class="flex items-center"
55+
></div>
56+
</template>
57+
</MessageItem>
5058
<!-- 图片消息 -->
51-
<ImageMessageItem :message="item" />
59+
<MessageItem :message="item">
60+
<el-image
61+
v-if="KeFuMessageContentTypeEnum.IMAGE === item.contentType"
62+
:initial-index="0"
63+
:preview-src-list="[item.content]"
64+
:src="item.content"
65+
class="w-200px"
66+
fit="contain"
67+
preview-teleported
68+
/>
69+
</MessageItem>
5270
<!-- 商品消息 -->
53-
<ProductMessageItem :message="item" />
71+
<MessageItem :message="item">
72+
<ProductItem
73+
v-if="KeFuMessageContentTypeEnum.PRODUCT === item.contentType"
74+
:picUrl="getMessageContent(item).picUrl"
75+
:price="getMessageContent(item).price"
76+
:skuText="getMessageContent(item).introduction"
77+
:title="getMessageContent(item).spuName"
78+
:titleWidth="400"
79+
class="max-w-70%"
80+
priceColor="#FF3000"
81+
/>
82+
</MessageItem>
5483
<!-- 订单消息 -->
55-
<OrderMessageItem :message="item" />
84+
<MessageItem :message="item">
85+
<OrderItem
86+
v-if="KeFuMessageContentTypeEnum.ORDER === item.contentType"
87+
:message="item"
88+
class="max-w-70%"
89+
/>
90+
</MessageItem>
5691
</div>
5792
<el-avatar
5893
v-if="item.senderType === UserTypeEnum.ADMIN"
@@ -97,24 +132,24 @@ import { KeFuMessageApi, KeFuMessageRespVO } from '@/api/mall/promotion/kefu/mes
97132
import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation'
98133
import EmojiSelectPopover from './tools/EmojiSelectPopover.vue'
99134
import PictureSelectUpload from './tools/PictureSelectUpload.vue'
100-
import TextMessageItem from './message/TextMessageItem.vue'
101-
import ImageMessageItem from './message/ImageMessageItem.vue'
102-
import ProductMessageItem from './message/ProductMessageItem.vue'
103-
import OrderMessageItem from './message/OrderMessageItem.vue'
104-
import { Emoji } from './tools/emoji'
135+
import ProductItem from './message/ProductItem.vue'
136+
import OrderItem from './message/OrderItem.vue'
137+
import { Emoji, useEmoji } from './tools/emoji'
105138
import { KeFuMessageContentTypeEnum } from './tools/constants'
106139
import { isEmpty } from '@/utils/is'
107140
import { UserTypeEnum } from '@/utils/constants'
108141
import { formatDate } from '@/utils/formatTime'
109142
import dayjs from 'dayjs'
110143
import relativeTime from 'dayjs/plugin/relativeTime'
144+
import { debounce } from 'lodash-es'
145+
import { jsonParse } from '@/utils'
111146
112147
dayjs.extend(relativeTime)
113148
114149
defineOptions({ name: 'KeFuMessageList' })
115150
116151
const message = ref('') // 消息弹窗
117-
152+
const { replaceEmoji } = useEmoji()
118153
const messageTool = useMessage()
119154
const messageList = ref<KeFuMessageRespVO[]>([]) // 消息列表
120155
const conversation = ref<KeFuConversationRespVO>({} as KeFuConversationRespVO) // 用户会话
@@ -126,18 +161,11 @@ const queryParams = reactive({
126161
})
127162
const total = ref(0) // 消息总条数
128163
const refreshContent = ref(false) // 内容刷新,主要解决会话消息页面高度不一致导致的滚动功能精度失效
164+
165+
/** 获悉消息内容 */
166+
const getMessageContent = computed(() => (item: any) => jsonParse(item.content))
129167
/** 获得消息列表 */
130-
const getMessageList = async (val: KeFuConversationRespVO, conversationChange: boolean) => {
131-
// 会话切换,重置相关参数
132-
if (conversationChange) {
133-
queryParams.pageNo = 1
134-
messageList.value = []
135-
total.value = 0
136-
loadHistory.value = false
137-
refreshContent.value = false
138-
}
139-
conversation.value = val
140-
queryParams.conversationId = val.id
168+
const getMessageList = async () => {
141169
const res = await KeFuMessageApi.getKeFuMessagePage(queryParams)
142170
total.value = res.total
143171
// 情况一:加载最新消息
@@ -146,14 +174,18 @@ const getMessageList = async (val: KeFuConversationRespVO, conversationChange: b
146174
} else {
147175
// 情况二:加载历史消息
148176
for (const item of res.list) {
149-
if (messageList.value.some((val) => val.id === item.id)) {
150-
continue
151-
}
152-
messageList.value.push(item)
177+
pushMessage(item)
153178
}
154179
}
155180
refreshContent.value = true
156-
await scrollToBottom()
181+
}
182+
183+
/** 添加消息 */
184+
const pushMessage = (message: any) => {
185+
if (messageList.value.some((val) => val.id === message.id)) {
186+
return
187+
}
188+
messageList.value.push(message)
157189
}
158190
159191
/** 按照时间倒序,获取消息列表 */
@@ -163,20 +195,46 @@ const getMessageList0 = computed(() => {
163195
})
164196
165197
/** 刷新消息列表 */
166-
const refreshMessageList = async () => {
198+
const refreshMessageList = async (message?: any) => {
167199
if (!conversation.value) {
168200
return
169201
}
170202
171-
queryParams.pageNo = 1
172-
await getMessageList(conversation.value, false)
203+
if (typeof message !== 'undefined') {
204+
// 当前查询会话与消息所属会话不一致则不做处理
205+
if (message.conversationId !== conversation.value.id) {
206+
return
207+
}
208+
pushMessage(message)
209+
} else {
210+
queryParams.pageNo = 1
211+
await getMessageList()
212+
}
213+
173214
if (loadHistory.value) {
174215
// 右下角显示有新消息提示
175216
showNewMessageTip.value = true
217+
} else {
218+
// 滚动到最新消息处
219+
await handleToNewMessage()
176220
}
177221
}
178222
179-
defineExpose({ getMessageList, refreshMessageList })
223+
const getNewMessageList = async (val: KeFuConversationRespVO) => {
224+
// 会话切换,重置相关参数
225+
queryParams.pageNo = 1
226+
messageList.value = []
227+
total.value = 0
228+
loadHistory.value = false
229+
refreshContent.value = false
230+
// 设置会话相关属性
231+
conversation.value = val
232+
queryParams.conversationId = val.id
233+
// 获取消息
234+
await refreshMessageList()
235+
}
236+
defineExpose({ getNewMessageList, refreshMessageList })
237+
180238
const showKeFuMessageList = computed(() => !isEmpty(conversation.value)) // 是否显示聊天区域
181239
const skipGetMessageList = computed(() => {
182240
// 已加载到最后一页的话则不触发新的消息获取
@@ -221,9 +279,7 @@ const sendMessage = async (msg: any) => {
221279
await KeFuMessageApi.sendKeFuMessage(msg)
222280
message.value = ''
223281
// 加载消息列表
224-
await getMessageList(conversation.value, false)
225-
// 滚动到最新消息处
226-
await scrollToBottom()
282+
await refreshMessageList()
227283
}
228284
229285
/** 滚动到底部 */
@@ -248,17 +304,24 @@ const handleToNewMessage = async () => {
248304
await scrollToBottom()
249305
}
250306
251-
/** 加载历史消息 */
252307
const loadHistory = ref(false) // 加载历史消息
253-
const handleScroll = async ({ scrollTop }) => {
308+
/** 处理消息列表滚动事件(debounce 限流) */
309+
const handleScroll = debounce(({ scrollTop }) => {
254310
if (skipGetMessageList.value) {
255311
return
256312
}
257313
// 触顶自动加载下一页数据
258-
if (scrollTop === 0) {
259-
await handleOldMessage()
314+
if (Math.floor(scrollTop) === 0) {
315+
handleOldMessage()
260316
}
261-
}
317+
const wrap = scrollbarRef.value?.wrapRef
318+
// 触底重置
319+
if (Math.abs(wrap!.scrollHeight - wrap!.clientHeight - wrap!.scrollTop) < 1) {
320+
loadHistory.value = false
321+
refreshMessageList()
322+
}
323+
}, 200)
324+
/** 加载历史消息 */
262325
const handleOldMessage = async () => {
263326
// 记录已有页面高度
264327
const oldPageHeight = innerRef.value?.clientHeight
@@ -268,7 +331,7 @@ const handleOldMessage = async () => {
268331
loadHistory.value = true
269332
// 加载消息列表
270333
queryParams.pageNo += 1
271-
await getMessageList(conversation.value, false)
334+
await getMessageList()
272335
// 等页面加载完后,获得上一页最后一条消息的位置,控制滚动到它所在位置
273336
scrollbarRef.value!.setScrollTop(innerRef.value!.clientHeight - oldPageHeight)
274337
}

0 commit comments

Comments
 (0)