feat:增加实际使用量
This commit is contained in:
parent
81ee22d2ee
commit
2f672920d9
@ -161,6 +161,9 @@ const info = await cacheManager.getCacheInfo()
|
||||
// quotaTotalBytes, // 配额总量 = uni.getStorageInfoSync().limitSize*1024
|
||||
// quotaAvailableBytes, // 配额可用 = quotaTotalBytes - appUsedBytes
|
||||
// usagePercent, // 百分比(0-100,1 位小数)= appUsedBytes / quotaTotalBytes * 100
|
||||
// deviceTotalBytes, // 设备总存储 = plus.io.getStorageInfo().totalSize * 1024(HTML5+ API,MVP 已支持)
|
||||
// deviceFreeBytes, // 设备可用存储 = plus.io.getStorageInfo().availableSize * 1024
|
||||
// deviceUsagePercent, // 设备占比(0-100,2 位小数)= appUsedBytes / deviceTotalBytes * 100
|
||||
// othersBytes, // "其他" section 大小 = 所有黑名单 keys + 不可清理文件大小
|
||||
// categories: [{id, label, description, sizeBytes, keyCount, warning}, ...]
|
||||
// }
|
||||
@ -265,13 +268,18 @@ await invalidateAll() // 清空 memoryMap + inFlightMap
|
||||
│ │
|
||||
│ 49.7 MB │ ← 大字号主指标(主色)
|
||||
│ │
|
||||
│ 占据配额 16% 存储空间 │ ← 百分比副文字(次要色)
|
||||
│ │
|
||||
│ ▓▓▓▓░░░░░░░░░░░░░░░░░░░░░ 16% │ ← 进度条(当前用量占配额比例)
|
||||
│ │
|
||||
│ ┌────────────┬─────────────┬────────────┐ │
|
||||
│ │ Topfans 已用空间 │ 内存缓存空间 │ 总内存空间 │ │ ← 一行 3 个 chip 标签(无数值)
|
||||
│ └────────────┴─────────────┴────────────┘ │ 数值已分别显示在:大字 / 缓存分类 sum / 总配额
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────┐ │
|
||||
│ │ 设备总空间 │ 设备可用 │ │ ← 新增:HTML5+ 设备级信息行
|
||||
│ │ 128.0 GB │ 45.2 GB │ │ (plus.io.getStorageInfo;非 APP-PLUS 显示 "—")
|
||||
│ └──────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 占设备 0.04% 存储空间 │ ← 百分比副文字(分母=设备总存储,2 位小数)
|
||||
├─────────────────────────────────────────────┤
|
||||
│ 缓存分类 │ ← section 标题(次要色)
|
||||
├─────────────────────────────────────────────┤
|
||||
@ -314,8 +322,9 @@ await invalidateAll() // 清空 memoryMap + inFlightMap
|
||||
- 该行**不可点击进入详情**(没有可清理内容)
|
||||
|
||||
**关于"磁盘" vs "配额"**:
|
||||
- MVP 用 `uni.getStorageInfoSync().limitSize`(app 自己的 SQLite 配额),文案写"配额"而非"磁盘",不误导用户
|
||||
- 设备级"磁盘总空间/可用空间"需要 native plugin(iOS `NSFileManager` / Android `StatFs`),**MVP 不引入**,列为后续优化(§2)
|
||||
- **进度条**仍以 `uni.getStorageInfoSync().limitSize`(app 自己的 SQLite 配额)为 100%,表达"app 缓存压力"(用户的清理决策依据)
|
||||
- **百分比分母** = `plus.io.getStorageInfo().totalSize`(设备总存储),即"占设备 X% 存储空间"——HTML5+ 标准 API,Android/iOS 均原生支持,**不需要 native plugin**
|
||||
- **设备信息行** = `plus.io.getStorageInfo()` 直接拿 `{ totalSize, availableSize }`,无权限要求;非 APP-PLUS 平台或调用失败时显示 `—`
|
||||
|
||||
**草稿/引导的二级提示**:行右侧副文字"按账号分组清理",警示用户详情页会有分组。
|
||||
|
||||
@ -416,15 +425,19 @@ cacheManager.getCacheInfo()
|
||||
│ └─ others.computeSize → 上述未匹配的 key 汇总
|
||||
├─ [并行 2] 读取存储配额
|
||||
│ ├─ uni.getStorageInfoSync() → { currentSize (KB), limitSize (KB) }
|
||||
│ └─ ioPath.getSandboxTotalSize() → 沙盒 doc 目录下所有文件总字节数(新增 ioPath 只读 API;与 scanSandboxTmpFiles 不同,前者含白名单 preload/share/image 所有文件,后者仅统计 tmp/)
|
||||
│ ├─ ioPath.getSandboxTotalSize() → 沙盒 doc 目录下所有文件总字节数(新增 ioPath 只读 API;与 scanSandboxTmpFiles 不同,前者含白名单 preload/share/image 所有文件,后者仅统计 tmp/)
|
||||
│ └─ ioPath.getDeviceStorageInfo() → 设备级 { totalSize (KB), availableSize (KB) },HTML5+ API,非 APP-PLUS 返回 {0,0}
|
||||
↓
|
||||
聚合:
|
||||
totalBytes = sum(categories.sizeBytes) // 可清理总量(=内存缓存空间 chip)
|
||||
appUsedBytes = currentSize * 1024 + sandboxBytes // 软件占用(大字 + Topfans已用空间 chip)
|
||||
// 注:currentSize 是 uni storage 全量(含黑名单),这是 WeChat "已用空间" 口径
|
||||
quotaTotalBytes = limitSize * 1024 // 配额总量(=总内存空间 chip)
|
||||
quotaTotalBytes = limitSize * 1024 // 配额总量(=总内存空间 chip,进度条 100% 基准)
|
||||
quotaAvailableBytes = quotaTotalBytes - appUsedBytes // 配额可用
|
||||
usagePercent = (appUsedBytes / quotaTotalBytes) * 100 // 百分比
|
||||
usagePercent = (appUsedBytes / quotaTotalBytes) * 100 // 配额百分比(进度条用)
|
||||
deviceTotalBytes = deviceTotalKB * 1024 // 设备总存储(设备信息行"设备总空间")
|
||||
deviceFreeBytes = deviceFreeKB * 1024 // 设备可用(设备信息行"设备可用")
|
||||
deviceUsagePercent = (appUsedBytes / deviceTotalBytes) * 100 // 设备百分比(百分比副文字"占设备 X%"用)
|
||||
othersBytes = sum(黑名单 keys size) + 不可清理文件大小 // "其他" section
|
||||
↓
|
||||
渲染页面(大字 + 百分比 + 进度条 + 3 chip 标签 + 6 缓存分类行 + 1 其他 section)
|
||||
|
||||
@ -46,8 +46,21 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 设备级信息:总空间 / 可用空间(来自 plus.io.getStorageInfo) -->
|
||||
<view class="device-info">
|
||||
<view class="device-info-item">
|
||||
<text class="device-info-label">设备总空间</text>
|
||||
<text class="device-info-value">{{ formatSize(info.deviceTotalBytes) }}</text>
|
||||
</view>
|
||||
<view class="device-info-divider"></view>
|
||||
<view class="device-info-item">
|
||||
<text class="device-info-label">设备可用</text>
|
||||
<text class="device-info-value">{{ formatSize(info.deviceFreeBytes) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<text class="hero-percent"
|
||||
>占手机 {{ info.usagePercent.toFixed(1) }}% 存储空间</text
|
||||
>占设备 {{ info.deviceUsagePercent.toFixed(2) }}% 存储空间</text
|
||||
>
|
||||
</view>
|
||||
|
||||
@ -122,6 +135,9 @@ const info = ref({
|
||||
quotaTotalBytes: 0,
|
||||
quotaAvailableBytes: 0,
|
||||
usagePercent: 0,
|
||||
deviceTotalBytes: 0,
|
||||
deviceFreeBytes: 0,
|
||||
deviceUsagePercent: 0,
|
||||
othersBytes: 0,
|
||||
totalBytes: 0,
|
||||
categories: [],
|
||||
@ -231,6 +247,41 @@ onPullDownRefresh(async () => {
|
||||
display: block;
|
||||
margin-top: 24rpx;
|
||||
}
|
||||
|
||||
/* ── 设备级信息行(总空间 / 可用空间)── */
|
||||
.device-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 24rpx;
|
||||
padding: 16rpx 20rpx;
|
||||
background: #fafbfc;
|
||||
border-radius: 12rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.device-info-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4rpx;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.device-info-divider {
|
||||
width: 1rpx;
|
||||
height: 32rpx;
|
||||
background: #e8e8e8;
|
||||
margin: 0 16rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.device-info-label {
|
||||
font-size: 22rpx;
|
||||
color: #8c8c8c;
|
||||
}
|
||||
.device-info-value {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #262626;
|
||||
}
|
||||
.hero-tip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@ -9,7 +9,7 @@ import othersHandler from './handlers/othersHandler'
|
||||
import preloadHandler from './handlers/preloadHandler'
|
||||
import guideHandler from './handlers/guideHandler'
|
||||
import draftHandler from './handlers/draftHandler'
|
||||
import { getSandboxTotalSize } from './ioPath'
|
||||
import { getSandboxTotalSize, getDeviceStorageInfo } from './ioPath'
|
||||
|
||||
// ── 黑名单(§3.4.1)──
|
||||
// 全等匹配
|
||||
@ -105,6 +105,16 @@ export async function getCacheInfo() {
|
||||
} catch (e) {
|
||||
console.warn('[cacheManager] getSandboxTotalSize failed:', e.message)
|
||||
}
|
||||
let deviceTotalKB = 0, deviceFreeKB = 0
|
||||
try {
|
||||
const dev = await getDeviceStorageInfo()
|
||||
deviceTotalKB = dev.totalBytes || 0
|
||||
deviceFreeKB = dev.freeBytes || 0
|
||||
// 调试日志:把 getDeviceStorageInfo 的原始返回和 cacheManager 解析后的值都打出来
|
||||
console.log('[cacheManager][debug] getDeviceStorageInfo raw =', JSON.stringify(dev), 'parsed totalKB =', deviceTotalKB, 'freeKB =', deviceFreeKB)
|
||||
} catch (e) {
|
||||
console.warn('[cacheManager] getDeviceStorageInfo failed:', e.message)
|
||||
}
|
||||
|
||||
const totalBytes = categories.reduce((sum, c) => sum + (c.sizeBytes > 0 ? c.sizeBytes : 0), 0)
|
||||
const appUsedBytes = currentSizeKB * 1024 + sandboxBytes
|
||||
@ -113,9 +123,16 @@ export async function getCacheInfo() {
|
||||
const quotaAvailableBytes = Math.max(0, raw)
|
||||
const quotaExceeded = raw < 0
|
||||
const usagePercent = quotaTotalBytes > 0 ? (appUsedBytes / quotaTotalBytes) * 100 : 0
|
||||
// 设备级数据:plus.io.getStorageInfo 返回 KB,转字节
|
||||
const deviceTotalBytes = deviceTotalKB * 1024
|
||||
const deviceFreeBytes = deviceFreeKB * 1024
|
||||
const deviceUsagePercent = deviceTotalBytes > 0
|
||||
? (appUsedBytes / deviceTotalBytes) * 100
|
||||
: 0
|
||||
|
||||
return {
|
||||
totalBytes, appUsedBytes, quotaTotalBytes, quotaAvailableBytes, quotaExceeded, usagePercent,
|
||||
deviceTotalBytes, deviceFreeBytes, deviceUsagePercent,
|
||||
othersBytes: blacklistBytes + sandboxBytes,
|
||||
categories,
|
||||
}
|
||||
|
||||
@ -522,3 +522,38 @@ async function _listDir(dirEntry) {
|
||||
return []
|
||||
// #endif
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备级存储信息(HTML5+ 标准 API,Android/iOS 均支持)
|
||||
* 不需要任何 native plugin;非 APP-PLUS 平台或失败时返回安全零值
|
||||
* 注意:单位为 KB(plus.io 原始返回),调用方按需 * 1024 转字节
|
||||
* @returns {Promise<{totalBytes:number, freeBytes:number}>}
|
||||
*/
|
||||
export function getDeviceStorageInfo() {
|
||||
return new Promise((resolve) => {
|
||||
// #ifdef APP-PLUS
|
||||
try {
|
||||
plus.io.getStorageInfo({
|
||||
success: (res) => {
|
||||
// 调试日志:打印 plus.io.getStorageInfo 的真实返回 shape
|
||||
console.log('[ioPath][debug] plus.io.getStorageInfo res =', JSON.stringify(res), 'keys =', res ? Object.keys(res) : null)
|
||||
resolve({
|
||||
totalBytes: Number(res?.totalSize) || 0,
|
||||
freeBytes: Number(res?.availableSize) || 0,
|
||||
})
|
||||
},
|
||||
fail: (e) => {
|
||||
console.warn('[ioPath] getStorageInfo failed:', e?.message)
|
||||
resolve({ totalBytes: 0, freeBytes: 0 })
|
||||
},
|
||||
})
|
||||
} catch (e) {
|
||||
console.warn('[ioPath] getStorageInfo threw:', e?.message)
|
||||
resolve({ totalBytes: 0, freeBytes: 0 })
|
||||
}
|
||||
// #endif
|
||||
// #ifndef APP-PLUS
|
||||
resolve({ totalBytes: 0, freeBytes: 0 })
|
||||
// #endif
|
||||
})
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user