add clean memory

This commit is contained in:
Julian Freeman
2026-03-03 22:03:36 -04:00
parent 0c77149c9e
commit 92adfd7a2e
5 changed files with 501 additions and 16 deletions

View File

@@ -23,6 +23,13 @@ interface FileNode {
level: number; isOpen: boolean; isLoading: boolean;
}
interface MemoryStats {
total: number;
used: number;
free: number;
percent: number;
}
// --- 状态管理 ---
const fastState = ref({
isScanning: false,
@@ -33,6 +40,13 @@ const fastState = ref({
cleanResult: null as CleanResult | null,
});
const memoryState = ref({
stats: null as MemoryStats | null,
isCleaning: false,
lastFreed: "",
isDone: false,
});
const chromeState = ref({
isScanning: false,
isCleaning: false,
@@ -349,6 +363,55 @@ function splitSize(sizeStr: string | number) {
}
return { value: str, unit: '' };
}
// --- 内存清理逻辑 ---
async function getMemoryStats() {
try {
const stats = await invoke<MemoryStats>("get_memory_stats");
memoryState.value.stats = stats;
} catch (err) {
console.error("Failed to fetch memory stats", err);
}
}
async function startMemoryClean(deep = false) {
if (memoryState.value.isCleaning) return;
memoryState.value.isCleaning = true;
memoryState.value.isDone = false;
try {
const cmd = deep ? "run_deep_memory_clean" : "run_memory_clean";
const freedBytes = await invoke<number>(cmd);
memoryState.value.lastFreed = formatItemSize(freedBytes);
memoryState.value.isDone = true;
await getMemoryStats();
} catch (err) {
showAlert("清理失败", String(err), 'error');
} finally {
memoryState.value.isCleaning = false;
}
}
// 自动刷新内存
import { onMounted, onUnmounted, watch } from "vue";
let memoryInterval: any = null;
onMounted(() => {
getMemoryStats();
memoryInterval = setInterval(() => {
if (activeTab.value === 'clean-memory') {
getMemoryStats();
}
}, 3000);
});
onUnmounted(() => {
if (memoryInterval) clearInterval(memoryInterval);
});
watch(activeTab, (newTab) => {
if (newTab === 'clean-memory') getMemoryStats();
});
</script>
<template>
@@ -856,7 +919,73 @@ function splitSize(sizeStr: string | number) {
</div>
</section>
<!-- 4. 其他占位 -->
<!-- 4. 内存清理页面 -->
<section v-else-if="activeTab === 'clean-memory'" class="page-container">
<div class="page-header">
<div class="header-info">
<h1>内存加速</h1>
<p>通过压缩进程工作集释放物理内存占用</p>
</div>
</div>
<div class="main-action">
<div class="memory-dashboard">
<div class="memory-gauge" :style="{ '--percent': memoryState.stats?.percent || 0 }">
<svg viewBox="0 0 100 100">
<circle class="gauge-bg" cx="50" cy="50" r="45"></circle>
<circle class="gauge-fill" cx="50" cy="50" r="45" :style="{ strokeDashoffset: 283 - (283 * (memoryState.stats?.percent || 0)) / 100 }"></circle>
</svg>
<div class="gauge-content">
<span class="gauge-value">{{ Math.round(memoryState.stats?.percent || 0) }}<small>%</small></span>
<span class="gauge-label">内存占用</span>
</div>
</div>
</div>
</div>
<div class="memory-stats-grid">
<div class="stat-box shadow-card">
<span class="label">已用内存</span>
<span class="value">{{ formatItemSize(memoryState.stats?.used || 0) }}</span>
</div>
<div class="stat-box shadow-card">
<span class="label">可用内存</span>
<span class="value">{{ formatItemSize(memoryState.stats?.free || 0) }}</span>
</div>
<div class="stat-box shadow-card">
<span class="label">内存总量</span>
<span class="value">{{ formatItemSize(memoryState.stats?.total || 0) }}</span>
</div>
</div>
<div class="memory-actions">
<div class="action-card shadow-card" :class="{ cleaning: memoryState.isCleaning }">
<div class="action-info">
<h3>普通加速</h3>
<p>压缩所有进程的内存占用不影响程序运行</p>
</div>
<button class="btn-primary btn-sm" @click="startMemoryClean(false)" :disabled="memoryState.isCleaning">
{{ memoryState.isCleaning ? '清理中...' : '立即加速' }}
</button>
</div>
<div class="action-card shadow-card secondary" :class="{ cleaning: memoryState.isCleaning }">
<div class="action-info">
<h3>深度加速</h3>
<p>清空系统备用列表待机列表释放更多物理空间</p>
</div>
<button class="btn-secondary btn-sm" @click="startMemoryClean(true)" :disabled="memoryState.isCleaning">
深度加速
</button>
</div>
</div>
<div class="clean-feedback" v-if="memoryState.isDone">
<span class="success-icon"></span>
已为您释放 <span class="freed-amount">{{ memoryState.lastFreed }}</span> 内存空间
</div>
</section>
<!-- 5. 其他占位 -->
<section v-else class="placeholder-page">
<div class="empty-state">
<span class="empty-icon">🛠</span>
@@ -1502,4 +1631,163 @@ body {
background: #F5F5F7;
margin: 4px 0;
}
/* --- 内存清理特有样式 --- */
.memory-dashboard {
margin: 20px 0 40px;
display: flex;
justify-content: center;
}
.memory-gauge {
position: relative;
width: 240px;
height: 240px;
}
.memory-gauge svg {
transform: rotate(-90deg);
width: 100%;
height: 100%;
}
.gauge-bg {
fill: none;
stroke: #F2F2F7;
stroke-width: 8;
}
.gauge-fill {
fill: none;
stroke: var(--primary-color);
stroke-width: 8;
stroke-linecap: round;
stroke-dasharray: 283;
transition: stroke-dashoffset 1s cubic-bezier(0.4, 0, 0.2, 1), stroke 0.3s;
}
/* 根据百分比改变颜色 */
.memory-gauge[style*="--percent: 7"], .memory-gauge[style*="--percent: 8"] { --gauge-color: #FF9500; }
.memory-gauge[style*="--percent: 9"] { --gauge-color: #FF3B30; }
.gauge-content {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
text-align: center;
display: flex;
flex-direction: column;
}
.gauge-value {
font-size: 56px;
font-weight: 800;
color: var(--text-main);
line-height: 1;
letter-spacing: -2px;
}
.gauge-value small {
font-size: 24px;
margin-left: 2px;
letter-spacing: 0;
}
.gauge-label {
font-size: 14px;
color: var(--text-sec);
font-weight: 600;
margin-top: 4px;
}
.memory-stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
margin-bottom: 40px;
}
.stat-box {
background: white;
padding: 20px;
border-radius: 20px;
text-align: center;
display: flex;
flex-direction: column;
gap: 8px;
}
.stat-box .label {
font-size: 13px;
color: var(--text-sec);
font-weight: 500;
}
.stat-box .value {
font-size: 18px;
font-weight: 700;
color: var(--text-main);
}
.memory-actions {
display: flex;
flex-direction: column;
gap: 16px;
}
.action-card {
background: white;
padding: 24px 32px;
border-radius: 24px;
display: flex;
align-items: center;
justify-content: space-between;
transition: all 0.3s;
}
.action-card.secondary {
background-color: #FBFBFD;
border: 1px dashed var(--border-color);
box-shadow: none;
}
.action-info h3 {
font-size: 17px;
font-weight: 700;
margin-bottom: 4px;
}
.action-info p {
font-size: 13px;
color: var(--text-sec);
}
.clean-feedback {
margin-top: 32px;
text-align: center;
padding: 16px;
background-color: #E8F5E9;
color: #2E7D32;
border-radius: 16px;
font-weight: 600;
font-size: 14px;
animation: slideUp 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.freed-amount {
font-size: 18px;
font-weight: 800;
text-decoration: underline;
}
@keyframes slideUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.action-card.cleaning {
filter: grayscale(1);
opacity: 0.7;
pointer-events: none;
}
</style>