/** * 顶栏长连接通知:共享状态 + 只绑定一次 appWs:notice * 多页各挂 AppTopPushNotice 时,仅「页面栈顶」的实例展示(用 $root 与栈顶 $vm 比较) */ import Vue from 'vue' import { parseAppWsNoticeDisplay, formatNoticeTimeForBanner } from '@/common/utils/parseAppWsNotice.js' const HIDE_MS = 3000 function _fingerprint(item) { if (item && item.id) return 'id:' + item.id return 't:' + (item.time || '') + '|' + (item.text || '') } function _createState() { // 非 H5/非 Vue2 时降级为普通对象 if (typeof Vue !== 'undefined' && Vue.observable) { return Vue.observable({ visible: false, enterActive: false, displayTime: '', displayText: '', displayPicture: '', gnpLastKey: '', gnpLastKeyAt: 0, gnpNoticeSeen: {}, gnpHideTimer: null, }) } return { visible: false, enterActive: false, displayTime: '', displayText: '', displayPicture: '', gnpLastKey: '', gnpLastKeyAt: 0, gnpNoticeSeen: {}, gnpHideTimer: null, } } export const noticeTopState = _createState() let _bound = false function _onMsg(msg) { const item = parseAppWsNoticeDisplay(msg) if (!item || !String(item.text).trim()) return const key = _fingerprint(item) const now = Date.now() if (key === noticeTopState.gnpLastKey && now - (noticeTopState.gnpLastKeyAt || 0) < 2000) return if (item.id && noticeTopState.gnpNoticeSeen[item.id]) return if (item.id) { noticeTopState.gnpNoticeSeen = { ...noticeTopState.gnpNoticeSeen, [item.id]: 1 } } noticeTopState.gnpLastKey = key noticeTopState.gnpLastKeyAt = now noticeTopState.displayTime = formatNoticeTimeForBanner(item.time) || '—' noticeTopState.displayText = item.text noticeTopState.displayPicture = item.picture || '' if (noticeTopState.gnpHideTimer) { clearTimeout(noticeTopState.gnpHideTimer) noticeTopState.gnpHideTimer = null } noticeTopState.visible = true noticeTopState.enterActive = false // 与 index 内联版一致,下一帧后触发入场动画 setTimeout(() => { noticeTopState.enterActive = true }, 30) noticeTopState.gnpHideTimer = setTimeout(() => { hideTopNotice() }, HIDE_MS) } export function hideTopNotice() { if (noticeTopState.gnpHideTimer) { clearTimeout(noticeTopState.gnpHideTimer) noticeTopState.gnpHideTimer = null } noticeTopState.enterActive = false setTimeout(() => { noticeTopState.visible = false noticeTopState.displayPicture = '' }, 220) } /** 在 App onLaunch 或首屏调用一次 */ export function bindAppWsTopNoticeListenerOnce() { if (_bound) return _bound = true uni.$off('appWs:notice', _onMsg) uni.$on('appWs:notice', _onMsg) }