using System; using System.Collections.ObjectModel; using System.IO; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Microsoft.Extensions.Logging; using BetterGenshinImpact.Core.Script; using Newtonsoft.Json; using System.Collections.Generic; using System.Linq; using BetterGenshinImpact.ViewModel.Pages.Component; namespace BetterGenshinImpact.ViewModel.Windows.GearTask; /// /// 地图追踪任务选择窗口ViewModel /// public partial class PathingTaskSelectionViewModel : ViewModel { private readonly ILogger _logger = App.GetLogger(); /// /// 地图追踪任务列表 /// [ObservableProperty] private ObservableCollection _pathingTasks = new(); /// /// 过滤后的地图追踪任务列表 /// [ObservableProperty] private ObservableCollection _filteredPathingTasks = new(); /// /// 当前选中的地图追踪任务 /// [ObservableProperty] private PathingTaskInfo? _selectedTask; /// /// 搜索关键词 /// [ObservableProperty] private string _searchKeyword = string.Empty; /// /// 右侧显示的内容 /// [ObservableProperty] private string _displayContent = string.Empty; /// /// 右侧显示的内容类型(JSON或README) /// [ObservableProperty] private string _displayContentType = string.Empty; /// /// 任务导入方式:true=按组引用,false=逐个添加 /// [ObservableProperty] private bool _isGroupImportMode = true; /// /// 选中目录下的任务数量 /// [ObservableProperty] private int _selectedDirectoryTaskCount = 0; // /// // /// 图标字典 // /// // private Dictionary _iconDictionary = new(); public PathingTaskSelectionViewModel() { // LoadIconDictionary(); LoadPathingTasks(); } public Action? OnTaskAdded { get; set; } // /// // /// 加载图标字典 // /// // private void LoadIconDictionary() // { // try // { // var jsonContent = ResourceHelper.GetString("pack://application:,,,/Resources/Json/icons.json"); // if (string.IsNullOrEmpty(jsonContent)) // { // return; // } // var iconArray = JsonConvert.DeserializeObject(jsonContent); // if (iconArray != null) // { // foreach (var item in iconArray) // { // var name = item["name"]?.ToString(); // var link = item["link"]?.ToString(); // if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(link)) // { // _iconDictionary[name] = link; // } // } // } // } // catch (Exception ex) // { // _logger.LogError(ex, "加载图标字典失败"); // } // } /// /// 加载地图追踪任务 /// private void LoadPathingTasks() { try { PathingTasks.Clear(); var pathingPath = Path.Combine(ScriptRepoUpdater.CenterRepoPath, "repo", "pathing"); if (!Directory.Exists(pathingPath)) { _logger.LogWarning($"地图追踪任务目录不存在: {pathingPath}"); return; } // 加载根目录下的直接子项 LoadDirectChildrenFromDirectory(pathingPath, pathingPath, PathingTasks); FilterTasks(); } catch (Exception ex) { _logger.LogError(ex, "加载地图追踪任务失败"); } } /// /// 从目录加载直接子项(用于构建层级结构) /// private void LoadDirectChildrenFromDirectory(string directoryPath, string rootPath, ObservableCollection parentCollection) { try { // 加载文件夹 foreach (var dir in Directory.GetDirectories(directoryPath)) { var taskInfo = new PathingTaskInfo(dir, rootPath) { IsDirectory = true }; // 设置图标 SetTaskIcon(taskInfo); // 递归加载子目录到当前任务的Children集合中 LoadDirectChildrenFromDirectory(dir, rootPath, taskInfo.Children); parentCollection.Add(taskInfo); } // 加载JSON文件(默认展示到文件级别) foreach (var file in Directory.GetFiles(directoryPath, "*.json")) { var taskInfo = new PathingTaskInfo(file, rootPath) { IsDirectory = false }; // 设置图标 SetTaskIcon(taskInfo); parentCollection.Add(taskInfo); } } catch (Exception ex) { _logger.LogError(ex, $"加载目录任务失败: {directoryPath}"); } } /// /// 设置任务图标 /// private void SetTaskIcon(PathingTaskInfo taskInfo) { // var fileName = Path.GetFileNameWithoutExtension(taskInfo.Name); // // if (_iconDictionary.TryGetValue(fileName, out var iconUrl)) // { // taskInfo.IconUrl = iconUrl; // taskInfo.UseSystemIcon = false; // } // else // { // taskInfo.UseSystemIcon = true; // } taskInfo.UseSystemIcon = true; } /// /// 为显示加载README内容(按需加载) /// private void LoadReadmeContentForDisplay(PathingTaskInfo taskInfo) { try { if (taskInfo.IsDirectory && string.IsNullOrEmpty(taskInfo.ReadmeContent)) { var readmePath = Path.Combine(taskInfo.FullPath, "README.md"); if (File.Exists(readmePath)) { taskInfo.ReadmeContent = File.ReadAllText(readmePath); } } } catch (Exception ex) { _logger.LogError(ex, $"加载README内容失败: {taskInfo.FullPath}"); taskInfo.ReadmeContent = "README加载失败"; } } /// /// 为显示加载JSON内容(按需加载) /// private void LoadJsonContentForDisplay(PathingTaskInfo taskInfo) { try { if (!taskInfo.IsDirectory && taskInfo.FullPath.EndsWith(".json") && string.IsNullOrEmpty(taskInfo.JsonContent)) { var jsonContent = File.ReadAllText(taskInfo.FullPath); // 格式化JSON var jsonObject = JsonConvert.DeserializeObject(jsonContent); taskInfo.JsonContent = JsonConvert.SerializeObject(jsonObject, Formatting.Indented); } } catch (Exception ex) { _logger.LogError(ex, $"加载JSON内容失败: {taskInfo.FullPath}"); taskInfo.JsonContent = "JSON格式错误"; } } /// /// 过滤任务 /// private void FilterTasks() { FilteredPathingTasks.Clear(); foreach (var task in PathingTasks) { var filteredTask = FilterTaskRecursively(task); if (filteredTask != null) { FilteredPathingTasks.Add(filteredTask); } } } /// /// 递归过滤任务(支持搜索所有子节点) /// private PathingTaskInfo? FilterTaskRecursively(PathingTaskInfo task) { // 检查当前节点是否匹配搜索条件 bool currentMatches = string.IsNullOrWhiteSpace(SearchKeyword) || task.Name.Contains(SearchKeyword, StringComparison.OrdinalIgnoreCase) || task.RelativePath.Contains(SearchKeyword, StringComparison.OrdinalIgnoreCase); // 始终显示文件和目录(默认展示到文件级别) bool modeMatches = true; // 创建新的任务对象用于显示 var filteredTask = new PathingTaskInfo { Name = task.Name, FolderName = task.FolderName, FullPath = task.FullPath, IsDirectory = task.IsDirectory, JsonContent = task.JsonContent, ReadmeContent = task.ReadmeContent, IconUrl = task.IconUrl, UseSystemIcon = task.UseSystemIcon, ParentPath = task.ParentPath, RelativePath = task.RelativePath }; // 递归处理子节点 bool hasMatchingChildren = false; foreach (var child in task.Children) { var filteredChild = FilterTaskRecursively(child); if (filteredChild != null) { filteredTask.Children.Add(filteredChild); hasMatchingChildren = true; } } // 如果当前节点匹配条件且符合显示模式,或者有匹配的子节点,则返回该节点 if ((currentMatches && modeMatches) || hasMatchingChildren) { return filteredTask; } return null; } /// /// 当选中任务改变时 /// partial void OnSelectedTaskChanged(PathingTaskInfo? value) { if (value == null) { DisplayContent = string.Empty; DisplayContentType = string.Empty; SelectedDirectoryTaskCount = 0; return; } if (value.IsDirectory) { // 动态加载README内容 LoadReadmeContentForDisplay(value); DisplayContent = value.ReadmeContent ?? string.Empty; DisplayContentType = "README"; // 计算选中目录下的任务数量 SelectedDirectoryTaskCount = CountTasksInDirectory(value); } else { // 动态加载JSON内容 LoadJsonContentForDisplay(value); DisplayContent = value.JsonContent ?? string.Empty; DisplayContentType = "JSON"; SelectedDirectoryTaskCount = 0; } } /// /// 当搜索关键词改变时 /// partial void OnSearchKeywordChanged(string value) { FilterTasks(); } /// /// 计算目录下的任务数量(递归计算所有子目录中的JSON文件) /// private int CountTasksInDirectory(PathingTaskInfo directory) { if (!directory.IsDirectory) return 0; int count = 0; // 计算当前目录下的JSON文件数量 try { count += Directory.GetFiles(directory.FullPath, "*.json").Length; // 递归计算子目录 foreach (var subDir in Directory.GetDirectories(directory.FullPath)) { count += CountTasksInDirectoryPath(subDir); } } catch (Exception ex) { _logger.LogError(ex, $"计算目录任务数量失败: {directory.FullPath}"); } return count; } /// /// 计算指定路径目录下的任务数量(递归) /// private int CountTasksInDirectoryPath(string directoryPath) { int count = 0; try { count += Directory.GetFiles(directoryPath, "*.json").Length; foreach (var subDir in Directory.GetDirectories(directoryPath)) { count += CountTasksInDirectoryPath(subDir); } } catch (Exception ex) { _logger.LogError(ex, $"计算目录任务数量失败: {directoryPath}"); } return count; } /// /// 添加文件夹引用 /// [RelayCommand] private void AddFolderTask() { if (SelectedTask?.IsDirectory == true) { // 按组引用:添加选中目录作为一个任务组 var gearTaskViewModel = new GearTaskViewModel { Name = SelectedTask.Name, Path = @$"{{pathingRepoFolder}}\{SelectedTask.RelativePath}\", IsDirectory = true }; // 触发添加事件或通过其他方式返回给调用方 OnTaskAdded?.Invoke(gearTaskViewModel); } } /// /// 添加文件夹引用,保持目录结构 /// [RelayCommand] private void AddFolderTasksWithStructure() { if (SelectedTask?.IsDirectory == true) { var task = GetAllFolderTasksInDirectoryWithStructure(SelectedTask); OnTaskAdded?.Invoke(task); } } /// /// 添加目录下所有文件,不要目录结构 /// [RelayCommand] private void AddAllFileTasks() { if (SelectedTask?.IsDirectory == true) { var rootGearTaskViewModel = new GearTaskViewModel { Name = SelectedTask.Name, IsDirectory = true }; // 逐个添加:添加目录下所有JSON文件作为独立任务 var taskInfos = GetAllJsonFilesInDirectory(SelectedTask); foreach (var taskInfo in taskInfos) { var gearTaskViewModel = new GearTaskViewModel { Name = Path.GetFileNameWithoutExtension(taskInfo.Name), TaskType = "Pathing", Path = @$"{{pathingRepoFolder}}\{taskInfo.RelativePath}\", IsDirectory = false }; rootGearTaskViewModel.Children.Add(gearTaskViewModel); } if (rootGearTaskViewModel.Children.Count > 0) { OnTaskAdded?.Invoke(rootGearTaskViewModel); } } } /// /// 保持目录结构添加所有目录下文件 /// [RelayCommand] private void AddFileTasksWithStructure() { if (SelectedTask?.IsDirectory == true) { // 保持目录结构添加所有子任务 var task = GetAllFileTasksInDirectoryWithStructure(SelectedTask); OnTaskAdded?.Invoke(task); } } /// /// 获取目录下所有JSON文件 /// private List GetAllJsonFilesInDirectory(PathingTaskInfo directory) { var jsonFiles = new List(); if (directory.Children is { Count: > 0 }) { foreach (var child in directory.Children) { if (child.IsDirectory) { jsonFiles.AddRange(GetAllJsonFilesInDirectory(child)); } else if (child.FullPath.EndsWith(".json", StringComparison.OrdinalIgnoreCase)) { jsonFiles.Add(child); } } } return jsonFiles; } /// /// 获取目录下所有json文件任务并保持结构 /// private GearTaskViewModel? GetAllFileTasksInDirectoryWithStructure(PathingTaskInfo node) { if (node.IsDirectory) { // 添加子目录作为组 var groupTask = new GearTaskViewModel { Name = node.Name, IsDirectory = true }; foreach (var pathingTaskInfo in node.Children) { var gearTask = GetAllFileTasksInDirectoryWithStructure(pathingTaskInfo); if (gearTask != null) { groupTask.Children.Add(gearTask); } } return groupTask; } else if (node.FullPath.EndsWith(".json", StringComparison.OrdinalIgnoreCase)) { // 添加JSON文件作为任务 var fileTask = new GearTaskViewModel { Name = Path.GetFileNameWithoutExtension(node.Name), TaskType = "Pathing", Path = @$"{{pathingRepoFolder}}\{node.RelativePath}\", IsDirectory = false }; return fileTask; } return null; } /// /// 获取目录下所有文件夹任务并保持结构 /// private GearTaskViewModel? GetAllFolderTasksInDirectoryWithStructure(PathingTaskInfo directory) { if (directory.Children is { Count: > 0 }) { // 判断 directory 的子节点是否是文件 var hasJsonFile = directory.Children.Any(grandChild => !grandChild.IsDirectory && grandChild.FullPath.EndsWith(".json", StringComparison.OrdinalIgnoreCase)); if (hasJsonFile) { // 添加子目录作为任务 var groupTask = new GearTaskViewModel { Name = directory.Name, TaskType = "Pathing", Path = @$"{{pathingRepoFolder}}\{directory.RelativePath}\", IsDirectory = false }; return groupTask; } else { // 添加子目录作为组 var groupTask = new GearTaskViewModel { Name = directory.Name, IsDirectory = true }; foreach (var pathingTaskInfo in directory.Children) { var gearTask = GetAllFolderTasksInDirectoryWithStructure(pathingTaskInfo); if (gearTask != null) { groupTask.Children.Add(gearTask); } } return groupTask; } } else { return null; } } }