diff --git a/bun.lockb b/bun.lockb index 52a6cbe..8fa750c 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/next-env.d.ts b/next-env.d.ts index 9edff1c..c4b7818 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/package.json b/package.json index aa0a484..8d0b041 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "tauri-plugin-system-info-api": "^2.0.10" }, "devDependencies": { - "@tailwindcss/postcss": "^4.1.16", + "@tailwindcss/postcss": "^4.1.17", "@tauri-apps/cli": "^2.9.3", "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^6.9.1", @@ -73,7 +73,7 @@ "postcss-import": "^16.1.1", "postcss-nesting": "^13.0.2", "tailwind-merge": "3.0.2", - "tailwindcss": "^4.1.16", + "tailwindcss": "^4.1.17", "typescript": "^5.9.3" }, "browserslist": { diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index e2e13ae..ed1131c 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -34,6 +34,7 @@ dependencies = [ "tauri-plugin-store", "tauri-plugin-system-info", "tauri-plugin-valtio", + "tokio", "walkdir", "window-vibrancy", "winreg 0.55.0", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index e238379..7461b6d 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -54,6 +54,7 @@ tauri-plugin-deep-link = "2.4.5" anyhow = "1.0.100" notify = "8.2.0" dirs = "6.0.0" +tokio = { version = "1.40", features = ["process"] } [target.'cfg(windows)'.dependencies] # Windows Only winreg = "0.55.0" diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs index a2fbe5d..0d8bb61 100644 --- a/src-tauri/src/cmds.rs +++ b/src-tauri/src/cmds.rs @@ -336,3 +336,47 @@ pub async fn download_app_update( pub fn install_app_update(installer_path: String) -> Result<(), String> { wrap_err!(install_update(&installer_path)) } + +/// 获取 PowerShell Get-ComputerInfo 信息(异步版本) +#[tauri::command] +#[cfg(target_os = "windows")] +pub async fn get_computer_info() -> Result { + use tokio::process::Command; + + // 异步执行 PowerShell 命令获取计算机信息并转换为 JSON + let output = Command::new("powershell") + .args(&[ + "-NoProfile", + "-Command", + "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-ComputerInfo | Select-Object OsName, OSDisplayVersion, BiosSMBIOSBIOSVersion, CsManufacturer, CsName | ConvertTo-Json -Compress" + ]) + .output() + .await + .map_err(|e| format!("执行 PowerShell 命令失败: {}", e))?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + return Err(format!("PowerShell 命令执行失败: {}", stderr)); + } + + // 处理 PowerShell 输出,移除 BOM 和空白字符 + let stdout = String::from_utf8_lossy(&output.stdout); + let cleaned = stdout.trim().trim_start_matches('\u{feff}'); // 移除 BOM + + // 如果输出为空,返回空对象 + if cleaned.is_empty() { + return Ok(serde_json::json!({})); + } + + let json: serde_json::Value = serde_json::from_str(cleaned) + .map_err(|e| format!("解析 JSON 失败: {},原始输出: {}", e, cleaned))?; + + Ok(json) +} + +/// 获取 PowerShell Get-ComputerInfo 信息(非 Windows 平台返回空对象) +#[tauri::command] +#[cfg(not(target_os = "windows"))] +pub async fn get_computer_info() -> Result { + Ok(serde_json::json!({})) +} \ No newline at end of file diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index a18afbb..a82ddc9 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -169,6 +169,7 @@ fn main() { cmds::check_app_update, cmds::download_app_update, cmds::install_app_update, + cmds::get_computer_info, on_button_clicked ]) .run(ctx) diff --git a/src/app/(main)/gear/page.tsx b/src/app/(main)/gear/page.tsx index 60d45e4..a194e05 100644 --- a/src/app/(main)/gear/page.tsx +++ b/src/app/(main)/gear/page.tsx @@ -7,11 +7,12 @@ import { CardTool, } from "@/components/window/Card" import { ToolButton } from "@/components/window/ToolButton" -import { Chip } from "@heroui/react" +import { Chip, Skeleton } from "@heroui/react" import { Refresh, SettingConfig } from "@icon-park/react" // import { version } from "@tauri-apps/plugin-os" import { useEffect, useState } from "react" import { type AllSystemInfo, allSysInfo } from "tauri-plugin-system-info-api" +import { invoke } from "@tauri-apps/api/core" export default function Page() { return ( @@ -27,14 +28,12 @@ export default function Page() { 云同步 */} - - 刷新 - + - + @@ -43,39 +42,336 @@ export default function Page() { } function HardwareInfo() { - const [allSysData, setAllSysData] = useState() - // const [memInfo, setMemInfo] = useState("") - // const [staticData, setStaticData] = useState("") - // const [cpuData, setCpuData] = useState("") - // const [batteryData, setBatteryData] = useState("") + return ( + { + // 触发刷新事件 + window.dispatchEvent(new CustomEvent('refresh-hardware-info')) + }}> + 刷新 + + ) +} +interface ComputerInfo { + OsName?: string + OSDisplayVersion?: string + BiosSMBIOSBIOSVersion?: string + CsManufacturer?: string + CsName?: string +} + +function HardwareInfoContent() { + const [allSysData, setAllSysData] = useState() + const [computerInfo, setComputerInfo] = useState({}) + const [loading, setLoading] = useState(false) + + const fetchData = async () => { + setLoading(true) + try { + // 并行获取系统信息和 PowerShell 信息 + const [sys, computerInfoData] = await Promise.all([ + allSysInfo(), + invoke("get_computer_info").catch((error) => { + console.error("获取 PowerShell 信息失败:", error) + return {} as ComputerInfo + }) + ]) + + console.log("系统信息:", sys) + console.log("PowerShell 信息:", computerInfoData) + + if (sys?.cpus) { + console.log("CPU数据:", sys.cpus) + console.log("第一个CPU:", sys.cpus[0]) + if (sys.cpus[0]) { + console.log("CPU字段:", Object.keys(sys.cpus[0])) + } + } + setAllSysData(sys) + setComputerInfo(computerInfoData) + } catch (error) { + console.error("获取系统信息失败:", error) + } finally { + setLoading(false) + } + } useEffect(() => { - const fetchData = async () => { - const sys = await allSysInfo() - console.log(sys) - setAllSysData(sys) - // console.log(await memoryInfo()) - // console.log(await staticInfo()) - // console.log(await cpuInfo()) - // console.log(await batteries()) - } - void fetchData() + + // 监听刷新事件 + const handleRefresh = () => { + void fetchData() + } + window.addEventListener('refresh-hardware-info', handleRefresh) + return () => { + window.removeEventListener('refresh-hardware-info', handleRefresh) + } }, []) + const formatBytes = (bytes?: number) => { + if (!bytes) return "未知" + const gb = bytes / 1024 / 1024 / 1024 + if (gb >= 1) { + return `${gb.toFixed(2)}GB` + } + const mb = bytes / 1024 / 1024 + return `${mb.toFixed(2)}MB` + } + + // 如果 PowerShell 提供了 OSDisplayVersion,直接使用;否则尝试从 kernel_version 推断 + const windowsVersionCode = computerInfo.OSDisplayVersion || null + const memoryUsagePercent = allSysData?.total_memory && allSysData?.used_memory !== undefined + ? Math.round((allSysData.used_memory / allSysData.total_memory) * 100) + : null + + // 计算所有CPU核心的平均频率(统一转换为GHz) + const averageCpuFrequency = allSysData?.cpus && allSysData.cpus.length > 0 + ? (() => { + // 尝试多个可能的频率字段名 + const frequencies = allSysData.cpus + .map(cpu => { + // 尝试不同的字段名 + const freq = (cpu as any).frequency ?? (cpu as any).freq ?? (cpu as any).clock_speed + return freq + }) + .filter((freq): freq is number => { + // 确保是有效的数字且大于0 + return typeof freq === 'number' && !isNaN(freq) && freq > 0 + }) + + if (frequencies.length === 0) { + console.log("未找到有效的CPU频率数据,CPU对象:", allSysData.cpus[0]) + return null + } + + const sum = frequencies.reduce((acc, freq) => acc + freq, 0) + const avg = sum / frequencies.length + + // 判断单位并统一转换为GHz + // 如果值在2-10范围,可能是GHz + // 如果值在2000-10000范围,可能是MHz(需要除以1000) + // 如果值在百万级别(2000000+),可能是Hz(需要除以1,000,000) + let freqInGhz: number + if (avg >= 1_000_000) { + // Hz单位,转换为GHz + freqInGhz = avg / 1_000_000 + } else if (avg >= 1000) { + // MHz单位,转换为GHz + freqInGhz = avg / 1000 + } else { + // 已经是GHz单位 + freqInGhz = avg + } + + console.log("CPU频率数据:", frequencies, "原始平均值:", avg, "转换为GHz:", freqInGhz) + + return freqInGhz + })() + : null + + // 如果正在加载,显示 Skeleton 骨架屏 + if (loading) { + return ( +
+ {/* 系统信息 Skeleton */} +
+ +
+ + +
+
+ + {/* 主板信息 Skeleton */} +
+ +
+ + +
+
+ + {/* CPU 信息 Skeleton */} +
+ +
+ + + +
+
+ + {/* 内存信息 Skeleton */} +
+ +
+ + + +
+
+ + {/* GPU 信息 Skeleton */} +
+ +
+ +
+
+
+ ) + } + return ( -
- CPU型号: {allSysData?.cpus[0]?.brand} - 线程数: {allSysData?.cpu_count} - - 系统: {allSysData?.name} {allSysData?.os_version} - - - 内存: - {allSysData?.total_memory && - `${(allSysData.total_memory / 1024 / 1024 / 1024).toFixed(0)}GB`} - +
+ {/* 系统信息 */} +
+
系统信息
+
+ {computerInfo.OsName && ( + + 系统: {computerInfo.OsName} + {windowsVersionCode && ( + ({windowsVersionCode}) + )} + + )} + {!computerInfo.OsName && ( + + 系统: {allSysData?.name || "未知"} {allSysData?.os_version || ""} + {allSysData?.kernel_version && ( + <> + {" "}{allSysData.kernel_version} + {windowsVersionCode && ( + ({windowsVersionCode}) + )} + + )} + + )} + {computerInfo.CsName && ( + + 主机名: {computerInfo.CsName} + + )} + {!computerInfo.CsName && allSysData?.hostname && ( + + 主机名: {allSysData.hostname} + + )} +
+
+ + {/* 主板信息 */} + {(computerInfo.CsManufacturer || computerInfo.BiosSMBIOSBIOSVersion) && ( +
+
主板
+
+ {computerInfo.CsManufacturer && ( + + 制造商: {computerInfo.CsManufacturer} + + )} + {computerInfo.BiosSMBIOSBIOSVersion && ( + + BIOS版本: {computerInfo.BiosSMBIOSBIOSVersion} + + )} +
+
+ )} + + {/* CPU 信息 */} +
+
处理器
+
+ + 型号: {allSysData?.cpus?.[0]?.brand || "未知"} + + {averageCpuFrequency !== null && ( + + 频率: {averageCpuFrequency.toFixed(2)} GHz + + )} + + 核心数: {allSysData?.cpu_count || "未知"} + +
+
+ + {/* 内存信息 */} + {allSysData?.total_memory && ( +
+
内存
+
+ + 总容量: {formatBytes(allSysData.total_memory)} + + {allSysData.used_memory !== undefined && ( + + 已用: {formatBytes(allSysData.used_memory)} + {memoryUsagePercent !== null && ( + ({memoryUsagePercent}%) + )} + + )} + {allSysData.total_memory !== undefined && allSysData.used_memory !== undefined && ( + + 可用: {formatBytes(allSysData.total_memory - allSysData.used_memory)} + + )} +
+
+ )} + + {/* GPU 信息 */} + {allSysData?.components && allSysData.components.length > 0 && ( + (() => { + const gpuComponents = allSysData.components.filter((comp) => + comp.label?.toLowerCase().includes('gpu') || + comp.label?.toLowerCase().includes('graphics') || + comp.label?.toLowerCase().includes('显卡') + ) + + if (gpuComponents.length === 0) return null + + return ( +
+
显卡
+
+ {gpuComponents.map((gpu, index) => ( + + GPU{index > 0 ? ` ${index + 1}` : ""}: {gpu.label || "未知"} + {gpu.temperature !== undefined && ( + ({gpu.temperature}°C{gpu.max !== undefined ? ` / ${gpu.max}°C` : ""}) + )} + + ))} +
+
+ ) + })() + )} + + {/* 电池信息 */} + {allSysData?.batteries && allSysData.batteries.length > 0 && ( +
+
电池
+
+ {allSysData.batteries.map((battery, index) => ( + + 电池{index > 0 ? ` ${index + 1}` : ""}: + {battery.state && `${battery.state} `} + {battery.state_of_charge !== undefined && `${battery.state_of_charge}% `} + {battery.energy_full !== undefined && battery.energy !== undefined && ( + ({formatBytes(battery.energy)} / {formatBytes(battery.energy_full)}) + )} + + ))} +
+
+ )}
) }