Files
personal-toolbox/PersonalToolBox/ViewModels/GroupEditViewModel.cs
home-PC 2c985e8d63 Phase 6: 一键多开 (工具组合) 功能
- 数据模型: ToolItem 新增 IsGroup(bool) + SubToolIds(List<string>) 字段

- 执行逻辑: ProcessExecutionService 改为 ExecuteAsync, 组合卡片遍历子工具逐一启动(500ms延迟), 孤儿ID跳过并打印警告

- 组合编辑: GroupEditViewModel + GroupEditWindow, 复选框列表勾选非组合工具

- 主界面: 标题栏新增 '+添加组合' 按钮(蓝色), 组合卡片右下角显示 📦 角标

- 右键菜单: 区分 '编辑工具' (普通) 和 '编辑组合' (IsGroup=true)

- 快捷键: HotKeyManager 适配 ExecuteAsync 异步调用

- 测试: 82 tests total (ProcessExecution 4->6, GroupEdit 5 new)
2026-05-10 00:15:39 +08:00

145 lines
4.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.ObjectModel;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using PersonalToolBox.Models;
using PersonalToolBox.Services;
namespace PersonalToolBox.ViewModels;
/// <summary>
/// 组合编辑窗口 ViewModel管理一键多开组合的创建与编辑
/// </summary>
public partial class GroupEditViewModel : ObservableObject
{
private readonly IDataService _dataService;
private readonly ILogService _logService;
private readonly ToolItem? _editingGroup;
// ──────── 可观察属性 ────────
[ObservableProperty]
private string _windowTitle = "添加组合";
[ObservableProperty]
private string _name = string.Empty;
[ObservableProperty]
private string _hotKey = string.Empty;
[ObservableProperty]
private Category? _selectedCategory;
/// <summary>
/// 可供勾选的普通工具列表IsGroup == false
/// </summary>
public ObservableCollection<SelectableTool> AvailableTools { get; } = new();
/// <summary>
/// 分类下拉列表
/// </summary>
public ObservableCollection<Category> Categories { get; } = new();
public Action<bool?>? CloseAction { get; set; }
public bool Saved { get; private set; }
// ──────── 构造 ────────
public GroupEditViewModel(IDataService dataService, ILogService logService, ToolItem? groupToEdit = null)
{
_dataService = dataService;
_logService = logService;
_editingGroup = groupToEdit;
foreach (var cat in _dataService.Config.Categories)
Categories.Add(cat);
// 加载所有普通工具(非组合)
var selectedIds = _editingGroup?.SubToolIds ?? new List<string>();
foreach (var tool in _dataService.Config.Tools.Where(t => !t.IsGroup))
{
AvailableTools.Add(new SelectableTool
{
Tool = tool,
IsSelected = selectedIds.Contains(tool.Id)
});
}
if (groupToEdit != null)
{
WindowTitle = "编辑组合";
Name = groupToEdit.Name;
HotKey = groupToEdit.HotKey;
SelectedCategory = Categories.FirstOrDefault(c => c.Id == groupToEdit.CategoryId);
}
}
// ──────── 命令 ────────
[RelayCommand]
private void Save()
{
try
{
if (string.IsNullOrWhiteSpace(Name))
{
_logService.Warning("组合名称不能为空");
return;
}
var selectedIds = AvailableTools
.Where(t => t.IsSelected)
.Select(t => t.Tool.Id)
.ToList();
if (_editingGroup != null)
{
_editingGroup.Name = Name.Trim();
_editingGroup.HotKey = HotKey.Trim();
_editingGroup.CategoryId = SelectedCategory?.Id ?? string.Empty;
_editingGroup.SubToolIds = selectedIds;
_editingGroup.IsValid = true;
_logService.Info($"已更新组合: {Name.Trim()}(包含 {selectedIds.Count} 个工具)");
}
else
{
_dataService.Config.Tools.Add(new ToolItem
{
Name = Name.Trim(),
HotKey = HotKey.Trim(),
CategoryId = SelectedCategory?.Id ?? string.Empty,
IsGroup = true,
SubToolIds = selectedIds,
IsValid = true
});
_logService.Info($"已添加组合: {Name.Trim()}(包含 {selectedIds.Count} 个工具)");
}
_dataService.Save();
Saved = true;
CloseAction?.Invoke(true);
}
catch (Exception ex)
{
_logService.Error($"保存组合失败: {ex.Message}");
}
}
[RelayCommand]
private void Cancel()
{
CloseAction?.Invoke(false);
}
}
/// <summary>
/// 可勾选的工具项(用于 CheckBox 列表绑定)
/// </summary>
public partial class SelectableTool : ObservableObject
{
public ToolItem Tool { get; set; } = null!;
[ObservableProperty]
private bool _isSelected;
}