From 26a22eef1c30d25a4608d9c773e2b595e684bd11 Mon Sep 17 00:00:00 2001 From: home-PC Date: Wed, 27 May 2026 14:20:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BB=9F=E4=B8=80=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E5=91=BD=E5=90=8D=E5=B9=B6=E8=A1=A5=E5=85=85=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E5=A4=B1=E6=95=88=E6=8A=A5=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将内部项目目录、命名空间、配置目录、自启注册表值和设计/开发文档统一为 PersonalToolbox。 扩展路径校验服务,输出失效工具、字段、原因和路径,并在启动日志、设置页路径检查与导入配置流程中展示明细报告。 验证:dotnet build PersonalToolbox.sln --- PersonalToolbox.sln | 4 +- docs/development.md | 33 +++-- src/{ToolboxApp => PersonalToolbox}/App.xaml | 2 +- .../App.xaml.cs | 4 +- .../AssemblyInfo.cs | 0 .../Commands/RelayCommand.cs | 2 +- .../MainWindow.xaml | 4 +- .../MainWindow.xaml.cs | 8 +- .../Models/ToolModels.cs | 2 +- .../PersonalToolbox.csproj} | 0 .../Services/AutoRunService.cs | 4 +- .../Services/ConfigurationService.cs | 8 +- .../Services/HotkeyService.cs | 4 +- .../Services/PathValidationService.cs | 126 ++++++++++++++++++ .../Services/StartupService.cs | 4 +- .../Services/SystemToolService.cs | 4 +- .../Services/ToolLaunchService.cs | 4 +- .../Services/TrayService.cs | 2 +- .../ViewModels/CombinationMemberViewModel.cs | 4 +- .../ViewModels/MainWindowViewModel.cs | 38 ++++-- .../ViewModels/ObservableObject.cs | 2 +- .../ViewModels/ToolCardViewModel.cs | 4 +- .../Views/CombinationEditorWindow.xaml | 2 +- .../Views/CombinationEditorWindow.xaml.cs | 8 +- .../Views/PromptWindow.xaml | 2 +- .../Views/PromptWindow.xaml.cs | 2 +- .../Views/SettingsWindow.xaml | 4 +- .../Views/SettingsWindow.xaml.cs | 18 +-- .../Views/ToolEditorWindow.xaml | 2 +- .../Views/ToolEditorWindow.xaml.cs | 6 +- .../Services/PathValidationService.cs | 69 ---------- windows_personal_toolbox_product_design.md | 10 +- 32 files changed, 236 insertions(+), 150 deletions(-) rename src/{ToolboxApp => PersonalToolbox}/App.xaml (96%) rename src/{ToolboxApp => PersonalToolbox}/App.xaml.cs (75%) rename src/{ToolboxApp => PersonalToolbox}/AssemblyInfo.cs (100%) rename src/{ToolboxApp => PersonalToolbox}/Commands/RelayCommand.cs (98%) rename src/{ToolboxApp => PersonalToolbox}/MainWindow.xaml (99%) rename src/{ToolboxApp => PersonalToolbox}/MainWindow.xaml.cs (97%) rename src/{ToolboxApp => PersonalToolbox}/Models/ToolModels.cs (99%) rename src/{ToolboxApp/ToolboxApp.csproj => PersonalToolbox/PersonalToolbox.csproj} (100%) rename src/{ToolboxApp => PersonalToolbox}/Services/AutoRunService.cs (96%) rename src/{ToolboxApp => PersonalToolbox}/Services/ConfigurationService.cs (97%) rename src/{ToolboxApp => PersonalToolbox}/Services/HotkeyService.cs (99%) create mode 100644 src/PersonalToolbox/Services/PathValidationService.cs rename src/{ToolboxApp => PersonalToolbox}/Services/StartupService.cs (89%) rename src/{ToolboxApp => PersonalToolbox}/Services/SystemToolService.cs (98%) rename src/{ToolboxApp => PersonalToolbox}/Services/ToolLaunchService.cs (99%) rename src/{ToolboxApp => PersonalToolbox}/Services/TrayService.cs (98%) rename src/{ToolboxApp => PersonalToolbox}/ViewModels/CombinationMemberViewModel.cs (95%) rename src/{ToolboxApp => PersonalToolbox}/ViewModels/MainWindowViewModel.cs (93%) rename src/{ToolboxApp => PersonalToolbox}/ViewModels/ObservableObject.cs (94%) rename src/{ToolboxApp => PersonalToolbox}/ViewModels/ToolCardViewModel.cs (98%) rename src/{ToolboxApp => PersonalToolbox}/Views/CombinationEditorWindow.xaml (99%) rename src/{ToolboxApp => PersonalToolbox}/Views/CombinationEditorWindow.xaml.cs (97%) rename src/{ToolboxApp => PersonalToolbox}/Views/PromptWindow.xaml (96%) rename src/{ToolboxApp => PersonalToolbox}/Views/PromptWindow.xaml.cs (97%) rename src/{ToolboxApp => PersonalToolbox}/Views/SettingsWindow.xaml (99%) rename src/{ToolboxApp => PersonalToolbox}/Views/SettingsWindow.xaml.cs (92%) rename src/{ToolboxApp => PersonalToolbox}/Views/ToolEditorWindow.xaml (99%) rename src/{ToolboxApp => PersonalToolbox}/Views/ToolEditorWindow.xaml.cs (98%) delete mode 100644 src/ToolboxApp/Services/PathValidationService.cs diff --git a/PersonalToolbox.sln b/PersonalToolbox.sln index b1cf354..f19fd31 100644 --- a/PersonalToolbox.sln +++ b/PersonalToolbox.sln @@ -1,11 +1,11 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DF1687D8-B6FA-4DF9-90EC-E749B85024EC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ToolboxApp", "src\ToolboxApp\ToolboxApp.csproj", "{9A4ED1BF-510A-4481-AE7B-62490D3D7BBA}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PersonalToolbox", "src\PersonalToolbox\PersonalToolbox.csproj", "{9A4ED1BF-510A-4481-AE7B-62490D3D7BBA}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/docs/development.md b/docs/development.md index 6a402a6..2066aa5 100644 --- a/docs/development.md +++ b/docs/development.md @@ -2,23 +2,24 @@ ## 当前项目状态 -- 项目名称:Personal Toolbox / ToolboxApp +- 项目名称:Personal Toolbox / PersonalToolbox - 技术栈:WPF + .NET 8 + C# - 架构方向:MVVM 分层,UI 层通过 ViewModel 调用服务层 - 当前阶段:MVP 基础版本已搭建,可编译运行 -- 主要入口:`src/ToolboxApp/MainWindow.xaml` +- 主要入口:`src/PersonalToolbox/MainWindow.xaml` +- 配置目录:`%AppData%\PersonalToolbox` ## 已实现能力 1. 基础工程 - `PersonalToolbox.sln` - - `src/ToolboxApp/ToolboxApp.csproj` + - `src/PersonalToolbox/PersonalToolbox.csproj` - WPF 桌面应用,启用 WinForms 托盘能力 + - 内部命名空间、项目路径、启动项名称和配置目录已统一为 `PersonalToolbox` 2. 数据与配置 - 本地 JSON 配置读写 - 原子写入:先写 `.tmp`,再替换正式文件 - - 默认配置目录:`%AppData%\ToolboxApp` - 配置文件: - `appsettings.json` - `categories.json` @@ -26,6 +27,7 @@ - `autorun.json` - `icons/` - 导入、导出、重置配置基础能力 + - 路径失效检查会输出具体工具、字段、原因和路径 3. 工具模型 - 系统工具 @@ -60,7 +62,7 @@ - 托盘常驻服务 - 托盘菜单:显示/隐藏主界面、全局快捷键开关、设置、退出 - 关闭窗口时隐藏到托盘 - - 当前用户开机自启 + - 当前用户开机自启,注册表值名为 `PersonalToolbox` - 全局快捷键注册、注销、内部冲突和注册失败提示 8. 界面 @@ -73,6 +75,15 @@ - 设置窗口 - 主要 UI 元素均提供 `ToolTip` 悬浮说明 +## 最近开发记录 + +### 2026-05-27 + +- 将项目内部名从旧临时代号统一更改为 `PersonalToolbox`,包括目录、项目文件、命名空间、XAML 类名、配置目录、自启注册表值和导出文件名。 +- 设计文档中的临时代号和 AppData 路径同步改为 `PersonalToolbox`。 +- 路径失效检查从单纯数量扩展为明细报告,设置页导入配置后也会提示具体失效工具。 +- 验证命令:`dotnet build PersonalToolbox.sln`,结果为 0 警告、0 错误。 + ## 运行与验证 构建: @@ -84,7 +95,7 @@ dotnet build PersonalToolbox.sln 运行: ```powershell -dotnet run --project src\ToolboxApp\ToolboxApp.csproj +dotnet run --project src\PersonalToolbox\PersonalToolbox.csproj ``` 当前验证结果: @@ -98,7 +109,7 @@ dotnet build PersonalToolbox.sln ## 目录说明 ```text -src/ToolboxApp +src/PersonalToolbox ├─ Commands 命令封装 ├─ Models 工具、分类、组合、配置、日志等模型 ├─ Services 配置、启动、托盘、自启、快捷键、路径校验等服务 @@ -116,10 +127,11 @@ src/ToolboxApp - 配置写入必须保持原子写入策略,避免中途失败写坏 JSON。 - 快捷键必须包含至少一个修饰键,不支持纯单键快捷键。 - 开机自启只写当前用户注册表,不要求管理员权限。 +- 本项目尚未投入使用,不需要维护旧临时代号对应配置目录的兼容迁移。 ## Git 记录约定 -提交信息使用 Conventional Commits 格式,并使用中文说明: +提交信息使用 Conventional Commits 格式,并使用中文说明标题和正文: ```text feat: 添加某项用户能力 @@ -142,6 +154,5 @@ feat: 添加某项用户能力 2. 更完整的图标选择器和分类图标编辑。 3. 更细的快捷键录入控件,减少手写格式错误。 4. 拖拽调整卡片和分类顺序。 -5. 导入配置后的更详细路径失效报告。 -6. UI 视觉打磨和深浅色主题。 -7. 为组合校验、快捷键解析和配置读写增加单元测试。 +5. UI 视觉打磨和深浅色主题。 +6. 为组合校验、快捷键解析和配置读写增加单元测试。 diff --git a/src/ToolboxApp/App.xaml b/src/PersonalToolbox/App.xaml similarity index 96% rename from src/ToolboxApp/App.xaml rename to src/PersonalToolbox/App.xaml index 7cdd8a9..391d37d 100644 --- a/src/ToolboxApp/App.xaml +++ b/src/PersonalToolbox/App.xaml @@ -1,4 +1,4 @@ - diff --git a/src/ToolboxApp/App.xaml.cs b/src/PersonalToolbox/App.xaml.cs similarity index 75% rename from src/ToolboxApp/App.xaml.cs rename to src/PersonalToolbox/App.xaml.cs index f05315d..a85a807 100644 --- a/src/ToolboxApp/App.xaml.cs +++ b/src/PersonalToolbox/App.xaml.cs @@ -1,8 +1,8 @@ -using System.Configuration; +using System.Configuration; using System.Data; using System.Windows; -namespace ToolboxApp; +namespace PersonalToolbox; /// /// Interaction logic for App.xaml diff --git a/src/ToolboxApp/AssemblyInfo.cs b/src/PersonalToolbox/AssemblyInfo.cs similarity index 100% rename from src/ToolboxApp/AssemblyInfo.cs rename to src/PersonalToolbox/AssemblyInfo.cs diff --git a/src/ToolboxApp/Commands/RelayCommand.cs b/src/PersonalToolbox/Commands/RelayCommand.cs similarity index 98% rename from src/ToolboxApp/Commands/RelayCommand.cs rename to src/PersonalToolbox/Commands/RelayCommand.cs index d923ef0..6f621f9 100644 --- a/src/ToolboxApp/Commands/RelayCommand.cs +++ b/src/PersonalToolbox/Commands/RelayCommand.cs @@ -1,6 +1,6 @@ using System.Windows.Input; -namespace ToolboxApp.Commands; +namespace PersonalToolbox.Commands; public sealed class RelayCommand : ICommand { diff --git a/src/ToolboxApp/MainWindow.xaml b/src/PersonalToolbox/MainWindow.xaml similarity index 99% rename from src/ToolboxApp/MainWindow.xaml rename to src/PersonalToolbox/MainWindow.xaml index 02475a5..d349f00 100644 --- a/src/ToolboxApp/MainWindow.xaml +++ b/src/PersonalToolbox/MainWindow.xaml @@ -1,9 +1,9 @@ - LoadAsync(CancellationToken cancellationToken = default) @@ -112,7 +112,7 @@ public sealed class ConfigurationService var tempDirectory = ""; if (File.Exists(sourcePath) && Path.GetExtension(sourcePath).Equals(".zip", StringComparison.OrdinalIgnoreCase)) { - tempDirectory = Path.Combine(Path.GetTempPath(), "ToolboxAppImport_" + Guid.NewGuid().ToString("N")); + tempDirectory = Path.Combine(Path.GetTempPath(), "PersonalToolboxImport_" + Guid.NewGuid().ToString("N")); ZipFile.ExtractToDirectory(sourcePath, tempDirectory); importDirectory = tempDirectory; } diff --git a/src/ToolboxApp/Services/HotkeyService.cs b/src/PersonalToolbox/Services/HotkeyService.cs similarity index 99% rename from src/ToolboxApp/Services/HotkeyService.cs rename to src/PersonalToolbox/Services/HotkeyService.cs index 1acfa51..2895c95 100644 --- a/src/ToolboxApp/Services/HotkeyService.cs +++ b/src/PersonalToolbox/Services/HotkeyService.cs @@ -1,9 +1,9 @@ using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; -using ToolboxApp.Models; +using PersonalToolbox.Models; -namespace ToolboxApp.Services; +namespace PersonalToolbox.Services; public sealed class HotkeyService : IDisposable { diff --git a/src/PersonalToolbox/Services/PathValidationService.cs b/src/PersonalToolbox/Services/PathValidationService.cs new file mode 100644 index 0000000..4d4d71f --- /dev/null +++ b/src/PersonalToolbox/Services/PathValidationService.cs @@ -0,0 +1,126 @@ +using System.IO; +using System.Text; +using PersonalToolbox.Models; + +namespace PersonalToolbox.Services; + +public sealed class PathValidationService +{ + public PathValidationReport ValidateTools(IEnumerable tools) + { + var issues = new List(); + foreach (var tool in tools) + { + tool.PathInvalid = false; + + if (tool.IsDeleted || tool.Type != ToolType.Local) + { + continue; + } + + if (string.IsNullOrWhiteSpace(tool.LaunchTarget) || !PathExists(tool.LaunchTarget)) + { + tool.PathInvalid = true; + issues.Add(CreateIssue(tool, "启动目标", tool.LaunchTarget, string.IsNullOrWhiteSpace(tool.LaunchTarget) ? "启动目标为空" : "启动目标不存在")); + } + + if (!string.IsNullOrWhiteSpace(tool.WorkingDirectory) && !Directory.Exists(tool.WorkingDirectory)) + { + tool.PathInvalid = true; + issues.Add(CreateIssue(tool, "工作目录", tool.WorkingDirectory, "工作目录不存在")); + } + } + + return new PathValidationReport(issues); + } + + public static bool IsValidUrl(string? rawUrl, out string normalizedUrl) + { + normalizedUrl = ""; + if (string.IsNullOrWhiteSpace(rawUrl)) + { + return false; + } + + var value = rawUrl.Trim(); + if (!value.Contains("://", StringComparison.Ordinal)) + { + value = "https://" + value; + } + + if (!Uri.TryCreate(value, UriKind.Absolute, out var uri)) + { + return false; + } + + if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps) + { + return false; + } + + normalizedUrl = uri.ToString(); + return true; + } + + private static bool PathExists(string path) + { + return File.Exists(path) || Directory.Exists(path); + } + + private static PathValidationIssue CreateIssue(ToolItem tool, string fieldName, string? path, string reason) + { + return new PathValidationIssue + { + ToolId = tool.Id, + ToolName = tool.Name, + FieldName = fieldName, + Path = path ?? "", + Reason = reason + }; + } +} + +public sealed class PathValidationReport +{ + public PathValidationReport(IReadOnlyList issues) + { + Issues = issues; + } + + public IReadOnlyList Issues { get; } + public bool HasIssues => Issues.Count > 0; + public int InvalidToolCount => Issues.Select(issue => issue.ToolId).Distinct(StringComparer.OrdinalIgnoreCase).Count(); + + public string ToStatusText(int maxIssues = 8) + { + if (!HasIssues) + { + return "路径检查完成:未发现失效工具。"; + } + + var builder = new StringBuilder(); + builder.AppendLine($"路径检查完成:发现 {InvalidToolCount} 个失效工具,{Issues.Count} 个问题。"); + + foreach (var issue in Issues.Take(maxIssues)) + { + var pathText = string.IsNullOrWhiteSpace(issue.Path) ? "" : $"({issue.Path})"; + builder.AppendLine($"- {issue.ToolName}:{issue.FieldName} {issue.Reason}{pathText}"); + } + + if (Issues.Count > maxIssues) + { + builder.AppendLine($"还有 {Issues.Count - maxIssues} 个问题未显示,请逐项检查本地工具路径。"); + } + + return builder.ToString().TrimEnd(); + } +} + +public sealed class PathValidationIssue +{ + public string ToolId { get; init; } = ""; + public string ToolName { get; init; } = ""; + public string FieldName { get; init; } = ""; + public string Path { get; init; } = ""; + public string Reason { get; init; } = ""; +} diff --git a/src/ToolboxApp/Services/StartupService.cs b/src/PersonalToolbox/Services/StartupService.cs similarity index 89% rename from src/ToolboxApp/Services/StartupService.cs rename to src/PersonalToolbox/Services/StartupService.cs index 6b85302..21befc2 100644 --- a/src/ToolboxApp/Services/StartupService.cs +++ b/src/PersonalToolbox/Services/StartupService.cs @@ -1,11 +1,11 @@ using Microsoft.Win32; -namespace ToolboxApp.Services; +namespace PersonalToolbox.Services; public sealed class StartupService { private const string RunKeyPath = @"Software\Microsoft\Windows\CurrentVersion\Run"; - private const string RunValueName = "ToolboxApp"; + private const string RunValueName = "PersonalToolbox"; public bool IsEnabled() { diff --git a/src/ToolboxApp/Services/SystemToolService.cs b/src/PersonalToolbox/Services/SystemToolService.cs similarity index 98% rename from src/ToolboxApp/Services/SystemToolService.cs rename to src/PersonalToolbox/Services/SystemToolService.cs index 8ae682c..dfdf76a 100644 --- a/src/ToolboxApp/Services/SystemToolService.cs +++ b/src/PersonalToolbox/Services/SystemToolService.cs @@ -1,6 +1,6 @@ -using ToolboxApp.Models; +using PersonalToolbox.Models; -namespace ToolboxApp.Services; +namespace PersonalToolbox.Services; public static class SystemToolService { diff --git a/src/ToolboxApp/Services/ToolLaunchService.cs b/src/PersonalToolbox/Services/ToolLaunchService.cs similarity index 99% rename from src/ToolboxApp/Services/ToolLaunchService.cs rename to src/PersonalToolbox/Services/ToolLaunchService.cs index 6ee54c0..401114c 100644 --- a/src/ToolboxApp/Services/ToolLaunchService.cs +++ b/src/PersonalToolbox/Services/ToolLaunchService.cs @@ -1,9 +1,9 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; -using ToolboxApp.Models; +using PersonalToolbox.Models; -namespace ToolboxApp.Services; +namespace PersonalToolbox.Services; public sealed class ToolLaunchService { diff --git a/src/ToolboxApp/Services/TrayService.cs b/src/PersonalToolbox/Services/TrayService.cs similarity index 98% rename from src/ToolboxApp/Services/TrayService.cs rename to src/PersonalToolbox/Services/TrayService.cs index ee8794f..f86bed1 100644 --- a/src/ToolboxApp/Services/TrayService.cs +++ b/src/PersonalToolbox/Services/TrayService.cs @@ -2,7 +2,7 @@ using System.Drawing; using System.Windows; using Forms = System.Windows.Forms; -namespace ToolboxApp.Services; +namespace PersonalToolbox.Services; public sealed class TrayService : IDisposable { diff --git a/src/ToolboxApp/ViewModels/CombinationMemberViewModel.cs b/src/PersonalToolbox/ViewModels/CombinationMemberViewModel.cs similarity index 95% rename from src/ToolboxApp/ViewModels/CombinationMemberViewModel.cs rename to src/PersonalToolbox/ViewModels/CombinationMemberViewModel.cs index df6f650..327101c 100644 --- a/src/ToolboxApp/ViewModels/CombinationMemberViewModel.cs +++ b/src/PersonalToolbox/ViewModels/CombinationMemberViewModel.cs @@ -1,6 +1,6 @@ -using ToolboxApp.Models; +using PersonalToolbox.Models; -namespace ToolboxApp.ViewModels; +namespace PersonalToolbox.ViewModels; public sealed class CombinationMemberViewModel : ObservableObject { diff --git a/src/ToolboxApp/ViewModels/MainWindowViewModel.cs b/src/PersonalToolbox/ViewModels/MainWindowViewModel.cs similarity index 93% rename from src/ToolboxApp/ViewModels/MainWindowViewModel.cs rename to src/PersonalToolbox/ViewModels/MainWindowViewModel.cs index 6285701..c56ead2 100644 --- a/src/ToolboxApp/ViewModels/MainWindowViewModel.cs +++ b/src/PersonalToolbox/ViewModels/MainWindowViewModel.cs @@ -1,13 +1,13 @@ using System.Collections.ObjectModel; using System.Windows; -using ToolboxApp.Commands; -using ToolboxApp.Models; -using ToolboxApp.Services; -using ToolboxApp.Views; +using PersonalToolbox.Commands; +using PersonalToolbox.Models; +using PersonalToolbox.Services; +using PersonalToolbox.Views; using Clipboard = System.Windows.Clipboard; using MessageBox = System.Windows.MessageBox; -namespace ToolboxApp.ViewModels; +namespace PersonalToolbox.ViewModels; public sealed class MainWindowViewModel : ObservableObject { @@ -128,15 +128,15 @@ public sealed class MainWindowViewModel : ObservableObject _isLogPanelExpanded = _data.Settings.LogPanelExpanded; OnPropertyChanged(nameof(IsLogPanelExpanded)); - var invalidCount = _pathValidationService.ValidateTools(_data.Tools); + var pathReport = _pathValidationService.ValidateTools(_data.Tools); RefreshCategories(); RefreshTools(); AddLog(LogLevel.Info, $"配置目录:{_configurationService.ConfigDirectory}"); AddLog(LogLevel.Success, "个人工具箱已启动。"); - if (invalidCount > 0) + if (pathReport.HasIssues) { - AddLog(LogLevel.Warning, $"路径检查完成:发现 {invalidCount} 个失效工具。"); + LogPathValidationReport(pathReport); } await SaveAsync(); @@ -230,7 +230,7 @@ public sealed class MainWindowViewModel : ObservableObject edited.SortOrder = NextToolSortOrder(); _data.Tools.Add(edited); - _pathValidationService.ValidateTools(_data.Tools); + _ = _pathValidationService.ValidateTools(_data.Tools); RefreshTools(); AddLog(LogLevel.Success, $"已添加本地工具:{edited.Name}"); _ = SaveAsync(); @@ -297,7 +297,7 @@ public sealed class MainWindowViewModel : ObservableObject } CopyToolValues(edited, original); - _pathValidationService.ValidateTools(_data.Tools); + _ = _pathValidationService.ValidateTools(_data.Tools); RefreshTools(); AddLog(LogLevel.Success, $"已保存工具:{original.Name}"); _ = SaveAsync(); @@ -346,7 +346,7 @@ public sealed class MainWindowViewModel : ObservableObject if (window.ShowDialog() == true) { _data = window.Data; - _pathValidationService.ValidateTools(_data.Tools); + _ = _pathValidationService.ValidateTools(_data.Tools); RefreshCategories(); RefreshTools(); AddLog(LogLevel.Success, "设置已保存。"); @@ -444,6 +444,22 @@ public sealed class MainWindowViewModel : ObservableObject AddLog(LogLevel.Success, "已复制底部信息。"); } + private void LogPathValidationReport(PathValidationReport report) + { + AddLog(LogLevel.Warning, $"路径检查完成:发现 {report.InvalidToolCount} 个失效工具,{report.Issues.Count} 个问题。"); + + foreach (var issue in report.Issues.Take(8)) + { + var pathText = string.IsNullOrWhiteSpace(issue.Path) ? "" : $",{issue.Path}"; + AddLog(LogLevel.Warning, $"路径失效:{issue.ToolName},{issue.FieldName} {issue.Reason}{pathText}"); + } + + if (report.Issues.Count > 8) + { + AddLog(LogLevel.Warning, $"还有 {report.Issues.Count - 8} 个路径问题未显示,可在设置中查看完整报告。"); + } + } + private ToolItem CreateBaseTool(ToolType type) { return new ToolItem diff --git a/src/ToolboxApp/ViewModels/ObservableObject.cs b/src/PersonalToolbox/ViewModels/ObservableObject.cs similarity index 94% rename from src/ToolboxApp/ViewModels/ObservableObject.cs rename to src/PersonalToolbox/ViewModels/ObservableObject.cs index 626daf3..397ea38 100644 --- a/src/ToolboxApp/ViewModels/ObservableObject.cs +++ b/src/PersonalToolbox/ViewModels/ObservableObject.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.Runtime.CompilerServices; -namespace ToolboxApp.ViewModels; +namespace PersonalToolbox.ViewModels; public abstract class ObservableObject : INotifyPropertyChanged { diff --git a/src/ToolboxApp/ViewModels/ToolCardViewModel.cs b/src/PersonalToolbox/ViewModels/ToolCardViewModel.cs similarity index 98% rename from src/ToolboxApp/ViewModels/ToolCardViewModel.cs rename to src/PersonalToolbox/ViewModels/ToolCardViewModel.cs index 03a24e1..d5e4b0b 100644 --- a/src/ToolboxApp/ViewModels/ToolCardViewModel.cs +++ b/src/PersonalToolbox/ViewModels/ToolCardViewModel.cs @@ -1,6 +1,6 @@ -using ToolboxApp.Models; +using PersonalToolbox.Models; -namespace ToolboxApp.ViewModels; +namespace PersonalToolbox.ViewModels; public sealed class ToolCardViewModel : ObservableObject { diff --git a/src/ToolboxApp/Views/CombinationEditorWindow.xaml b/src/PersonalToolbox/Views/CombinationEditorWindow.xaml similarity index 99% rename from src/ToolboxApp/Views/CombinationEditorWindow.xaml rename to src/PersonalToolbox/Views/CombinationEditorWindow.xaml index 0205c12..8258ef5 100644 --- a/src/ToolboxApp/Views/CombinationEditorWindow.xaml +++ b/src/PersonalToolbox/Views/CombinationEditorWindow.xaml @@ -1,4 +1,4 @@ -