[fix] powershell black screens and try to solve update re-start not working
This commit is contained in:
2
next-env.d.ts
vendored
2
next-env.d.ts
vendored
@@ -1,6 +1,6 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
import "./.next/types/routes.d.ts";
|
import "./.next/dev/types/routes.d.ts";
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"tauri": "tauri",
|
"tauri": "tauri",
|
||||||
"build": "tauri build",
|
"build": "tauri build",
|
||||||
"build-fast": "tauri build -b nsis -- --profile dev",
|
"build-fast": "tauri build -b nsis -- --profile dev",
|
||||||
|
"build-fast-prod": "tauri build -b nsis -- --profile fast-release",
|
||||||
"dev": "tauri dev",
|
"dev": "tauri dev",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"fix": "next lint --fix"
|
"fix": "next lint --fix"
|
||||||
|
|||||||
@@ -21,6 +21,13 @@ strip = true # Remove debug symbols
|
|||||||
opt-level = 0 # 关闭优化
|
opt-level = 0 # 关闭优化
|
||||||
debug = true # 保留调试信息
|
debug = true # 保留调试信息
|
||||||
|
|
||||||
|
[profile.fast-release]
|
||||||
|
inherits = "release"
|
||||||
|
lto = false # 关闭链接时优化,加快构建速度
|
||||||
|
codegen-units = 16 # 增加并行编译单元,加快构建速度
|
||||||
|
strip = false # 不剥离调试符号,加快构建速度
|
||||||
|
opt-level = 2 # 使用适中的优化级别(比 release 的 "s" 更快)
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { version = "2.5.1", features = [] }
|
tauri-build = { version = "2.5.1", features = [] }
|
||||||
|
|
||||||
|
|||||||
@@ -377,14 +377,23 @@ pub fn install_app_update(installer_path: String) -> Result<(), String> {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub async fn get_computer_info() -> Result<serde_json::Value, String> {
|
pub async fn get_computer_info() -> Result<serde_json::Value, String> {
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
#[cfg(windows)]
|
||||||
|
const CREATE_NO_WINDOW: u32 = 0x08000000;
|
||||||
|
|
||||||
// 异步执行 PowerShell 命令获取计算机信息并转换为 JSON
|
// 异步执行 PowerShell 命令获取计算机信息并转换为 JSON
|
||||||
let output = Command::new("powershell")
|
let mut cmd = Command::new("powershell");
|
||||||
.args(&[
|
cmd.args(&[
|
||||||
"-NoProfile",
|
"-NoProfile",
|
||||||
"-Command",
|
"-WindowStyle",
|
||||||
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-ComputerInfo | Select-Object OsName, OSDisplayVersion, BiosSMBIOSBIOSVersion, CsManufacturer, CsName | ConvertTo-Json -Compress"
|
"Hidden",
|
||||||
])
|
"-Command",
|
||||||
|
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-ComputerInfo | Select-Object OsName, OSDisplayVersion, BiosSMBIOSBIOSVersion, CsManufacturer, CsName | ConvertTo-Json -Compress"
|
||||||
|
]);
|
||||||
|
#[cfg(windows)]
|
||||||
|
cmd.creation_flags(CREATE_NO_WINDOW);
|
||||||
|
let output = cmd
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("执行 PowerShell 命令失败: {}", e))?;
|
.map_err(|e| format!("执行 PowerShell 命令失败: {}", e))?;
|
||||||
@@ -423,14 +432,17 @@ pub async fn get_computer_info() -> Result<serde_json::Value, String> {
|
|||||||
|
|
||||||
// 如果没有从 OSDisplayVersion 获取到版本代码,尝试从注册表获取 ReleaseId
|
// 如果没有从 OSDisplayVersion 获取到版本代码,尝试从注册表获取 ReleaseId
|
||||||
if !json.get("ReleaseId").and_then(|v| v.as_str()).is_some() {
|
if !json.get("ReleaseId").and_then(|v| v.as_str()).is_some() {
|
||||||
let release_id_output = Command::new("powershell")
|
let mut release_cmd = Command::new("powershell");
|
||||||
.args(&[
|
release_cmd.args(&[
|
||||||
"-NoProfile",
|
"-NoProfile",
|
||||||
"-Command",
|
"-WindowStyle",
|
||||||
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; try { (Get-ItemProperty -Path 'HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion').ReleaseId } catch { $null }"
|
"Hidden",
|
||||||
])
|
"-Command",
|
||||||
.output()
|
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; try { (Get-ItemProperty -Path 'HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion').ReleaseId } catch { $null }"
|
||||||
.await;
|
]);
|
||||||
|
#[cfg(windows)]
|
||||||
|
release_cmd.creation_flags(CREATE_NO_WINDOW);
|
||||||
|
let release_id_output = release_cmd.output().await;
|
||||||
|
|
||||||
if let Ok(release_output) = release_id_output {
|
if let Ok(release_output) = release_id_output {
|
||||||
if release_output.status.success() {
|
if release_output.status.success() {
|
||||||
@@ -552,14 +564,23 @@ pub struct MotherboardInfo {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub async fn get_memory_info() -> Result<Vec<MemoryInfo>, String> {
|
pub async fn get_memory_info() -> Result<Vec<MemoryInfo>, String> {
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
#[cfg(windows)]
|
||||||
|
const CREATE_NO_WINDOW: u32 = 0x08000000;
|
||||||
|
|
||||||
// 执行 PowerShell 命令获取内存信息
|
// 执行 PowerShell 命令获取内存信息
|
||||||
let output = Command::new("powershell")
|
let mut cmd = Command::new("powershell");
|
||||||
.args(&[
|
cmd.args(&[
|
||||||
"-NoProfile",
|
"-NoProfile",
|
||||||
"-Command",
|
"-WindowStyle",
|
||||||
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-WmiObject Win32_PhysicalMemory | Select-Object Capacity, Manufacturer, ConfiguredClockSpeed, Speed | ConvertTo-Json -Compress"
|
"Hidden",
|
||||||
])
|
"-Command",
|
||||||
|
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-WmiObject Win32_PhysicalMemory | Select-Object Capacity, Manufacturer, ConfiguredClockSpeed, Speed | ConvertTo-Json -Compress"
|
||||||
|
]);
|
||||||
|
#[cfg(windows)]
|
||||||
|
cmd.creation_flags(CREATE_NO_WINDOW);
|
||||||
|
let output = cmd
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("执行 PowerShell 命令失败: {}", e))?;
|
.map_err(|e| format!("执行 PowerShell 命令失败: {}", e))?;
|
||||||
@@ -635,14 +656,23 @@ pub async fn get_memory_info() -> Result<Vec<MemoryInfo>, String> {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub async fn get_monitor_info() -> Result<Vec<MonitorInfo>, String> {
|
pub async fn get_monitor_info() -> Result<Vec<MonitorInfo>, String> {
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
#[cfg(windows)]
|
||||||
|
const CREATE_NO_WINDOW: u32 = 0x08000000;
|
||||||
|
|
||||||
// 执行 PowerShell 命令获取显示器信息
|
// 执行 PowerShell 命令获取显示器信息
|
||||||
let output = Command::new("powershell")
|
let mut cmd = Command::new("powershell");
|
||||||
.args(&[
|
cmd.args(&[
|
||||||
"-NoProfile",
|
"-NoProfile",
|
||||||
"-Command",
|
"-WindowStyle",
|
||||||
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-CimInstance -Namespace root/wmi -ClassName WmiMonitorID | ForEach-Object { [PSCustomObject]@{ Manufacturer = [System.Text.Encoding]::ASCII.GetString($_.ManufacturerName) -replace \"`0\"; Model = [System.Text.Encoding]::ASCII.GetString($_.UserFriendlyName) -replace \"`0\" } } | ConvertTo-Json -Compress"
|
"Hidden",
|
||||||
])
|
"-Command",
|
||||||
|
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-CimInstance -Namespace root/wmi -ClassName WmiMonitorID | ForEach-Object { [PSCustomObject]@{ Manufacturer = [System.Text.Encoding]::ASCII.GetString($_.ManufacturerName) -replace \"`0\"; Model = [System.Text.Encoding]::ASCII.GetString($_.UserFriendlyName) -replace \"`0\" } } | ConvertTo-Json -Compress"
|
||||||
|
]);
|
||||||
|
#[cfg(windows)]
|
||||||
|
cmd.creation_flags(CREATE_NO_WINDOW);
|
||||||
|
let output = cmd
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("执行 PowerShell 命令失败: {}", e))?;
|
.map_err(|e| format!("执行 PowerShell 命令失败: {}", e))?;
|
||||||
@@ -673,34 +703,43 @@ pub async fn get_monitor_info() -> Result<Vec<MonitorInfo>, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 尝试获取刷新率和分辨率信息
|
// 尝试获取刷新率和分辨率信息
|
||||||
let _display_output = Command::new("powershell")
|
let mut _display_cmd = Command::new("powershell");
|
||||||
.args(&[
|
_display_cmd.args(&[
|
||||||
"-NoProfile",
|
"-NoProfile",
|
||||||
"-Command",
|
"-WindowStyle",
|
||||||
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-CimInstance -Namespace root/wmi -ClassName WmiMonitorBasicDisplayParams | Select-Object MaxHorizontalImageSize, MaxVerticalImageSize | ConvertTo-Json -Compress"
|
"Hidden",
|
||||||
])
|
"-Command",
|
||||||
.output()
|
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-CimInstance -Namespace root/wmi -ClassName WmiMonitorBasicDisplayParams | Select-Object MaxHorizontalImageSize, MaxVerticalImageSize | ConvertTo-Json -Compress"
|
||||||
.await;
|
]);
|
||||||
|
#[cfg(windows)]
|
||||||
|
_display_cmd.creation_flags(CREATE_NO_WINDOW);
|
||||||
|
let _display_output = _display_cmd.output().await;
|
||||||
|
|
||||||
// 获取刷新率信息
|
// 获取刷新率信息
|
||||||
let _refresh_output = Command::new("powershell")
|
let mut _refresh_cmd = Command::new("powershell");
|
||||||
.args(&[
|
_refresh_cmd.args(&[
|
||||||
"-NoProfile",
|
"-NoProfile",
|
||||||
"-Command",
|
"-WindowStyle",
|
||||||
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-CimInstance -Namespace root/wmi -ClassName WmiMonitorListedSupportedSourceModes | Select-Object -First 1 -ExpandProperty ModeTimings | Select-Object -First 1 -ExpandProperty RefreshRate | ConvertTo-Json -Compress"
|
"Hidden",
|
||||||
])
|
"-Command",
|
||||||
.output()
|
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-CimInstance -Namespace root/wmi -ClassName WmiMonitorListedSupportedSourceModes | Select-Object -First 1 -ExpandProperty ModeTimings | Select-Object -First 1 -ExpandProperty RefreshRate | ConvertTo-Json -Compress"
|
||||||
.await;
|
]);
|
||||||
|
#[cfg(windows)]
|
||||||
|
_refresh_cmd.creation_flags(CREATE_NO_WINDOW);
|
||||||
|
let _refresh_output = _refresh_cmd.output().await;
|
||||||
|
|
||||||
// 获取当前显示器的分辨率和刷新率
|
// 获取当前显示器的分辨率和刷新率
|
||||||
let current_display_output = Command::new("powershell")
|
let mut current_display_cmd = Command::new("powershell");
|
||||||
.args(&[
|
current_display_cmd.args(&[
|
||||||
"-NoProfile",
|
"-NoProfile",
|
||||||
"-Command",
|
"-WindowStyle",
|
||||||
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Add-Type -AssemblyName System.Windows.Forms; $screens = [System.Windows.Forms.Screen]::AllScreens; $screens | ForEach-Object { [PSCustomObject]@{ Width = $_.Bounds.Width; Height = $_.Bounds.Height; Primary = $_.Primary } } | ConvertTo-Json -Compress"
|
"Hidden",
|
||||||
])
|
"-Command",
|
||||||
.output()
|
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Add-Type -AssemblyName System.Windows.Forms; $screens = [System.Windows.Forms.Screen]::AllScreens; $screens | ForEach-Object { [PSCustomObject]@{ Width = $_.Bounds.Width; Height = $_.Bounds.Height; Primary = $_.Primary } } | ConvertTo-Json -Compress"
|
||||||
.await;
|
]);
|
||||||
|
#[cfg(windows)]
|
||||||
|
current_display_cmd.creation_flags(CREATE_NO_WINDOW);
|
||||||
|
let current_display_output = current_display_cmd.output().await;
|
||||||
|
|
||||||
// 合并显示器信息
|
// 合并显示器信息
|
||||||
if let Ok(display_result) = current_display_output {
|
if let Ok(display_result) = current_display_output {
|
||||||
@@ -783,14 +822,23 @@ pub async fn get_monitor_info() -> Result<Vec<MonitorInfo>, String> {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub async fn get_motherboard_info() -> Result<MotherboardInfo, String> {
|
pub async fn get_motherboard_info() -> Result<MotherboardInfo, String> {
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
#[cfg(windows)]
|
||||||
|
const CREATE_NO_WINDOW: u32 = 0x08000000;
|
||||||
|
|
||||||
// 执行 PowerShell 命令获取主板信息
|
// 执行 PowerShell 命令获取主板信息
|
||||||
let output = Command::new("powershell")
|
let mut cmd = Command::new("powershell");
|
||||||
.args(&[
|
cmd.args(&[
|
||||||
"-NoProfile",
|
"-NoProfile",
|
||||||
"-Command",
|
"-WindowStyle",
|
||||||
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-CimInstance -ClassName Win32_BaseBoard | Select-Object Manufacturer, Product, Version | ConvertTo-Json -Compress"
|
"Hidden",
|
||||||
])
|
"-Command",
|
||||||
|
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-CimInstance -ClassName Win32_BaseBoard | Select-Object Manufacturer, Product, Version | ConvertTo-Json -Compress"
|
||||||
|
]);
|
||||||
|
#[cfg(windows)]
|
||||||
|
cmd.creation_flags(CREATE_NO_WINDOW);
|
||||||
|
let output = cmd
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("执行 PowerShell 命令失败: {}", e))?;
|
.map_err(|e| format!("执行 PowerShell 命令失败: {}", e))?;
|
||||||
|
|||||||
@@ -36,10 +36,15 @@ pub fn get_exe_path(name: &str) -> Result<String, std::io::Error> {
|
|||||||
// ----
|
// ----
|
||||||
// 进程路径
|
// 进程路径
|
||||||
let command = format!("Get-Process {} | Select-Object path", name);
|
let command = format!("Get-Process {} | Select-Object path", name);
|
||||||
let args = command.split_whitespace().collect::<Vec<&str>>();
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let output = Command::new("powershell.exe")
|
let output = Command::new("powershell.exe")
|
||||||
.args(&args)
|
.args(&[
|
||||||
|
"-NoProfile",
|
||||||
|
"-WindowStyle",
|
||||||
|
"Hidden",
|
||||||
|
"-Command",
|
||||||
|
&command,
|
||||||
|
])
|
||||||
.creation_flags(CREATE_NO_WINDOW)
|
.creation_flags(CREATE_NO_WINDOW)
|
||||||
.output()?;
|
.output()?;
|
||||||
|
|
||||||
|
|||||||
@@ -415,17 +415,23 @@ pub async fn download_update(
|
|||||||
/// 安装更新(Windows)
|
/// 安装更新(Windows)
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub fn install_update(installer_path: &str) -> Result<()> {
|
pub fn install_update(installer_path: &str) -> Result<()> {
|
||||||
|
// 使用 /S 静默安装
|
||||||
let mut cmd = Command::new(installer_path);
|
let mut cmd = Command::new(installer_path);
|
||||||
cmd.args(&["/S"]); // 静默安装
|
cmd.args(&["/S"]); // 静默安装
|
||||||
cmd.creation_flags(CREATE_NO_WINDOW);
|
cmd.creation_flags(CREATE_NO_WINDOW);
|
||||||
cmd.spawn()?;
|
let mut child = cmd.spawn()?;
|
||||||
|
// 等待安装程序完成
|
||||||
|
child.wait()?;
|
||||||
|
// 安装完成后,由前端调用 relaunch() 来启动新版本
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 安装更新(macOS)
|
/// 安装更新(macOS)
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn install_update(installer_path: &str) -> Result<()> {
|
pub fn install_update(installer_path: &str) -> Result<()> {
|
||||||
Command::new("open").arg(installer_path).spawn()?;
|
let mut child = Command::new("open").arg(installer_path).spawn()?;
|
||||||
|
// 等待安装程序完成
|
||||||
|
child.wait()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,13 +439,15 @@ pub fn install_update(installer_path: &str) -> Result<()> {
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub fn install_update(installer_path: &str) -> Result<()> {
|
pub fn install_update(installer_path: &str) -> Result<()> {
|
||||||
if installer_path.ends_with(".deb") {
|
if installer_path.ends_with(".deb") {
|
||||||
Command::new("sudo")
|
let mut child = Command::new("sudo")
|
||||||
.args(&["dpkg", "-i", installer_path])
|
.args(&["dpkg", "-i", installer_path])
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
child.wait()?;
|
||||||
} else if installer_path.ends_with(".AppImage") {
|
} else if installer_path.ends_with(".AppImage") {
|
||||||
Command::new("chmod")
|
let mut child = Command::new("chmod")
|
||||||
.args(&["+x", installer_path])
|
.args(&["+x", installer_path])
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
child.wait()?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
},
|
},
|
||||||
"productName": "CS工具箱",
|
"productName": "CS工具箱",
|
||||||
"mainBinaryName": "cstb",
|
"mainBinaryName": "cstb",
|
||||||
"version": "0.0.6-beta.7",
|
"version": "0.0.6-beta.6",
|
||||||
"identifier": "upup.cool",
|
"identifier": "upup.cool",
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"deep-link": {
|
"deep-link": {
|
||||||
|
|||||||
@@ -3,10 +3,8 @@ import { Card, CardBody, CardHeader, CardIcon, CardTool } from "@/components/win
|
|||||||
import { ToolButton } from "@/components/window/ToolButton"
|
import { ToolButton } from "@/components/window/ToolButton"
|
||||||
import { Chip, Skeleton } from "@heroui/react"
|
import { Chip, Skeleton } from "@heroui/react"
|
||||||
import { Refresh, SettingConfig } from "@icon-park/react"
|
import { Refresh, SettingConfig } from "@icon-park/react"
|
||||||
// import { version } from "@tauri-apps/plugin-os"
|
import { useHardwareStore } from "@/store/hardware"
|
||||||
import { type AllSystemInfo, allSysInfo } from "tauri-plugin-system-info-api"
|
import { useEffect, useState } from "react"
|
||||||
import { invoke } from "@tauri-apps/api/core"
|
|
||||||
import useSWR, { useSWRConfig } from "swr"
|
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
return (
|
return (
|
||||||
@@ -36,135 +34,47 @@ export default function Page() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function HardwareInfo() {
|
function HardwareInfo() {
|
||||||
const { mutate } = useSWRConfig()
|
const { refreshHardwareInfo } = useHardwareStore()
|
||||||
|
const [isRefreshing, setIsRefreshing] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToolButton
|
<ToolButton
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
// 使用 SWR 的 mutate 来刷新数据
|
setIsRefreshing(true)
|
||||||
mutate("/api/hardware-info")
|
try {
|
||||||
|
await refreshHardwareInfo()
|
||||||
|
} finally {
|
||||||
|
setIsRefreshing(false)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
|
disabled={isRefreshing}
|
||||||
>
|
>
|
||||||
<Refresh /> 刷新
|
<Refresh /> 刷新
|
||||||
</ToolButton>
|
</ToolButton>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ComputerInfo {
|
|
||||||
OsName?: string
|
|
||||||
OSDisplayVersion?: string
|
|
||||||
BiosSMBIOSBIOSVersion?: string
|
|
||||||
CsManufacturer?: string
|
|
||||||
CsName?: string
|
|
||||||
ReleaseId?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GpuInfo {
|
|
||||||
vendor: string
|
|
||||||
model: string
|
|
||||||
family: string
|
|
||||||
device_id: string
|
|
||||||
total_vram: number
|
|
||||||
used_vram: number
|
|
||||||
load_pct: number
|
|
||||||
temperature: number
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MemoryInfo {
|
|
||||||
capacity?: number // 容量(字节)
|
|
||||||
manufacturer?: string
|
|
||||||
speed?: number // MHz,实际频率 ConfiguredClockSpeed
|
|
||||||
default_speed?: number // MHz,默认频率 Speed(如果存在)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MonitorInfo {
|
|
||||||
name?: string
|
|
||||||
refresh_rate?: number // Hz
|
|
||||||
resolution_width?: number
|
|
||||||
resolution_height?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MotherboardInfo {
|
|
||||||
manufacturer?: string // 制造商
|
|
||||||
model?: string // 型号
|
|
||||||
version?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface HardwareData {
|
|
||||||
allSysData: AllSystemInfo
|
|
||||||
computerInfo: ComputerInfo
|
|
||||||
gpuInfo: GpuInfo | null
|
|
||||||
memoryInfo: MemoryInfo[]
|
|
||||||
monitorInfo: MonitorInfo[]
|
|
||||||
motherboardInfo: MotherboardInfo | null
|
|
||||||
}
|
|
||||||
|
|
||||||
// 硬件信息 fetcher
|
|
||||||
const hardwareInfoFetcher = async (): Promise<HardwareData> => {
|
|
||||||
// 并行获取系统信息、PowerShell 信息、GPU 信息、内存信息、显示器信息和主板信息
|
|
||||||
const [sys, computerInfoData, gpuInfoData, memoryInfoData, monitorInfoData, motherboardInfoData] =
|
|
||||||
await Promise.all([
|
|
||||||
allSysInfo(),
|
|
||||||
invoke<ComputerInfo>("get_computer_info").catch((error) => {
|
|
||||||
console.error("获取 PowerShell 信息失败:", error)
|
|
||||||
return {} as ComputerInfo
|
|
||||||
}),
|
|
||||||
invoke<GpuInfo | null>("get_gpu_info").catch((error) => {
|
|
||||||
console.error("获取 GPU 信息失败:", error)
|
|
||||||
return null
|
|
||||||
}),
|
|
||||||
invoke<MemoryInfo[]>("get_memory_info").catch((error) => {
|
|
||||||
console.error("获取内存信息失败:", error)
|
|
||||||
return [] as MemoryInfo[]
|
|
||||||
}),
|
|
||||||
invoke<MonitorInfo[]>("get_monitor_info").catch((error) => {
|
|
||||||
console.error("获取显示器信息失败:", error)
|
|
||||||
return [] as MonitorInfo[]
|
|
||||||
}),
|
|
||||||
invoke<MotherboardInfo>("get_motherboard_info").catch((error) => {
|
|
||||||
console.error("获取主板信息失败:", error)
|
|
||||||
return { manufacturer: undefined, model: undefined, version: undefined } as MotherboardInfo
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
|
|
||||||
console.log("系统信息:", sys)
|
|
||||||
console.log("PowerShell 信息:", computerInfoData)
|
|
||||||
console.log("GPU 信息:", gpuInfoData)
|
|
||||||
console.log("内存信息:", memoryInfoData)
|
|
||||||
console.log("显示器信息:", monitorInfoData)
|
|
||||||
console.log("主板信息:", motherboardInfoData)
|
|
||||||
|
|
||||||
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]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
allSysData: sys,
|
|
||||||
computerInfo: computerInfoData,
|
|
||||||
gpuInfo: gpuInfoData,
|
|
||||||
memoryInfo: memoryInfoData,
|
|
||||||
monitorInfo: monitorInfoData,
|
|
||||||
motherboardInfo: motherboardInfoData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function HardwareInfoContent() {
|
function HardwareInfoContent() {
|
||||||
const { data, isLoading, isValidating } = useSWR<HardwareData>("/api/hardware-info", hardwareInfoFetcher, {
|
const { state, fetchHardwareInfo } = useHardwareStore()
|
||||||
revalidateOnFocus: false,
|
const [isLoading, setIsLoading] = useState(!state.allSysData)
|
||||||
revalidateOnReconnect: false,
|
|
||||||
dedupingInterval: 5 * 60 * 1000, // 5分钟内相同请求去重
|
|
||||||
})
|
|
||||||
|
|
||||||
const allSysData = data?.allSysData
|
useEffect(() => {
|
||||||
const computerInfo = data?.computerInfo || {}
|
// 如果数据不存在,则加载数据
|
||||||
const gpuInfo = data?.gpuInfo
|
if (!state.allSysData) {
|
||||||
const memoryInfo = data?.memoryInfo || []
|
setIsLoading(true)
|
||||||
const monitorInfo = data?.monitorInfo || []
|
void fetchHardwareInfo().finally(() => {
|
||||||
const motherboardInfo = data?.motherboardInfo
|
setIsLoading(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []) // 只在组件挂载时执行一次,state 是响应式的,不需要作为依赖
|
||||||
|
|
||||||
|
const allSysData = state.allSysData
|
||||||
|
const computerInfo = state.computerInfo || {}
|
||||||
|
const gpuInfo = state.gpuInfo
|
||||||
|
const memoryInfo = state.memoryInfo || []
|
||||||
|
const monitorInfo = state.monitorInfo || []
|
||||||
|
const motherboardInfo = state.motherboardInfo
|
||||||
|
|
||||||
const formatBytes = (bytes?: number) => {
|
const formatBytes = (bytes?: number) => {
|
||||||
if (!bytes) return "未知"
|
if (!bytes) return "未知"
|
||||||
@@ -243,8 +153,8 @@ function HardwareInfoContent() {
|
|||||||
})()
|
})()
|
||||||
: null
|
: null
|
||||||
|
|
||||||
// 如果正在加载或正在验证(包括刷新),显示 Skeleton 骨架屏
|
// 如果正在加载,显示 Skeleton 骨架屏
|
||||||
if (isLoading || isValidating) {
|
if (isLoading || !allSysData) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
{/* 系统信息 Skeleton */}
|
{/* 系统信息 Skeleton */}
|
||||||
|
|||||||
@@ -1,48 +1,13 @@
|
|||||||
import { useState, useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
import { allSysInfo, type AllSystemInfo } from "tauri-plugin-system-info-api"
|
import { useHardwareStore } from "@/store/hardware"
|
||||||
import { invoke } from "@tauri-apps/api/core"
|
import type { AllSystemInfo } from "tauri-plugin-system-info-api"
|
||||||
|
import type {
|
||||||
interface GpuInfo {
|
GpuInfo,
|
||||||
vendor: string
|
ComputerInfo,
|
||||||
model: string
|
MemoryInfo,
|
||||||
family: string
|
MonitorInfo,
|
||||||
device_id: string
|
MotherboardInfo,
|
||||||
total_vram: number
|
} from "@/store/hardware"
|
||||||
used_vram: number
|
|
||||||
load_pct: number
|
|
||||||
temperature: number
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ComputerInfo {
|
|
||||||
OsName?: string
|
|
||||||
OSDisplayVersion?: string
|
|
||||||
BiosSMBIOSBIOSVersion?: string
|
|
||||||
CsManufacturer?: string
|
|
||||||
CsName?: string
|
|
||||||
ReleaseId?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MemoryInfo {
|
|
||||||
capacity?: number // 容量(字节)
|
|
||||||
manufacturer?: string
|
|
||||||
speed?: number // MHz,实际频率 ConfiguredClockSpeed
|
|
||||||
default_speed?: number // MHz,默认频率 Speed(如果存在)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MonitorInfo {
|
|
||||||
manufacturer?: string
|
|
||||||
model?: string
|
|
||||||
name?: string
|
|
||||||
refresh_rate?: number // Hz
|
|
||||||
resolution_width?: number
|
|
||||||
resolution_height?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MotherboardInfo {
|
|
||||||
manufacturer?: string // 制造商
|
|
||||||
model?: string // 型号
|
|
||||||
version?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HardwareInfoWithGpu {
|
export interface HardwareInfoWithGpu {
|
||||||
systemInfo: AllSystemInfo | null
|
systemInfo: AllSystemInfo | null
|
||||||
@@ -54,49 +19,23 @@ export interface HardwareInfoWithGpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useHardwareInfo() {
|
export function useHardwareInfo() {
|
||||||
const [hardwareInfo, setHardwareInfo] = useState<HardwareInfoWithGpu | null>(null)
|
const { state, fetchHardwareInfo } = useHardwareStore()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchHardwareInfo = async () => {
|
// 如果数据不存在,则加载数据(store 初始化时已经加载,这里只是确保)
|
||||||
try {
|
if (!state.allSysData) {
|
||||||
const [sys, gpuInfo, computerInfo, memoryInfo, monitorInfo, motherboardInfo] = await Promise.all([
|
void fetchHardwareInfo()
|
||||||
allSysInfo(),
|
|
||||||
invoke<GpuInfo | null>("get_gpu_info").catch((error) => {
|
|
||||||
console.error("获取 GPU 信息失败:", error)
|
|
||||||
return null
|
|
||||||
}),
|
|
||||||
invoke<ComputerInfo>("get_computer_info").catch((error) => {
|
|
||||||
console.error("获取 PowerShell 信息失败:", error)
|
|
||||||
return {} as ComputerInfo
|
|
||||||
}),
|
|
||||||
invoke<MemoryInfo[]>("get_memory_info").catch((error) => {
|
|
||||||
console.error("获取内存信息失败:", error)
|
|
||||||
return [] as MemoryInfo[]
|
|
||||||
}),
|
|
||||||
invoke<MonitorInfo[]>("get_monitor_info").catch((error) => {
|
|
||||||
console.error("获取显示器信息失败:", error)
|
|
||||||
return [] as MonitorInfo[]
|
|
||||||
}),
|
|
||||||
invoke<MotherboardInfo>("get_motherboard_info").catch((error) => {
|
|
||||||
console.error("获取主板信息失败:", error)
|
|
||||||
return { manufacturer: undefined, model: undefined, version: undefined } as MotherboardInfo
|
|
||||||
})
|
|
||||||
])
|
|
||||||
setHardwareInfo({
|
|
||||||
systemInfo: sys,
|
|
||||||
gpuInfo,
|
|
||||||
computerInfo,
|
|
||||||
memoryInfo,
|
|
||||||
monitorInfo,
|
|
||||||
motherboardInfo
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error("获取硬件信息失败:", error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void fetchHardwareInfo()
|
}, []) // 只在组件挂载时执行一次
|
||||||
}, [])
|
|
||||||
|
|
||||||
return hardwareInfo
|
// 将 store 中的数据转换为兼容的格式
|
||||||
|
return {
|
||||||
|
systemInfo: state.allSysData,
|
||||||
|
gpuInfo: state.gpuInfo,
|
||||||
|
computerInfo: state.computerInfo,
|
||||||
|
memoryInfo: state.memoryInfo,
|
||||||
|
monitorInfo: state.monitorInfo,
|
||||||
|
motherboardInfo: state.motherboardInfo,
|
||||||
|
} as HardwareInfoWithGpu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -170,19 +170,22 @@ export function UpdateChecker({ useMirror = true, customEndpoint, includePrerele
|
|||||||
if (!installerPath) return
|
if (!installerPath) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
addToast({
|
||||||
|
title: "安装已启动",
|
||||||
|
description: "应用将在安装完成后自动重启",
|
||||||
|
color: "success",
|
||||||
|
})
|
||||||
|
|
||||||
|
// 调用安装命令(这会阻塞直到安装完成)
|
||||||
await invoke("install_app_update", {
|
await invoke("install_app_update", {
|
||||||
installerPath: installerPath,
|
installerPath: installerPath,
|
||||||
})
|
})
|
||||||
|
|
||||||
addToast({
|
// 安装完成后,等待一小段时间确保安装程序完全退出
|
||||||
title: "安装已启动",
|
await new Promise(resolve => setTimeout(resolve, 500))
|
||||||
description: "应用将在安装完成后重启",
|
|
||||||
color: "success",
|
// 启动新版本
|
||||||
})
|
await relaunch()
|
||||||
|
|
||||||
setTimeout(async () => {
|
|
||||||
await relaunch()
|
|
||||||
}, 1000)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("安装更新失败:", error)
|
console.error("安装更新失败:", error)
|
||||||
addToast({
|
addToast({
|
||||||
|
|||||||
151
src/store/hardware.ts
Normal file
151
src/store/hardware.ts
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
import { store } from "@tauri-store/valtio"
|
||||||
|
import { useSnapshot } from "valtio"
|
||||||
|
import { DEFAULT_STORE_CONFIG } from "./config"
|
||||||
|
import { allSysInfo, type AllSystemInfo } from "tauri-plugin-system-info-api"
|
||||||
|
import { invoke } from "@tauri-apps/api/core"
|
||||||
|
|
||||||
|
export interface ComputerInfo {
|
||||||
|
OsName?: string
|
||||||
|
OSDisplayVersion?: string
|
||||||
|
BiosSMBIOSBIOSVersion?: string
|
||||||
|
CsManufacturer?: string
|
||||||
|
CsName?: string
|
||||||
|
ReleaseId?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GpuInfo {
|
||||||
|
vendor: string
|
||||||
|
model: string
|
||||||
|
family: string
|
||||||
|
device_id: string
|
||||||
|
total_vram: number
|
||||||
|
used_vram: number
|
||||||
|
load_pct: number
|
||||||
|
temperature: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MemoryInfo {
|
||||||
|
capacity?: number // 容量(字节)
|
||||||
|
manufacturer?: string
|
||||||
|
speed?: number // MHz,实际频率 ConfiguredClockSpeed
|
||||||
|
default_speed?: number // MHz,默认频率 Speed(如果存在)
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MonitorInfo {
|
||||||
|
name?: string
|
||||||
|
refresh_rate?: number // Hz
|
||||||
|
resolution_width?: number
|
||||||
|
resolution_height?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MotherboardInfo {
|
||||||
|
manufacturer?: string // 制造商
|
||||||
|
model?: string // 型号
|
||||||
|
version?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HardwareData {
|
||||||
|
allSysData: AllSystemInfo | null
|
||||||
|
computerInfo: ComputerInfo
|
||||||
|
gpuInfo: GpuInfo | null
|
||||||
|
memoryInfo: MemoryInfo[]
|
||||||
|
monitorInfo: MonitorInfo[]
|
||||||
|
motherboardInfo: MotherboardInfo | null
|
||||||
|
lastUpdated: number // 最后更新时间戳
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultValue: HardwareData = {
|
||||||
|
allSysData: null,
|
||||||
|
computerInfo: {},
|
||||||
|
gpuInfo: null,
|
||||||
|
memoryInfo: [],
|
||||||
|
monitorInfo: [],
|
||||||
|
motherboardInfo: null,
|
||||||
|
lastUpdated: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 硬件信息 fetcher
|
||||||
|
const hardwareInfoFetcher = async (): Promise<HardwareData> => {
|
||||||
|
// 并行获取系统信息、PowerShell 信息、GPU 信息、内存信息、显示器信息和主板信息
|
||||||
|
const [sys, computerInfoData, gpuInfoData, memoryInfoData, monitorInfoData, motherboardInfoData] =
|
||||||
|
await Promise.all([
|
||||||
|
allSysInfo(),
|
||||||
|
invoke<ComputerInfo>("get_computer_info").catch((error) => {
|
||||||
|
console.error("获取 PowerShell 信息失败:", error)
|
||||||
|
return {} as ComputerInfo
|
||||||
|
}),
|
||||||
|
invoke<GpuInfo | null>("get_gpu_info").catch((error) => {
|
||||||
|
console.error("获取 GPU 信息失败:", error)
|
||||||
|
return null
|
||||||
|
}),
|
||||||
|
invoke<MemoryInfo[]>("get_memory_info").catch((error) => {
|
||||||
|
console.error("获取内存信息失败:", error)
|
||||||
|
return [] as MemoryInfo[]
|
||||||
|
}),
|
||||||
|
invoke<MonitorInfo[]>("get_monitor_info").catch((error) => {
|
||||||
|
console.error("获取显示器信息失败:", error)
|
||||||
|
return [] as MonitorInfo[]
|
||||||
|
}),
|
||||||
|
invoke<MotherboardInfo>("get_motherboard_info").catch((error) => {
|
||||||
|
console.error("获取主板信息失败:", error)
|
||||||
|
return { manufacturer: undefined, model: undefined, version: undefined } as MotherboardInfo
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
return {
|
||||||
|
allSysData: sys,
|
||||||
|
computerInfo: computerInfoData,
|
||||||
|
gpuInfo: gpuInfoData,
|
||||||
|
memoryInfo: memoryInfoData,
|
||||||
|
monitorInfo: monitorInfoData,
|
||||||
|
motherboardInfo: motherboardInfoData,
|
||||||
|
lastUpdated: Date.now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hardwareStore = store("hardware", { ...defaultValue }, DEFAULT_STORE_CONFIG)
|
||||||
|
|
||||||
|
// 检查数据是否过期(30分钟)
|
||||||
|
const isDataStale = (lastUpdated: number): boolean => {
|
||||||
|
const thirtyMinutes = 30 * 60 * 1000
|
||||||
|
return Date.now() - lastUpdated > thirtyMinutes
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取硬件信息(如果数据过期或不存在则重新获取)
|
||||||
|
export const fetchHardwareInfo = async (force = false): Promise<void> => {
|
||||||
|
// 如果数据存在且未过期,且不是强制刷新,则直接返回
|
||||||
|
if (!force && hardwareStore.state.allSysData && !isDataStale(hardwareStore.state.lastUpdated)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await hardwareInfoFetcher()
|
||||||
|
hardwareStore.state.allSysData = data.allSysData
|
||||||
|
hardwareStore.state.computerInfo = data.computerInfo
|
||||||
|
hardwareStore.state.gpuInfo = data.gpuInfo
|
||||||
|
hardwareStore.state.memoryInfo = data.memoryInfo
|
||||||
|
hardwareStore.state.monitorInfo = data.monitorInfo
|
||||||
|
hardwareStore.state.motherboardInfo = data.motherboardInfo
|
||||||
|
hardwareStore.state.lastUpdated = data.lastUpdated
|
||||||
|
} catch (error) {
|
||||||
|
console.error("获取硬件信息失败:", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 强制刷新硬件信息
|
||||||
|
export const refreshHardwareInfo = async (): Promise<void> => {
|
||||||
|
await fetchHardwareInfo(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useHardwareStore = () => {
|
||||||
|
void hardwareStore.start
|
||||||
|
const state = useSnapshot(hardwareStore.state)
|
||||||
|
|
||||||
|
return {
|
||||||
|
state,
|
||||||
|
store: hardwareStore,
|
||||||
|
fetchHardwareInfo,
|
||||||
|
refreshHardwareInfo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@ import { authStore } from "./auth"
|
|||||||
import { steamStore } from "./steam"
|
import { steamStore } from "./steam"
|
||||||
import { toolStore } from "./tool"
|
import { toolStore } from "./tool"
|
||||||
import { fpsTestStore } from "./fps_test"
|
import { fpsTestStore } from "./fps_test"
|
||||||
|
import { hardwareStore, fetchHardwareInfo } from "./hardware"
|
||||||
|
|
||||||
export async function init() {
|
export async function init() {
|
||||||
await appStore.start()
|
await appStore.start()
|
||||||
@@ -10,4 +11,7 @@ export async function init() {
|
|||||||
await toolStore.start()
|
await toolStore.start()
|
||||||
await steamStore.start()
|
await steamStore.start()
|
||||||
await fpsTestStore.start()
|
await fpsTestStore.start()
|
||||||
|
await hardwareStore.start()
|
||||||
|
// 初始化时自动加载硬件信息(如果数据过期或不存在)
|
||||||
|
await fetchHardwareInfo()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user