feat(消息列表): 添加消息轮询功能以实时更新消息列表
添加轮询机制,每隔30秒自动获取最新消息 在搜索和切换标签时自动重启轮询 页面卸载时清理定时器防止内存泄漏
Showing
1 changed file
with
89 additions
and
1 deletions
| ... | @@ -96,7 +96,7 @@ | ... | @@ -96,7 +96,7 @@ |
| 96 | </template> | 96 | </template> |
| 97 | 97 | ||
| 98 | <script setup> | 98 | <script setup> |
| 99 | -import { ref, computed, onMounted, markRaw } from 'vue' | 99 | +import { ref, computed, onMounted, onUnmounted, markRaw } from 'vue' |
| 100 | import { Search2, Notice } from '@nutui/icons-vue-taro' | 100 | import { Search2, Notice } from '@nutui/icons-vue-taro' |
| 101 | import TabBar from '@/components/TabBar.vue' | 101 | import TabBar from '@/components/TabBar.vue' |
| 102 | import MessageDetail from '@/components/MessageDetail.vue' | 102 | import MessageDetail from '@/components/MessageDetail.vue' |
| ... | @@ -125,6 +125,8 @@ const onBlurSearch = async () => { | ... | @@ -125,6 +125,8 @@ const onBlurSearch = async () => { |
| 125 | hasMore.value = true | 125 | hasMore.value = true |
| 126 | // 重新获取数据 | 126 | // 重新获取数据 |
| 127 | await initData() | 127 | await initData() |
| 128 | + // 重新启动轮询以适应新的搜索条件 | ||
| 129 | + startPolling() | ||
| 128 | } | 130 | } |
| 129 | // 当前激活的Tab | 131 | // 当前激活的Tab |
| 130 | const activeTab = ref('all') | 132 | const activeTab = ref('all') |
| ... | @@ -137,6 +139,10 @@ const pageSize = 10 | ... | @@ -137,6 +139,10 @@ const pageSize = 10 |
| 137 | // 是否还有更多数据 | 139 | // 是否还有更多数据 |
| 138 | const hasMore = ref(true) | 140 | const hasMore = ref(true) |
| 139 | 141 | ||
| 142 | +// 轮询相关 | ||
| 143 | +const pollingTimer = ref(null) | ||
| 144 | +const POLLING_INTERVAL = 30000 // 30秒 | ||
| 145 | + | ||
| 140 | // 对话数据 | 146 | // 对话数据 |
| 141 | const conversations = ref([]) | 147 | const conversations = ref([]) |
| 142 | 148 | ||
| ... | @@ -147,6 +153,79 @@ const selectedConversation = ref(null) | ... | @@ -147,6 +153,79 @@ const selectedConversation = ref(null) |
| 147 | // 模拟消息历史记录 | 153 | // 模拟消息历史记录 |
| 148 | const mockMessages = ref([]) | 154 | const mockMessages = ref([]) |
| 149 | 155 | ||
| 156 | +/** | ||
| 157 | + * 轮询获取消息列表 | ||
| 158 | + */ | ||
| 159 | +const pollMessages = async () => { | ||
| 160 | + try { | ||
| 161 | + // 静默获取数据,不显示loading状态 | ||
| 162 | + const params = { | ||
| 163 | + page: 0, | ||
| 164 | + limit: pageSize | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + // 根据activeTab设置过滤参数 | ||
| 168 | + if (activeTab.value === 'unread') { | ||
| 169 | + params.status = 3 // 未读 | ||
| 170 | + } else if (activeTab.value === 'system') { | ||
| 171 | + params.type = 'system' // 系统消息 | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + // 如果有搜索关键词 | ||
| 175 | + if (searchValue.value) { | ||
| 176 | + params.keyword = searchValue.value | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + const response = await getMessagesListAPI(params) | ||
| 180 | + | ||
| 181 | + if (response.code && response.data && response.data.list) { | ||
| 182 | + // 转换API数据格式为组件需要的格式 | ||
| 183 | + const transformedData = response.data.list.map(item => ({ | ||
| 184 | + id: item.id, | ||
| 185 | + name: item.type === 'system' ? '系统通知' : (item.partner_nickname || '未知用户'), | ||
| 186 | + avatar: item.type === 'chat' ? (item.partner_avatar_url || defaultAvatar) : '', | ||
| 187 | + icon: item.type === 'system' ? markRaw(Notice) : null, | ||
| 188 | + lastMessage: item.note || '', | ||
| 189 | + time: item.created_time_desc || '', | ||
| 190 | + unread: item.status === 3, // 3=未读,5=已读 | ||
| 191 | + type: item.type, | ||
| 192 | + create_time: item.create_time | ||
| 193 | + })) | ||
| 194 | + | ||
| 195 | + // 更新消息列表,保持当前页面状态 | ||
| 196 | + conversations.value = transformedData | ||
| 197 | + } | ||
| 198 | + } catch (error) { | ||
| 199 | + console.error('轮询获取消息列表失败:', error) | ||
| 200 | + // 轮询失败时不显示错误提示,避免干扰用户 | ||
| 201 | + } | ||
| 202 | +} | ||
| 203 | + | ||
| 204 | +/** | ||
| 205 | + * 启动轮询 | ||
| 206 | + */ | ||
| 207 | +const startPolling = () => { | ||
| 208 | + // 清除现有定时器 | ||
| 209 | + if (pollingTimer.value) { | ||
| 210 | + clearInterval(pollingTimer.value) | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + // 启动新的定时器 | ||
| 214 | + pollingTimer.value = setInterval(() => { | ||
| 215 | + pollMessages() | ||
| 216 | + }, POLLING_INTERVAL) | ||
| 217 | +} | ||
| 218 | + | ||
| 219 | +/** | ||
| 220 | + * 停止轮询 | ||
| 221 | + */ | ||
| 222 | +const stopPolling = () => { | ||
| 223 | + if (pollingTimer.value) { | ||
| 224 | + clearInterval(pollingTimer.value) | ||
| 225 | + pollingTimer.value = null | ||
| 226 | + } | ||
| 227 | +} | ||
| 228 | + | ||
| 150 | // 初始化数据 | 229 | // 初始化数据 |
| 151 | const initData = async () => { | 230 | const initData = async () => { |
| 152 | try { | 231 | try { |
| ... | @@ -256,6 +335,8 @@ const setActiveTab = async (tabKey) => { | ... | @@ -256,6 +335,8 @@ const setActiveTab = async (tabKey) => { |
| 256 | }, 50); | 335 | }, 50); |
| 257 | // 重新获取数据 | 336 | // 重新获取数据 |
| 258 | await initData(); | 337 | await initData(); |
| 338 | + // 重新启动轮询以适应新的筛选条件 | ||
| 339 | + startPolling(); | ||
| 259 | 340 | ||
| 260 | // 添加淡入效果 | 341 | // 添加淡入效果 |
| 261 | setTimeout(() => { | 342 | setTimeout(() => { |
| ... | @@ -426,6 +507,13 @@ onMounted(async () => { | ... | @@ -426,6 +507,13 @@ onMounted(async () => { |
| 426 | } | 507 | } |
| 427 | }, 500); | 508 | }, 500); |
| 428 | await initData() | 509 | await initData() |
| 510 | + // 启动轮询 | ||
| 511 | + startPolling() | ||
| 512 | +}) | ||
| 513 | + | ||
| 514 | +// 页面卸载时清理轮询 | ||
| 515 | +onUnmounted(() => { | ||
| 516 | + stopPolling() | ||
| 429 | }) | 517 | }) |
| 430 | </script> | 518 | </script> |
| 431 | 519 | ... | ... |
-
Please register or login to post a comment