using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Microsoft.Extensions.Logging; using System.Linq; using System; using System.Collections.Generic; using BetterGenshinImpact.ViewModel.Pages.Component; using BetterGenshinImpact.Service; using System.Threading.Tasks; using System.Collections.Specialized; using System.IO; using System.Windows; using System.Windows.Controls; using BetterGenshinImpact.Core.Config; using BetterGenshinImpact.View.Windows; using BetterGenshinImpact.View.Windows.GearTask; using BetterGenshinImpact.ViewModel.Windows; using Wpf.Ui.Violeta.Controls; namespace BetterGenshinImpact.ViewModel.Pages; /// /// 任务列表页面ViewModel /// public partial class GearTaskListPageViewModel : ViewModel { private readonly ILogger _logger; private readonly GearTaskStorageService _storageService; /// /// 任务定义列表(左侧) /// [ObservableProperty] private ObservableCollection _taskDefinitions = new(); /// /// 当前选中的任务定义 /// [ObservableProperty] private GearTaskDefinitionViewModel? _selectedTaskDefinition; /// /// 当前任务树根节点(右侧) /// [ObservableProperty] private GearTaskViewModel _currentTaskTreeRoot = new(); /// /// 当前选中的任务节点 /// [ObservableProperty] private GearTaskViewModel? _selectedTaskNode; public GearTaskListPageViewModel(ILogger logger, GearTaskStorageService storageService) { _logger = logger; _storageService = storageService; InitializeData(); // 监听集合变化,实现自动保存 TaskDefinitions.CollectionChanged += OnTaskDefinitionsChanged; // 监听当前任务树根节点的子集合变化,用于拖拽后自动保存 CurrentTaskTreeRoot.Children.CollectionChanged += OnCurrentTaskTreeChanged; } /// /// 任务定义集合变化时的处理 /// private async void OnTaskDefinitionsChanged(object? sender, NotifyCollectionChangedEventArgs e) { // 当集合发生变化时(包括拖拽重排序),更新Order属性并保存 try { // 更新所有任务定义的Order属性以反映当前顺序 for (int i = 0; i < TaskDefinitions.Count; i++) { if (TaskDefinitions[i].Order != i) { TaskDefinitions[i].Order = i; TaskDefinitions[i].ModifiedTime = DateTime.Now; } } // 保存所有受影响的任务定义 foreach (var taskDef in TaskDefinitions) { await _storageService.SaveTaskDefinitionAsync(taskDef); } _logger.LogInformation("任务定义列表顺序已更新并保存"); } catch (Exception ex) { _logger.LogError(ex, "保存任务定义列表顺序时发生错误"); } } /// /// 当前任务树集合变化时的处理(用于拖拽后自动保存) /// private async void OnCurrentTaskTreeChanged(object? sender, NotifyCollectionChangedEventArgs e) { if (SelectedTaskDefinition != null) { try { SelectedTaskDefinition.ModifiedTime = DateTime.Now; await _storageService.SaveTaskDefinitionAsync(SelectedTaskDefinition); _logger.LogInformation("任务树根级别结构变化,已自动保存任务定义 '{TaskName}'", SelectedTaskDefinition.Name); } catch (Exception ex) { _logger.LogError(ex, "自动保存任务定义 {TaskName} 时发生错误", SelectedTaskDefinition.Name); } } } /// /// 初始化数据 /// private async void InitializeData() { try { // 从 JSON 文件加载任务定义 var loadedTasks = await _storageService.LoadAllTaskDefinitionsAsync(); // 按order字段排序 var sortedTasks = loadedTasks.OrderBy(t => t.Order).ToList(); foreach (var task in sortedTasks) { TaskDefinitions.Add(task); // 为每个任务定义设置属性变化监听 SetupTaskDefinitionPropertyChanged(task); } // 如果没有加载到任何任务,创建一个示例任务 if (TaskDefinitions.Count == 0) { await CreateSampleTaskAsync(); } } catch (Exception ex) { _logger.LogError(ex, "初始化任务数据时发生错误"); // 发生错误时创建示例任务 await CreateSampleTaskAsync(); } } /// /// 创建示例任务 /// private async Task CreateSampleTaskAsync() { var sampleTask = new GearTaskDefinitionViewModel("示例任务组", "这是一个示例任务组"); if (sampleTask.RootTask != null) { sampleTask.RootTask.AddChild(new GearTaskViewModel("采集任务1") { TaskType = "采集任务" }); sampleTask.RootTask.AddChild(new GearTaskViewModel("战斗任务1") { TaskType = "战斗任务" }); var subGroup = new GearTaskViewModel("子任务组", true); subGroup.AddChild(new GearTaskViewModel("传送任务1") { TaskType = "传送任务" }); subGroup.AddChild(new GearTaskViewModel("交互任务1") { TaskType = "交互任务" }); sampleTask.RootTask.AddChild(subGroup); } TaskDefinitions.Add(sampleTask); SetupTaskDefinitionPropertyChanged(sampleTask); // 保存示例任务到文件 await _storageService.SaveTaskDefinitionAsync(sampleTask); } /// /// 选中任务定义时的处理 /// partial void OnSelectedTaskDefinitionChanged(GearTaskDefinitionViewModel? value) { // 清除之前选中项的状态 foreach (var task in TaskDefinitions) { task.IsSelected = false; } // 设置当前选中项 if (value != null) { value.IsSelected = true; } // 先解除之前的事件绑定 CurrentTaskTreeRoot.Children.CollectionChanged -= OnCurrentTaskTreeChanged; // 设置当前任务树根节点 if (value?.RootTask != null) { CurrentTaskTreeRoot = value.RootTask; } else { CurrentTaskTreeRoot = new GearTaskViewModel(); } // 重新绑定事件 CurrentTaskTreeRoot.Children.CollectionChanged += OnCurrentTaskTreeChanged; } /// /// 选择任务定义命令 /// [RelayCommand] private void SelectTaskDefinition(GearTaskDefinitionViewModel? taskDefinition) { SelectedTaskDefinition = taskDefinition; } /// /// 添加新的任务定义 /// [RelayCommand] private async Task AddTaskDefinition() { var editViewModel = App.GetService(); if (editViewModel == null) return; editViewModel.Name = $"新任务组{TaskDefinitions.Count + 1}"; editViewModel.Description = ""; var editWindow = App.GetService(); if (editWindow == null) return; editWindow.ViewModel.Name = editViewModel.Name; editWindow.ViewModel.Description = editViewModel.Description; editWindow.Owner = Application.Current.MainWindow; if (editWindow.ShowDialog() == true) { var newTask = new GearTaskDefinitionViewModel(editWindow.ViewModel.Name, editWindow.ViewModel.Description); // 设置新任务的order为当前最大值+1 newTask.Order = TaskDefinitions.Count > 0 ? TaskDefinitions.Max(t => t.Order) + 1 : 0; TaskDefinitions.Add(newTask); SetupTaskDefinitionPropertyChanged(newTask); SelectedTaskDefinition = newTask; // 自动保存到文件 await _storageService.SaveTaskDefinitionAsync(newTask); } } /// /// 删除任务定义 /// [RelayCommand] private async Task DeleteTaskDefinition(GearTaskDefinitionViewModel? taskDefinition) { if (taskDefinition == null) return; var result = MessageBox.Show($"确定要删除任务定义 '{taskDefinition.Name}' 吗?", "确认删除", MessageBoxButton.YesNo, MessageBoxImage.Question); if (result == MessageBoxResult.Yes) { var taskName = taskDefinition.Name; TaskDefinitions.Remove(taskDefinition); if (SelectedTaskDefinition == taskDefinition) { SelectedTaskDefinition = TaskDefinitions.FirstOrDefault(); } // 删除对应的 JSON 文件 await _storageService.DeleteTaskDefinitionAsync(taskName); } } /// /// 编辑选中的任务定义 /// [RelayCommand] private async Task EditSelectedTaskDefinition() { if (SelectedTaskDefinition == null) return; var editViewModel = App.GetService(); if (editViewModel == null) return; editViewModel.Name = SelectedTaskDefinition.Name; editViewModel.Description = SelectedTaskDefinition.Description; var editWindow = App.GetService(); if (editWindow == null) return; editWindow.ViewModel.Name = editViewModel.Name; editWindow.ViewModel.Description = editViewModel.Description; editWindow.Owner = Application.Current.MainWindow; if (editWindow.ShowDialog() == true) { SelectedTaskDefinition.Name = editWindow.ViewModel.Name; SelectedTaskDefinition.Description = editWindow.ViewModel.Description; SelectedTaskDefinition.ModifiedTime = DateTime.Now; // 自动保存到文件 await _storageService.SaveTaskDefinitionAsync(SelectedTaskDefinition); _logger.LogInformation("编辑了任务定义: {Name}", SelectedTaskDefinition.Name); } } /// /// 删除选中的任务定义 /// [RelayCommand] private async Task DeleteSelectedTaskDefinition() { if (SelectedTaskDefinition == null) return; await DeleteTaskDefinition(SelectedTaskDefinition); } /// /// 执行选中的任务定义(整组执行) /// [RelayCommand] private async Task ExecuteSelectedTaskDefinition() { await ExecuteTaskDefinition(SelectedTaskDefinition); } /// /// 执行指定任务定义(整组执行) /// [RelayCommand] private async Task ExecuteTaskDefinition(GearTaskDefinitionViewModel? taskDefinition) { taskDefinition ??= SelectedTaskDefinition; if (taskDefinition == null) { Toast.Warning("请先选择要执行的任务组"); return; } try { var executor = App.GetRequiredService(); if (executor.IsExecuting) { Toast.Warning("已有任务组正在执行,请稍后再试"); return; } await executor.ExecuteTaskDefinitionAsync(taskDefinition.Name); } catch (Exception ex) { _logger.LogError(ex, "执行任务定义失败: {TaskName}", taskDefinition.Name); Toast.Error($"执行任务组失败:{ex.Message}"); } } /// /// 添加任务节点 /// [RelayCommand] private async Task AddTaskNode(string? taskType = null) { if (SelectedTaskDefinition?.RootTask == null) { Toast.Warning("请先选择一个任务定义"); return; } // 检查选中的节点是否为任务组,任务节点下不允许添加任务节点 if (SelectedTaskNode != null && !SelectedTaskNode.IsDirectory) { Toast.Warning("只有任务组下能够添加任务!"); return; } // 如果没有指定任务类型,默认为Javascript taskType ??= "Javascript"; GearTaskViewModel newTask; // 如果是JS脚本类型,使用JS脚本选择窗口 if (taskType == "Javascript") { var jsSelectionWindow = new JsScriptSelectionWindow { Owner = Application.Current.MainWindow }; jsSelectionWindow.ShowDialog(); if (jsSelectionWindow.DialogResult && jsSelectionWindow.ViewModel.SelectedScript != null) { var selectedScript = jsSelectionWindow.ViewModel.SelectedScript; newTask = new GearTaskViewModel(string.IsNullOrWhiteSpace(selectedScript.Name) ? selectedScript.FolderName : selectedScript.Name) { TaskType = "Javascript", Path = @$"{{jsUserFolder}}\{selectedScript.FolderName}\" }; } else { return; // 用户取消了操作 } } // 如果是地图追踪类型,使用地图追踪任务选择窗口 else if (taskType == "Pathing") { var pathingSelectionWindow = new PathingTaskSelectionWindow { Owner = Application.Current.MainWindow }; pathingSelectionWindow.ShowDialog(); if (pathingSelectionWindow.DialogResult && pathingSelectionWindow.SelectedGearTask != null) { newTask = pathingSelectionWindow.SelectedGearTask; } else { return; // 用户取消了操作 } } else if (taskType == "Shell") { var list = LoadAllKmScripts(); var folder = KeyMouseRecordPageViewModel.ScriptPath; var combobox = new ComboBox { VerticalAlignment = VerticalAlignment.Top }; foreach (var fileInfo in list) { // 计算相对于 KeyMouseScript 文件夹的相对路径 var relativePath = Path.GetRelativePath(folder, fileInfo.FullName); combobox.Items.Add(relativePath); } var str = PromptDialog.Prompt("请选择需要添加的键鼠脚本", "请选择需要添加的键鼠脚本", combobox); if (!string.IsNullOrEmpty(str)) { newTask = new GearTaskViewModel(str) { TaskType = "Javascript", Path = @$"{{kmUserFolder}}\{str}\" }; } else { return; } } else if (taskType == "Shell") { var str = PromptDialog.Prompt("执行 shell 操作存在极大风险!请勿输入你看不懂的指令!以免引发安全隐患并损坏系统!\n执行 shell 的时候,游戏可能会失去焦点", "请输入需要执行的shell"); if (!string.IsNullOrEmpty(str)) { newTask = new GearTaskViewModel(str) { TaskType = "Shell", Parameters = str }; } else { return; } } else { // 其他类型使用原有的对话框 var dialogResult = AddTaskNodeDialog.ShowDialog(taskType, Application.Current.MainWindow); if (dialogResult == null) { return; // 用户取消了操作 } newTask = new GearTaskViewModel(dialogResult.TaskName) { TaskType = dialogResult.TaskType, }; } // 如果有选中的节点,则在选中节点下新增 // 如果未选择节点,则在根节点下直接新增 var targetParent = SelectedTaskNode ?? SelectedTaskDefinition.RootTask; targetParent.AddChild(newTask); // 展开父节点 targetParent.IsExpanded = true; SelectedTaskDefinition.ModifiedTime = DateTime.Now; // 自动保存到文件 await _storageService.SaveTaskDefinitionAsync(SelectedTaskDefinition); } private List LoadAllKmScripts() { var folder = KeyMouseRecordPageViewModel.ScriptPath; // 获取所有脚本项目 var files = Directory.GetFiles(folder, "*.*", SearchOption.AllDirectories); return files.Select(file => new FileInfo(file)).ToList(); } /// /// 添加任务组 /// [RelayCommand] private async Task AddTaskGroup() { if (SelectedTaskDefinition?.RootTask == null) { Toast.Warning("请先选择一个任务定义"); return; } // 检查选中的节点是否为任务组,任务节点下不允许添加任务组 if (SelectedTaskNode != null && !SelectedTaskNode.IsDirectory) { Toast.Warning("任务节点下不允许添加任务组,只有任务组下能够添加任务组"); return; } // 弹出对话框输入任务组名称 var groupName = PromptDialog.Prompt("请输入任务组名称:", "添加任务组", $"新任务组{DateTime.Now:HHmmss}"); if (string.IsNullOrWhiteSpace(groupName)) { return; // 用户取消了操作 } var newGroup = new GearTaskViewModel(groupName, true); // 如果有选中的节点,则在选中节点下新增 // 如果未选择节点,则在根节点下直接新增 var targetParent = SelectedTaskNode ?? SelectedTaskDefinition.RootTask; targetParent.AddChild(newGroup); // 展开父节点 targetParent.IsExpanded = true; SelectedTaskDefinition.ModifiedTime = DateTime.Now; // 自动保存到文件 await _storageService.SaveTaskDefinitionAsync(SelectedTaskDefinition); } /// /// 删除任务节点 /// [RelayCommand] private async Task DeleteTaskNode(GearTaskViewModel? taskNode) { if (taskNode == null || SelectedTaskDefinition?.RootTask == null) return; var result = MessageBox.Show($"确定要删除任务 '{taskNode.Name}' 吗?", "确认删除", MessageBoxButton.YesNo, MessageBoxImage.Question); if (result == MessageBoxResult.Yes) { RemoveTaskFromTree(SelectedTaskDefinition.RootTask, taskNode); SelectedTaskDefinition.ModifiedTime = DateTime.Now; // 自动保存到文件 await _storageService.SaveTaskDefinitionAsync(SelectedTaskDefinition); } } /// /// 从树中移除任务节点 /// private bool RemoveTaskFromTree(GearTaskViewModel parent, GearTaskViewModel target) { if (parent.Children.Contains(target)) { parent.RemoveChild(target); return true; } foreach (var child in parent.Children) { if (RemoveTaskFromTree(child, target)) { return true; } } return false; } /// /// 从JSON文件重新加载所有任务定义(内部使用) /// private async Task LoadFromJsonInternal() { try { TaskDefinitions.Clear(); var loadedTasks = await _storageService.LoadAllTaskDefinitionsAsync(); foreach (var task in loadedTasks) { TaskDefinitions.Add(task); SetupTaskDefinitionPropertyChanged(task); } _logger.LogInformation("从JSON文件重新加载了 {Count} 个任务定义", loadedTasks.Count); } catch (Exception ex) { _logger.LogError(ex, "从JSON文件加载任务定义时发生错误"); } } /// /// 为任务定义设置属性变化监听器,实现自动保存 /// private void SetupTaskDefinitionPropertyChanged(GearTaskDefinitionViewModel taskDefinition) { taskDefinition.PropertyChanged += async (sender, e) => { if (sender is GearTaskDefinitionViewModel task) { try { await _storageService.SaveTaskDefinitionAsync(task); } catch (Exception ex) { _logger.LogError(ex, "自动保存任务定义 {TaskName} 时发生错误", task.Name); } } }; // 为根任务及其所有子任务设置监听器 if (taskDefinition.RootTask != null) { SetupTaskPropertyChangeListener(taskDefinition.RootTask, taskDefinition); } } /// /// 递归为任务及其子任务设置属性变化监听器 /// private void SetupTaskPropertyChangeListener(GearTaskViewModel task, GearTaskDefinitionViewModel parentDefinition) { task.PropertyChanged += async (sender, e) => { try { parentDefinition.ModifiedTime = DateTime.Now; await _storageService.SaveTaskDefinitionAsync(parentDefinition); } catch (Exception ex) { _logger.LogError(ex, "自动保存任务定义 {TaskName} 时发生错误", parentDefinition.Name); } }; // 为子任务设置监听器 foreach (var child in task.Children) { SetupTaskPropertyChangeListener(child, parentDefinition); } // 监听子任务集合变化 task.Children.CollectionChanged += async (sender, e) => { if (e.NewItems != null) { foreach (GearTaskViewModel newTask in e.NewItems) { SetupTaskPropertyChangeListener(newTask, parentDefinition); } } // 任何集合变化都触发保存(包括拖拽重排序) try { parentDefinition.ModifiedTime = DateTime.Now; await _storageService.SaveTaskDefinitionAsync(parentDefinition); _logger.LogInformation("任务树结构变化,已自动保存任务定义 '{TaskName}'", parentDefinition.Name); } catch (Exception ex) { _logger.LogError(ex, "自动保存任务定义 {TaskName} 时发生错误", parentDefinition.Name); } }; } /// /// 刷新当前任务树显示 /// }