203 lines
6.0 KiB
JavaScript
203 lines
6.0 KiB
JavaScript
import request from '../utils/request.js'
|
||
|
||
const STORAGE_RECORDS = 'popup_records'
|
||
const STORAGE_MUTE_TODAY = 'popup_mute_today'
|
||
|
||
class PopupService {
|
||
constructor() {
|
||
this.records = this.loadRecords()
|
||
this.muteToday = this.loadMuteToday()
|
||
this.currentPageKey = null
|
||
this.isShowing = false // 是否正在展示弹窗队列
|
||
this.isFetching = false // 是否正在请求弹窗数据
|
||
}
|
||
|
||
loadRecords() {
|
||
try {
|
||
return wx.getStorageSync(STORAGE_RECORDS) || {}
|
||
} catch (e) {
|
||
return {}
|
||
}
|
||
}
|
||
|
||
saveRecords() {
|
||
try {
|
||
wx.setStorageSync(STORAGE_RECORDS, this.records)
|
||
} catch (e) {}
|
||
}
|
||
|
||
loadMuteToday() {
|
||
try {
|
||
return wx.getStorageSync(STORAGE_MUTE_TODAY) || {}
|
||
} catch (e) {
|
||
return {}
|
||
}
|
||
}
|
||
|
||
saveMuteToday() {
|
||
try {
|
||
wx.setStorageSync(STORAGE_MUTE_TODAY, this.muteToday)
|
||
} catch (e) {}
|
||
}
|
||
|
||
isSamePeriod(date1, date2, interval) {
|
||
const d1 = new Date(date1)
|
||
const d2 = new Date(date2)
|
||
if (interval === 'day') {
|
||
return d1.toDateString() === d2.toDateString()
|
||
} else if (interval === 'week') {
|
||
const getWeek = (d) => {
|
||
const year = d.getFullYear()
|
||
const firstDay = new Date(year, 0, 1)
|
||
const week = Math.ceil((((d - firstDay) / 86400000) + firstDay.getDay() + 1) / 7)
|
||
return `${year}-${week}`
|
||
}
|
||
return getWeek(d1) === getWeek(d2)
|
||
} else if (interval === 'month') {
|
||
return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth()
|
||
} else if (interval === 'year') {
|
||
return d1.getFullYear() === d2.getFullYear()
|
||
}
|
||
return false
|
||
}
|
||
|
||
shouldShow(popup, pageKey, serverDate, pageIgnoreUserMute) {
|
||
const popupId = popup.popup_id
|
||
const strategy = popup.strategy
|
||
const force_even_muted = popup.force_even_muted || false
|
||
|
||
const todayStr = serverDate.split('T')[0]
|
||
const now = new Date(serverDate)
|
||
|
||
const skipMuteCheck = pageIgnoreUserMute || force_even_muted
|
||
if (!skipMuteCheck) {
|
||
const mutedDate = this.muteToday[pageKey]
|
||
if (mutedDate === todayStr) {
|
||
return false
|
||
}
|
||
}
|
||
|
||
const key = `${pageKey}_${popupId}`
|
||
const record = this.records[key]
|
||
const { type, maxCount = 1, resetInterval = 'day' } = strategy
|
||
|
||
if (type === 'once') return !record
|
||
if (type === 'always') return true
|
||
if (type === 'daily' || type === 'weekly' || type === 'monthly' || type === 'yearly') {
|
||
const interval = type
|
||
if (!record) return true
|
||
const lastTime = record.lastShowTime
|
||
if (!lastTime) return true
|
||
const same = this.isSamePeriod(lastTime, now, interval)
|
||
if (!same) return true
|
||
const currentCount = record.showCount || 1
|
||
return currentCount < maxCount
|
||
}
|
||
if (type === 'count') {
|
||
if (!record) return true
|
||
const lastTime = record.lastShowTime
|
||
if (!lastTime) return true
|
||
const same = this.isSamePeriod(lastTime, now, resetInterval)
|
||
if (!same) return true
|
||
const currentCount = record.showCount || 1
|
||
return currentCount < maxCount
|
||
}
|
||
return false
|
||
}
|
||
|
||
recordShow(popupId, pageKey, serverDate) {
|
||
const key = `${pageKey}_${popupId}`
|
||
const now = new Date(serverDate)
|
||
const record = this.records[key] || { showCount: 0, lastShowTime: 0, lastShowDate: '' }
|
||
record.showCount = (record.showCount || 0) + 1
|
||
record.lastShowTime = now.getTime()
|
||
record.lastShowDate = serverDate.split('T')[0]
|
||
this.records[key] = record
|
||
this.saveRecords()
|
||
}
|
||
|
||
setMuteToday(pageKey, serverDate) {
|
||
const todayStr = serverDate.split('T')[0]
|
||
this.muteToday[pageKey] = todayStr
|
||
this.saveMuteToday()
|
||
}
|
||
|
||
async checkAndShow(pageInstance, pageKey) {
|
||
if (this.isShowing || this.isFetching) return
|
||
|
||
this.isFetching = true
|
||
try {
|
||
const res = await request({
|
||
url: '/peizhi/tanchuang',
|
||
method: 'POST',
|
||
data: { pageKey }
|
||
})
|
||
if (res.statusCode !== 200 || res.data.code !== 0) return
|
||
const { serverTime, popups = [], ignore_user_mute = false } = res.data.data
|
||
if (!popups.length) return
|
||
|
||
const queue = []
|
||
for (const popup of popups) {
|
||
if (this.shouldShow(popup, pageKey, serverTime, ignore_user_mute)) {
|
||
queue.push(popup)
|
||
}
|
||
}
|
||
if (!queue.length) return
|
||
|
||
this.isShowing = true
|
||
this.currentPageKey = pageKey
|
||
await this.showQueue(pageInstance, queue, 0, serverTime, ignore_user_mute)
|
||
} catch (error) {
|
||
console.error('[弹窗] 服务错误:', error)
|
||
} finally {
|
||
this.isFetching = false
|
||
this.isShowing = false
|
||
}
|
||
}
|
||
|
||
showQueue(pageInstance, queue, index, serverTime, pageIgnoreUserMute) {
|
||
if (index >= queue.length) return Promise.resolve()
|
||
const popup = queue[index]
|
||
const isLast = index === queue.length - 1
|
||
|
||
const popupComp = pageInstance.selectComponent('#popupNotice')
|
||
if (!popupComp) {
|
||
console.error('[弹窗] 未找到组件 #popupNotice')
|
||
return Promise.resolve()
|
||
}
|
||
|
||
return new Promise((resolve) => {
|
||
const showCheckbox = isLast && !pageIgnoreUserMute && !popup.force_even_muted
|
||
const showData = {
|
||
popupId: popup.popup_id,
|
||
title: popup.title || '',
|
||
duration: popup.duration || 0,
|
||
images: popup.images || [],
|
||
showMuteCheckbox: showCheckbox,
|
||
serverTime: serverTime
|
||
}
|
||
const onClose = (result) => {
|
||
this.recordShow(popup.popup_id, this.currentPageKey, serverTime)
|
||
if (result.muteToday && showCheckbox) {
|
||
this.setMuteToday(this.currentPageKey, serverTime)
|
||
resolve()
|
||
return
|
||
}
|
||
this.showQueue(pageInstance, queue, index + 1, serverTime, pageIgnoreUserMute).then(resolve)
|
||
}
|
||
popupComp.show(showData, onClose)
|
||
})
|
||
}
|
||
|
||
// ========== 🆕 新增:强制重置锁状态 ==========
|
||
/**
|
||
* 当页面被隐藏(onHide)时调用,用于释放全局锁,避免影响其他页面的弹窗
|
||
*/
|
||
reset() {
|
||
this.isShowing = false;
|
||
this.isFetching = false;
|
||
this.currentPageKey = null;
|
||
}
|
||
}
|
||
|
||
export default new PopupService() |