messageList.vue 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. <template>
  2. <view class="app-container pb-20">
  3. <TopBar title="消息通知" show-back>
  4. <template #right>
  5. <text class="text-blue-500 text-sm" @click="markAllRead">全部已读</text>
  6. </template>
  7. </TopBar>
  8. <!-- 筛选标签 -->
  9. <view class="bg-white px-4 py-3 flex gap-2">
  10. <view
  11. v-for="tab in filterTabs"
  12. :key="tab.value"
  13. class="px-4 py-2 rounded-full text-sm whitespace-nowrap"
  14. :class="currentFilter === tab.value ? 'bg-blue-500 text-white' : 'bg-gray-100 text-gray-600'"
  15. @click="currentFilter = tab.value"
  16. >
  17. {{ tab.label }}
  18. </view>
  19. </view>
  20. <!-- 消息列表 -->
  21. <view class="bg-white">
  22. <view
  23. v-for="msg in filteredMessages"
  24. :key="msg.id"
  25. class="notice-item"
  26. @click="goToDetail(msg)"
  27. >
  28. <view class="flex justify-between items-start mb-2">
  29. <view class="flex items-center flex-1">
  30. <text v-if="!msg.read" class="w-2 h-2 bg-red-500 rounded-full mr-2 flex-shrink-0"></text>
  31. <text v-else class="w-2 h-2 rounded-full mr-2 flex-shrink-0"></text>
  32. <text class="font-medium text-sm" :class="msg.read ? 'text-gray-600' : 'text-gray-800'">{{ msg.title }}</text>
  33. </view>
  34. <text class="text-gray-400 text-xs whitespace-nowrap">{{ formatRelativeTime(msg.createTime) }}</text>
  35. </view>
  36. <text class="text-gray-500 text-sm line-clamp-2">{{ msg.content }}</text>
  37. </view>
  38. </view>
  39. <view v-if="filteredMessages.length === 0" class="px-4 mt-3">
  40. <EmptyState message="暂无消息" />
  41. </view>
  42. </view>
  43. </template>
  44. <script setup lang="ts">
  45. import { ref, computed } from 'vue'
  46. import TopBar from '@/components/common/TopBar.vue'
  47. import EmptyState from '@/components/common/EmptyState.vue'
  48. import { useNotificationStore } from '@/stores/notification'
  49. import { formatRelativeTime, navigateTo } from '@/utils'
  50. const notificationStore = useNotificationStore()
  51. const currentFilter = ref('all')
  52. const filterTabs = [
  53. { label: '全部', value: 'all' },
  54. { label: '任务消息', value: 'task' },
  55. { label: '系统消息', value: 'system' },
  56. ]
  57. const filteredMessages = computed(() => {
  58. let list = notificationStore.notifications
  59. if (currentFilter.value !== 'all') {
  60. list = list.filter(n => n.type === currentFilter.value)
  61. }
  62. return list.map(n => ({
  63. ...n,
  64. content: n.content.length > 60 ? n.content.slice(0, 60) + '...' : n.content
  65. }))
  66. })
  67. function markAllRead() {
  68. notificationStore.markAllAsRead()
  69. }
  70. function goToDetail(msg: typeof filteredMessages.value[0]) {
  71. notificationStore.markAsRead(msg.id)
  72. uni.setStorageSync('current_message', msg)
  73. navigateTo('/subPackages/pages-common/messageDetail')
  74. }
  75. </script>
  76. <style scoped>
  77. .notice-item {
  78. background: white;
  79. padding: 16px;
  80. border-bottom: 1px solid #f0f0f0;
  81. }
  82. .notice-item:active {
  83. background: #f9fafb;
  84. }
  85. .line-clamp-2 {
  86. display: -webkit-box;
  87. -webkit-line-clamp: 2;
  88. -webkit-box-orient: vertical;
  89. overflow: hidden;
  90. }
  91. </style>