|
|
@@ -0,0 +1,688 @@
|
|
|
+<template>
|
|
|
+ <view class="container">
|
|
|
+ <!-- 顶部导航栏 -->
|
|
|
+ <view class="nav-bar">
|
|
|
+ <view class="nav-back" @click="goBack">
|
|
|
+ <text class="nav-back-icon">←</text>
|
|
|
+ </view>
|
|
|
+ <text class="nav-title">消息历史</text>
|
|
|
+ <view class="nav-placeholder"></view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 筛选标签 -->
|
|
|
+ <view class="filter-tabs">
|
|
|
+ <view
|
|
|
+ class="filter-tab"
|
|
|
+ :class="{ active: activeFilter === 'all' }"
|
|
|
+ @click="switchFilter('all')">
|
|
|
+ <text>全部</text>
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ class="filter-tab"
|
|
|
+ :class="{ active: activeFilter === 'energy' }"
|
|
|
+ @click="switchFilter('energy')">
|
|
|
+ <text>能量</text>
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ class="filter-tab"
|
|
|
+ :class="{ active: activeFilter === 'points' }"
|
|
|
+ @click="switchFilter('points')">
|
|
|
+ <text>积分</text>
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ class="filter-tab"
|
|
|
+ :class="{ active: activeFilter === 'cf' }"
|
|
|
+ @click="switchFilter('cf')">
|
|
|
+ <text>CF值</text>
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ class="filter-tab"
|
|
|
+ :class="{ active: activeFilter === 'system' }"
|
|
|
+ @click="switchFilter('system')">
|
|
|
+ <text>系统</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 消息列表 -->
|
|
|
+ <scroll-view
|
|
|
+ class="message-list"
|
|
|
+ scroll-y
|
|
|
+ @scrolltolower="loadMore">
|
|
|
+ <view v-if="loading && messages.length === 0" class="loading-state">
|
|
|
+ <text>加载中...</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view v-else-if="messages.length === 0" class="empty-state">
|
|
|
+ <text class="empty-icon">📭</text>
|
|
|
+ <text class="empty-text">暂无消息</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <template v-else>
|
|
|
+ <!-- 能量变更消息 -->
|
|
|
+ <view
|
|
|
+ v-for="(msg, index) in energyMessages"
|
|
|
+ :key="msg.id"
|
|
|
+ class="message-item"
|
|
|
+ :class="{ unread: !msg.isRead }"
|
|
|
+ @click="markAsRead(msg)">
|
|
|
+ <view class="message-icon" :style="{ background: 'rgba(249,115,22,0.15)' }">
|
|
|
+ <text>⚡</text>
|
|
|
+ </view>
|
|
|
+ <view class="message-content">
|
|
|
+ <text class="message-title">{{ msg.fullText || msg.description }}</text>
|
|
|
+ <text v-if="msg.amount !== 0" class="message-amount" :style="{ color: msg.amount >= 0 ? '#10B981' : '#EF4444' }">
|
|
|
+ {{ msg.amount >= 0 ? '+' : '' }}{{ msg.amount }}
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <view class="message-meta">
|
|
|
+ <text class="message-time">{{ msg.time }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 积分变更消息 -->
|
|
|
+ <view
|
|
|
+ v-for="(msg, index) in pointsMessages"
|
|
|
+ :key="msg.id"
|
|
|
+ class="message-item"
|
|
|
+ :class="{ unread: !msg.isRead }"
|
|
|
+ @click="markAsRead(msg)">
|
|
|
+ <view class="message-icon" :style="{ background: 'rgba(16,185,129,0.15)' }">
|
|
|
+ <text>🪙</text>
|
|
|
+ </view>
|
|
|
+ <view class="message-content">
|
|
|
+ <text class="message-title">{{ msg.fullText || msg.description }}</text>
|
|
|
+ <text v-if="msg.amount !== 0" class="message-amount" :style="{ color: msg.amount >= 0 ? '#10B981' : '#EF4444' }">
|
|
|
+ {{ msg.amount >= 0 ? '+' : '' }}{{ msg.amount }}
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <view class="message-meta">
|
|
|
+ <text class="message-time">{{ msg.time }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- CF值变更消息 -->
|
|
|
+ <view
|
|
|
+ v-for="(msg, index) in cfMessages"
|
|
|
+ :key="msg.id"
|
|
|
+ class="message-item"
|
|
|
+ :class="{ unread: !msg.isRead }"
|
|
|
+ @click="markAsRead(msg)">
|
|
|
+ <view class="message-icon" :style="{ background: 'rgba(99,102,241,0.15)' }">
|
|
|
+ <text>💰</text>
|
|
|
+ </view>
|
|
|
+ <view class="message-content">
|
|
|
+ <text class="message-title">{{ msg.fullText || msg.description }}</text>
|
|
|
+ <text v-if="msg.amount !== 0" class="message-amount" :style="{ color: msg.amount >= 0 ? '#10B981' : '#EF4444' }">
|
|
|
+ {{ msg.amount >= 0 ? '+' : '' }}{{ msg.amount }}
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <view class="message-meta">
|
|
|
+ <text class="message-time">{{ msg.time }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 系统通知 -->
|
|
|
+ <view
|
|
|
+ v-for="(msg, index) in systemMessages"
|
|
|
+ :key="msg.id"
|
|
|
+ class="message-item"
|
|
|
+ :class="{ unread: !msg.isRead }"
|
|
|
+ @click="markAsRead(msg)">
|
|
|
+ <view class="message-icon" :style="{ background: 'rgba(100,116,139,0.15)' }">
|
|
|
+ <text>📢</text>
|
|
|
+ </view>
|
|
|
+ <view class="message-content">
|
|
|
+ <text class="message-title">{{ msg.title }}</text>
|
|
|
+ <text class="message-desc">{{ msg.description }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="message-meta">
|
|
|
+ <text class="message-time">{{ msg.time }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 加载更多 -->
|
|
|
+ <view v-if="loadingMore" class="loading-more">
|
|
|
+ <text>加载中...</text>
|
|
|
+ </view>
|
|
|
+ <view v-else-if="!hasMore && messages.length > 0" class="no-more">
|
|
|
+ <text>没有更多了</text>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+ </scroll-view>
|
|
|
+
|
|
|
+ <!-- 底部操作 -->
|
|
|
+ <view class="bottom-actions">
|
|
|
+ <button class="btn-clear-all" @click="clearAllMessages">
|
|
|
+ 清除所有消息
|
|
|
+ </button>
|
|
|
+ <button class="btn-mark-read" @click="markAllAsRead">
|
|
|
+ 全部已读
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import {
|
|
|
+ getEnergyLogs,
|
|
|
+ getPointsLogs,
|
|
|
+ getCfList,
|
|
|
+ getNotificationList,
|
|
|
+ readNotification
|
|
|
+} from '../../utils/api.js'
|
|
|
+import { parseDate } from '../../utils/format.js'
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'MessageHistory',
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ activeFilter: 'all',
|
|
|
+ loading: true,
|
|
|
+ loadingMore: false,
|
|
|
+ hasMore: true,
|
|
|
+ currentPage: 1,
|
|
|
+ pageSize: 20,
|
|
|
+
|
|
|
+ // 各类消息
|
|
|
+ energyMessages: [],
|
|
|
+ pointsMessages: [],
|
|
|
+ cfMessages: [],
|
|
|
+ systemMessages: [],
|
|
|
+
|
|
|
+ // 用于分页
|
|
|
+ energyPage: 1,
|
|
|
+ pointsPage: 1,
|
|
|
+ cfPage: 1,
|
|
|
+ notificationPage: 1,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ messages() {
|
|
|
+ // 根据当前筛选返回对应消息
|
|
|
+ switch(this.activeFilter) {
|
|
|
+ case 'energy': return this.energyMessages
|
|
|
+ case 'points': return this.pointsMessages
|
|
|
+ case 'cf': return this.cfMessages
|
|
|
+ case 'system': return this.systemMessages
|
|
|
+ default:
|
|
|
+ // 合并所有消息并按时间排序
|
|
|
+ var all = [
|
|
|
+ ...this.energyMessages.map(m => ({...m, type: 'energy'})),
|
|
|
+ ...this.pointsMessages.map(m => ({...m, type: 'points'})),
|
|
|
+ ...this.cfMessages.map(m => ({...m, type: 'cf'})),
|
|
|
+ ...this.systemMessages.map(m => ({...m, type: 'system'}))
|
|
|
+ ]
|
|
|
+ return all.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onLoad() {
|
|
|
+ this.loadAllMessages()
|
|
|
+ },
|
|
|
+ onShow() {
|
|
|
+ // 每次显示时刷新未读数
|
|
|
+ this.refreshUnreadCounts()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ goBack() {
|
|
|
+ uni.navigateBack()
|
|
|
+ },
|
|
|
+
|
|
|
+ switchFilter(filter) {
|
|
|
+ this.activeFilter = filter
|
|
|
+ // 如果还没加载过该类型消息,则加载
|
|
|
+ if (filter === 'energy' && this.energyMessages.length === 0) {
|
|
|
+ this.loadEnergyMessages()
|
|
|
+ } else if (filter === 'points' && this.pointsMessages.length === 0) {
|
|
|
+ this.loadPointsMessages()
|
|
|
+ } else if (filter === 'cf' && this.cfMessages.length === 0) {
|
|
|
+ this.loadCfMessages()
|
|
|
+ } else if (filter === 'system' && this.systemMessages.length === 0) {
|
|
|
+ this.loadSystemMessages()
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ async loadAllMessages() {
|
|
|
+ this.loading = true
|
|
|
+ try {
|
|
|
+ await Promise.all([
|
|
|
+ this.loadEnergyMessages(),
|
|
|
+ this.loadPointsMessages(),
|
|
|
+ this.loadCfMessages(),
|
|
|
+ this.loadSystemMessages()
|
|
|
+ ])
|
|
|
+ } finally {
|
|
|
+ this.loading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ async loadEnergyMessages() {
|
|
|
+ var memberId = uni.getStorageSync('currentMemberId') || this.currentChildId
|
|
|
+ if (!memberId) return
|
|
|
+
|
|
|
+ var res = await getEnergyLogs(memberId, null, this.energyPage, this.pageSize)
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
+ var records = res.data.records || []
|
|
|
+ this.energyMessages = records.map(record => this.formatEnergyMessage(record))
|
|
|
+ this.energyPage++
|
|
|
+ this.hasMore = records.length === this.pageSize
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ async loadPointsMessages() {
|
|
|
+ var memberId = uni.getStorageSync('currentMemberId') || this.currentChildId
|
|
|
+ if (!memberId) return
|
|
|
+
|
|
|
+ var res = await getPointsLogs(memberId, this.pointsPage, this.pageSize)
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
+ var records = res.data.records || []
|
|
|
+ this.pointsMessages = records.map(record => this.formatPointsMessage(record))
|
|
|
+ this.pointsPage++
|
|
|
+ this.hasMore = records.length === this.pageSize
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ async loadCfMessages() {
|
|
|
+ var res = await getCfList(this.cfPage, this.pageSize)
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
+ var records = res.data.records || []
|
|
|
+ this.cfMessages = records.map(record => this.formatCfMessage(record))
|
|
|
+ this.cfPage++
|
|
|
+ this.hasMore = records.length === this.pageSize
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ async loadSystemMessages() {
|
|
|
+ var res = await getNotificationList()
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
+ var records = res.data || []
|
|
|
+ this.systemMessages = records.map(record => this.formatSystemMessage(record))
|
|
|
+ this.notificationPage++
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ formatEnergyMessage(record) {
|
|
|
+ var desc = record.description || ''
|
|
|
+ var sourceType = record.sourceType || ''
|
|
|
+
|
|
|
+ var contentText = ''
|
|
|
+ switch(sourceType) {
|
|
|
+ case 'task': contentText = '完成了' + (desc || '任务'); break
|
|
|
+ case 'product': contentText = '购买了' + (desc || '商品'); break
|
|
|
+ case 'medical_report': contentText = '上传了' + (desc || '体检报告'); break
|
|
|
+ case 'daily_record': contentText = '完成了' + (desc || '日常记录'); break
|
|
|
+ default: contentText = desc || '能量变动'
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ id: 'energy-' + record.id,
|
|
|
+ type: 'energy',
|
|
|
+ title: '能量变动',
|
|
|
+ fullText: '⚡ ' + contentText,
|
|
|
+ description: contentText,
|
|
|
+ amount: record.amount,
|
|
|
+ isRead: true,
|
|
|
+ createdAt: record.createdAt,
|
|
|
+ time: this.formatTime(record.createdAt)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ formatPointsMessage(record) {
|
|
|
+ var desc = record.description || ''
|
|
|
+ var type = record.type || ''
|
|
|
+
|
|
|
+ var contentText = ''
|
|
|
+ switch(type) {
|
|
|
+ case 'task':
|
|
|
+ contentText = '完成了' + (desc || '任务') + '获得' + (record.amount >= 0 ? '+' : '') + record.amount + '积分'; break
|
|
|
+ case 'reward':
|
|
|
+ contentText = '完成了' + (desc || '心愿兑换') + '获得' + (record.amount >= 0 ? '+' : '') + record.amount + '积分'; break
|
|
|
+ case 'adjust':
|
|
|
+ contentText = '管理员调整' + (record.amount >= 0 ? '+' : '') + record.amount + '积分'; break
|
|
|
+ case 'expire':
|
|
|
+ contentText = '积分过期扣除' + Math.abs(record.amount) + '积分'; break
|
|
|
+ default:
|
|
|
+ contentText = (desc || '积分变动') + (record.amount >= 0 ? '获得' : '扣除') + Math.abs(record.amount) + '积分'
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ id: 'points-' + record.id,
|
|
|
+ type: 'points',
|
|
|
+ fullText: '🪙 ' + contentText,
|
|
|
+ description: contentText,
|
|
|
+ amount: record.amount,
|
|
|
+ isRead: true,
|
|
|
+ createdAt: record.createdAt,
|
|
|
+ time: this.formatTime(record.createdAt)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ formatCfMessage(record) {
|
|
|
+ var desc = record.description || ''
|
|
|
+ var action = record.action || ''
|
|
|
+
|
|
|
+ var contentText = ''
|
|
|
+ switch(action) {
|
|
|
+ case 'transfer_send': contentText = 'CF值转出' + Math.abs(record.amount) + 'CF'; break
|
|
|
+ case 'transfer_receive': contentText = 'CF值转入' + record.amount + 'CF'; break
|
|
|
+ case 'commission': contentText = '获得' + record.amount + 'CF分佣'; break
|
|
|
+ default: contentText = (desc || 'CF值变动') + (record.amount >= 0 ? '+' : '') + record.amount + 'CF'
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ id: 'cf-' + record.id,
|
|
|
+ type: 'cf',
|
|
|
+ fullText: '💰 ' + contentText,
|
|
|
+ description: contentText,
|
|
|
+ amount: record.amount,
|
|
|
+ isRead: true,
|
|
|
+ createdAt: record.createdAt,
|
|
|
+ time: this.formatTime(record.createdAt)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ formatSystemMessage(record) {
|
|
|
+ return {
|
|
|
+ id: 'system-' + record.id,
|
|
|
+ type: 'system',
|
|
|
+ title: record.title || '系统通知',
|
|
|
+ description: record.content || '',
|
|
|
+ amount: 0,
|
|
|
+ isRead: record.isRead === 1,
|
|
|
+ createdAt: record.createdAt,
|
|
|
+ time: this.formatTime(record.createdAt),
|
|
|
+ record: record
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ formatTime(dateStr) {
|
|
|
+ if (!dateStr) return ''
|
|
|
+ var d = parseDate(dateStr)
|
|
|
+ if (!d) return ''
|
|
|
+
|
|
|
+ var now = new Date()
|
|
|
+ var diff = now - d
|
|
|
+ var minutes = Math.floor(diff / 60000)
|
|
|
+
|
|
|
+ if (minutes < 1) return '刚刚'
|
|
|
+ if (minutes < 60) return minutes + '分钟前'
|
|
|
+
|
|
|
+ var hours = Math.floor(minutes / 60)
|
|
|
+ if (hours < 24) return hours + '小时前'
|
|
|
+
|
|
|
+ var days = Math.floor(hours / 24)
|
|
|
+ if (days === 1) return '昨天'
|
|
|
+ if (days < 7) return days + '天前'
|
|
|
+
|
|
|
+ return (d.getMonth() + 1) + '月' + d.getDate() + '日'
|
|
|
+ },
|
|
|
+
|
|
|
+ markAsRead(msg) {
|
|
|
+ msg.isRead = true
|
|
|
+ // 如果是系统通知,调用API标记为已读
|
|
|
+ if (msg.type === 'system' && msg.record && msg.record.id) {
|
|
|
+ readNotification({ id: msg.record.id }).catch(function() {})
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ markAllAsRead() {
|
|
|
+ // 标记所有消息为已读
|
|
|
+ this.energyMessages.forEach(m => m.isRead = true)
|
|
|
+ this.pointsMessages.forEach(m => m.isRead = true)
|
|
|
+ this.cfMessages.forEach(m => m.isRead = true)
|
|
|
+ this.systemMessages.forEach(m => m.isRead = true)
|
|
|
+
|
|
|
+ // 批量标记系统通知为已读
|
|
|
+ var unreadNotifications = this.systemMessages.filter(m => !m.isRead)
|
|
|
+ if (unreadNotifications.length > 0) {
|
|
|
+ readNotification({ ids: unreadNotifications.map(m => m.record.id) }).catch(function() {})
|
|
|
+ }
|
|
|
+
|
|
|
+ uni.showToast({ title: '已全部标为已读', icon: 'success' })
|
|
|
+ },
|
|
|
+
|
|
|
+ clearAllMessages() {
|
|
|
+ uni.showModal({
|
|
|
+ title: '清除消息',
|
|
|
+ content: '确定要清除所有历史消息吗?',
|
|
|
+ success: (res) => {
|
|
|
+ if (res.confirm) {
|
|
|
+ this.energyMessages = []
|
|
|
+ this.pointsMessages = []
|
|
|
+ this.cfMessages = []
|
|
|
+ this.systemMessages = []
|
|
|
+ this.currentPage = 1
|
|
|
+ this.energyPage = 1
|
|
|
+ this.pointsPage = 1
|
|
|
+ this.cfPage = 1
|
|
|
+ this.notificationPage = 1
|
|
|
+ uni.showToast({ title: '已清除', icon: 'success' })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ refreshUnreadCounts() {
|
|
|
+ // 刷新未读数(可选:从后端获取)
|
|
|
+ },
|
|
|
+
|
|
|
+ loadMore() {
|
|
|
+ if (!this.hasMore || this.loadingMore) return
|
|
|
+ this.loadingMore = true
|
|
|
+
|
|
|
+ var self = this
|
|
|
+ Promise.all([
|
|
|
+ this.energyPage < 10 ? this.loadEnergyMessages() : Promise.resolve(),
|
|
|
+ this.pointsPage < 10 ? this.loadPointsMessages() : Promise.resolve(),
|
|
|
+ this.cfPage < 10 ? this.loadCfMessages() : Promise.resolve(),
|
|
|
+ this.notificationPage < 10 ? this.loadSystemMessages() : Promise.resolve()
|
|
|
+ ]).finally(() => {
|
|
|
+ this.loadingMore = false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.container {
|
|
|
+ min-height: 100vh;
|
|
|
+ background: #f5f7fa;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-bar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 20rpx 30rpx;
|
|
|
+ background: #fff;
|
|
|
+ border-bottom: 1rpx solid #eee;
|
|
|
+ position: sticky;
|
|
|
+ top: 0;
|
|
|
+ z-index: 100;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-back {
|
|
|
+ width: 60rpx;
|
|
|
+ height: 60rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-back-icon {
|
|
|
+ font-size: 40rpx;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-title {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-placeholder {
|
|
|
+ width: 60rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.filter-tabs {
|
|
|
+ display: flex;
|
|
|
+ padding: 20rpx 30rpx;
|
|
|
+ background: #fff;
|
|
|
+ border-bottom: 1rpx solid #eee;
|
|
|
+ gap: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.filter-tab {
|
|
|
+ padding: 12rpx 24rpx;
|
|
|
+ background: #f5f5f5;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.filter-tab.active {
|
|
|
+ background: linear-gradient(135deg, #F97316, #FB923C);
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.message-list {
|
|
|
+ flex: 1;
|
|
|
+ padding: 20rpx 30rpx;
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.message-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ padding: 24rpx;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+ box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04);
|
|
|
+}
|
|
|
+
|
|
|
+.message-item.unread {
|
|
|
+ border: 2rpx solid #F97316;
|
|
|
+}
|
|
|
+
|
|
|
+.message-icon {
|
|
|
+ width: 64rpx;
|
|
|
+ height: 64rpx;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-right: 20rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.message-icon text {
|
|
|
+ font-size: 32rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.message-content {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.message-title {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+ display: block;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ -webkit-line-clamp: 1;
|
|
|
+ -webkit-box-orient: vertical;
|
|
|
+}
|
|
|
+
|
|
|
+.message-desc {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #999;
|
|
|
+ margin-top: 6rpx;
|
|
|
+ display: block;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ -webkit-line-clamp: 1;
|
|
|
+ -webkit-box-orient: vertical;
|
|
|
+}
|
|
|
+
|
|
|
+.message-amount {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ margin-top: 4rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.message-meta {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: flex-end;
|
|
|
+ gap: 8rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.message-time {
|
|
|
+ font-size: 20rpx;
|
|
|
+ color: #bbb;
|
|
|
+}
|
|
|
+
|
|
|
+.loading-state,
|
|
|
+.empty-state {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 100rpx 0;
|
|
|
+}
|
|
|
+
|
|
|
+.empty-icon {
|
|
|
+ font-size: 80rpx;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.empty-text {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+.loading-more,
|
|
|
+.no-more {
|
|
|
+ text-align: center;
|
|
|
+ padding: 30rpx 0;
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+.bottom-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 20rpx;
|
|
|
+ padding: 30rpx;
|
|
|
+ background: #fff;
|
|
|
+ border-top: 1rpx solid #eee;
|
|
|
+ position: sticky;
|
|
|
+ bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.btn-clear-all,
|
|
|
+.btn-mark-read {
|
|
|
+ flex: 1;
|
|
|
+ height: 80rpx;
|
|
|
+ line-height: 80rpx;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+
|
|
|
+.btn-clear-all {
|
|
|
+ background: #f5f5f5;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.btn-mark-read {
|
|
|
+ background: linear-gradient(135deg, #F97316, #FB923C);
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+</style>
|