update file struct

This commit is contained in:
Julian Freeman
2026-03-30 19:22:11 -04:00
parent 626a9c21b0
commit 6b64f36cfb
3 changed files with 50 additions and 12 deletions

View File

@@ -16,6 +16,12 @@ pub struct AppSettings {
pub repo_url: String, pub repo_url: String,
} }
#[derive(Clone, Serialize, Deserialize)]
pub struct EssentialsRepo {
pub version: String,
pub essentials: Vec<Software>,
}
impl Default for AppSettings { impl Default for AppSettings {
fn default() -> Self { fn default() -> Self {
Self { Self {
@@ -99,15 +105,15 @@ async fn sync_essentials(app: AppHandle) -> Result<bool, String> {
Ok(response) => { Ok(response) => {
if response.status().is_success() { if response.status().is_success() {
let content = response.text().await.map_err(|e| e.to_string())?; let content = response.text().await.map_err(|e| e.to_string())?;
// 验证 JSON 格式 // 验证 JSON 格式(新格式:{ version: string, essentials: Vec<Software> }
let validation: Result<Vec<Software>, _> = serde_json::from_str(&content); let validation: Result<EssentialsRepo, _> = serde_json::from_str(&content);
if validation.is_ok() { if validation.is_ok() {
let path = get_essentials_path(&app); let path = get_essentials_path(&app);
fs::write(path, content).map_err(|e| e.to_string())?; fs::write(path, content).map_err(|e| e.to_string())?;
emit_log(&app, "sync-essentials", "Result", "Essentials list updated successfully.", "success"); emit_log(&app, "sync-essentials", "Result", "Essentials list updated successfully.", "success");
Ok(true) Ok(true)
} else { } else {
emit_log(&app, "sync-essentials", "Error", "Invalid JSON format from repository.", "error"); emit_log(&app, "sync-essentials", "Error", "Invalid JSON format from repository. Expected { version, essentials }.", "error");
Err("Invalid JSON format".to_string()) Err("Invalid JSON format".to_string())
} }
} else { } else {
@@ -118,7 +124,7 @@ async fn sync_essentials(app: AppHandle) -> Result<bool, String> {
} }
Err(e) => { Err(e) => {
emit_log(&app, "sync-essentials", "Skipped", &format!("Network issue: {}. Using local cache.", e), "info"); emit_log(&app, "sync-essentials", "Skipped", &format!("Network issue: {}. Using local cache.", e), "info");
Ok(false) // 静默失败,返回 false 表示未更新但可继续 Ok(false)
} }
} }
} }
@@ -132,14 +138,14 @@ async fn initialize_app(app: AppHandle) -> Result<bool, String> {
} }
#[tauri::command] #[tauri::command]
fn get_essentials(app: AppHandle) -> Vec<Software> { fn get_essentials(app: AppHandle) -> Option<EssentialsRepo> {
let file_path = get_essentials_path(&app); let file_path = get_essentials_path(&app);
if !file_path.exists() { if !file_path.exists() {
return vec![]; return None;
} }
let content = fs::read_to_string(file_path).unwrap_or_else(|_| "[]".to_string()); let content = fs::read_to_string(file_path).unwrap_or_default();
serde_json::from_str(&content).unwrap_or_default() serde_json::from_str(&content).ok()
} }
#[tauri::command] #[tauri::command]

View File

@@ -15,6 +15,7 @@ export interface LogEntry {
export const useSoftwareStore = defineStore('software', { export const useSoftwareStore = defineStore('software', {
state: () => ({ state: () => ({
essentials: [] as any[], essentials: [] as any[],
essentialsVersion: '',
updates: [] as any[], updates: [] as any[],
allSoftware: [] as any[], allSoftware: [] as any[],
selectedEssentialIds: [] as string[], selectedEssentialIds: [] as string[],
@@ -117,7 +118,14 @@ export const useSoftwareStore = defineStore('software', {
}, },
async fetchEssentials() { async fetchEssentials() {
this.essentials = await invoke('get_essentials') const res = await invoke('get_essentials') as any;
if (res) {
this.essentials = res.essentials;
this.essentialsVersion = res.version;
} else {
this.essentials = [];
this.essentialsVersion = '';
}
}, },
async fetchUpdates() { async fetchUpdates() {
if (this.isBusy) return; if (this.isBusy) return;
@@ -156,12 +164,20 @@ export const useSoftwareStore = defineStore('software', {
// 在获取全量数据之前,先同步云端清单 // 在获取全量数据之前,先同步云端清单
await invoke('sync_essentials').catch(() => {}); await invoke('sync_essentials').catch(() => {});
const [essentials, all, updates] = await Promise.all([ const [repo, all, updates] = await Promise.all([
invoke('get_essentials'), invoke('get_essentials') as Promise<any>,
invoke('get_all_software'), invoke('get_all_software'),
invoke('get_updates') invoke('get_updates')
]); ]);
this.essentials = essentials as any[];
if (repo) {
this.essentials = repo.essentials;
this.essentialsVersion = repo.version;
} else {
this.essentials = [];
this.essentialsVersion = '';
}
this.allSoftware = all as any[]; this.allSoftware = all as any[];
this.updates = updates as any[]; this.updates = updates as any[];
this.lastFetched = Date.now(); this.lastFetched = Date.now();

View File

@@ -3,6 +3,7 @@
<header class="content-header"> <header class="content-header">
<div class="header-left"> <div class="header-left">
<h1>装机必备</h1> <h1>装机必备</h1>
<span v-if="store.essentialsVersion" class="version-badge">版本: {{ store.essentialsVersion }}</span>
</div> </div>
<div class="header-actions"> <div class="header-actions">
<button <button
@@ -101,6 +102,21 @@ onMounted(() => {
margin-bottom: 24px; margin-bottom: 24px;
} }
.header-left {
display: flex;
align-items: baseline;
gap: 12px;
}
.version-badge {
font-size: 13px;
font-weight: 500;
color: var(--text-sec);
background-color: rgba(0, 0, 0, 0.05);
padding: 4px 10px;
border-radius: 20px;
}
.content-header h1 { .content-header h1 {
font-size: 32px; font-size: 32px;
font-weight: 700; font-weight: 700;