121 lines
4.3 KiB
JavaScript
121 lines
4.3 KiB
JavaScript
import {
|
|
getNotificationsApi, getUnreadCountApi,
|
|
markAsReadApi, markAllAsReadApi,
|
|
deleteNotificationApi, clearNotificationsApi,
|
|
} from '@/utils/api.js'
|
|
|
|
// 站内邮箱 4 类分组 (V1.2.10 排除 like/system)
|
|
export const GROUPS = [
|
|
{ type: 'activity', label: '活动通知' },
|
|
{ type: 'feedback_replied', label: '反馈回复' },
|
|
{ type: 'report_resolved', label: '举报结果' },
|
|
{ type: 'target_reported', label: '被举报' },
|
|
// ⚠️ like / system 不进 V1.2.10 (用户已确认保留旧 push 体验)
|
|
]
|
|
|
|
const state = () => ({
|
|
itemsByType: GROUPS.reduce((acc, g) => { acc[g.type] = []; return acc }, {}),
|
|
unreadByType: GROUPS.reduce((acc, g) => { acc[g.type] = 0; return acc },
|
|
{ like: 0, system: 0 }), // 仍接收所有 type 用于聚合,只不进 INBOX
|
|
totalUnread: 0,
|
|
detailCache: null,
|
|
isInMailboxPage: false,
|
|
loading: false,
|
|
noMoreByType: GROUPS.reduce((acc, g) => { acc[g.type] = true; return acc }, {}),
|
|
})
|
|
|
|
const getters = {
|
|
// profile.vue 📬 badge 显示值 (V1.2.10: 排除 like/system)
|
|
inboxUnreadOnly: (state) => {
|
|
return GROUPS.reduce((sum, g) => sum + (state.unreadByType[g.type] || 0), 0)
|
|
},
|
|
}
|
|
|
|
const mutations = {
|
|
SET_ITEMS(state, { type, items, sortUnreadFirst = true }) {
|
|
const sorted = sortUnreadFirst
|
|
? [...items].sort((a, b) =>
|
|
(a.is_read === b.is_read) ? (b.created_at - a.created_at) : (a.is_read ? 1 : -1)
|
|
)
|
|
: items
|
|
state.itemsByType[type] = sorted
|
|
},
|
|
APPEND_ITEMS(state, { type, items }) {
|
|
state.itemsByType[type].push(...items)
|
|
},
|
|
UPDATE_ITEM(state, { type, id, patch }) {
|
|
const arr = state.itemsByType[type]
|
|
const i = arr.findIndex(n => n.id === id)
|
|
if (i >= 0) arr[i] = { ...arr[i], ...patch }
|
|
},
|
|
REMOVE_ITEM(state, { type, id }) {
|
|
state.itemsByType[type] = state.itemsByType[type].filter(n => n.id !== id)
|
|
},
|
|
RESORT_ITEMS(state, type) {
|
|
state.itemsByType[type].sort((a, b) =>
|
|
(a.is_read === b.is_read) ? (b.created_at - a.created_at) : (a.is_read ? 1 : -1)
|
|
)
|
|
},
|
|
SET_NO_MORE(state, { type, value }) {
|
|
state.noMoreByType[type] = value
|
|
},
|
|
DECREMENT_TYPE(state, type) {
|
|
state.unreadByType[type] = Math.max(0, (state.unreadByType[type] || 0) - 1)
|
|
},
|
|
REPLACE_UNREAD_BY_TYPE(state, byType) {
|
|
state.unreadByType = { ...state.unreadByType, ...byType }
|
|
},
|
|
SET_TOTAL_UNREAD(state, n) { state.totalUnread = n },
|
|
MARK_ALL_READ(state) {
|
|
state.unreadByType = GROUPS.reduce((acc, g) => { acc[g.type] = 0; return acc },
|
|
{ ...state.unreadByType })
|
|
Object.keys(state.itemsByType).forEach(t => {
|
|
state.itemsByType[t] = state.itemsByType[t].map(n => ({ ...n, is_read: true }))
|
|
})
|
|
},
|
|
CLEAR_ALL(state) {
|
|
GROUPS.forEach(g => { state.itemsByType[g.type] = [] })
|
|
GROUPS.forEach(g => { state.unreadByType[g.type] = 0 })
|
|
},
|
|
SET_DETAIL_CACHE(state, item) { state.detailCache = item },
|
|
SET_LOADING(state, v) { state.loading = v },
|
|
SET_IS_IN_PAGE(state, v) { state.isInMailboxPage = v },
|
|
PREPEND_ITEM(state, { type, notification }) {
|
|
// V1.2.6 幂等:防重复
|
|
const list = state.itemsByType[type] || []
|
|
if (list.some(n => n.id === notification.id)) return
|
|
list.unshift(notification)
|
|
list.sort((a, b) =>
|
|
(a.is_read === b.is_read) ? (b.created_at - a.created_at) : (a.is_read ? 1 : -1)
|
|
)
|
|
state.itemsByType[type] = list
|
|
},
|
|
}
|
|
|
|
const actions = {
|
|
// App.vue receive 事件后调用,只更新未读 + 可选 PREPEND_ITEM
|
|
applyPushPayload({ commit, rootState }, { data, title = '', content = '' }) {
|
|
if (!data || !data.unreads_by_type) return
|
|
commit('REPLACE_UNREAD_BY_TYPE', data.unreads_by_type)
|
|
commit('SET_TOTAL_UNREAD', data.total_unread || 0)
|
|
if (rootState.mailbox.isInMailboxPage && data.notification_id && data.type) {
|
|
commit('PREPEND_ITEM', {
|
|
type: data.type,
|
|
notification: {
|
|
id: data.notification_id,
|
|
title, content,
|
|
data: JSON.stringify(data),
|
|
is_read: false,
|
|
created_at: Date.now(),
|
|
},
|
|
})
|
|
}
|
|
},
|
|
async alignFromServerUnread({ commit }) {
|
|
const resp = await getUnreadCountApi()
|
|
commit('REPLACE_UNREAD_BY_TYPE', resp.data)
|
|
},
|
|
}
|
|
|
|
export default { namespaced: true, state, getters, mutations, actions }
|