hookehuyr

feat(消息): 新增消息详情组件并重构消息页面

将消息详情弹框抽离为独立组件 MessageDetail,支持消息发送功能
重构消息页面代码,移除冗余样式,优化消息列表布局
...@@ -10,6 +10,7 @@ declare module 'vue' { ...@@ -10,6 +10,7 @@ declare module 'vue' {
10 BrandModelPicker: typeof import('./src/components/BrandModelPicker.vue')['default'] 10 BrandModelPicker: typeof import('./src/components/BrandModelPicker.vue')['default']
11 FeaturedRecommendations: typeof import('./src/components/FeaturedRecommendations.vue')['default'] 11 FeaturedRecommendations: typeof import('./src/components/FeaturedRecommendations.vue')['default']
12 LatestScooters: typeof import('./src/components/LatestScooters.vue')['default'] 12 LatestScooters: typeof import('./src/components/LatestScooters.vue')['default']
13 + MessageDetail: typeof import('./src/components/MessageDetail.vue')['default']
13 NavBar: typeof import('./src/components/navBar.vue')['default'] 14 NavBar: typeof import('./src/components/navBar.vue')['default']
14 NutActionSheet: typeof import('@nutui/nutui-taro')['ActionSheet'] 15 NutActionSheet: typeof import('@nutui/nutui-taro')['ActionSheet']
15 NutButton: typeof import('@nutui/nutui-taro')['Button'] 16 NutButton: typeof import('@nutui/nutui-taro')['Button']
......
1 +<template>
2 + <nut-popup
3 + v-model:visible="visible"
4 + position="right"
5 + :style="{ width: '100%', height: '100%' }"
6 + closeable
7 + close-icon-position="top-right"
8 + @close="handleClose"
9 + >
10 + <view class="message-detail-container">
11 + <!-- 详情页头部 -->
12 + <view class="detail-header">
13 + <view class="flex items-center">
14 + <image
15 + v-if="conversation?.avatar"
16 + :src="conversation.avatar"
17 + class="w-12 h-12 rounded-full object-cover mr-3"
18 + mode="aspectFill"
19 + />
20 + <view v-else class="w-12 h-12 rounded-full bg-gray-100 flex items-center justify-center mr-3">
21 + <component :is="conversation?.icon" />
22 + </view>
23 + <view class="flex-1">
24 + <text class="text-lg font-medium">{{ conversation?.name }}</text>
25 + <text class="text-sm text-gray-500 block">{{ conversation?.time }}</text>
26 + </view>
27 + </view>
28 + </view>
29 +
30 + <!-- 消息内容区域 -->
31 + <view class="detail-content">
32 + <!-- 系统通知样式 -->
33 + <view v-if="conversation?.type === 'notification'" class="notification-content">
34 + <view class="message-content">
35 + <text class="text-base">{{ conversation?.lastMessage }}</text>
36 + </view>
37 + </view>
38 +
39 + <!-- 聊天记录样式 -->
40 + <view v-else class="chat-content">
41 + <scroll-view
42 + class="chat-messages"
43 + :scroll-y="true"
44 + :scroll-top="scrollTop"
45 + :scroll-into-view="scrollIntoView"
46 + >
47 + <view
48 + v-for="(message, index) in messages"
49 + :key="index"
50 + :id="`msg-${index}`"
51 + class="message-item"
52 + :class="{
53 + 'message-sent': message.type === 'sent',
54 + 'message-received': message.type === 'received'
55 + }"
56 + >
57 + <view class="message-bubble">
58 + <text class="message-text">{{ message.content }}</text>
59 + <text class="message-time">{{ message.time }}</text>
60 + </view>
61 + </view>
62 + </scroll-view>
63 +
64 + <!-- 输入框区域 -->
65 + <view class="chat-input-area">
66 + <view class="input-container">
67 + <nut-textarea
68 + v-model="inputMessage"
69 + placeholder="请输入回复内容..."
70 + :rows="2"
71 + :max-length="500"
72 + class="message-input"
73 + @focus="handleInputFocus"
74 + />
75 + <nut-button
76 + type="primary"
77 + size="small"
78 + color="orange"
79 + @click="sendMessage"
80 + :disabled="!inputMessage.trim()"
81 + class="send-button"
82 + >
83 + 发送
84 + </nut-button>
85 + </view>
86 + </view>
87 + </view>
88 + </view>
89 +
90 + <!-- 底部按钮 -->
91 + <view class="detail-footer">
92 + <nut-button
93 + type="primary"
94 + size="large"
95 + block
96 + @click="handleClose"
97 + color="orange"
98 + >
99 + {{ conversation?.type === 'notification' ? '关闭' : '返回' }}
100 + </nut-button>
101 + </view>
102 + </view>
103 + </nut-popup>
104 +</template>
105 +
106 +<script setup>
107 +import { ref, computed, watch, nextTick } from 'vue'
108 +import Taro from '@tarojs/taro'
109 +
110 +/**
111 + * 消息详情组件 Props
112 + */
113 +const props = defineProps({
114 + // 弹框显示状态
115 + modelValue: {
116 + type: Boolean,
117 + default: false
118 + },
119 + // 当前对话信息
120 + conversation: {
121 + type: Object,
122 + default: () => ({})
123 + }
124 +})
125 +
126 +/**
127 + * 组件事件
128 + */
129 +const emit = defineEmits(['update:modelValue', 'close', 'sendMessage'])
130 +
131 +// 弹框显示状态
132 +const visible = computed({
133 + get: () => props.modelValue,
134 + set: (value) => emit('update:modelValue', value)
135 +})
136 +
137 +// 输入消息内容
138 +const inputMessage = ref('')
139 +
140 +// 滚动相关
141 +const scrollTop = ref(0)
142 +const scrollIntoView = ref('')
143 +
144 +// 模拟聊天消息数据
145 +const messages = ref([])
146 +
147 +/**
148 + * 初始化聊天消息
149 + */
150 +const initChatMessages = () => {
151 + if (props.conversation?.type === 'message' || props.conversation?.type === 'chat') {
152 + // 模拟历史消息
153 + messages.value = [
154 + {
155 + type: 'received',
156 + content: props.conversation.lastMessage || '您好,有什么可以帮助您的吗?',
157 + time: '10:30'
158 + },
159 + {
160 + type: 'sent',
161 + content: '我想咨询一下车辆的相关问题',
162 + time: '10:32'
163 + },
164 + {
165 + type: 'received',
166 + content: '好的,请问您具体想了解哪方面的信息呢?我会尽力为您解答。',
167 + time: '10:33'
168 + },
169 + {
170 + type: 'sent',
171 + content: '我想咨询一下车辆的相关问题',
172 + time: '10:34'
173 + },
174 + {
175 + type: 'received',
176 + content: '好的,请问您具体想了解哪方面的信息呢?我会尽力为您解答。',
177 + time: '10:35'
178 + },
179 + {
180 + type: 'sent',
181 + content: '我想咨询一下车辆的相关问题',
182 + time: '10:36'
183 + },
184 + {
185 + type: 'received',
186 + content: '好的,请问您具体想了解哪方面的信息呢?我会尽力为您解答。',
187 + time: '10:37'
188 + },
189 + ]
190 + }
191 +}
192 +
193 +/**
194 + * 发送消息
195 + */
196 +const sendMessage = async () => {
197 + if (!inputMessage.value.trim()) {
198 + Taro.showToast({
199 + title: '请输入消息内容',
200 + icon: 'none'
201 + })
202 + return
203 + }
204 +
205 + const newMessage = {
206 + type: 'sent',
207 + content: inputMessage.value.trim(),
208 + time: new Date().toLocaleTimeString('zh-CN', {
209 + hour: '2-digit',
210 + minute: '2-digit'
211 + })
212 + }
213 +
214 + messages.value.push(newMessage)
215 +
216 + // 清空输入框
217 + const messageContent = inputMessage.value
218 + inputMessage.value = ''
219 +
220 + // 滚动到底部
221 + await nextTick()
222 + scrollToBottom()
223 +
224 + // 触发发送消息事件
225 + emit('sendMessage', {
226 + conversation: props.conversation,
227 + message: messageContent
228 + })
229 +
230 + // 模拟对方回复
231 + setTimeout(() => {
232 + const replyMessage = {
233 + type: 'received',
234 + content: '收到您的消息,我们会尽快处理并回复您。',
235 + time: new Date().toLocaleTimeString('zh-CN', {
236 + hour: '2-digit',
237 + minute: '2-digit'
238 + })
239 + }
240 + messages.value.push(replyMessage)
241 + nextTick(() => {
242 + scrollToBottom()
243 + })
244 + }, 1000)
245 +}
246 +
247 +/**
248 + * 滚动到底部
249 + */
250 +const scrollToBottom = () => {
251 + if (messages.value.length > 0) {
252 + // 使用 setTimeout 确保 DOM 更新完成后再滚动
253 + setTimeout(() => {
254 + scrollIntoView.value = `msg-${messages.value.length - 1}`
255 + }, 100)
256 + }
257 +}
258 +
259 +/**
260 + * 输入框获得焦点
261 + */
262 +const handleInputFocus = () => {
263 + setTimeout(() => {
264 + scrollToBottom()
265 + }, 300)
266 +}
267 +
268 +/**
269 + * 关闭弹框
270 + */
271 +const handleClose = () => {
272 + visible.value = false
273 + inputMessage.value = ''
274 + emit('close')
275 +}
276 +
277 +/**
278 + * 监听对话变化,初始化消息
279 + */
280 +watch(
281 + () => props.conversation,
282 + (newConversation) => {
283 + if (newConversation && visible.value) {
284 + initChatMessages()
285 + // 延迟滚动确保消息渲染完成
286 + setTimeout(() => {
287 + nextTick(() => {
288 + scrollToBottom()
289 + })
290 + }, 200)
291 + }
292 + },
293 + { immediate: true }
294 +)
295 +
296 +/**
297 + * 监听弹框显示状态
298 + */
299 +watch(visible, (newVisible) => {
300 + if (newVisible && props.conversation) {
301 + initChatMessages()
302 + // 确保弹框完全打开后再滚动到底部
303 + setTimeout(() => {
304 + nextTick(() => {
305 + scrollToBottom()
306 + })
307 + }, 300)
308 + }
309 +})
310 +</script>
311 +
312 +<style lang="less">
313 +.message-detail-container {
314 + height: 100%;
315 + display: flex;
316 + flex-direction: column;
317 + background: #ffffff;
318 +}
319 +
320 +.detail-header {
321 + padding: 32rpx 24rpx;
322 + border-bottom: 1rpx solid #f0f0f0;
323 + background: #ffffff;
324 + flex-shrink: 0;
325 +}
326 +
327 +.detail-content {
328 + flex: 1;
329 + overflow: hidden;
330 + background: #f8f9fa;
331 +}
332 +
333 +// 系统通知样式
334 +.notification-content {
335 + padding: 24rpx;
336 + height: 100%;
337 + overflow-y: auto;
338 +
339 + .message-content {
340 + background: #ffffff;
341 + padding: 24rpx;
342 + border-radius: 16rpx;
343 + margin-bottom: 24rpx;
344 + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
345 + }
346 +}
347 +
348 +// 聊天记录样式
349 +.chat-content {
350 + height: 100%;
351 + display: flex;
352 + flex-direction: column;
353 +}
354 +
355 +.chat-messages {
356 + flex: 1;
357 + padding: 24rpx;
358 + overflow-y: auto;
359 +}
360 +
361 +.message-item {
362 + margin-bottom: 24rpx;
363 + display: flex;
364 + padding: 0 8rpx; // 添加左右内边距防止遮挡
365 +
366 + &.message-sent {
367 + justify-content: flex-end;
368 + padding-right: 60rpx; // 右侧消息增加右边距
369 +
370 + .message-bubble {
371 + background: #f97316;
372 + color: #ffffff;
373 + border-radius: 20rpx 20rpx 8rpx 20rpx;
374 + max-width: 65%; // 减少最大宽度,留出更多空间
375 + }
376 + }
377 +
378 + &.message-received {
379 + justify-content: flex-start;
380 + padding-left: 16rpx; // 左侧消息增加左边距
381 +
382 + .message-bubble {
383 + background: #ffffff;
384 + color: #333333;
385 + border-radius: 20rpx 20rpx 20rpx 8rpx;
386 + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
387 + max-width: 65%; // 减少最大宽度,保持一致
388 + }
389 + }
390 +}
391 +
392 +.message-bubble {
393 + padding: 16rpx 20rpx;
394 + position: relative;
395 + word-wrap: break-word;
396 + overflow-wrap: break-word;
397 +}
398 +
399 +.message-text {
400 + font-size: 30rpx;
401 + line-height: 1.5;
402 + word-break: break-word;
403 + display: block;
404 +}
405 +
406 +.message-time {
407 + font-size: 22rpx;
408 + opacity: 0.7;
409 + margin-top: 8rpx;
410 + display: block;
411 +}
412 +
413 +.chat-input-area {
414 + background: #ffffff;
415 + border-top: 1rpx solid #f0f0f0;
416 + flex-shrink: 0;
417 +}
418 +
419 +.input-container {
420 + padding: 24rpx;
421 + display: flex;
422 + align-items: flex-end;
423 + gap: 16rpx;
424 +}
425 +
426 +.message-input {
427 + flex: 1;
428 + min-height: 80rpx;
429 + max-height: 160rpx;
430 +}
431 +
432 +.send-button {
433 + height: 80rpx;
434 + padding: 0 24rpx;
435 + flex-shrink: 0;
436 +}
437 +
438 +.detail-footer {
439 + padding: 24rpx;
440 + background: #ffffff;
441 + border-top: 1rpx solid #f0f0f0;
442 + flex-shrink: 0;
443 +}
444 +
445 +// Tailwind CSS 类的补充样式
446 +// .w-12 {
447 +// width: 88rpx;
448 +// }
449 +
450 +// .h-12 {
451 +// height: 88rpx;
452 +// }
453 +
454 +// .rounded-full {
455 +// border-radius: 50%;
456 +// }
457 +
458 +// .object-cover {
459 +// object-fit: cover;
460 +// }
461 +
462 +// .bg-gray-100 {
463 +// background-color: #f3f4f6;
464 +// }
465 +
466 +// .flex {
467 +// display: flex;
468 +// }
469 +
470 +// .flex-1 {
471 +// flex: 1;
472 +// }
473 +
474 +// .items-center {
475 +// align-items: center;
476 +// }
477 +
478 +// .mr-3 {
479 +// margin-right: 24rpx;
480 +// }
481 +
482 +// .font-medium {
483 +// font-weight: 500;
484 +// }
485 +
486 +// .text-lg {
487 +// font-size: 36rpx;
488 +// }
489 +
490 +// .text-sm {
491 +// font-size: 28rpx;
492 +// }
493 +
494 +// .text-base {
495 +// font-size: 32rpx;
496 +// line-height: 1.5;
497 +// }
498 +
499 +// .text-gray-500 {
500 +// color: #6b7280;
501 +// }
502 +
503 +// .block {
504 +// display: block;
505 +// }
506 +
507 +// NutUI 组件样式覆盖
508 +:deep(.nut-textarea) {
509 + .nut-textarea__textarea {
510 + border: 1rpx solid #e5e7eb;
511 + border-radius: 12rpx;
512 + padding: 16rpx;
513 + font-size: 30rpx;
514 + line-height: 1.5;
515 + }
516 +}
517 +
518 +:deep(.nut-button) {
519 + border-radius: 12rpx;
520 +}
521 +</style>
...@@ -40,8 +40,9 @@ ...@@ -40,8 +40,9 @@
40 </nut-sticky> 40 </nut-sticky>
41 41
42 <!-- 消息列表内容 --> 42 <!-- 消息列表内容 -->
43 - <scroll-view ref="scrollViewRef" class="conversation-list" :style="scrollStyle" :scroll-y="true" @scrolltolower="loadMore" 43 + <scroll-view ref="scrollViewRef" class="conversation-list" :style="scrollStyle" :scroll-y="true"
44 - @scroll="scroll" :lower-threshold="100" :enable-flex="false" :scroll-top="scrollTop"> 44 + @scrolltolower="loadMore" @scroll="scroll" :lower-threshold="100" :enable-flex="false"
45 + :scroll-top="scrollTop">
45 <view v-for="conversation in filteredConversations" :key="conversation.id" 46 <view v-for="conversation in filteredConversations" :key="conversation.id"
46 class="conversation-item mt-2 mb-4 border-b border-gray-100 pb-2" 47 class="conversation-item mt-2 mb-4 border-b border-gray-100 pb-2"
47 @click="onConversationClick(conversation)"> 48 @click="onConversationClick(conversation)">
...@@ -70,7 +71,8 @@ ...@@ -70,7 +71,8 @@
70 </view> 71 </view>
71 72
72 <!-- 空状态提示 --> 73 <!-- 空状态提示 -->
73 - <view v-if="filteredConversations.length === 0 && !loading && !hasMore" class="empty-state py-8 text-center"> 74 + <view v-if="filteredConversations.length === 0 && !loading && !hasMore"
75 + class="empty-state py-8 text-center">
74 <Message size="48" color="#9ca3af" class="mb-4" /> 76 <Message size="48" color="#9ca3af" class="mb-4" />
75 <text class="text-gray-500 text-base block mb-2">暂无消息</text> 77 <text class="text-gray-500 text-base block mb-2">暂无消息</text>
76 <text class="text-gray-400 text-sm">当前筛选条件下没有找到相关消息</text> 78 <text class="text-gray-400 text-sm">当前筛选条件下没有找到相关消息</text>
...@@ -91,39 +93,8 @@ ...@@ -91,39 +93,8 @@
91 <TabBar /> 93 <TabBar />
92 94
93 <!-- 消息详情弹框 --> 95 <!-- 消息详情弹框 -->
94 - <nut-popup v-model:visible="showMessageDetail" position="right" :style="{ width: '100%', height: '100%' }" 96 + <MessageDetail v-model="showMessageDetail" :conversation="selectedConversation" @close="closeMessageDetail"
95 - closeable close-icon-position="top-right" @close="closeMessageDetail"> 97 + @sendMessage="handleSendMessage" />
96 - <view class="message-detail-container">
97 - <!-- 详情页头部 -->
98 - <view class="detail-header">
99 - <view class="flex items-center">
100 - <image v-if="selectedConversation?.avatar" :src="selectedConversation.avatar"
101 - class="w-12 h-12 rounded-full object-cover mr-3" mode="aspectFill" />
102 - <view v-else class="w-12 h-12 rounded-full bg-gray-100 flex items-center justify-center mr-3">
103 - <component :is="selectedConversation?.icon" />
104 - </view>
105 - <view class="flex-1">
106 - <text class="text-lg font-medium">{{ selectedConversation?.name }}</text>
107 - <text class="text-sm text-gray-500 block">{{ selectedConversation?.time }}</text>
108 - </view>
109 - </view>
110 - </view>
111 -
112 - <!-- 消息内容 -->
113 - <view class="detail-content">
114 - <view class="message-content">
115 - <text class="text-base">{{ selectedConversation?.lastMessage }}</text>
116 - </view>
117 - </view>
118 -
119 - <!-- 底部关闭按钮 -->
120 - <view class="detail-footer">
121 - <nut-button type="primary" size="large" block @click="closeMessageDetail" color="orange">
122 - 关闭
123 - </nut-button>
124 - </view>
125 - </view>
126 - </nut-popup>
127 </view> 98 </view>
128 </template> 99 </template>
129 100
...@@ -131,10 +102,12 @@ ...@@ -131,10 +102,12 @@
131 import { ref, computed, onMounted, markRaw } from 'vue' 102 import { ref, computed, onMounted, markRaw } from 'vue'
132 import { Search2, Notice, Message } from '@nutui/icons-vue-taro' 103 import { Search2, Notice, Message } from '@nutui/icons-vue-taro'
133 import TabBar from '@/components/TabBar.vue' 104 import TabBar from '@/components/TabBar.vue'
105 +import MessageDetail from '@/components/MessageDetail.vue'
134 import { $ } from '@tarojs/extend' 106 import { $ } from '@tarojs/extend'
107 +import Taro from '@tarojs/taro'
135 108
136 // 默认头像 109 // 默认头像
137 -const defaultAvatar = 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg' 110 +// const defaultAvatar = 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'
138 111
139 const scrollStyle = ref({ 112 const scrollStyle = ref({
140 height: 'calc(100vh - 500rpx)' 113 height: 'calc(100vh - 500rpx)'
...@@ -329,6 +302,25 @@ const markAsRead = (conversationId) => { ...@@ -329,6 +302,25 @@ const markAsRead = (conversationId) => {
329 } 302 }
330 } 303 }
331 304
305 +// 处理发送消息
306 +const handleSendMessage = (data) => {
307 + const { conversation, message } = data
308 + if (!conversation || !message.trim()) return
309 +
310 + // 更新对话的最后一条消息
311 + const conv = conversations.value.find(conv => conv.id === conversation.id)
312 + if (conv) {
313 + conv.lastMessage = message
314 + conv.time = '刚刚'
315 + conv.unread = false // 标记为已读
316 + }
317 +
318 + Taro.showToast({
319 + title: '消息发送成功',
320 + icon: 'success'
321 + })
322 +}
323 +
332 // 页面加载时初始化数据 324 // 页面加载时初始化数据
333 onMounted(() => { 325 onMounted(() => {
334 // 设置滚动列表可视高度 326 // 设置滚动列表可视高度
...@@ -560,69 +552,7 @@ onMounted(() => { ...@@ -560,69 +552,7 @@ onMounted(() => {
560 position: relative; 552 position: relative;
561 } 553 }
562 554
563 - /* 消息详情弹框样式 */
564 - .message-detail-container {
565 - height: 100%;
566 - display: flex;
567 - flex-direction: column;
568 - background: #ffffff;
569 - }
570 555
571 - .detail-header {
572 - padding: 32rpx 24rpx;
573 - border-bottom: 1rpx solid #f0f0f0;
574 - background: #ffffff;
575 - flex-shrink: 0;
576 - }
577 -
578 - .detail-content {
579 - flex: 1;
580 - padding: 24rpx;
581 - overflow-y: auto;
582 - background: #f8f9fa;
583 - }
584 -
585 - .message-content {
586 - background: #ffffff;
587 - padding: 24rpx;
588 - border-radius: 16rpx;
589 - margin-bottom: 24rpx;
590 - box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
591 - }
592 -
593 - .message-history {
594 - .message-item {
595 - background: #ffffff;
596 - padding: 20rpx;
597 - border-radius: 12rpx;
598 - margin-bottom: 16rpx;
599 - box-shadow: 0 1rpx 4rpx rgba(0, 0, 0, 0.05);
600 - }
601 - }
602 -
603 - .detail-footer {
604 - padding: 24rpx;
605 - background: #ffffff;
606 - border-top: 1rpx solid #f0f0f0;
607 - flex-shrink: 0;
608 - }
609 -
610 - .text-lg {
611 - font-size: 36rpx;
612 - }
613 -
614 - .text-base {
615 - font-size: 32rpx;
616 - line-height: 1.5;
617 - }
618 -
619 - .mr-3 {
620 - margin-right: 24rpx;
621 - }
622 -
623 - .mt-1 {
624 - margin-top: 8rpx;
625 - }
626 556
627 } 557 }
628 558
...@@ -659,7 +589,8 @@ onMounted(() => { ...@@ -659,7 +589,8 @@ onMounted(() => {
659 /* 状态筛选标签 */ 589 /* 状态筛选标签 */
660 .status-tabs { 590 .status-tabs {
661 background: white; 591 background: white;
662 - padding: 20rpx 35rpx; /* 增加内边距 */ 592 + padding: 20rpx 35rpx;
593 + /* 增加内边距 */
663 border-bottom: 1rpx solid #e5e7eb; 594 border-bottom: 1rpx solid #e5e7eb;
664 display: flex; 595 display: flex;
665 position: relative; 596 position: relative;
...@@ -668,14 +599,15 @@ onMounted(() => { ...@@ -668,14 +599,15 @@ onMounted(() => {
668 -ms-overflow-style: none; 599 -ms-overflow-style: none;
669 600
670 &::-webkit-scrollbar { 601 &::-webkit-scrollbar {
671 - display: none; 602 + display: none;
672 } 603 }
673 } 604 }
674 605
675 .tab-item { 606 .tab-item {
676 margin-right: 48rpx; 607 margin-right: 48rpx;
677 padding-bottom: 16rpx; 608 padding-bottom: 16rpx;
678 - font-size: 30rpx; /* 增大字体 */ 609 + font-size: 30rpx;
610 + /* 增大字体 */
679 color: #6b7280; 611 color: #6b7280;
680 position: relative; 612 position: relative;
681 cursor: pointer; 613 cursor: pointer;
...@@ -685,30 +617,30 @@ onMounted(() => { ...@@ -685,30 +617,30 @@ onMounted(() => {
685 transform: translateX(0); 617 transform: translateX(0);
686 618
687 &.active { 619 &.active {
688 - color: #f97316; 620 + color: #f97316;
689 - font-weight: 500; 621 + font-weight: 500;
690 - transform: translateY(-2rpx); 622 + transform: translateY(-2rpx);
691 - 623 +
692 - &::after { 624 + &::after {
693 - content: ''; 625 + content: '';
694 - position: absolute; 626 + position: absolute;
695 - bottom: 0; 627 + bottom: 0;
696 - left: 0; 628 + left: 0;
697 - right: 0; 629 + right: 0;
698 - height: 4rpx; 630 + height: 4rpx;
699 - background: linear-gradient(90deg, #f97316, #fb923c); 631 + background: linear-gradient(90deg, #f97316, #fb923c);
700 - border-radius: 2rpx; 632 + border-radius: 2rpx;
701 - animation: slideIn 0.3s cubic-bezier(0.4, 0, 0.2, 1); 633 + animation: slideIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);
702 - } 634 + }
703 } 635 }
704 636
705 &:hover { 637 &:hover {
706 - color: #f97316; 638 + color: #f97316;
707 - transform: translateY(-1rpx); 639 + transform: translateY(-1rpx);
708 } 640 }
709 641
710 &:last-child { 642 &:last-child {
711 - margin-right: 0; 643 + margin-right: 0;
712 } 644 }
713 } 645 }
714 646
...@@ -720,6 +652,7 @@ onMounted(() => { ...@@ -720,6 +652,7 @@ onMounted(() => {
720 transform: scaleX(0); 652 transform: scaleX(0);
721 opacity: 0; 653 opacity: 0;
722 } 654 }
655 +
723 100% { 656 100% {
724 transform: scaleX(1); 657 transform: scaleX(1);
725 opacity: 1; 658 opacity: 1;
...@@ -737,6 +670,7 @@ onMounted(() => { ...@@ -737,6 +670,7 @@ onMounted(() => {
737 opacity: 0; 670 opacity: 0;
738 transform: translateY(20rpx); 671 transform: translateY(20rpx);
739 } 672 }
673 +
740 to { 674 to {
741 opacity: 1; 675 opacity: 1;
742 transform: translateY(0); 676 transform: translateY(0);
...@@ -749,17 +683,32 @@ onMounted(() => { ...@@ -749,17 +683,32 @@ onMounted(() => {
749 animation-fill-mode: both; 683 animation-fill-mode: both;
750 } 684 }
751 685
752 -.conversation-item:nth-child(1) { animation-delay: 0.1s; } 686 +.conversation-item:nth-child(1) {
753 -.conversation-item:nth-child(2) { animation-delay: 0.15s; } 687 + animation-delay: 0.1s;
754 -.conversation-item:nth-child(3) { animation-delay: 0.2s; } 688 +}
755 -.conversation-item:nth-child(4) { animation-delay: 0.25s; } 689 +
756 -.conversation-item:nth-child(5) { animation-delay: 0.3s; } 690 +.conversation-item:nth-child(2) {
691 + animation-delay: 0.15s;
692 +}
693 +
694 +.conversation-item:nth-child(3) {
695 + animation-delay: 0.2s;
696 +}
697 +
698 +.conversation-item:nth-child(4) {
699 + animation-delay: 0.25s;
700 +}
701 +
702 +.conversation-item:nth-child(5) {
703 + animation-delay: 0.3s;
704 +}
757 705
758 @keyframes fadeInItem { 706 @keyframes fadeInItem {
759 from { 707 from {
760 opacity: 0; 708 opacity: 0;
761 transform: translateX(-20rpx); 709 transform: translateX(-20rpx);
762 } 710 }
711 +
763 to { 712 to {
764 opacity: 1; 713 opacity: 1;
765 transform: translateX(0); 714 transform: translateX(0);
......