remove all software

This commit is contained in:
Julian Freeman
2026-03-30 20:51:01 -04:00
parent f89ff7173b
commit a699df0b1a
6 changed files with 9 additions and 224 deletions

View File

@@ -14,7 +14,7 @@
</router-link>
<router-link to="/updates" class="nav-item">
<span class="nav-icon">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 2v6h-6"></path>
<path d="M3 12a9 9 0 0 1 15-6.7L21 8"></path>
<path d="M3 22v-6h6"></path>
@@ -23,16 +23,6 @@
</span>
软件更新
</router-link>
<router-link to="/all" class="nav-item">
<span class="nav-icon">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"></path>
<path d="m3.3 7 8.7 5 8.7-5"></path>
<path d="M12 22V12"></path>
</svg>
</span>
全部软件
</router-link>
<!-- 底部选项 -->
<div class="sidebar-footer">

View File

@@ -15,10 +15,6 @@ const router = createRouter({
path: '/updates',
component: () => import('../views/Updates.vue')
},
{
path: '/all',
component: () => import('../views/AllSoftware.vue')
},
{
path: '/logs',
component: () => import('../views/Logs.vue')

View File

@@ -61,7 +61,6 @@ export const useSoftwareStore = defineStore('software', {
});
},
sortedUpdates: (state) => [...state.updates].sort(sortByName),
sortedAllSoftware: (state) => [...state.allSoftware].sort(sortByName),
isBusy: (state) => {
const allItems = [...state.essentials, ...state.updates, ...state.allSoftware];
return allItems.some(item => item.status === 'pending' || item.status === 'installing');
@@ -159,16 +158,6 @@ export const useSoftwareStore = defineStore('software', {
this.loading = false
}
},
async fetchAll() {
if (this.isBusy) return;
this.loading = true
try {
const res = await invoke('get_all_software')
this.allSoftware = res as any[]
} finally {
this.loading = false
}
},
async syncDataIfNeeded(force = false) {
if (this.isBusy) return;
const now = Date.now();
@@ -187,7 +176,7 @@ export const useSoftwareStore = defineStore('software', {
// 然后同步本地软件安装/更新状态,不再强制联网下载 JSON
const [all, updates] = await Promise.all([
invoke('get_all_software'),
invoke('get_installed_software'),
invoke('get_updates')
]);

View File

@@ -1,190 +0,0 @@
<template>
<main class="content">
<header class="content-header">
<div class="header-left">
<h1>全部软件</h1>
<p class="count"> {{ filteredSoftware.length }} 个项目</p>
</div>
<div class="header-actions">
<button
@click="store.fetchAll"
class="secondary-btn action-btn"
:disabled="store.loading || store.isBusy"
>
<span class="icon" :class="{ 'spinning': store.loading }">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 2v6h-6"></path>
<path d="M3 12a9 9 0 0 1 15-6.7L21 8"></path>
<path d="M3 22v-6h6"></path>
<path d="M21 12a9 9 0 0 1-15 6.7L3 16"></path>
</svg>
</span>
{{ store.loading ? '正在扫描...' : '重新扫描' }}
</button>
<div class="search-box">
<input
type="text"
v-model="searchQuery"
placeholder="搜索已安装的软件..."
class="search-input"
:disabled="store.isBusy"
/>
</div>
</div>
</header>
<div v-if="store.loading && store.sortedAllSoftware.length === 0" class="loading-state">
<div class="spinner"></div>
<p>正在读取已安装软件列表...</p>
</div>
<div v-else class="software-list">
<SoftwareCard
v-for="item in filteredSoftware"
:key="item.id"
:software="item"
/>
</div>
</main>
</template>
<script setup lang="ts">
import SoftwareCard from '../components/SoftwareCard.vue';
import { useSoftwareStore } from '../store/software';
import { onMounted, ref, computed } from 'vue';
const store = useSoftwareStore();
const searchQuery = ref('');
onMounted(() => {
if (store.allSoftware.length === 0) {
store.fetchAll();
}
});
const filteredSoftware = computed(() => {
const data = store.sortedAllSoftware;
if (!searchQuery.value) return data;
const q = searchQuery.value.toLowerCase();
return data.filter(s =>
s.name.toLowerCase().includes(q) || s.id.toLowerCase().includes(q)
);
});
</script>
<style scoped>
.content {
flex: 1;
padding: 40px 60px;
overflow-y: auto;
}
.content-header {
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-bottom: 30px;
}
.header-left h1 {
font-size: 32px;
font-weight: 700;
}
.header-left .count {
font-size: 14px;
color: var(--text-sec);
margin-top: 4px;
}
.header-actions {
display: flex;
align-items: center;
gap: 16px;
}
.action-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
border-radius: 10px;
font-weight: 600;
font-size: 13px;
cursor: pointer;
transition: all 0.2s ease;
border: 1px solid var(--border-color);
background-color: var(--bg-light);
color: var(--text-main);
white-space: nowrap;
}
.action-btn:hover:not(:disabled) {
background-color: white;
border-color: var(--primary-color);
color: var(--primary-color);
}
.action-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.icon {
display: flex;
align-items: center;
}
.icon.spinning {
animation: spin 1s linear infinite;
}
.search-input {
width: 240px;
padding: 8px 16px;
border-radius: 10px;
border: 1px solid var(--border-color);
background-color: white;
font-size: 13px;
outline: none;
transition: all 0.2s ease;
}
.search-input:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.1);
}
.search-input:disabled {
background-color: #F2F2F7;
cursor: not-allowed;
}
.software-list {
display: flex;
flex-direction: column;
}
.loading-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 300px;
color: var(--text-sec);
}
.spinner {
width: 32px;
height: 32px;
border: 3px solid rgba(0, 122, 255, 0.1);
border-top-color: var(--primary-color);
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 16px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>