From 693922a659c1011328f7f4cd2d2263c2ba574dd5 Mon Sep 17 00:00:00 2001 From: Julian Freeman Date: Tue, 25 Nov 2025 23:09:06 -0400 Subject: [PATCH] add export and import --- src/App.vue | 127 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 120 insertions(+), 7 deletions(-) diff --git a/src/App.vue b/src/App.vue index 36325af..6e41144 100644 --- a/src/App.vue +++ b/src/App.vue @@ -6,10 +6,31 @@
+ + + +
+ + +
+ + + +
⚠️ {{ errorMsg }}
@@ -30,14 +51,14 @@ CPU 型号 {{ report.hardware.cpu_name }}
- +
整机型号 (System) {{ report.hardware.sys_vendor }} {{ report.hardware.sys_product }}
- +
主板型号 (BaseBoard) @@ -195,6 +216,7 @@ import { invoke } from '@tauri-apps/api/core'; const report = ref(null); const loading = ref(false); const errorMsg = ref(''); +const fileInput = ref(null); // 文件输入框的引用 const hasStorageDanger = computed(() => { return report.value?.storage.some(d => d.is_danger); @@ -228,16 +250,75 @@ function getBatteryColor(percentage) { } function formatTime(wmiTime) { - // 如果是空值或者格式不对,直接返回 if (!wmiTime) return "Unknown Time"; - // 简单的容错处理,如果是标准 ISO 时间或自定义格式 return wmiTime.replace('T', ' ').substring(0, 19); } +// --- 导出报告功能 --- +function exportReport() { + if (!report.value) return; + + try { + const dataStr = JSON.stringify(report.value, null, 2); + // 使用 Blob 创建文件对象 + const blob = new Blob([dataStr], { type: "application/json" }); + const url = URL.createObjectURL(blob); + + // 创建临时链接触发下载 + const link = document.createElement('a'); + link.href = url; + // 文件名包含时间戳,避免重名 + const timestamp = new Date().toISOString().slice(0, 19).replace(/[:T]/g, "-"); + link.download = `SystemDoctor_Report_${timestamp}.json`; + document.body.appendChild(link); + link.click(); + + // 清理 + document.body.removeChild(link); + URL.revokeObjectURL(url); + } catch (err) { + errorMsg.value = "导出失败: " + err.message; + } +} + +// --- 导入报告功能 --- +function triggerImport() { + // 触发隐藏的文件输入框点击 + fileInput.value.click(); +} + +function handleFileImport(event) { + const file = event.target.files[0]; + if (!file) return; + + const reader = new FileReader(); + reader.onload = (e) => { + try { + const json = JSON.parse(e.target.result); + // 简单的格式校验:检查是否有关键字段 + if (json && json.hardware && json.storage) { + report.value = json; + errorMsg.value = ''; + } else { + errorMsg.value = "无效的报告文件:格式不正确或内容缺失。"; + } + } catch (err) { + errorMsg.value = "导入失败: 无法解析文件 (" + err.message + ")"; + } + }; + reader.readAsText(file); + // 清空 value 以便允许重复选择同一个文件 + event.target.value = ''; +} + async function startScan() { + // 1. 如果界面已有报告,先清空 + if (report.value) { + report.value = null; + } + loading.value = true; errorMsg.value = ''; - report.value = null; try { const result = await invoke('run_diagnosis'); @@ -267,7 +348,6 @@ body { max-width: 960px; margin: 0 auto; padding: 30px 20px; - /* 关键修改:border-box 让 padding 包含在 height 内 */ box-sizing: border-box; font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; color: #2c3e50; @@ -298,6 +378,12 @@ h1 { flex-direction: column; align-items: center; margin-bottom: 35px; + gap: 15px; /* 增加按钮组之间的间距 */ +} + +.secondary-actions { + display: flex; + gap: 15px; } .scan-btn { @@ -334,8 +420,35 @@ h1 { opacity: 0.8; } +/* 辅助按钮样式 */ +.secondary-btn { + background: white; + border: 1px solid #dcdfe6; + color: #606266; + padding: 8px 20px; + font-size: 0.9rem; + border-radius: 20px; + cursor: pointer; + transition: all 0.2s; + display: flex; + align-items: center; + gap: 5px; +} + +.secondary-btn:hover:not(:disabled) { + color: #409eff; + border-color: #c6e2ff; + background-color: #ecf5ff; +} + +.secondary-btn:disabled { + color: #c0c4cc; + cursor: not-allowed; + background-color: #f5f7fa; +} + .error-box { - margin-top: 15px; + margin-top: 5px; padding: 12px 20px; background-color: #ffeaea; color: #c0392b;