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;