95 lines
2.6 KiB
JavaScript
95 lines
2.6 KiB
JavaScript
/**
|
|
* 顶栏长连接通知:共享状态 + 只绑定一次 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)
|
|
}
|