// frontend/utils/handlers/draftHandler.js // 创作草稿 handler(分组型,按 uid 分组;草稿 key 已通过 M0 改造为 *_${uid} 形式) import { getCurrentUid, getAllBaseKeys } from '@/utils/draftStorage' 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 } function listAllDraftLikeKeys() { try { const info = uni.getStorageInfoSync() const all = info.keys || [] const baseKeys = getAllBaseKeys() return all.filter((k) => baseKeys.some((base) => k === base || k.startsWith(`${base}_`))) } catch (e) { return [] } } function extractUidFromDraftKey(key, baseKey) { const prefix = `${baseKey}_` if (!key.startsWith(prefix)) return null return key.slice(prefix.length) } /** * Remove the listed storage keys, counting only successful removals. * Reads each value first to capture accurate freedBytes before deletion. * @param {string[]} targets * @returns {{freedBytes: number, keyCount: number}} */ function removeAndCount(targets) { let freed = 0 let count = 0 for (const k of targets) { try { let bytes = 0 try { const v = uni.getStorageSync(k); if (v != null) bytes = JSON.stringify(v).length } catch (e) {} uni.removeStorageSync(k) freed += bytes count++ } catch (e) { console.warn('[draftHandler] remove failed:', k, e.message) } } return { freedBytes: freed, keyCount: count } } export default { id: 'draft', label: '创作中的草稿', description: '未提交的创作表单/生成结果', warning: true, warningText: '将清空你未提交的创作草稿,是否继续?', strongWarningText: '将清空该账号的草稿,对方下次登录不会看到。是否继续?', async computeSize() { const keys = listAllDraftLikeKeys() return { sizeBytes: bytesOf(keys), keyCount: keys.length } }, async computeBreakdown() { const currentUid = getCurrentUid() const allKeys = listAllDraftLikeKeys() const groups = [] const baseKeys = getAllBaseKeys() const isLoggedIn = !!currentUid // 按 uid 聚合 const byUid = new Map() for (const k of allKeys) { const matchedBase = baseKeys.find((b) => k === b || k.startsWith(`${b}_`)) if (!matchedBase) continue const uid = extractUidFromDraftKey(k, matchedBase) const groupUid = uid || '__legacy__' if (!byUid.has(groupUid)) byUid.set(groupUid, []) byUid.get(groupUid).push(k) } for (const [uid, keys] of byUid) { const isCurrent = uid === currentUid const isLegacy = uid === '__legacy__' let canClean, disabledReason if (!isLoggedIn) { canClean = false disabledReason = 'logged-out' } else if (isLegacy) { // 老无 uid 后缀 key 单独分组(不与他人草稿混合) canClean = keys.length > 0 disabledReason = keys.length === 0 ? 'empty' : null } else { canClean = keys.length > 0 disabledReason = keys.length === 0 ? 'empty' : null } groups.push({ uid, displayUid: isLegacy ? '老版本数据' : (isCurrent ? `我的 (${uid})` : `其他用户 (${uid})`), isCurrent, sizeBytes: bytesOf(keys), keyCount: keys.length, canClean, disabledReason, }) } return groups.sort((a, b) => b.sizeBytes - a.sizeBytes) }, async cleanGroup({ uid }) { const currentUid = getCurrentUid() const allKeys = listAllDraftLikeKeys() const baseKeys = getAllBaseKeys() const reserved = new Set() if (currentUid) { // 保留当前 uid 的 keys for (const k of allKeys) { const base = baseKeys.find((b) => k === b || k.startsWith(`${b}_`)) if (!base) continue if (extractUidFromDraftKey(k, base) === currentUid) reserved.add(k) } } if (uid === 'self') { const targets = allKeys.filter((k) => { const base = baseKeys.find((b) => k === b || k.startsWith(`${b}_`)) if (!base) return false return extractUidFromDraftKey(k, base) === currentUid }) return removeAndCount(targets) } else if (uid === '__legacy__') { // 单独清老无 uid 后缀 key(不删其他用户的!) const targets = allKeys.filter((k) => { const base = baseKeys.find((b) => k === b || k.startsWith(`${b}_`)) if (!base) return false return k === base }) return removeAndCount(targets) } else if (uid === 'others') { // 其他用户聚合(不含 legacy) const targets = allKeys.filter((k) => { const base = baseKeys.find((b) => k === b || k.startsWith(`${b}_`)) if (!base) return false const u = extractUidFromDraftKey(k, base) return u && u !== currentUid }) return removeAndCount(targets) } else { // 具体其他 uid const targets = allKeys.filter((k) => { const base = baseKeys.find((b) => k === b || k.startsWith(`${b}_`)) if (!base) return false if (reserved.has(k)) return false // defensive return extractUidFromDraftKey(k, base) === uid }) return removeAndCount(targets) } }, }