fix(size): 修复轻量包占用显示为 0 MB 的精度问题
后端 fmtMb 用 toFixed(1) 保留 1 位小数,<0.05MB 的包(几 KB~几十 KB 的轻量组件)被截断为 0。改为保留 KB 级精度;前端统一使用 store 的 fmtSize/fmtBytes(新增 KB 档位),所有包大小显示点(检索/忽略/概览/ 卡片/抽屉/清理对话框/Top20)统一替换,消除各组件重复的本地格式化。
This commit is contained in:
+2
-1
@@ -65,7 +65,8 @@ function readJson(file) {
|
||||
}
|
||||
|
||||
function fmtMb(bytes) {
|
||||
return Number((bytes / 1024 / 1024).toFixed(1))
|
||||
// 保留到 KB 级精度:toFixed(1) 会把 <0.05MB 的轻量包(几 KB~几十 KB)截成 0
|
||||
return Math.round((bytes / 1024 / 1024) * 1024) / 1024
|
||||
}
|
||||
|
||||
// 目录名 → 包名(支持 scoped:@scope/name)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useStore } from '../store'
|
||||
import { useStore, fmtSize } from '../store'
|
||||
import api from '../api'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -81,7 +81,7 @@ async function confirm() {
|
||||
<div class="cd-body">
|
||||
<div class="cd-pkg">
|
||||
<span class="cd-pkg-name">{{ pkg.name }}</span>
|
||||
<span class="cd-pkg-meta">当前 {{ pkg.versions }} 个版本 · {{ pkg.size }} MB</span>
|
||||
<span class="cd-pkg-meta">当前 {{ pkg.versions }} 个版本 · {{ fmtSize(pkg.size) }}</span>
|
||||
</div>
|
||||
|
||||
<div class="cd-row">
|
||||
@@ -105,7 +105,7 @@ async function confirm() {
|
||||
</div>
|
||||
|
||||
<div class="cd-foot">
|
||||
<span class="cd-freed">预计释放 {{ freedSpace.toFixed(1) }} MB</span>
|
||||
<span class="cd-freed">预计释放 {{ fmtSize(freedSpace) }}</span>
|
||||
<button class="btn unignore" @click="emit('close')">取消</button>
|
||||
<button class="btn clean" :class="{ disabled: !toDelete.length }" :disabled="cleaning || !toDelete.length" @click="confirm">
|
||||
{{ cleaning ? '清理中…' : `确认清理 ${toDelete.length} 个` }}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup>
|
||||
import StatusTag from './StatusTag.vue'
|
||||
import PkgLogo from './PkgLogo.vue'
|
||||
import { fmtSize } from '../store'
|
||||
|
||||
defineProps({
|
||||
pkg: { type: Object, required: true },
|
||||
@@ -41,7 +42,7 @@ function splitName(name) {
|
||||
<div class="m-l">版本数</div>
|
||||
</div>
|
||||
<div class="m-item">
|
||||
<div class="m-v">{{ pkg.size }} MB</div>
|
||||
<div class="m-v">{{ fmtSize(pkg.size) }}</div>
|
||||
<div class="m-l">占用空间</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ref, computed, watch } from 'vue'
|
||||
import StatusTag from './StatusTag.vue'
|
||||
import PkgLogo from './PkgLogo.vue'
|
||||
import api from '../api'
|
||||
import { fmtSize } from '../store'
|
||||
|
||||
const props = defineProps({
|
||||
visible: Boolean,
|
||||
@@ -90,7 +91,7 @@ function delVersion(v) {
|
||||
</div>
|
||||
<div class="kv">
|
||||
<div class="k">占用空间</div>
|
||||
<div class="v">{{ pkg.size }} MB</div>
|
||||
<div class="v">{{ fmtSize(pkg.size) }}</div>
|
||||
</div>
|
||||
<div class="kv">
|
||||
<div class="k">最近更新</div>
|
||||
@@ -127,7 +128,7 @@ function delVersion(v) {
|
||||
</div>
|
||||
<div v-for="v in verList" :key="v.version" class="ver-row">
|
||||
<span class="ver-no">{{ v.version }}</span>
|
||||
<span class="ver-size">{{ v.size }} MB</span>
|
||||
<span class="ver-size">{{ fmtSize(v.size) }}</span>
|
||||
<span class="ver-date">{{ fmtDate(v.date) }}</span>
|
||||
<button class="del-btn" title="删除此版本" @click="delVersion(v)">🗑</button>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
<script setup>
|
||||
// 排行 Top 30:有访问统计按热度,否则降级为缓存占用(真实环境无访问统计)
|
||||
import PkgLogo from './PkgLogo.vue'
|
||||
import { fmtSize } from '../store'
|
||||
const props = defineProps({
|
||||
top30: { type: Array, default: () => [] },
|
||||
top30By: { type: String, default: 'visits' },
|
||||
})
|
||||
const emit = defineEmits(['open'])
|
||||
const isVisits = props.top30By === 'visits'
|
||||
function fmtSize(mb) {
|
||||
if (mb >= 1024) return `${(mb / 1024).toFixed(1)} GB`
|
||||
return `${mb.toFixed(1)} MB`
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -64,16 +64,22 @@ const stats = computed(() => {
|
||||
|
||||
function fmtSize(mb) {
|
||||
if (mb >= 1024) return `${(mb / 1024).toFixed(1)} GB`
|
||||
return `${mb.toFixed(1)} MB`
|
||||
if (mb >= 0.05) return `${mb.toFixed(1)} MB`
|
||||
if (mb > 0) return `${Math.max(1, Math.round(mb * 1024))} KB`
|
||||
return '0 MB'
|
||||
}
|
||||
|
||||
/** 字节 → 可读文本 */
|
||||
function fmtBytes(b) {
|
||||
const mb = b / 1024 / 1024
|
||||
if (mb >= 1024) return `${(mb / 1024).toFixed(1)} GB`
|
||||
return `${mb.toFixed(1)} MB`
|
||||
if (mb >= 0.05) return `${mb.toFixed(1)} MB`
|
||||
if (mb > 0) return `${Math.max(1, Math.round(mb * 1024))} KB`
|
||||
return '0 MB'
|
||||
}
|
||||
|
||||
export { fmtSize, fmtBytes }
|
||||
|
||||
const fmtSizeFn = fmtSize
|
||||
|
||||
async function refreshPackages(keyword = '') {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useStore } from '../store'
|
||||
import { useStore, fmtSize } from '../store'
|
||||
|
||||
const { state, unignorePkg, refreshPackages } = useStore()
|
||||
|
||||
@@ -42,7 +42,7 @@ async function doUnignore(pkg) {
|
||||
<tr v-for="p in ignoredList" :key="p.name">
|
||||
<td><span class="pkg-cell">{{ p.name }}</span></td>
|
||||
<td><span class="num-cell">{{ p.versions }}</span></td>
|
||||
<td><span class="num-cell">{{ p.size }} MB</span></td>
|
||||
<td><span class="num-cell">{{ fmtSize(p.size) }}</span></td>
|
||||
<td><span class="ign-time">{{ p.ignoredAt || '—' }}</span></td>
|
||||
<td>
|
||||
<button class="btn unignore" @click="doUnignore(p)">↩️ 移出忽略</button>
|
||||
|
||||
@@ -7,7 +7,7 @@ import Top30Panel from '../components/Top30Panel.vue'
|
||||
import PackageCard from '../components/PackageCard.vue'
|
||||
import PackageDrawer from '../components/PackageDrawer.vue'
|
||||
import CleanDialog from '../components/CleanDialog.vue'
|
||||
import { useStore } from '../store'
|
||||
import { useStore, fmtSize } from '../store'
|
||||
|
||||
const router = useRouter()
|
||||
const { state, stats, refreshAll, ignorePkg, unignorePkg, cleanPkg } = useStore()
|
||||
@@ -86,7 +86,7 @@ function quickClean() {
|
||||
<div class="stats-2">
|
||||
<StatMini tone="blue" label="今日更新包数" ico="🆕" :main="String(stats.todayUpdated)" sub="今日有版本更新" link="查看" @link="router.push('/search')" />
|
||||
<StatMini tone="green" label="缓存版本总数" ico="🧩" :main="stats.totalVersions.toLocaleString()" sub="全部缓存包的版本数" link="查看" @link="router.push('/search')" />
|
||||
<StatMini tone="orange" label="最大包" ico="🐘" :main="stats.maxPkg?.name || '—'" :unit="stats.maxPkg ? stats.maxPkg.size + ' MB' : ''" :sub="`${stats.maxPkg?.versions || 0} 个版本`" link="详情" @link="stats.maxPkg && openDrawer(stats.maxPkg)" />
|
||||
<StatMini tone="orange" label="最大包" ico="🐘" :main="stats.maxPkg?.name || '—'" :unit="stats.maxPkg ? fmtSize(stats.maxPkg.size) : ''" :sub="`${stats.maxPkg?.versions || 0} 个版本`" link="详情" @link="stats.maxPkg && openDrawer(stats.maxPkg)" />
|
||||
<StatMini tone="purple" label="最老包时间" ico="⏳" :main="stats.oldestPkg?.lastUpdated || '—'" unit="⏰" :sub="stats.oldestPkg ? `${stats.oldestPkg.name} · 未更新` : ''" link="详情" @link="stats.oldestPkg && openDrawer(stats.oldestPkg)" />
|
||||
<StatMini tone="pink" label="版本数分布" ico="🧩" main=">15 版本" :unit="`${stats.warnCount} 个`" :sub="`超阈值共 ${warningExcess} 个版本`" link="查看" @link="router.push({ path: '/search', query: { status: 'warn' } })" />
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ import PackageDrawer from '../components/PackageDrawer.vue'
|
||||
import CleanDialog from '../components/CleanDialog.vue'
|
||||
import StatusTag from '../components/StatusTag.vue'
|
||||
import PkgLogo from '../components/PkgLogo.vue'
|
||||
import { useStore } from '../store'
|
||||
import { useStore, fmtSize } from '../store'
|
||||
|
||||
const { state, stats, refreshPackages, ignorePkg, unignorePkg, cleanPkg, deleteVersion } = useStore()
|
||||
const route = useRoute()
|
||||
@@ -138,7 +138,7 @@ async function onCleanConfirmed(res) {
|
||||
</span>
|
||||
</td>
|
||||
<td><span class="num-cell" :class="{ over: p.versions > state.threshold.versionThreshold }">{{ p.versions }}</span></td>
|
||||
<td><span class="num-cell">{{ p.size }} MB</span></td>
|
||||
<td><span class="num-cell">{{ fmtSize(p.size) }}</span></td>
|
||||
<td><span class="date-cell">{{ p.lastUpdated || '—' }}</span></td>
|
||||
<td><StatusTag :status="p.status" /></td>
|
||||
<td @click.stop>
|
||||
|
||||
Reference in New Issue
Block a user