mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-05-21 09:45:48 +08:00
feat: implement GearTaskStorageService for task definition persistence
This commit is contained in:
@@ -136,6 +136,7 @@ public partial class App : Application
|
||||
services.AddSingleton<HutaoNamedPipe>();
|
||||
services.AddSingleton<BgiOnnxFactory>();
|
||||
services.AddSingleton<OcrFactory>();
|
||||
services.AddSingleton<GearTaskStorageService>();
|
||||
|
||||
// Configuration
|
||||
//services.Configure<AppConfig>(context.Configuration.GetSection(nameof(AppConfig)));
|
||||
|
||||
65
BetterGenshinImpact/Model/Gear/GearTaskData.cs
Normal file
65
BetterGenshinImpact/Model/Gear/GearTaskData.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BetterGenshinImpact.Model.Gear;
|
||||
|
||||
/// <summary>
|
||||
/// 任务定义数据模型,用于 JSON 序列化
|
||||
/// </summary>
|
||||
public class GearTaskDefinitionData
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty("description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty("created_time")]
|
||||
public DateTime CreatedTime { get; set; } = DateTime.Now;
|
||||
|
||||
[JsonProperty("modified_time")]
|
||||
public DateTime ModifiedTime { get; set; } = DateTime.Now;
|
||||
|
||||
[JsonProperty("root_task")]
|
||||
public GearTaskData? RootTask { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 任务数据模型,用于 JSON 序列化
|
||||
/// </summary>
|
||||
public class GearTaskData
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty("description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty("task_type")]
|
||||
public string TaskType { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty("is_enabled")]
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
|
||||
[JsonProperty("is_directory")]
|
||||
public bool IsDirectory { get; set; } = false;
|
||||
|
||||
[JsonProperty("parameters")]
|
||||
public string Parameters { get; set; } = "{}";
|
||||
|
||||
[JsonProperty("created_time")]
|
||||
public DateTime CreatedTime { get; set; } = DateTime.Now;
|
||||
|
||||
[JsonProperty("modified_time")]
|
||||
public DateTime ModifiedTime { get; set; } = DateTime.Now;
|
||||
|
||||
[JsonProperty("priority")]
|
||||
public int Priority { get; set; } = 0;
|
||||
|
||||
[JsonProperty("tags")]
|
||||
public string Tags { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty("children")]
|
||||
public List<GearTaskData> Children { get; set; } = new();
|
||||
}
|
||||
304
BetterGenshinImpact/Service/GearTaskStorageService.cs
Normal file
304
BetterGenshinImpact/Service/GearTaskStorageService.cs
Normal file
@@ -0,0 +1,304 @@
|
||||
using BetterGenshinImpact.Model.Gear;
|
||||
using BetterGenshinImpact.ViewModel.Pages.Component;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BetterGenshinImpact.Core.Config;
|
||||
|
||||
namespace BetterGenshinImpact.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 齿轮任务存储服务,负责任务定义的 JSON 持久化
|
||||
/// </summary>
|
||||
public class GearTaskStorageService
|
||||
{
|
||||
private readonly ILogger<GearTaskStorageService> _logger;
|
||||
private readonly string _taskStoragePath;
|
||||
private readonly JsonSerializerSettings _jsonSettings;
|
||||
|
||||
public GearTaskStorageService(ILogger<GearTaskStorageService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_taskStoragePath = Path.Combine(Global.Absolute("User"), "task_v2", "list");
|
||||
|
||||
// 确保目录存在
|
||||
Directory.CreateDirectory(_taskStoragePath);
|
||||
|
||||
// 配置 JSON 序列化设置
|
||||
_jsonSettings = new JsonSerializerSettings
|
||||
{
|
||||
Formatting = Formatting.Indented,
|
||||
DateFormatString = "yyyy-MM-dd HH:mm:ss",
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存任务定义到 JSON 文件
|
||||
/// </summary>
|
||||
/// <param name="taskDefinition">任务定义</param>
|
||||
/// <returns></returns>
|
||||
public async Task SaveTaskDefinitionAsync(GearTaskDefinitionViewModel taskDefinition)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = ConvertToData(taskDefinition);
|
||||
var fileName = GetSafeFileName(taskDefinition.Name) + ".json";
|
||||
var filePath = Path.Combine(_taskStoragePath, fileName);
|
||||
|
||||
var json = JsonConvert.SerializeObject(data, _jsonSettings);
|
||||
await File.WriteAllTextAsync(filePath, json);
|
||||
|
||||
_logger.LogInformation("任务定义 '{TaskName}' 已保存到 {FilePath}", taskDefinition.Name, filePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "保存任务定义 '{TaskName}' 时发生错误", taskDefinition.Name);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从 JSON 文件加载任务定义
|
||||
/// </summary>
|
||||
/// <param name="fileName">文件名(不含扩展名)</param>
|
||||
/// <returns></returns>
|
||||
public async Task<GearTaskDefinitionViewModel?> LoadTaskDefinitionAsync(string fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var filePath = Path.Combine(_taskStoragePath, fileName + ".json");
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
_logger.LogWarning("任务定义文件不存在: {FilePath}", filePath);
|
||||
return null;
|
||||
}
|
||||
|
||||
var json = await File.ReadAllTextAsync(filePath);
|
||||
var data = JsonConvert.DeserializeObject<GearTaskDefinitionData>(json, _jsonSettings);
|
||||
|
||||
if (data == null)
|
||||
{
|
||||
_logger.LogWarning("无法反序列化任务定义文件: {FilePath}", filePath);
|
||||
return null;
|
||||
}
|
||||
|
||||
var viewModel = ConvertToViewModel(data);
|
||||
_logger.LogInformation("任务定义 '{TaskName}' 已从 {FilePath} 加载", data.Name, filePath);
|
||||
|
||||
return viewModel;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "加载任务定义文件 '{FileName}' 时发生错误", fileName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载所有任务定义
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<GearTaskDefinitionViewModel>> LoadAllTaskDefinitionsAsync()
|
||||
{
|
||||
var taskDefinitions = new List<GearTaskDefinitionViewModel>();
|
||||
|
||||
try
|
||||
{
|
||||
var jsonFiles = Directory.GetFiles(_taskStoragePath, "*.json");
|
||||
|
||||
foreach (var filePath in jsonFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = await File.ReadAllTextAsync(filePath);
|
||||
var data = JsonConvert.DeserializeObject<GearTaskDefinitionData>(json, _jsonSettings);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
var viewModel = ConvertToViewModel(data);
|
||||
taskDefinitions.Add(viewModel);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "加载任务定义文件 '{FilePath}' 时发生错误", filePath);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("已加载 {Count} 个任务定义", taskDefinitions.Count);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "加载任务定义列表时发生错误");
|
||||
}
|
||||
|
||||
return taskDefinitions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除任务定义文件
|
||||
/// </summary>
|
||||
/// <param name="taskName">任务名称</param>
|
||||
/// <returns></returns>
|
||||
public async Task DeleteTaskDefinitionAsync(string taskName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var fileName = GetSafeFileName(taskName) + ".json";
|
||||
var filePath = Path.Combine(_taskStoragePath, fileName);
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
await Task.Run(() => File.Delete(filePath));
|
||||
_logger.LogInformation("任务定义文件已删除: {FilePath}", filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("要删除的任务定义文件不存在: {FilePath}", filePath);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "删除任务定义 '{TaskName}' 时发生错误", taskName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重命名任务定义文件
|
||||
/// </summary>
|
||||
/// <param name="oldName">旧名称</param>
|
||||
/// <param name="newName">新名称</param>
|
||||
/// <returns></returns>
|
||||
public async Task RenameTaskDefinitionAsync(string oldName, string newName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var oldFileName = GetSafeFileName(oldName) + ".json";
|
||||
var newFileName = GetSafeFileName(newName) + ".json";
|
||||
var oldFilePath = Path.Combine(_taskStoragePath, oldFileName);
|
||||
var newFilePath = Path.Combine(_taskStoragePath, newFileName);
|
||||
|
||||
if (File.Exists(oldFilePath))
|
||||
{
|
||||
await Task.Run(() => File.Move(oldFilePath, newFilePath));
|
||||
_logger.LogInformation("任务定义文件已重命名: {OldPath} -> {NewPath}", oldFilePath, newFilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("要重命名的任务定义文件不存在: {FilePath}", oldFilePath);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "重命名任务定义 '{OldName}' -> '{NewName}' 时发生错误", oldName, newName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 ViewModel 转换为数据模型
|
||||
/// </summary>
|
||||
/// <param name="viewModel">视图模型</param>
|
||||
/// <returns></returns>
|
||||
private GearTaskDefinitionData ConvertToData(GearTaskDefinitionViewModel viewModel)
|
||||
{
|
||||
return new GearTaskDefinitionData
|
||||
{
|
||||
Name = viewModel.Name,
|
||||
Description = viewModel.Description,
|
||||
CreatedTime = viewModel.CreatedTime,
|
||||
ModifiedTime = viewModel.ModifiedTime,
|
||||
RootTask = viewModel.RootTask != null ? ConvertTaskToData(viewModel.RootTask) : null
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将任务 ViewModel 转换为数据模型
|
||||
/// </summary>
|
||||
/// <param name="viewModel">任务视图模型</param>
|
||||
/// <returns></returns>
|
||||
private GearTaskData ConvertTaskToData(GearTaskViewModel viewModel)
|
||||
{
|
||||
return new GearTaskData
|
||||
{
|
||||
Name = viewModel.Name,
|
||||
Description = viewModel.Description,
|
||||
TaskType = viewModel.TaskType,
|
||||
IsEnabled = viewModel.IsEnabled,
|
||||
IsDirectory = viewModel.IsDirectory,
|
||||
Parameters = viewModel.Parameters,
|
||||
CreatedTime = viewModel.CreatedTime,
|
||||
ModifiedTime = viewModel.ModifiedTime,
|
||||
Priority = viewModel.Priority,
|
||||
Tags = viewModel.Tags,
|
||||
Children = viewModel.Children.Select(ConvertTaskToData).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将数据模型转换为 ViewModel
|
||||
/// </summary>
|
||||
/// <param name="data">数据模型</param>
|
||||
/// <returns></returns>
|
||||
private GearTaskDefinitionViewModel ConvertToViewModel(GearTaskDefinitionData data)
|
||||
{
|
||||
var viewModel = new GearTaskDefinitionViewModel
|
||||
{
|
||||
Name = data.Name,
|
||||
Description = data.Description,
|
||||
CreatedTime = data.CreatedTime,
|
||||
ModifiedTime = data.ModifiedTime,
|
||||
RootTask = data.RootTask != null ? ConvertTaskToViewModel(data.RootTask) : null
|
||||
};
|
||||
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将任务数据模型转换为 ViewModel
|
||||
/// </summary>
|
||||
/// <param name="data">任务数据模型</param>
|
||||
/// <returns></returns>
|
||||
private GearTaskViewModel ConvertTaskToViewModel(GearTaskData data)
|
||||
{
|
||||
var viewModel = new GearTaskViewModel
|
||||
{
|
||||
Name = data.Name,
|
||||
Description = data.Description,
|
||||
TaskType = data.TaskType,
|
||||
IsEnabled = data.IsEnabled,
|
||||
IsDirectory = data.IsDirectory,
|
||||
Parameters = data.Parameters,
|
||||
CreatedTime = data.CreatedTime,
|
||||
ModifiedTime = data.ModifiedTime,
|
||||
Priority = data.Priority,
|
||||
Tags = data.Tags
|
||||
};
|
||||
|
||||
// 递归转换子任务
|
||||
foreach (var childData in data.Children)
|
||||
{
|
||||
viewModel.Children.Add(ConvertTaskToViewModel(childData));
|
||||
}
|
||||
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取安全的文件名(移除非法字符)
|
||||
/// </summary>
|
||||
/// <param name="name">原始名称</param>
|
||||
/// <returns></returns>
|
||||
private string GetSafeFileName(string name)
|
||||
{
|
||||
var invalidChars = Path.GetInvalidFileNameChars();
|
||||
var safeName = string.Join("_", name.Split(invalidChars, StringSplitOptions.RemoveEmptyEntries));
|
||||
return string.IsNullOrWhiteSpace(safeName) ? "unnamed_task" : safeName;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
xmlns:pages="clr-namespace:BetterGenshinImpact.ViewModel.Pages"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
xmlns:component="clr-namespace:BetterGenshinImpact.ViewModel.Pages.Component"
|
||||
xmlns:dd="urn:gong-wpf-dragdrop"
|
||||
d:DataContext="{d:DesignInstance Type=pages:GearTaskListPageViewModel}"
|
||||
d:DesignHeight="850"
|
||||
d:DesignWidth="1200"
|
||||
@@ -153,6 +154,9 @@
|
||||
ItemTemplate="{StaticResource TaskDefinitionItemTemplate}"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
dd:DragDrop.IsDragSource="True"
|
||||
dd:DragDrop.IsDropTarget="True"
|
||||
dd:DragDrop.UseDefaultDragAdorner="True"
|
||||
Padding="4">
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem">
|
||||
@@ -231,7 +235,11 @@
|
||||
|
||||
<ui:TreeListView BorderThickness="0"
|
||||
ItemsSource="{Binding CurrentTaskTree}"
|
||||
SelectedItem="{Binding SelectedTaskNode}">
|
||||
SelectedItem="{Binding SelectedTaskNode}"
|
||||
dd:DragDrop.IsDragSource="True"
|
||||
dd:DragDrop.IsDropTarget="True"
|
||||
dd:DragDrop.UseDefaultDragAdorner="True"
|
||||
>
|
||||
<ui:TreeListView.Columns>
|
||||
<GridViewColumnCollection>
|
||||
<ui:GridViewColumn Width="{Binding ActualWidth, ElementName=TreeColumnName}" Header="任务名称">
|
||||
|
||||
@@ -10,6 +10,9 @@ using System.Windows;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using BetterGenshinImpact.ViewModel.Pages.Component;
|
||||
using BetterGenshinImpact.Service;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace BetterGenshinImpact.ViewModel.Pages;
|
||||
|
||||
@@ -19,6 +22,7 @@ namespace BetterGenshinImpact.ViewModel.Pages;
|
||||
public partial class GearTaskListPageViewModel : ViewModel
|
||||
{
|
||||
private readonly ILogger<GearTaskListPageViewModel> _logger;
|
||||
private readonly GearTaskStorageService _storageService;
|
||||
|
||||
/// <summary>
|
||||
/// 任务定义列表(左侧)
|
||||
@@ -60,18 +64,61 @@ public partial class GearTaskListPageViewModel : ViewModel
|
||||
"组合任务"
|
||||
};
|
||||
|
||||
public GearTaskListPageViewModel(ILogger<GearTaskListPageViewModel> logger)
|
||||
public GearTaskListPageViewModel(ILogger<GearTaskListPageViewModel> logger, GearTaskStorageService storageService)
|
||||
{
|
||||
_logger = logger;
|
||||
_storageService = storageService;
|
||||
InitializeData();
|
||||
|
||||
// 监听集合变化,实现自动保存
|
||||
TaskDefinitions.CollectionChanged += OnTaskDefinitionsChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 任务定义集合变化时的处理
|
||||
/// </summary>
|
||||
private async void OnTaskDefinitionsChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
// 当集合发生变化时,可以在这里处理自动保存等逻辑
|
||||
// 例如:保存到配置文件等
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化数据
|
||||
/// </summary>
|
||||
private void InitializeData()
|
||||
private async void InitializeData()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 从 JSON 文件加载任务定义
|
||||
var loadedTasks = await _storageService.LoadAllTaskDefinitionsAsync();
|
||||
|
||||
foreach (var task in loadedTasks)
|
||||
{
|
||||
TaskDefinitions.Add(task);
|
||||
// 为每个任务定义设置属性变化监听
|
||||
SetupTaskDefinitionPropertyChanged(task);
|
||||
}
|
||||
|
||||
// 如果没有加载到任何任务,创建一个示例任务
|
||||
if (TaskDefinitions.Count == 0)
|
||||
{
|
||||
await CreateSampleTaskAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "初始化任务数据时发生错误");
|
||||
// 发生错误时创建示例任务
|
||||
await CreateSampleTaskAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建示例任务
|
||||
/// </summary>
|
||||
private async Task CreateSampleTaskAsync()
|
||||
{
|
||||
// 创建示例数据
|
||||
var sampleTask = new GearTaskDefinitionViewModel("示例任务组", "这是一个示例任务组");
|
||||
if (sampleTask.RootTask != null)
|
||||
{
|
||||
@@ -85,6 +132,10 @@ public partial class GearTaskListPageViewModel : ViewModel
|
||||
}
|
||||
|
||||
TaskDefinitions.Add(sampleTask);
|
||||
SetupTaskDefinitionPropertyChanged(sampleTask);
|
||||
|
||||
// 保存示例任务到文件
|
||||
await _storageService.SaveTaskDefinitionAsync(sampleTask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -124,18 +175,22 @@ public partial class GearTaskListPageViewModel : ViewModel
|
||||
/// 添加新的任务定义
|
||||
/// </summary>
|
||||
[RelayCommand]
|
||||
private void AddTaskDefinition()
|
||||
private async Task AddTaskDefinition()
|
||||
{
|
||||
var newTask = new GearTaskDefinitionViewModel($"新任务组 {TaskDefinitions.Count + 1}", "新创建的任务组");
|
||||
TaskDefinitions.Add(newTask);
|
||||
SetupTaskDefinitionPropertyChanged(newTask);
|
||||
SelectedTaskDefinition = newTask;
|
||||
|
||||
// 自动保存到文件
|
||||
await _storageService.SaveTaskDefinitionAsync(newTask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除任务定义
|
||||
/// </summary>
|
||||
[RelayCommand]
|
||||
private void DeleteTaskDefinition(GearTaskDefinitionViewModel? taskDefinition)
|
||||
private async Task DeleteTaskDefinition(GearTaskDefinitionViewModel? taskDefinition)
|
||||
{
|
||||
if (taskDefinition == null) return;
|
||||
|
||||
@@ -144,11 +199,15 @@ public partial class GearTaskListPageViewModel : ViewModel
|
||||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
var taskName = taskDefinition.Name;
|
||||
TaskDefinitions.Remove(taskDefinition);
|
||||
if (SelectedTaskDefinition == taskDefinition)
|
||||
{
|
||||
SelectedTaskDefinition = TaskDefinitions.FirstOrDefault();
|
||||
}
|
||||
|
||||
// 删除对应的 JSON 文件
|
||||
await _storageService.DeleteTaskDefinitionAsync(taskName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,21 +215,25 @@ public partial class GearTaskListPageViewModel : ViewModel
|
||||
/// 重命名任务定义
|
||||
/// </summary>
|
||||
[RelayCommand]
|
||||
private void RenameTaskDefinition(GearTaskDefinitionViewModel? taskDefinition)
|
||||
private async Task RenameTaskDefinition(GearTaskDefinitionViewModel? taskDefinition)
|
||||
{
|
||||
if (taskDefinition == null) return;
|
||||
|
||||
// 这里可以弹出重命名对话框,暂时简单处理
|
||||
var newName = "新名称"; // 简化处理,实际应该弹出输入框
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(newName))
|
||||
if (!string.IsNullOrWhiteSpace(newName) && newName != taskDefinition.Name)
|
||||
{
|
||||
var oldName = taskDefinition.Name;
|
||||
taskDefinition.Name = newName;
|
||||
taskDefinition.ModifiedTime = DateTime.Now;
|
||||
if (taskDefinition.RootTask != null)
|
||||
{
|
||||
taskDefinition.RootTask.Name = newName;
|
||||
}
|
||||
|
||||
// 重命名对应的 JSON 文件
|
||||
await _storageService.RenameTaskDefinitionAsync(oldName, newName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +241,7 @@ public partial class GearTaskListPageViewModel : ViewModel
|
||||
/// 添加任务节点
|
||||
/// </summary>
|
||||
[RelayCommand]
|
||||
private void AddTaskNode(string? taskType = null)
|
||||
private async Task AddTaskNode(string? taskType = null)
|
||||
{
|
||||
if (SelectedTaskDefinition?.RootTask == null) return;
|
||||
|
||||
@@ -198,13 +261,16 @@ public partial class GearTaskListPageViewModel : ViewModel
|
||||
}
|
||||
|
||||
SelectedTaskDefinition.ModifiedTime = DateTime.Now;
|
||||
|
||||
// 自动保存到文件
|
||||
await _storageService.SaveTaskDefinitionAsync(SelectedTaskDefinition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加任务组
|
||||
/// </summary>
|
||||
[RelayCommand]
|
||||
private void AddTaskGroup()
|
||||
private async Task AddTaskGroup()
|
||||
{
|
||||
if (SelectedTaskDefinition?.RootTask == null) return;
|
||||
|
||||
@@ -223,13 +289,16 @@ public partial class GearTaskListPageViewModel : ViewModel
|
||||
}
|
||||
|
||||
SelectedTaskDefinition.ModifiedTime = DateTime.Now;
|
||||
|
||||
// 自动保存到文件
|
||||
await _storageService.SaveTaskDefinitionAsync(SelectedTaskDefinition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除任务节点
|
||||
/// </summary>
|
||||
[RelayCommand]
|
||||
private void DeleteTaskNode(GearTaskViewModel? taskNode)
|
||||
private async Task DeleteTaskNode(GearTaskViewModel? taskNode)
|
||||
{
|
||||
if (taskNode == null || SelectedTaskDefinition?.RootTask == null) return;
|
||||
|
||||
@@ -240,6 +309,9 @@ public partial class GearTaskListPageViewModel : ViewModel
|
||||
{
|
||||
RemoveTaskFromTree(SelectedTaskDefinition.RootTask, taskNode);
|
||||
SelectedTaskDefinition.ModifiedTime = DateTime.Now;
|
||||
|
||||
// 自动保存到文件
|
||||
await _storageService.SaveTaskDefinitionAsync(SelectedTaskDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,46 +338,115 @@ public partial class GearTaskListPageViewModel : ViewModel
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存到JSON(预留功能)
|
||||
/// 保存所有任务定义到JSON文件
|
||||
/// </summary>
|
||||
[RelayCommand]
|
||||
private void SaveToJson()
|
||||
private async Task SaveToJson()
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = JsonSerializer.Serialize(TaskDefinitions, new JsonSerializerOptions
|
||||
foreach (var taskDefinition in TaskDefinitions)
|
||||
{
|
||||
WriteIndented = true,
|
||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
});
|
||||
|
||||
// 这里可以保存到配置文件
|
||||
_logger.LogInformation("任务定义已序列化为JSON: {Json}", json);
|
||||
await _storageService.SaveTaskDefinitionAsync(taskDefinition);
|
||||
}
|
||||
_logger.LogInformation("所有任务定义已保存到JSON文件");
|
||||
MessageBox.Show("保存成功!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "保存任务定义到JSON时发生错误");
|
||||
_logger.LogError(ex, "保存任务定义到JSON文件时发生错误");
|
||||
MessageBox.Show($"保存失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从JSON加载(预留功能)
|
||||
/// 从JSON文件重新加载所有任务定义
|
||||
/// </summary>
|
||||
[RelayCommand]
|
||||
private void LoadFromJson()
|
||||
private async Task LoadFromJson()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 这里可以从配置文件加载
|
||||
_logger.LogInformation("从JSON加载任务定义功能待实现");
|
||||
MessageBox.Show("加载功能待实现!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
TaskDefinitions.Clear();
|
||||
var loadedTasks = await _storageService.LoadAllTaskDefinitionsAsync();
|
||||
|
||||
foreach (var task in loadedTasks)
|
||||
{
|
||||
TaskDefinitions.Add(task);
|
||||
SetupTaskDefinitionPropertyChanged(task);
|
||||
}
|
||||
|
||||
_logger.LogInformation("从JSON文件重新加载了 {Count} 个任务定义", loadedTasks.Count);
|
||||
MessageBox.Show($"加载成功!共加载 {loadedTasks.Count} 个任务定义", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "从JSON加载任务定义时发生错误");
|
||||
_logger.LogError(ex, "从JSON文件加载任务定义时发生错误");
|
||||
MessageBox.Show($"加载失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为任务定义设置属性变化监听器,实现自动保存
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 递归为任务及其子任务设置属性变化监听器
|
||||
/// </summary>
|
||||
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 += (sender, e) =>
|
||||
{
|
||||
if (e.NewItems != null)
|
||||
{
|
||||
foreach (GearTaskViewModel newTask in e.NewItems)
|
||||
{
|
||||
SetupTaskPropertyChangeListener(newTask, parentDefinition);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user