139 lines
4.4 KiB
JavaScript
139 lines
4.4 KiB
JavaScript
// 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 }
|
||
},
|
||
}
|