diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 0d7b4c5..79c11fe 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -28,12 +28,12 @@ fn get_essentials(app: AppHandle) -> Vec { description: Some("Microsoft PowerToys 是一组实用程序,供高级用户调整和简化其 Windows 10 和 11 体验。".to_string()), version: None, available_version: None, - icon_url: Some("https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/logo.png".to_string()), + icon_url: Some("https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/icons/PowerToys icon/PNG/PowerToysAppList.targetsize-48.png".to_string()), status: "idle".to_string(), progress: 0.0, }, Software { - id: "Google.Chrome".to_string(), + id: "Google.Chrome.EXE".to_string(), name: "Google Chrome".to_string(), description: Some("Google Chrome 是一款快速、安全且免费的浏览器。".to_string()), version: None, diff --git a/src/store/software.ts b/src/store/software.ts index 77a692f..b562ce5 100644 --- a/src/store/software.ts +++ b/src/store/software.ts @@ -7,7 +7,8 @@ export const useSoftwareStore = defineStore('software', { essentials: [] as any[], updates: [] as any[], allSoftware: [] as any[], - loading: false + loading: false, + lastFetched: 0 // 记录上次完整同步的时间戳 }), getters: { mergedEssentials: (state) => { @@ -49,18 +50,34 @@ export const useSoftwareStore = defineStore('software', { this.allSoftware = await invoke('get_all_software') this.loading = false }, + // 智能同步:如果数据较新,则直接返回 + async syncDataIfNeeded(force = false) { + const now = Date.now(); + const CACHE_TIMEOUT = 5 * 60 * 1000; // 5 分钟缓存 + + if (!force && this.allSoftware.length > 0 && (now - this.lastFetched < CACHE_TIMEOUT)) { + // 如果不是强制刷新,且数据在 5 分钟内,且已经有数据,则跳过 + if (this.essentials.length === 0) await this.fetchEssentials(); + return; + } + + await this.fetchAllData(); + }, async fetchAllData() { this.loading = true; - // 并行获取三类数据 - const [essentials, all, updates] = await Promise.all([ - invoke('get_essentials'), - invoke('get_all_software'), - invoke('get_updates') - ]); - this.essentials = essentials as any[]; - this.allSoftware = all as any[]; - this.updates = updates as any[]; - this.loading = false; + try { + const [essentials, all, updates] = await Promise.all([ + invoke('get_essentials'), + invoke('get_all_software'), + invoke('get_updates') + ]); + this.essentials = essentials as any[]; + this.allSoftware = all as any[]; + this.updates = updates as any[]; + this.lastFetched = Date.now(); + } finally { + this.loading = false; + } }, async install(id: string) { const software = this.findSoftware(id) @@ -68,11 +85,16 @@ export const useSoftwareStore = defineStore('software', { await invoke('install_software', { id }) }, findSoftware(id: string) { + // 这里的逻辑会从多个列表中查找对象 return this.essentials.find(s => s.id === id) || this.updates.find(s => s.id === id) || this.allSoftware.find(s => s.id === id) }, initListener() { + // 避免重复监听 + if ((window as any).__tauri_listener_init) return; + (window as any).__tauri_listener_init = true; + listen('install-status', (event: any) => { const { id, status, progress } = event.payload const software = this.findSoftware(id) @@ -80,6 +102,11 @@ export const useSoftwareStore = defineStore('software', { software.status = status software.progress = progress } + + // 如果安装成功,标记数据过期,以便下次切换或刷新时同步最新状态 + if (status === 'success') { + this.lastFetched = 0; + } }) } } diff --git a/src/views/Essentials.vue b/src/views/Essentials.vue index 37396b1..824c56e 100644 --- a/src/views/Essentials.vue +++ b/src/views/Essentials.vue @@ -3,9 +3,31 @@

装机必备

-

正在同步软件状态...

- +
+ + +
@@ -33,7 +55,7 @@ import { onMounted } from 'vue'; const store = useSoftwareStore(); onMounted(() => { - store.fetchAllData(); + store.syncDataIfNeeded(); store.initListener(); }); @@ -57,32 +79,40 @@ const installAll = () => { display: flex; justify-content: space-between; align-items: center; - margin-bottom: 30px; + margin-bottom: 32px; } .content-header h1 { font-size: 32px; font-weight: 700; letter-spacing: -0.5px; + color: var(--text-main); } -.subtitle { - font-size: 14px; - color: var(--text-sec); - margin-top: 4px; +.header-actions { + display: flex; + gap: 12px; + align-items: center; } -.primary-btn { - background-color: var(--primary-color); - color: white; - border: none; +.action-btn { + display: flex; + align-items: center; + gap: 8px; padding: 10px 20px; border-radius: 12px; font-weight: 600; font-size: 14px; cursor: pointer; - box-shadow: var(--btn-shadow); transition: all 0.2s ease; + border: none; + white-space: nowrap; +} + +.primary-btn { + background-color: var(--primary-color); + color: white; + box-shadow: var(--btn-shadow); } .primary-btn:hover { @@ -90,10 +120,31 @@ const installAll = () => { transform: translateY(-1px); } -.primary-btn:disabled { - background-color: var(--border-color); - box-shadow: none; +.secondary-btn { + background-color: var(--bg-light); + color: var(--text-main); + border: 1px solid var(--border-color); +} + +.secondary-btn:hover { + background-color: white; + border-color: var(--primary-color); + color: var(--primary-color); +} + +.action-btn:disabled { + opacity: 0.6; cursor: not-allowed; + transform: none !important; +} + +.icon { + display: flex; + align-items: center; +} + +.icon.spinning { + animation: spin 1s linear infinite; } .software-list {