- 数据模型: 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)
104 lines
2.9 KiB
C#
104 lines
2.9 KiB
C#
using System.Diagnostics;
|
|
using PersonalToolBox.Models;
|
|
|
|
namespace PersonalToolBox.Services;
|
|
|
|
/// <summary>
|
|
/// 进程执行服务,负责启动外部工具进程并处理异常
|
|
/// 支持一键多开:当 IsGroup 为 true 时批量启动子工具
|
|
/// </summary>
|
|
public class ProcessExecutionService : IProcessExecutionService
|
|
{
|
|
private readonly ILogService _logService;
|
|
private readonly IDataService _dataService;
|
|
|
|
public ProcessExecutionService(ILogService logService, IDataService dataService)
|
|
{
|
|
_logService = logService;
|
|
_dataService = dataService;
|
|
}
|
|
|
|
public async Task ExecuteAsync(ToolItem tool)
|
|
{
|
|
if (tool == null)
|
|
{
|
|
_logService.Error("尝试执行空工具项");
|
|
return;
|
|
}
|
|
|
|
// 组合卡片:遍历子工具列表逐一启动
|
|
if (tool.IsGroup)
|
|
{
|
|
await ExecuteGroupAsync(tool);
|
|
return;
|
|
}
|
|
|
|
// 普通工具:直接启动
|
|
if (!tool.IsValid)
|
|
{
|
|
_logService.Warning($"无法运行工具 \"{tool.Name}\",路径失效: {tool.ExecutablePath}");
|
|
return;
|
|
}
|
|
|
|
LaunchSingleTool(tool);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 批量启动组合中的所有子工具,每次间隔 500ms 防止系统卡顿
|
|
/// </summary>
|
|
private async Task ExecuteGroupAsync(ToolItem group)
|
|
{
|
|
var subTools = new List<ToolItem>();
|
|
|
|
foreach (var subId in group.SubToolIds)
|
|
{
|
|
var subTool = _dataService.Config.Tools.FirstOrDefault(t => t.Id == subId);
|
|
if (subTool == null)
|
|
{
|
|
_logService.Warning($"组合启动跳过:找不到 ID 为 {subId} 的工具");
|
|
continue;
|
|
}
|
|
subTools.Add(subTool);
|
|
}
|
|
|
|
_logService.Info($"开始启动组合 \"{group.Name}\",共 {subTools.Count} 个工具");
|
|
|
|
foreach (var subTool in subTools)
|
|
{
|
|
if (!subTool.IsValid)
|
|
{
|
|
_logService.Warning($"组合启动跳过 \"{subTool.Name}\",路径失效: {subTool.ExecutablePath}");
|
|
continue;
|
|
}
|
|
|
|
LaunchSingleTool(subTool);
|
|
await Task.Delay(500);
|
|
}
|
|
|
|
_logService.Info($"组合 \"{group.Name}\" 启动完成");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 启动单个工具进程
|
|
/// </summary>
|
|
private void LaunchSingleTool(ToolItem tool)
|
|
{
|
|
try
|
|
{
|
|
var startInfo = new ProcessStartInfo
|
|
{
|
|
FileName = tool.ExecutablePath,
|
|
Arguments = tool.Arguments ?? string.Empty,
|
|
UseShellExecute = true
|
|
};
|
|
|
|
Process.Start(startInfo);
|
|
_logService.Info($"成功启动: {tool.Name}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logService.Error($"启动工具 \"{tool.Name}\" 失败: {ex.Message}");
|
|
}
|
|
}
|
|
}
|