// pages/message/message.js const app = getApp() const { graphqlRequest, formatDate, formatRelativeTime } = require('../../lib/utils') Page({ data: { loading: false, refreshing: false, loadingMore: false, hasMore: true, // 消息列表 messages: [], // 分页参数 pagination: { page: 1, limit: 20, total: 0 }, // 筛选条件 filter: { type: 'ALL', // ALL, SYSTEM, ACTIVITY, JUDGE, ORGANIZER status: 'ALL' // ALL, READ, UNREAD }, // 筛选选项 typeOptions: [ { value: 'ALL', label: '全部消息' }, { value: 'SYSTEM', label: '系统通知' }, { value: 'ACTIVITY', label: '活动消息' }, { value: 'JUDGE', label: '评审消息' }, { value: 'ORGANIZER', label: '主办方消息' } ], statusOptions: [ { value: 'ALL', label: '全部状态' }, { value: 'UNREAD', label: '未读' }, { value: 'READ', label: '已读' } ], // 显示筛选面板 showFilter: false, // 统计数据 stats: { total: 0, unread: 0 }, // 选择模式 selectMode: false, selectedMessages: [], // 消息类型图标映射 typeIcons: { 'SYSTEM': '🔔', 'ACTIVITY': '🎯', 'JUDGE': '⚖️', 'ORGANIZER': '👥', 'REGISTRATION': '📝', 'RESULT': '🏆', 'REMINDER': '⏰' } }, onLoad() { this.loadMessages() this.loadMessageStats() }, onShow() { // 页面显示时刷新未读数量 this.loadMessageStats() // 初始化自定义 tabbar if (typeof this.getTabBar === 'function' && this.getTabBar()) { this.getTabBar().init() } }, onPullDownRefresh() { this.refreshMessages() }, onReachBottom() { if (this.data.hasMore && !this.data.loadingMore) { this.loadMoreMessages() } }, // 加载消息列表 async loadMessages(reset = true) { try { if (reset) { this.setData({ loading: true, pagination: { ...this.data.pagination, page: 1 } }) } const { filter, pagination } = this.data const query = ` query GetMessages($input: MessageQueryInput!) { messages(input: $input) { items { id type title content isRead createdAt data relatedActivity { id title } } pagination { total page limit hasMore } } } ` const input = { type: filter.type === 'ALL' ? null : filter.type, status: filter.status === 'ALL' ? null : filter.status, page: pagination.page, limit: pagination.limit } const result = await graphqlRequest(query, { input }) if (result && result.messages) { const { items, pagination: newPagination } = result.messages // 为每个消息添加选中状态 const processedItems = items.map(item => ({ ...item, isSelected: this.data.selectedMessages.indexOf(item.id) > -1 })) this.setData({ messages: reset ? processedItems : [...this.data.messages, ...processedItems], pagination: newPagination, hasMore: newPagination.hasMore }) } } catch (error) { console.error('加载消息失败:', error) wx.showToast({ title: '加载失败', icon: 'error' }) } finally { this.setData({ loading: false, refreshing: false, loadingMore: false }) wx.stopPullDownRefresh() } }, // 刷新消息 async refreshMessages() { this.setData({ refreshing: true }) await this.loadMessages(true) await this.loadMessageStats() }, // 加载更多消息 async loadMoreMessages() { if (!this.data.hasMore || this.data.loadingMore) return this.setData({ loadingMore: true, pagination: { ...this.data.pagination, page: this.data.pagination.page + 1 } }) await this.loadMessages(false) }, // 加载消息统计 async loadMessageStats() { try { const query = ` query GetMessageStats { messageStats { total unread } } ` const result = await graphqlRequest(query) if (result && result.messageStats) { this.setData({ stats: result.messageStats }) // 更新底部导航栏的未读数量 if (typeof this.getTabBar === 'function' && this.getTabBar()) { this.getTabBar().setData({ unreadCount: result.messageStats.unread }) } } } catch (error) { console.error('加载消息统计失败:', error) } }, // 消息点击 async onMessageTap(e) { const { id, index } = e.currentTarget.dataset const message = this.data.messages[index] // 如果是选择模式,切换选择状态 if (this.data.selectMode) { this.toggleMessageSelection(id) return } // 标记为已读 if (!message.isRead) { await this.markAsRead(id, index) } // 根据消息类型处理跳转 this.handleMessageAction(message) }, // 处理消息动作 handleMessageAction(message) { const { type, data, relatedActivity } = message switch (type) { case 'ACTIVITY': if (relatedActivity && relatedActivity.id) { wx.navigateTo({ url: `/pages/activity/detail?id=${relatedActivity.id}` }) } break case 'REGISTRATION': if (data && data.registrationId) { wx.navigateTo({ url: `/pages/profile/registration-detail?id=${data.registrationId}` }) } break case 'JUDGE': if (data && data.submissionId) { wx.navigateTo({ url: `/pages/judge/review?id=${data.submissionId}` }) } break case 'ORGANIZER': if (relatedActivity && relatedActivity.id) { wx.navigateTo({ url: `/pages/organizer/activity-detail?id=${relatedActivity.id}` }) } break default: // 显示消息详情 this.showMessageDetail(message) break } }, // 显示消息详情 showMessageDetail(message) { wx.showModal({ title: message.title, content: message.content, showCancel: false, confirmText: '知道了' }) }, // 标记为已读 async markAsRead(messageId, index) { try { const mutation = ` mutation MarkMessageAsRead($id: ID!) { markMessageAsRead(id: $id) { success } } ` const result = await graphqlRequest(mutation, { id: messageId }) if (result && result.markMessageAsRead.success) { // 更新本地数据 const messages = [...this.data.messages] messages[index].isRead = true this.setData({ messages }) // 更新统计数据 this.setData({ 'stats.unread': Math.max(0, this.data.stats.unread - 1) }) } } catch (error) { console.error('标记已读失败:', error) } }, // 批量标记为已读 async markAllAsRead() { try { wx.showLoading({ title: '处理中...' }) const mutation = ` mutation MarkAllMessagesAsRead { markAllMessagesAsRead { success count } } ` const result = await graphqlRequest(mutation) if (result && result.markAllMessagesAsRead.success) { // 刷新消息列表 await this.refreshMessages() wx.showToast({ title: '已全部标记为已读', icon: 'success' }) } } catch (error) { console.error('批量标记已读失败:', error) wx.showToast({ title: '操作失败', icon: 'error' }) } finally { wx.hideLoading() } }, // 删除消息 async deleteMessage(messageId) { try { const mutation = ` mutation DeleteMessage($id: ID!) { deleteMessage(id: $id) { success } } ` const result = await graphqlRequest(mutation, { id: messageId }) if (result && result.deleteMessage.success) { // 从列表中移除 const messages = this.data.messages.filter(msg => msg.id !== messageId) this.setData({ messages }) wx.showToast({ title: '删除成功', icon: 'success' }) } } catch (error) { console.error('删除消息失败:', error) wx.showToast({ title: '删除失败', icon: 'error' }) } }, // 长按消息 onMessageLongPress(e) { const { id } = e.currentTarget.dataset wx.showActionSheet({ itemList: ['标记为已读', '删除消息'], success: (res) => { switch (res.tapIndex) { case 0: this.markAsRead(id) break case 1: wx.showModal({ title: '确认删除', content: '确定要删除这条消息吗?', success: (modalRes) => { if (modalRes.confirm) { this.deleteMessage(id) } } }) break } } }) }, // 切换筛选面板 onToggleFilter() { this.setData({ showFilter: !this.data.showFilter }) }, // 筛选条件改变 onFilterChange(e) { const { type, value } = e.currentTarget.dataset this.setData({ [`filter.${type}`]: value, showFilter: false }) // 重新加载消息 this.loadMessages(true) }, // 切换选择模式 onToggleSelectMode() { this.setData({ selectMode: !this.data.selectMode, selectedMessages: [] }) }, // 切换消息选择状态 toggleMessageSelection(messageId) { const selectedMessages = [...this.data.selectedMessages] const index = selectedMessages.indexOf(messageId) if (index > -1) { selectedMessages.splice(index, 1) } else { selectedMessages.push(messageId) } // 同时更新消息的isSelected字段 const messages = this.data.messages.map(msg => ({ ...msg, isSelected: selectedMessages.indexOf(msg.id) > -1 })) this.setData({ selectedMessages, messages }) }, // 全选/取消全选 onToggleSelectAll() { const { messages, selectedMessages } = this.data const allSelected = selectedMessages.length === messages.length const newSelectedMessages = allSelected ? [] : messages.map(msg => msg.id) // 同时更新消息的isSelected字段 const updatedMessages = messages.map(msg => ({ ...msg, isSelected: !allSelected })) this.setData({ selectedMessages: newSelectedMessages, messages: updatedMessages }) }, // 批量删除选中消息 async onDeleteSelected() { const { selectedMessages } = this.data if (selectedMessages.length === 0) { wx.showToast({ title: '请选择要删除的消息', icon: 'error' }) return } wx.showModal({ title: '确认删除', content: `确定要删除选中的 ${selectedMessages.length} 条消息吗?`, success: async (res) => { if (res.confirm) { try { wx.showLoading({ title: '删除中...' }) const mutation = ` mutation DeleteMessages($ids: [ID!]!) { deleteMessages(ids: $ids) { success count } } ` const result = await graphqlRequest(mutation, { ids: selectedMessages }) if (result && result.deleteMessages.success) { // 刷新消息列表 await this.refreshMessages() this.setData({ selectMode: false, selectedMessages: [] }) wx.showToast({ title: `已删除 ${result.deleteMessages.count} 条消息`, icon: 'success' }) } } catch (error) { console.error('批量删除失败:', error) wx.showToast({ title: '删除失败', icon: 'error' }) } finally { wx.hideLoading() } } } }) }, // 获取消息类型图标 getTypeIcon(type) { return this.data.typeIcons[type] || '📨' }, // 获取消息类型文本 getTypeText(type) { const typeMap = { 'SYSTEM': '系统通知', 'ACTIVITY': '活动消息', 'JUDGE': '评审消息', 'ORGANIZER': '主办方消息', 'REGISTRATION': '报名消息', 'RESULT': '结果通知', 'REMINDER': '提醒消息' } return typeMap[type] || '消息' }, // 格式化时间 formatTime(dateString) { const now = new Date() const date = new Date(dateString) const diff = now.getTime() - date.getTime() // 一天内显示相对时间 if (diff < 24 * 60 * 60 * 1000) { return formatRelativeTime(dateString) } // 超过一天显示具体日期 return formatDate(dateString, 'MM-DD HH:mm') }, // 分享页面 onShareAppMessage() { return { title: '蓉易创 - 消息中心', path: '/pages/index/index' } } })