diff --git a/src/store/software.ts b/src/store/software.ts index 3b35601..5f27da6 100644 --- a/src/store/software.ts +++ b/src/store/software.ts @@ -9,12 +9,14 @@ export const useSoftwareStore = defineStore('software', { essentials: [] as any[], updates: [] as any[], allSoftware: [] as any[], + selectedEssentialIds: [] as string[], + selectedUpdateIds: [] as string[], loading: false, - lastFetched: 0 // 记录上次完整同步的时间戳 + lastFetched: 0 }), getters: { mergedEssentials: (state) => { - const items = state.essentials.map(item => { + return state.essentials.map(item => { const isInstalled = state.allSoftware.some(s => s.id.toLowerCase() === item.id.toLowerCase()); const hasUpdate = state.updates.some(s => s.id.toLowerCase() === item.id.toLowerCase()); @@ -30,18 +32,45 @@ export const useSoftwareStore = defineStore('software', { } } - return { - ...item, - status: displayStatus, - actionLabel - }; + return { ...item, status: displayStatus, actionLabel }; }); - return items; // Essentials 通常保持自定义顺序 }, sortedUpdates: (state) => [...state.updates].sort(sortByName), sortedAllSoftware: (state) => [...state.allSoftware].sort(sortByName) }, actions: { + // 通用的勾选切换逻辑 + toggleSelection(id: string, type: 'essential' | 'update') { + const list = type === 'essential' ? this.selectedEssentialIds : this.selectedUpdateIds; + const index = list.indexOf(id); + if (index === -1) { + list.push(id); + } else { + list.splice(index, 1); + } + }, + selectAll(type: 'essential' | 'update') { + if (type === 'essential') { + const selectable = this.mergedEssentials.filter(s => s.status !== 'installed'); + this.selectedEssentialIds = selectable.map(s => s.id); + } else { + this.selectedUpdateIds = this.updates.map(s => s.id); + } + }, + deselectAll(type: 'essential' | 'update') { + if (type === 'essential') this.selectedEssentialIds = []; + else this.selectedUpdateIds = []; + }, + invertSelection(type: 'essential' | 'update') { + if (type === 'essential') { + const selectable = this.mergedEssentials.filter(s => s.status !== 'installed').map(s => s.id); + this.selectedEssentialIds = selectable.filter(id => !this.selectedEssentialIds.includes(id)); + } else { + const selectable = this.updates.map(s => s.id); + this.selectedUpdateIds = selectable.filter(id => !this.selectedUpdateIds.includes(id)); + } + }, + async fetchEssentials() { this.essentials = await invoke('get_essentials') }, @@ -50,6 +79,8 @@ export const useSoftwareStore = defineStore('software', { try { const res = await invoke('get_updates') this.updates = res as any[] + // 刷新数据后,如果没选过,默认全选 + if (this.selectedUpdateIds.length === 0) this.selectAll('update'); } finally { this.loading = false } @@ -63,16 +94,13 @@ export const useSoftwareStore = defineStore('software', { this.loading = false } }, - // 智能同步:如果数据较新,则直接返回 async syncDataIfNeeded(force = false) { const now = Date.now(); - const CACHE_TIMEOUT = 5 * 60 * 1000; // 5 分钟缓存 - + const CACHE_TIMEOUT = 5 * 60 * 1000; if (!force && this.allSoftware.length > 0 && (now - this.lastFetched < CACHE_TIMEOUT)) { if (this.essentials.length === 0) await this.fetchEssentials(); return; } - await this.fetchAllData(); }, async fetchAllData() { @@ -87,6 +115,8 @@ export const useSoftwareStore = defineStore('software', { this.allSoftware = all as any[]; this.updates = updates as any[]; this.lastFetched = Date.now(); + // 如果没选过,默认全选 + if (this.selectedEssentialIds.length === 0) this.selectAll('essential'); } finally { this.loading = false; } @@ -112,9 +142,11 @@ export const useSoftwareStore = defineStore('software', { software.status = status software.progress = progress } - if (status === 'success') { this.lastFetched = 0; + // 安装成功后从选择列表中移除 + this.selectedEssentialIds = this.selectedEssentialIds.filter(i => i !== id); + this.selectedUpdateIds = this.selectedUpdateIds.filter(i => i !== id); } }) } diff --git a/src/views/Essentials.vue b/src/views/Essentials.vue index 492e7a7..121cbfa 100644 --- a/src/views/Essentials.vue +++ b/src/views/Essentials.vue @@ -23,9 +23,9 @@ @@ -33,14 +33,14 @@
- 已选 {{ selectedIds.length }} / {{ selectableItems.length }} 项 + 已选 {{ store.selectedEssentialIds.length }} / {{ selectableItems.length }} 项
- +
- +
- +
@@ -56,9 +56,9 @@ :software="item" :action-label="item.actionLabel" :selectable="true" - :is-selected="selectedIds.includes(item.id)" + :is-selected="store.selectedEssentialIds.includes(item.id)" @install="store.install" - @toggle-select="toggleSelection" + @toggle-select="id => store.toggleSelection(id, 'essential')" /> @@ -67,51 +67,20 @@