From a59663f4d6442d4daa0d10f0c48a67ae1aaf3e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Mon, 28 Jul 2025 02:00:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=88=97=E8=A1=A8=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/App.xaml.cs | 1 + .../Model/Gear/Tasks/GearTaskRefence.cs | 2 +- BetterGenshinImpact/View/MainWindow.xaml | 13 +- .../View/Pages/GearTaskListPage.xaml | 290 ++++++++++++++++ .../View/Pages/GearTaskListPage.xaml.cs | 33 ++ .../Component/GearTaskDefinitionViewModel.cs | 65 ++++ .../Pages/Component/GearTaskViewModel.cs | 138 ++++++++ .../Pages/GearTaskListPageViewModel.cs | 311 ++++++++++++++++++ 8 files changed, 849 insertions(+), 4 deletions(-) create mode 100644 BetterGenshinImpact/View/Pages/GearTaskListPage.xaml create mode 100644 BetterGenshinImpact/View/Pages/GearTaskListPage.xaml.cs create mode 100644 BetterGenshinImpact/ViewModel/Pages/Component/GearTaskDefinitionViewModel.cs create mode 100644 BetterGenshinImpact/ViewModel/Pages/Component/GearTaskViewModel.cs create mode 100644 BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs diff --git a/BetterGenshinImpact/App.xaml.cs b/BetterGenshinImpact/App.xaml.cs index 3f169004..ea14c4d6 100644 --- a/BetterGenshinImpact/App.xaml.cs +++ b/BetterGenshinImpact/App.xaml.cs @@ -110,6 +110,7 @@ public partial class App : Application // services.AddView(); services.AddView(); services.AddView(); + services.AddView(); // 一条龙 ViewModels diff --git a/BetterGenshinImpact/Model/Gear/Tasks/GearTaskRefence.cs b/BetterGenshinImpact/Model/Gear/Tasks/GearTaskRefence.cs index 3762fb04..3f346032 100644 --- a/BetterGenshinImpact/Model/Gear/Tasks/GearTaskRefence.cs +++ b/BetterGenshinImpact/Model/Gear/Tasks/GearTaskRefence.cs @@ -16,7 +16,7 @@ public class GearTaskRefence public bool Enabled { get; set; } /// - /// GearTask 的文件路径 + /// GearTaskViewModel 的文件路径 /// public string GearTaskFilePath { get; set; } = string.Empty; diff --git a/BetterGenshinImpact/View/MainWindow.xaml b/BetterGenshinImpact/View/MainWindow.xaml index aaa2bcb8..9299280b 100644 --- a/BetterGenshinImpact/View/MainWindow.xaml +++ b/BetterGenshinImpact/View/MainWindow.xaml @@ -10,8 +10,8 @@ xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" xmlns:viewModel="clr-namespace:BetterGenshinImpact.ViewModel" Title="更好的原神" - Width="900" - Height="600" + Width="1050" + Height="700" d:Background="#D2D2D2" d:DataContext="{d:DesignInstance Type=viewModel:MainWindowViewModel}" ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}" @@ -79,6 +79,7 @@ + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BetterGenshinImpact/View/Pages/GearTaskListPage.xaml.cs b/BetterGenshinImpact/View/Pages/GearTaskListPage.xaml.cs new file mode 100644 index 00000000..91027ec7 --- /dev/null +++ b/BetterGenshinImpact/View/Pages/GearTaskListPage.xaml.cs @@ -0,0 +1,33 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using BetterGenshinImpact.ViewModel.Pages; +using BetterGenshinImpact.ViewModel.Pages.Component; + +namespace BetterGenshinImpact.View.Pages; + +/// +/// GearTaskListPage.xaml 的交互逻辑 +/// +public partial class GearTaskListPage : UserControl +{ + private GearTaskListPageViewModel ViewModel { get; } + + public GearTaskListPage(GearTaskListPageViewModel viewModel) + { + DataContext = ViewModel = viewModel; + InitializeComponent(); + } + + /// + /// 任务定义项双击事件 + /// + private void TaskDefinitionItem_MouseDoubleClick(object sender, MouseButtonEventArgs e) + { + if (sender is ListBoxItem item && item.DataContext is GearTaskDefinitionViewModel taskDefinition) + { + // 双击重命名 + ViewModel.RenameTaskDefinitionCommand.Execute(taskDefinition); + } + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/ViewModel/Pages/Component/GearTaskDefinitionViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/Component/GearTaskDefinitionViewModel.cs new file mode 100644 index 00000000..1e1b3e02 --- /dev/null +++ b/BetterGenshinImpact/ViewModel/Pages/Component/GearTaskDefinitionViewModel.cs @@ -0,0 +1,65 @@ +using System; +using System.Linq; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace BetterGenshinImpact.ViewModel.Pages.Component; + +/// +/// 任务定义模型,用于左侧列表显示 +/// +public partial class GearTaskDefinitionViewModel : ObservableObject +{ + [ObservableProperty] + private string _name = string.Empty; + + [ObservableProperty] + private string _description = string.Empty; + + [ObservableProperty] + private bool _isSelected = false; + + [ObservableProperty] + private DateTime _createdTime = DateTime.Now; + + [ObservableProperty] + private DateTime _modifiedTime = DateTime.Now; + + /// + /// 任务根节点 + /// + [ObservableProperty] + private GearTaskViewModel? _rootTask; + + public GearTaskDefinitionViewModel() + { + } + + public GearTaskDefinitionViewModel(string name, string description = "") + { + Name = name; + Description = description; + RootTask = new GearTaskViewModel(name, true); + } + + /// + /// 获取任务总数(包括所有子任务) + /// + /// + public int GetTotalTaskCount() + { + if (RootTask == null) return 0; + return 1 + Enumerable.Count(RootTask.GetAllChildren()); + } + + /// + /// 获取启用的任务数量 + /// + /// + public int GetEnabledTaskCount() + { + if (RootTask == null) return 0; + var count = RootTask.IsEnabled ? 1 : 0; + count += Enumerable.Count(RootTask.GetAllChildren(), t => t.IsEnabled); + return count; + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/ViewModel/Pages/Component/GearTaskViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/Component/GearTaskViewModel.cs new file mode 100644 index 00000000..6ba34fd1 --- /dev/null +++ b/BetterGenshinImpact/ViewModel/Pages/Component/GearTaskViewModel.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace BetterGenshinImpact.ViewModel.Pages.Component; + +/// +/// 齿轮任务模型,支持无限树嵌套层级 +/// +public partial class GearTaskViewModel : ObservableObject +{ + [ObservableProperty] + private string _name = string.Empty; + + [ObservableProperty] + private string _description = string.Empty; + + [ObservableProperty] + private string _taskType = string.Empty; + + [ObservableProperty] + private bool _isEnabled = true; + + [ObservableProperty] + private bool _isDirectory = false; + + [ObservableProperty] + private bool _isExpanded = false; + + [ObservableProperty] + private ObservableCollection _children = new(); + + /// + /// 任务参数,存储为JSON字符串 + /// + [ObservableProperty] + private string _parameters = "{}"; + + /// + /// 创建时间 + /// + public DateTime CreatedTime { get; set; } = DateTime.Now; + + /// + /// 修改时间 + /// + public DateTime ModifiedTime { get; set; } = DateTime.Now; + + /// + /// 任务优先级 + /// + [ObservableProperty] + private int _priority = 0; + + /// + /// 任务标签 + /// + [ObservableProperty] + private string _tags = string.Empty; + + public GearTaskViewModel() + { + } + + public GearTaskViewModel(string name, bool isDirectory = false) + { + Name = name; + IsDirectory = isDirectory; + } + + /// + /// 添加子任务 + /// + /// + public void AddChild(GearTaskViewModel child) + { + Children.Add(child); + IsDirectory = true; + } + + /// + /// 移除子任务 + /// + /// + public void RemoveChild(GearTaskViewModel child) + { + Children.Remove(child); + if (Children.Count == 0) + { + IsDirectory = false; + } + } + + /// + /// 获取所有子任务(递归) + /// + /// + public IEnumerable GetAllChildren() + { + foreach (var child in Children) + { + yield return child; + foreach (var grandChild in child.GetAllChildren()) + { + yield return grandChild; + } + } + } + + /// + /// 克隆任务 + /// + /// + public GearTaskViewModel Clone() + { + var clone = new GearTaskViewModel + { + Name = Name, + Description = Description, + TaskType = TaskType, + IsEnabled = IsEnabled, + IsDirectory = IsDirectory, + Parameters = Parameters, + Priority = Priority, + Tags = Tags, + CreatedTime = CreatedTime, + ModifiedTime = DateTime.Now + }; + + foreach (var child in Children) + { + clone.Children.Add(child.Clone()); + } + + return clone; + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs new file mode 100644 index 00000000..2af0eca4 --- /dev/null +++ b/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs @@ -0,0 +1,311 @@ +using System.Collections.ObjectModel; +using System.Text.Json; +using BetterGenshinImpact.Model; +using BetterGenshinImpact.ViewModel; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using Microsoft.Extensions.Logging; +using System.IO; +using System.Windows; +using System.Linq; +using System; +using BetterGenshinImpact.ViewModel.Pages.Component; + +namespace BetterGenshinImpact.ViewModel.Pages; + +/// +/// 任务列表页面ViewModel +/// +public partial class GearTaskListPageViewModel : ViewModel +{ + private readonly ILogger _logger; + + /// + /// 任务定义列表(左侧) + /// + [ObservableProperty] + private ObservableCollection _taskDefinitions = new(); + + /// + /// 当前选中的任务定义 + /// + [ObservableProperty] + private GearTaskDefinitionViewModel? _selectedTaskDefinition; + + /// + /// 当前任务树(右侧) + /// + [ObservableProperty] + private ObservableCollection _currentTaskTree = new(); + + /// + /// 当前选中的任务节点 + /// + [ObservableProperty] + private GearTaskViewModel? _selectedTaskNode; + + /// + /// 可用的任务类型 + /// + public ObservableCollection AvailableTaskTypes { get; } = new() + { + "采集任务", + "战斗任务", + "传送任务", + "交互任务", + "等待任务", + "脚本任务", + "条件任务", + "循环任务", + "组合任务" + }; + + public GearTaskListPageViewModel(ILogger logger) + { + _logger = logger; + InitializeData(); + } + + /// + /// 初始化数据 + /// + private void InitializeData() + { + // 创建示例数据 + var sampleTask = new GearTaskDefinitionViewModel("示例任务组", "这是一个示例任务组"); + if (sampleTask.RootTask != null) + { + sampleTask.RootTask.AddChild(new GearTaskViewModel("采集任务1") { TaskType = "采集任务", Description = "采集莲花" }); + sampleTask.RootTask.AddChild(new GearTaskViewModel("战斗任务1") { TaskType = "战斗任务", Description = "击败史莱姆" }); + + var subGroup = new GearTaskViewModel("子任务组", true); + subGroup.AddChild(new GearTaskViewModel("传送任务1") { TaskType = "传送任务", Description = "传送到蒙德" }); + subGroup.AddChild(new GearTaskViewModel("交互任务1") { TaskType = "交互任务", Description = "与NPC对话" }); + sampleTask.RootTask.AddChild(subGroup); + } + + TaskDefinitions.Add(sampleTask); + } + + /// + /// 选中任务定义时的处理 + /// + partial void OnSelectedTaskDefinitionChanged(GearTaskDefinitionViewModel? value) + { + // 清除之前选中项的状态 + foreach (var task in TaskDefinitions) + { + task.IsSelected = false; + } + + // 设置当前选中项 + if (value != null) + { + value.IsSelected = true; + } + + CurrentTaskTree.Clear(); + if (value?.RootTask != null) + { + CurrentTaskTree.Add(value.RootTask); + } + } + + /// + /// 选择任务定义命令 + /// + [RelayCommand] + private void SelectTaskDefinition(GearTaskDefinitionViewModel? taskDefinition) + { + SelectedTaskDefinition = taskDefinition; + } + + /// + /// 添加新的任务定义 + /// + [RelayCommand] + private void AddTaskDefinition() + { + var newTask = new GearTaskDefinitionViewModel($"新任务组 {TaskDefinitions.Count + 1}", "新创建的任务组"); + TaskDefinitions.Add(newTask); + SelectedTaskDefinition = newTask; + } + + /// + /// 删除任务定义 + /// + [RelayCommand] + private void DeleteTaskDefinition(GearTaskDefinitionViewModel? taskDefinition) + { + if (taskDefinition == null) return; + + var result = MessageBox.Show($"确定要删除任务定义 '{taskDefinition.Name}' 吗?", "确认删除", + MessageBoxButton.YesNo, MessageBoxImage.Question); + + if (result == MessageBoxResult.Yes) + { + TaskDefinitions.Remove(taskDefinition); + if (SelectedTaskDefinition == taskDefinition) + { + SelectedTaskDefinition = TaskDefinitions.FirstOrDefault(); + } + } + } + + /// + /// 重命名任务定义 + /// + [RelayCommand] + private void RenameTaskDefinition(GearTaskDefinitionViewModel? taskDefinition) + { + if (taskDefinition == null) return; + + // 这里可以弹出重命名对话框,暂时简单处理 + var newName = "新名称"; // 简化处理,实际应该弹出输入框 + + if (!string.IsNullOrWhiteSpace(newName)) + { + taskDefinition.Name = newName; + taskDefinition.ModifiedTime = DateTime.Now; + if (taskDefinition.RootTask != null) + { + taskDefinition.RootTask.Name = newName; + } + } + } + + /// + /// 添加任务节点 + /// + [RelayCommand] + private void AddTaskNode(string? taskType = null) + { + if (SelectedTaskDefinition?.RootTask == null) return; + + var newTask = new GearTaskViewModel($"新任务 {DateTime.Now:HHmmss}") + { + TaskType = taskType ?? AvailableTaskTypes.First(), + Description = "新创建的任务" + }; + + if (SelectedTaskNode != null) + { + SelectedTaskNode.AddChild(newTask); + } + else + { + SelectedTaskDefinition.RootTask.AddChild(newTask); + } + + SelectedTaskDefinition.ModifiedTime = DateTime.Now; + } + + /// + /// 添加任务组 + /// + [RelayCommand] + private void AddTaskGroup() + { + if (SelectedTaskDefinition?.RootTask == null) return; + + var newGroup = new GearTaskViewModel($"新任务组 {DateTime.Now:HHmmss}", true) + { + Description = "新创建的任务组" + }; + + if (SelectedTaskNode != null) + { + SelectedTaskNode.AddChild(newGroup); + } + else + { + SelectedTaskDefinition.RootTask.AddChild(newGroup); + } + + SelectedTaskDefinition.ModifiedTime = DateTime.Now; + } + + /// + /// 删除任务节点 + /// + [RelayCommand] + private void 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; + } + } + + /// + /// 从树中移除任务节点 + /// + 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(预留功能) + /// + [RelayCommand] + private void SaveToJson() + { + try + { + var json = JsonSerializer.Serialize(TaskDefinitions, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }); + + // 这里可以保存到配置文件 + _logger.LogInformation("任务定义已序列化为JSON: {Json}", json); + MessageBox.Show("保存成功!", "提示", MessageBoxButton.OK, MessageBoxImage.Information); + } + catch (Exception ex) + { + _logger.LogError(ex, "保存任务定义到JSON时发生错误"); + MessageBox.Show($"保存失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + /// + /// 从JSON加载(预留功能) + /// + [RelayCommand] + private void LoadFromJson() + { + try + { + // 这里可以从配置文件加载 + _logger.LogInformation("从JSON加载任务定义功能待实现"); + MessageBox.Show("加载功能待实现!", "提示", MessageBoxButton.OK, MessageBoxImage.Information); + } + catch (Exception ex) + { + _logger.LogError(ex, "从JSON加载任务定义时发生错误"); + MessageBox.Show($"加载失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); + } + } +} \ No newline at end of file