refactor(MessageDetail): 简化模板代码格式并优化消息排序
将多行属性合并为单行以提高可读性 后端返回的消息列表进行逆序排列以符合显示需求
Showing
1 changed file
with
22 additions
and
63 deletions
| 1 | <template> | 1 | <template> |
| 2 | - <nut-popup | 2 | + <nut-popup v-model:visible="visible" position="right" :style="{ width: '100%', height: '100%' }" closeable |
| 3 | - v-model:visible="visible" | 3 | + close-icon-position="top-right" @close="handleClose"> |
| 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"> | 4 | <view class="message-detail-container"> |
| 11 | <!-- 详情页头部 --> | 5 | <!-- 详情页头部 --> |
| 12 | <view class="detail-header"> | 6 | <view class="detail-header"> |
| 13 | <view class="flex items-center"> | 7 | <view class="flex items-center"> |
| 14 | - <image | 8 | + <image v-if="conversation?.avatar" :src="conversation.avatar" class="w-12 h-12 rounded-full object-cover mr-3" |
| 15 | - v-if="conversation?.avatar" | 9 | + mode="aspectFill" /> |
| 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"> | 10 | <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" /> | 11 | <component :is="conversation?.icon" /> |
| 22 | </view> | 12 | </view> |
| ... | @@ -46,30 +36,18 @@ | ... | @@ -46,30 +36,18 @@ |
| 46 | 36 | ||
| 47 | <!-- 聊天记录样式 --> | 37 | <!-- 聊天记录样式 --> |
| 48 | <view v-else class="chat-content"> | 38 | <view v-else class="chat-content"> |
| 49 | - <scroll-view | 39 | + <scroll-view class="chat-messages" :scroll-y="true" :scroll-top="scrollTop" :scroll-into-view="scrollIntoView" |
| 50 | - class="chat-messages" | 40 | + :refresher-enabled="true" :refresher-triggered="isLoadingMessages" @refresherrefresh="handleRefresh"> |
| 51 | - :scroll-y="true" | ||
| 52 | - :scroll-top="scrollTop" | ||
| 53 | - :scroll-into-view="scrollIntoView" | ||
| 54 | - :refresher-enabled="true" | ||
| 55 | - :refresher-triggered="isLoadingMessages" | ||
| 56 | - @refresherrefresh="handleRefresh" | ||
| 57 | - > | ||
| 58 | <!-- 数据加载完成提示 --> | 41 | <!-- 数据加载完成提示 --> |
| 59 | - <view v-if="!hasMoreMessages && !isInitialLoad && messages.length > 0 && hasTriedLoadMore" class="load-complete-tip"> | 42 | + <view v-if="!hasMoreMessages && !isInitialLoad && messages.length > 0 && hasTriedLoadMore" |
| 43 | + class="load-complete-tip"> | ||
| 60 | <text class="tip-text">已加载完所有数据</text> | 44 | <text class="tip-text">已加载完所有数据</text> |
| 61 | </view> | 45 | </view> |
| 62 | 46 | ||
| 63 | - <view | 47 | + <view v-for="(message, index) in messages" :key="index" :id="`msg-${index}`" class="message-item" :class="{ |
| 64 | - v-for="(message, index) in messages" | 48 | + 'message-sent': message.type === 'sent', |
| 65 | - :key="index" | 49 | + 'message-received': message.type === 'received' |
| 66 | - :id="`msg-${index}`" | 50 | + }"> |
| 67 | - class="message-item" | ||
| 68 | - :class="{ | ||
| 69 | - 'message-sent': message.type === 'sent', | ||
| 70 | - 'message-received': message.type === 'received' | ||
| 71 | - }" | ||
| 72 | - > | ||
| 73 | <view class="message-bubble"> | 51 | <view class="message-bubble"> |
| 74 | <text class="message-text">{{ message.content }}</text> | 52 | <text class="message-text">{{ message.content }}</text> |
| 75 | <text class="message-time">{{ message.time }}</text> | 53 | <text class="message-time">{{ message.time }}</text> |
| ... | @@ -80,23 +58,10 @@ | ... | @@ -80,23 +58,10 @@ |
| 80 | <!-- 输入框区域 --> | 58 | <!-- 输入框区域 --> |
| 81 | <view class="chat-input-area"> | 59 | <view class="chat-input-area"> |
| 82 | <view class="input-container"> | 60 | <view class="input-container"> |
| 83 | - <nut-textarea | 61 | + <nut-textarea v-model="inputMessage" placeholder="请输入回复内容..." :rows="2" :max-length="500" |
| 84 | - v-model="inputMessage" | 62 | + :cursorSpacing="100" class="message-input" @focus="handleInputFocus" /> |
| 85 | - placeholder="请输入回复内容..." | 63 | + <nut-button type="primary" size="small" color="orange" @click="sendMessage" |
| 86 | - :rows="2" | 64 | + :disabled="!inputMessage.trim()" class="send-button"> |
| 87 | - :max-length="500" | ||
| 88 | - :cursorSpacing="100" | ||
| 89 | - class="message-input" | ||
| 90 | - @focus="handleInputFocus" | ||
| 91 | - /> | ||
| 92 | - <nut-button | ||
| 93 | - type="primary" | ||
| 94 | - size="small" | ||
| 95 | - color="orange" | ||
| 96 | - @click="sendMessage" | ||
| 97 | - :disabled="!inputMessage.trim()" | ||
| 98 | - class="send-button" | ||
| 99 | - > | ||
| 100 | 发送 | 65 | 发送 |
| 101 | </nut-button> | 66 | </nut-button> |
| 102 | </view> | 67 | </view> |
| ... | @@ -106,13 +71,7 @@ | ... | @@ -106,13 +71,7 @@ |
| 106 | 71 | ||
| 107 | <!-- 底部按钮 --> | 72 | <!-- 底部按钮 --> |
| 108 | <view class="detail-footer"> | 73 | <view class="detail-footer"> |
| 109 | - <nut-button | 74 | + <nut-button type="primary" size="large" block @click="handleClose" color="orange"> |
| 110 | - type="primary" | ||
| 111 | - size="large" | ||
| 112 | - block | ||
| 113 | - @click="handleClose" | ||
| 114 | - color="orange" | ||
| 115 | - > | ||
| 116 | {{ conversation?.type === 'system' ? '关闭' : '返回' }} | 75 | {{ conversation?.type === 'system' ? '关闭' : '返回' }} |
| 117 | </nut-button> | 76 | </nut-button> |
| 118 | </view> | 77 | </view> |
| ... | @@ -186,10 +145,10 @@ const loadChatMessages = async (isLoadMore = false) => { | ... | @@ -186,10 +145,10 @@ const loadChatMessages = async (isLoadMore = false) => { |
| 186 | } | 145 | } |
| 187 | 146 | ||
| 188 | // 对于scrolltoupper事件,如果没有更多消息则不加载 | 147 | // 对于scrolltoupper事件,如果没有更多消息则不加载 |
| 189 | - // 但对于下拉刷新,总是允许尝试加载 | 148 | + // 但对于下拉刷新,总是允许尝试加载 |
| 190 | - if (!hasMoreMessages.value && isLoadMore && !isInitialLoad.value) { | 149 | + if (!hasMoreMessages.value && isLoadMore && !isInitialLoad.value) { |
| 191 | - // 这里可以根据具体需求决定是否允许重新加载 | 150 | + // 这里可以根据具体需求决定是否允许重新加载 |
| 192 | - } | 151 | + } |
| 193 | 152 | ||
| 194 | const userStore = useUserStore() | 153 | const userStore = useUserStore() |
| 195 | const currentUserId = userStore.userInfo?.id | 154 | const currentUserId = userStore.userInfo?.id |
| ... | @@ -207,7 +166,7 @@ const loadChatMessages = async (isLoadMore = false) => { | ... | @@ -207,7 +166,7 @@ const loadChatMessages = async (isLoadMore = false) => { |
| 207 | }) | 166 | }) |
| 208 | 167 | ||
| 209 | if (response.code && response.data) { | 168 | if (response.code && response.data) { |
| 210 | - const newMessages = response.data.list || [] | 169 | + const newMessages = (response.data.list || []).reverse() // 逆序排列,因为后端无法处理排序要求 |
| 211 | 170 | ||
| 212 | // 转换API数据格式为组件需要的格式 | 171 | // 转换API数据格式为组件需要的格式 |
| 213 | const formattedMessages = newMessages.map(msg => ({ | 172 | const formattedMessages = newMessages.map(msg => ({ | ... | ... |
-
Please register or login to post a comment