topfans/frontend/utils/handlers/guideHandler.js
2026-07-29 16:03:33 +08:00

139 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// frontend/utils/handlers/guideHandler.js
// 引导记录 handler分组型含保留规则
// spec §3.4.2: 保留当前 uid 的 + 全局 key其他用户组仅在登录态可清
import { getCurrentUid } from '@/utils/draftStorage' // 复用
import { listGuideKeys, extractUidFromGuideKey } from './guideKeys'
const GLOBAL_PROTECTED_KEYS = new Set(['guide_debug_mode', 'guide_first_show'])
function isGlobalKey(key) {
// guide_shown_xxx 是无 uid 段(但有 configKey
if (GLOBAL_PROTECTED_KEYS.has(key)) return true
if (key.startsWith('guide_shown_')) return true
return false
}
function bytesOf(keys) {
let total = 0
for (const k of keys) {
try { const v = uni.getStorageSync(k); if (v != null) total += JSON.stringify(v).length } catch (e) {}
}
return total
}
export default {
id: 'guide',
label: '引导记录',
description: '新手引导完成标记',
warning: false,
async computeSize() {
const keys = listGuideKeys()
return { sizeBytes: bytesOf(keys), keyCount: keys.length }
},
async computeBreakdown() {
const currentUid = getCurrentUid()
const allKeys = listGuideKeys()
const groups = []
const isLoggedIn = !!currentUid
// 1. 我的currentUid— 保留不可清
if (currentUid) {
const myKeys = allKeys.filter((k) => extractUidFromGuideKey(k) === currentUid)
groups.push({
uid: currentUid, displayUid: currentUid, isCurrent: true,
sizeBytes: bytesOf(myKeys), keyCount: myKeys.length,
canClean: false, disabledReason: 'guide-current',
})
}
// 2. 其他用户(按 uid 聚合)— 仅登录态可清;未登录态保留展示但按钮置灰
const otherUidKeys = new Map()
for (const k of allKeys) {
const uid = extractUidFromGuideKey(k)
if (!uid || uid === currentUid) continue
if (!otherUidKeys.has(uid)) otherUidKeys.set(uid, [])
otherUidKeys.get(uid).push(k)
}
for (const [uid, keys] of otherUidKeys) {
groups.push({
uid, displayUid: uid, isCurrent: false,
sizeBytes: bytesOf(keys), keyCount: keys.length,
canClean: isLoggedIn && keys.length > 0,
disabledReason: isLoggedIn ? (keys.length === 0 ? 'empty' : null) : 'logged-out',
})
}
// 3. 全局 guide_*(无 uid 段)— 永远不可清
const globalKeys = allKeys.filter(isGlobalKey)
if (globalKeys.length > 0) {
groups.push({
uid: '__global__', displayUid: '全局标记', isCurrent: false,
sizeBytes: bytesOf(globalKeys), keyCount: globalKeys.length, global: true,
canClean: false, disabledReason: 'guide-global',
})
}
// 按 sizeBytes 降序spec §4.3.2 要求)
return groups.sort((a, b) => b.sizeBytes - a.sizeBytes)
},
async cleanGroup({ uid }) {
const currentUid = getCurrentUid()
const allKeys = listGuideKeys()
// 保留:当前 uid 的 + 全局 key
const reserved = new Set()
if (currentUid) {
for (const k of allKeys) if (extractUidFromGuideKey(k) === currentUid) reserved.add(k)
}
for (const k of allKeys) if (isGlobalKey(k)) reserved.add(k)
let targetKeys = []
if (uid === 'self') {
// 不允许清自己的(保留规则)
return { freedBytes: 0, keyCount: 0 }
} else if (uid === null) {
// 其他用户聚合(不含全局)
targetKeys = allKeys.filter((k) => {
if (reserved.has(k)) return false
const u = extractUidFromGuideKey(k)
return u && u !== currentUid
})
} else if (uid === '__global__') {
// 全局 key 也不允许清
return { freedBytes: 0, keyCount: 0 }
} else {
// 具体其他 uid
targetKeys = allKeys.filter((k) => {
if (reserved.has(k)) return false // defensive
return extractUidFromGuideKey(k) === uid
})
}
// 逐 key先量后删per-key 精确值,避免 approximation
let freed = 0
let count = 0
for (const k of targetKeys) {
let valueBytes = 0
try {
const v = uni.getStorageSync(k)
if (v != null) valueBytes = JSON.stringify(v).length
} catch (e) {
console.warn('[guideHandler] read failed:', k, e.message)
continue
}
try {
uni.removeStorageSync(k)
freed += valueBytes
count++
} catch (e) {
console.warn('[guideHandler] remove failed:', k, e.message)
}
}
return { freedBytes: freed, keyCount: count }
},
}