stream cards
This commit is contained in:
@@ -8,22 +8,13 @@ use serde::Serialize;
|
||||
use sysinfo::{System, Disks};
|
||||
use wmi::{COMLibrary, WMIConnection};
|
||||
use std::fs;
|
||||
// 引入 chrono 用于时间计算和格式化
|
||||
// 引入 tauri::Emitter 用于发送事件 (Tauri v2)
|
||||
use tauri::Emitter;
|
||||
use chrono::{Duration, FixedOffset, Local, NaiveDate, TimeZone};
|
||||
|
||||
// --- 1. 数据结构 ---
|
||||
// --- 1. 数据结构 (保持不变,用于序列化部分数据) ---
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct SystemHealthReport {
|
||||
hardware: HardwareSummary,
|
||||
storage: Vec<StorageDevice>,
|
||||
events: Vec<SystemEvent>,
|
||||
minidumps: MinidumpInfo,
|
||||
drivers: Vec<DriverIssue>,
|
||||
battery: Option<BatteryInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, Clone)] // 增加 Clone trait 方便使用
|
||||
struct HardwareSummary {
|
||||
cpu_name: String,
|
||||
sys_vendor: String,
|
||||
@@ -38,7 +29,7 @@ struct HardwareSummary {
|
||||
c_drive_used_gb: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, Clone)]
|
||||
struct StorageDevice {
|
||||
model: String,
|
||||
health_status: String,
|
||||
@@ -46,7 +37,7 @@ struct StorageDevice {
|
||||
is_danger: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, Clone)]
|
||||
struct SystemEvent {
|
||||
time_generated: String,
|
||||
event_id: u32,
|
||||
@@ -55,21 +46,21 @@ struct SystemEvent {
|
||||
analysis_hint: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, Clone)]
|
||||
struct MinidumpInfo {
|
||||
found: bool,
|
||||
count: usize,
|
||||
explanation: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, Clone)]
|
||||
struct DriverIssue {
|
||||
device_name: String,
|
||||
error_code: u32,
|
||||
description: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, Clone)]
|
||||
struct BatteryInfo {
|
||||
health_percentage: u32,
|
||||
is_ac_connected: bool,
|
||||
@@ -122,269 +113,255 @@ struct Win32_ComputerSystem {
|
||||
Model: Option<String>,
|
||||
}
|
||||
|
||||
// --- 辅助函数:生成 WMI 查询用的时间字符串 ---
|
||||
// WMI 要求的时间格式类似于: 20231125000000.000000+000
|
||||
// --- 辅助函数 ---
|
||||
fn get_wmi_query_time(days_ago: i64) -> String {
|
||||
let target_date = Local::now() - Duration::days(days_ago);
|
||||
// 这里我们只生成前半部分 YYYYMMDDHHMMSS,WMI 字符串比较支持这种前缀
|
||||
// 或者生成完整格式 .000000+000 (简化处理,假设本地时区)
|
||||
target_date.format("%Y%m%d%H%M%S.000000+000").to_string()
|
||||
}
|
||||
|
||||
// --- 辅助函数:格式化显示用的时间 ---
|
||||
fn format_wmi_time(wmi_str: &str) -> String {
|
||||
if wmi_str.len() < 25 {
|
||||
return wmi_str.to_string();
|
||||
}
|
||||
|
||||
let year = wmi_str[0..4].parse::<i32>().unwrap_or(1970);
|
||||
let month = wmi_str[4..6].parse::<u32>().unwrap_or(1);
|
||||
let day = wmi_str[6..8].parse::<u32>().unwrap_or(1);
|
||||
let hour = wmi_str[8..10].parse::<u32>().unwrap_or(0);
|
||||
let min = wmi_str[10..12].parse::<u32>().unwrap_or(0);
|
||||
let sec = wmi_str[12..14].parse::<u32>().unwrap_or(0);
|
||||
|
||||
let sign = &wmi_str[21..22];
|
||||
let offset_val = wmi_str[22..25].parse::<i32>().unwrap_or(0);
|
||||
let offset_mins = if sign == "-" { -offset_val } else { offset_val };
|
||||
|
||||
let offset = FixedOffset::east_opt(offset_mins * 60).unwrap_or(FixedOffset::east_opt(0).unwrap());
|
||||
|
||||
let naive_date = NaiveDate::from_ymd_opt(year, month, day).unwrap_or(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap());
|
||||
let naive_dt = naive_date.and_hms_opt(hour, min, sec).unwrap_or_default();
|
||||
|
||||
match offset.from_local_datetime(&naive_dt).single() {
|
||||
Some(dt) => {
|
||||
dt.with_timezone(&Local).format("%Y-%m-%d %H:%M:%S").to_string()
|
||||
},
|
||||
Some(dt) => dt.with_timezone(&Local).format("%Y-%m-%d %H:%M:%S").to_string(),
|
||||
None => format!("{}-{:02}-{:02} {:02}:{:02}:{:02}", year, month, day, hour, min, sec)
|
||||
}
|
||||
}
|
||||
|
||||
// --- 核心逻辑 ---
|
||||
// --- 核心逻辑:分步流式传输 ---
|
||||
|
||||
#[tauri::command]
|
||||
async fn run_diagnosis() -> Result<SystemHealthReport, String> {
|
||||
let report = tokio::task::spawn_blocking(|| {
|
||||
// 1. 高效初始化:只创建空实例,不扫描进程
|
||||
let mut sys = System::new();
|
||||
sys.refresh_memory();
|
||||
sys.refresh_cpu();
|
||||
async fn run_diagnosis(window: tauri::Window) -> Result<(), String> {
|
||||
// 使用 spawn 在后台线程运行,避免阻塞 Tauri 主线程
|
||||
// 注意:这里不等待 join,而是让它在后台跑,通过 window.emit 发送进度
|
||||
std::thread::spawn(move || {
|
||||
// 1. 硬件概览 (最快)
|
||||
{
|
||||
let mut sys = System::new();
|
||||
sys.refresh_memory();
|
||||
sys.refresh_cpu();
|
||||
|
||||
let wmi_con = WMIConnection::new(COMLibrary::new().unwrap()).ok();
|
||||
|
||||
let mut bios_ver = "Unknown".to_string();
|
||||
let mut mobo_vendor = "Unknown".to_string();
|
||||
let mut mobo_product = "Unknown".to_string();
|
||||
let mut sys_vendor = "Unknown".to_string();
|
||||
let mut sys_product = "Unknown".to_string();
|
||||
|
||||
if let Some(con) = &wmi_con {
|
||||
if let Ok(results) = con.raw_query::<Win32_BIOS>("SELECT SMBIOSBIOSVersion FROM Win32_BIOS") {
|
||||
if let Some(bios) = results.first() { bios_ver = bios.SMBIOSBIOSVersion.clone().unwrap_or_default(); }
|
||||
}
|
||||
if let Ok(results) = con.raw_query::<Win32_BaseBoard>("SELECT Manufacturer, Product FROM Win32_BaseBoard") {
|
||||
if let Some(board) = results.first() {
|
||||
mobo_vendor = board.Manufacturer.clone().unwrap_or_default();
|
||||
mobo_product = board.Product.clone().unwrap_or_default();
|
||||
}
|
||||
}
|
||||
if let Ok(results) = con.raw_query::<Win32_ComputerSystem>("SELECT Manufacturer, Model FROM Win32_ComputerSystem") {
|
||||
if let Some(cs) = results.first() {
|
||||
sys_vendor = cs.Manufacturer.clone().unwrap_or_default();
|
||||
sys_product = cs.Model.clone().unwrap_or_default();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// C盘
|
||||
let mut c_total = 0u64;
|
||||
let mut c_used = 0u64;
|
||||
let disks = Disks::new_with_refreshed_list();
|
||||
for disk in &disks {
|
||||
if disk.mount_point().to_string_lossy().starts_with("C:") {
|
||||
c_total = disk.total_space() / 1024 / 1024 / 1024;
|
||||
let free = disk.available_space() / 1024 / 1024 / 1024;
|
||||
c_used = c_total - free;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let cpu_brand = if let Some(cpu) = sys.cpus().first() {
|
||||
cpu.brand().trim().to_string()
|
||||
} else {
|
||||
"Unknown CPU".to_string()
|
||||
};
|
||||
|
||||
let hardware = HardwareSummary {
|
||||
cpu_name: cpu_brand,
|
||||
sys_vendor, sys_product, mobo_vendor, mobo_product,
|
||||
memory_total_gb: sys.total_memory() / 1024 / 1024 / 1024,
|
||||
memory_used_gb: sys.used_memory() / 1024 / 1024 / 1024,
|
||||
os_version: System::long_os_version().unwrap_or("Unknown".to_string()),
|
||||
bios_version: bios_ver,
|
||||
c_drive_total_gb: c_total,
|
||||
c_drive_used_gb: c_used,
|
||||
};
|
||||
|
||||
// 发送硬件事件
|
||||
let _ = window.emit("report-hardware", hardware);
|
||||
}
|
||||
|
||||
// WMI 连接复用 (如果需要) 或者重新建立
|
||||
let wmi_con = WMIConnection::new(COMLibrary::new().unwrap()).ok();
|
||||
|
||||
// 1. 硬件基础信息
|
||||
let mut bios_ver = "Unknown".to_string();
|
||||
let mut mobo_vendor = "Unknown".to_string();
|
||||
let mut mobo_product = "Unknown".to_string();
|
||||
let mut sys_vendor = "Unknown".to_string();
|
||||
let mut sys_product = "Unknown".to_string();
|
||||
|
||||
if let Some(con) = &wmi_con {
|
||||
if let Ok(results) = con.raw_query::<Win32_BIOS>("SELECT SMBIOSBIOSVersion FROM Win32_BIOS") {
|
||||
if let Some(bios) = results.first() {
|
||||
bios_ver = bios.SMBIOSBIOSVersion.clone().unwrap_or("Unknown".to_string());
|
||||
}
|
||||
}
|
||||
if let Ok(results) = con.raw_query::<Win32_BaseBoard>("SELECT Manufacturer, Product FROM Win32_BaseBoard") {
|
||||
if let Some(board) = results.first() {
|
||||
mobo_vendor = board.Manufacturer.clone().unwrap_or("Unknown".to_string());
|
||||
mobo_product = board.Product.clone().unwrap_or("Unknown".to_string());
|
||||
}
|
||||
}
|
||||
if let Ok(results) = con.raw_query::<Win32_ComputerSystem>("SELECT Manufacturer, Model FROM Win32_ComputerSystem") {
|
||||
if let Some(cs) = results.first() {
|
||||
sys_vendor = cs.Manufacturer.clone().unwrap_or("Unknown".to_string());
|
||||
sys_product = cs.Model.clone().unwrap_or("Unknown".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- C 盘空间检查 ---
|
||||
let mut c_total = 0u64;
|
||||
let mut c_used = 0u64;
|
||||
let disks = Disks::new_with_refreshed_list();
|
||||
for disk in &disks {
|
||||
if disk.mount_point().to_string_lossy().starts_with("C:") {
|
||||
c_total = disk.total_space() / 1024 / 1024 / 1024;
|
||||
let free = disk.available_space() / 1024 / 1024 / 1024;
|
||||
c_used = c_total - free;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let cpu_brand = if let Some(cpu) = sys.cpus().first() {
|
||||
cpu.brand().trim().to_string()
|
||||
} else {
|
||||
"Unknown CPU".to_string()
|
||||
};
|
||||
|
||||
let hardware = HardwareSummary {
|
||||
cpu_name: cpu_brand,
|
||||
mobo_vendor,
|
||||
mobo_product,
|
||||
sys_vendor,
|
||||
sys_product,
|
||||
memory_total_gb: sys.total_memory() / 1024 / 1024 / 1024,
|
||||
memory_used_gb: sys.used_memory() / 1024 / 1024 / 1024,
|
||||
os_version: System::long_os_version().unwrap_or("Unknown".to_string()),
|
||||
bios_version: bios_ver,
|
||||
c_drive_total_gb: c_total,
|
||||
c_drive_used_gb: c_used,
|
||||
};
|
||||
|
||||
// 2. 存储设备健康度
|
||||
let mut storage = Vec::new();
|
||||
if let Some(con) = &wmi_con {
|
||||
let query = "SELECT Model, Status FROM Win32_DiskDrive";
|
||||
if let Ok(results) = con.raw_query::<Win32_DiskDrive>(query) {
|
||||
for disk in results {
|
||||
let status = disk.Status.unwrap_or("Unknown".to_string());
|
||||
let (explanation, is_danger) = match status.as_str() {
|
||||
"OK" => ("健康".to_string(), false),
|
||||
"Pred Fail" => ("预测即将损坏".to_string(), true),
|
||||
_ => ("状态异常".to_string(), true),
|
||||
};
|
||||
storage.push(StorageDevice {
|
||||
model: disk.Model.unwrap_or("Generic Disk".to_string()),
|
||||
health_status: status,
|
||||
human_explanation: explanation,
|
||||
is_danger,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 关键日志 (严格模式 + 时间优化 + 扩展)
|
||||
let mut events = Vec::new();
|
||||
if let Some(con) = &wmi_con {
|
||||
// [关键优化] 计算30天前的时间字符串
|
||||
let start_time_str = get_wmi_query_time(30);
|
||||
|
||||
// [关键优化] SQL 中加入 TimeGenerated >= '...' 过滤,大幅减少扫描量
|
||||
let query = format!(
|
||||
"SELECT TimeGenerated, EventCode, SourceName, Message FROM Win32_NTLogEvent WHERE Logfile = 'System' AND TimeGenerated >= '{}' AND (EventCode = 41 OR EventCode = 18 OR EventCode = 19 OR EventCode = 7 OR EventCode = 1001 OR EventCode = 4101)",
|
||||
start_time_str
|
||||
);
|
||||
|
||||
if let Ok(results) = con.raw_query::<Win32_NTLogEvent>(&query) {
|
||||
for event in results {
|
||||
let mut is_target_event = false;
|
||||
let mut hint = String::new();
|
||||
|
||||
// 严格来源校验
|
||||
if event.EventCode == 41 && event.SourceName == "Microsoft-Windows-Kernel-Power" {
|
||||
is_target_event = true;
|
||||
hint = "系统意外断电 (电源/强关)".to_string();
|
||||
} else if (event.EventCode == 18 || event.EventCode == 19) && event.SourceName == "Microsoft-Windows-WHEA-Logger" {
|
||||
is_target_event = true;
|
||||
hint = "WHEA 硬件致命错误 (CPU/超频/PCIe)".to_string();
|
||||
} else if event.EventCode == 7 && (event.SourceName == "Disk" || event.SourceName == "disk") {
|
||||
is_target_event = true;
|
||||
hint = "硬盘出现坏道 (Disk Bad Block)".to_string();
|
||||
} else if event.EventCode == 1001 && event.SourceName == "BugCheck" {
|
||||
is_target_event = true;
|
||||
hint = "系统发生蓝屏死机 (BSOD)".to_string();
|
||||
} else if event.EventCode == 4101 && event.SourceName == "Display" {
|
||||
is_target_event = true;
|
||||
hint = "显卡驱动停止响应并已恢复 (TDR)".to_string();
|
||||
}
|
||||
|
||||
if is_target_event {
|
||||
events.push(SystemEvent {
|
||||
time_generated: format_wmi_time(&event.TimeGenerated),
|
||||
event_id: event.EventCode,
|
||||
source: event.SourceName,
|
||||
message: event.Message.unwrap_or("无详细信息".to_string()),
|
||||
analysis_hint: hint,
|
||||
});
|
||||
}
|
||||
|
||||
// 显示最近 10 条(因为加了时间范围,可以多显示一点)
|
||||
if events.len() >= 10 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Minidump
|
||||
let mut minidump = MinidumpInfo { found: false, count: 0, explanation: "无蓝屏记录".to_string() };
|
||||
if let Ok(entries) = fs::read_dir("C:\\Windows\\Minidump") {
|
||||
let count = entries.count();
|
||||
if count > 0 {
|
||||
minidump = MinidumpInfo {
|
||||
found: true,
|
||||
count,
|
||||
explanation: format!("发现 {} 次蓝屏崩溃", count),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 驱动设备检查
|
||||
let mut driver_issues = Vec::new();
|
||||
if let Some(con) = &wmi_con {
|
||||
let query = "SELECT Name, ConfigManagerErrorCode FROM Win32_PnPEntity WHERE ConfigManagerErrorCode <> 0";
|
||||
if let Ok(results) = con.raw_query::<Win32_PnPEntity>(query) {
|
||||
for dev in results {
|
||||
let code = dev.ConfigManagerErrorCode.unwrap_or(0);
|
||||
let desc = match code {
|
||||
10 => "设备无法启动 (Code 10)。通常是驱动不兼容。",
|
||||
28 => "驱动程序未安装 (Code 28)。",
|
||||
43 => "硬件报告问题已被停止 (Code 43)。显卡常见,可能虚焊。",
|
||||
_ => "设备状态异常。",
|
||||
};
|
||||
driver_issues.push(DriverIssue {
|
||||
device_name: dev.Name.unwrap_or("未知设备".to_string()),
|
||||
error_code: code,
|
||||
description: desc.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 电池健康度
|
||||
let mut battery_info = None;
|
||||
if let Some(con) = &wmi_con {
|
||||
if let Ok(results) = con.raw_query::<Win32_Battery>("SELECT DesignCapacity, FullChargeCapacity, BatteryStatus FROM Win32_Battery") {
|
||||
if let Some(bat) = results.first() {
|
||||
let design = bat.DesignCapacity.unwrap_or(0);
|
||||
let full = bat.FullChargeCapacity.unwrap_or(0);
|
||||
let status = bat.BatteryStatus.unwrap_or(0);
|
||||
|
||||
if design > 0 {
|
||||
let health = ((full as f64 / design as f64) * 100.0) as u32;
|
||||
let ac_plugged = status == 2 || status == 6 || status == 1;
|
||||
|
||||
let explain = if health < 60 {
|
||||
"电池老化严重,建议更换,否则可能导致供电不稳。".to_string()
|
||||
} else {
|
||||
"电池状态良好。".to_string()
|
||||
// 2. 存储设备 (较快)
|
||||
{
|
||||
let mut storage = Vec::new();
|
||||
if let Some(con) = &wmi_con {
|
||||
let query = "SELECT Model, Status FROM Win32_DiskDrive";
|
||||
if let Ok(results) = con.raw_query::<Win32_DiskDrive>(query) {
|
||||
for disk in results {
|
||||
let status = disk.Status.unwrap_or("Unknown".to_string());
|
||||
let (explanation, is_danger) = match status.as_str() {
|
||||
"OK" => ("健康".to_string(), false),
|
||||
"Pred Fail" => ("预测即将损坏".to_string(), true),
|
||||
_ => ("状态异常".to_string(), true),
|
||||
};
|
||||
|
||||
battery_info = Some(BatteryInfo {
|
||||
health_percentage: health,
|
||||
is_ac_connected: ac_plugged,
|
||||
explanation: explain,
|
||||
storage.push(StorageDevice {
|
||||
model: disk.Model.unwrap_or("Generic Disk".to_string()),
|
||||
health_status: status,
|
||||
human_explanation: explanation,
|
||||
is_danger,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
let _ = window.emit("report-storage", storage);
|
||||
}
|
||||
|
||||
SystemHealthReport {
|
||||
hardware,
|
||||
storage,
|
||||
events,
|
||||
minidumps: minidump,
|
||||
drivers: driver_issues,
|
||||
battery: battery_info
|
||||
// 3. 驱动 (快)
|
||||
{
|
||||
let mut driver_issues = Vec::new();
|
||||
if let Some(con) = &wmi_con {
|
||||
let query = "SELECT Name, ConfigManagerErrorCode FROM Win32_PnPEntity WHERE ConfigManagerErrorCode <> 0";
|
||||
if let Ok(results) = con.raw_query::<Win32_PnPEntity>(query) {
|
||||
for dev in results {
|
||||
let code = dev.ConfigManagerErrorCode.unwrap_or(0);
|
||||
let desc = match code {
|
||||
10 => "设备无法启动 (Code 10)。通常是驱动不兼容。",
|
||||
28 => "驱动程序未安装 (Code 28)。",
|
||||
43 => "硬件报告问题已被停止 (Code 43)。显卡常见,可能虚焊。",
|
||||
_ => "设备状态异常。",
|
||||
};
|
||||
driver_issues.push(DriverIssue {
|
||||
device_name: dev.Name.unwrap_or("未知设备".to_string()),
|
||||
error_code: code,
|
||||
description: desc.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
let _ = window.emit("report-drivers", driver_issues);
|
||||
}
|
||||
})
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(report)
|
||||
// 4. Minidump (快)
|
||||
{
|
||||
let mut minidump = MinidumpInfo { found: false, count: 0, explanation: "无蓝屏记录".to_string() };
|
||||
if let Ok(entries) = fs::read_dir("C:\\Windows\\Minidump") {
|
||||
let count = entries.count();
|
||||
if count > 0 {
|
||||
minidump = MinidumpInfo {
|
||||
found: true,
|
||||
count,
|
||||
explanation: format!("发现 {} 次蓝屏崩溃", count),
|
||||
};
|
||||
}
|
||||
}
|
||||
let _ = window.emit("report-minidumps", minidump);
|
||||
}
|
||||
|
||||
// 5. 电池 (快)
|
||||
{
|
||||
let mut battery_info = None;
|
||||
if let Some(con) = &wmi_con {
|
||||
if let Ok(results) = con.raw_query::<Win32_Battery>("SELECT DesignCapacity, FullChargeCapacity, BatteryStatus FROM Win32_Battery") {
|
||||
if let Some(bat) = results.first() {
|
||||
let design = bat.DesignCapacity.unwrap_or(0);
|
||||
let full = bat.FullChargeCapacity.unwrap_or(0);
|
||||
let status = bat.BatteryStatus.unwrap_or(0);
|
||||
if design > 0 {
|
||||
let health = ((full as f64 / design as f64) * 100.0) as u32;
|
||||
let ac_plugged = status == 2 || status == 6 || status == 1;
|
||||
let explain = if health < 60 {
|
||||
"电池老化严重,建议更换,否则可能导致供电不稳。".to_string()
|
||||
} else {
|
||||
"电池状态良好。".to_string()
|
||||
};
|
||||
battery_info = Some(BatteryInfo {
|
||||
health_percentage: health,
|
||||
is_ac_connected: ac_plugged,
|
||||
explanation: explain,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 即使是 None 也要发,以便前端知道检查完成了
|
||||
// 这里为了简化,直接发 Option
|
||||
let _ = window.emit("report-battery", battery_info);
|
||||
}
|
||||
|
||||
// 6. 日志 (最慢,放在最后)
|
||||
{
|
||||
let mut events = Vec::new();
|
||||
if let Some(con) = &wmi_con {
|
||||
let start_time_str = get_wmi_query_time(30);
|
||||
let query = format!(
|
||||
"SELECT TimeGenerated, EventCode, SourceName, Message FROM Win32_NTLogEvent WHERE Logfile = 'System' AND TimeGenerated >= '{}' AND (EventCode = 41 OR EventCode = 18 OR EventCode = 19 OR EventCode = 7 OR EventCode = 1001 OR EventCode = 4101)",
|
||||
start_time_str
|
||||
);
|
||||
|
||||
if let Ok(results) = con.raw_query::<Win32_NTLogEvent>(&query) {
|
||||
for event in results {
|
||||
let mut is_target_event = false;
|
||||
let mut hint = String::new();
|
||||
|
||||
if event.EventCode == 41 && event.SourceName == "Microsoft-Windows-Kernel-Power" {
|
||||
is_target_event = true; hint = "系统意外断电 (电源/强关)".to_string();
|
||||
} else if (event.EventCode == 18 || event.EventCode == 19) && event.SourceName == "Microsoft-Windows-WHEA-Logger" {
|
||||
is_target_event = true; hint = "WHEA 硬件致命错误 (CPU/超频/PCIe)".to_string();
|
||||
} else if event.EventCode == 7 && (event.SourceName == "Disk" || event.SourceName == "disk") {
|
||||
is_target_event = true; hint = "硬盘出现坏道 (Disk Bad Block)".to_string();
|
||||
} else if event.EventCode == 1001 && event.SourceName == "BugCheck" {
|
||||
is_target_event = true; hint = "系统发生蓝屏死机 (BSOD)".to_string();
|
||||
} else if event.EventCode == 4101 && event.SourceName == "Display" {
|
||||
is_target_event = true; hint = "显卡驱动停止响应并已恢复 (TDR)".to_string();
|
||||
}
|
||||
|
||||
if is_target_event {
|
||||
events.push(SystemEvent {
|
||||
time_generated: format_wmi_time(&event.TimeGenerated),
|
||||
event_id: event.EventCode,
|
||||
source: event.SourceName,
|
||||
message: event.Message.unwrap_or("无详细信息".to_string()),
|
||||
analysis_hint: hint,
|
||||
});
|
||||
}
|
||||
if events.len() >= 10 { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
let _ = window.emit("report-events", events);
|
||||
}
|
||||
|
||||
// 7. 全部完成信号
|
||||
let _ = window.emit("diagnosis-finished", ());
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
Reference in New Issue
Block a user