diff --git a/BetterGenshinImpact/View/Windows/AddTaskNodeDialog.xaml b/BetterGenshinImpact/View/Windows/AddTaskNodeDialog.xaml
new file mode 100644
index 00000000..bef0d7e2
--- /dev/null
+++ b/BetterGenshinImpact/View/Windows/AddTaskNodeDialog.xaml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BetterGenshinImpact/View/Windows/AddTaskNodeDialog.xaml.cs b/BetterGenshinImpact/View/Windows/AddTaskNodeDialog.xaml.cs
new file mode 100644
index 00000000..31193b7c
--- /dev/null
+++ b/BetterGenshinImpact/View/Windows/AddTaskNodeDialog.xaml.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Windows;
+using BetterGenshinImpact.Helpers.Ui;
+using BetterGenshinImpact.ViewModel.Windows;
+
+namespace BetterGenshinImpact.View.Windows;
+
+public partial class AddTaskNodeDialog
+{
+ public AddTaskNodeDialogViewModel ViewModel { get; }
+
+ public AddTaskNodeDialog(string taskType)
+ {
+ ViewModel = new AddTaskNodeDialogViewModel(taskType);
+ DataContext = ViewModel;
+
+ InitializeComponent();
+
+ ViewModel.RequestClose += OnRequestClose;
+ this.SourceInitialized += OnSourceInitialized;
+ }
+
+ private void OnSourceInitialized(object? sender, EventArgs e)
+ {
+ // 应用与主窗口相同的背景主题
+ WindowHelper.TryApplySystemBackdrop(this);
+ }
+
+ private void OnRequestClose(object? sender, bool result)
+ {
+ DialogResult = result;
+ Close();
+ }
+
+ ///
+ /// 显示添加任务对话框
+ ///
+ /// 任务类型
+ /// 父窗口
+ /// 如果用户点击确定返回ViewModel,否则返回null
+ public static AddTaskNodeDialogViewModel? ShowDialog(string taskType, Window? owner = null)
+ {
+ var dialog = new AddTaskNodeDialog(taskType);
+ if (owner != null)
+ {
+ dialog.Owner = owner;
+ }
+
+ var result = dialog.ShowDialog();
+ return result == true ? dialog.ViewModel : null;
+ }
+}
\ No newline at end of file
diff --git a/BetterGenshinImpact/View/Windows/JsScriptSelectionWindow.xaml b/BetterGenshinImpact/View/Windows/JsScriptSelectionWindow.xaml
new file mode 100644
index 00000000..741df141
--- /dev/null
+++ b/BetterGenshinImpact/View/Windows/JsScriptSelectionWindow.xaml
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BetterGenshinImpact/View/Windows/JsScriptSelectionWindow.xaml.cs b/BetterGenshinImpact/View/Windows/JsScriptSelectionWindow.xaml.cs
new file mode 100644
index 00000000..aab74a08
--- /dev/null
+++ b/BetterGenshinImpact/View/Windows/JsScriptSelectionWindow.xaml.cs
@@ -0,0 +1,40 @@
+using System.Windows;
+using BetterGenshinImpact.ViewModel.Windows;
+using Wpf.Ui.Controls;
+
+namespace BetterGenshinImpact.View.Windows;
+
+public partial class JsScriptSelectionWindow : FluentWindow
+{
+ public JsScriptSelectionViewModel ViewModel { get; }
+
+ public JsScriptInfo? SelectedScript => ViewModel.SelectedScript;
+
+ public bool DialogResult { get; private set; }
+
+ public JsScriptSelectionWindow()
+ {
+ ViewModel = new JsScriptSelectionViewModel();
+ DataContext = ViewModel;
+ InitializeComponent();
+ }
+
+ private void OnOkClick(object sender, RoutedEventArgs e)
+ {
+ if (ViewModel.SelectedScript != null)
+ {
+ DialogResult = true;
+ Close();
+ }
+ else
+ {
+ Wpf.Ui.Violeta.Controls.Toast.Warning("请选择一个JS脚本");
+ }
+ }
+
+ private void OnCancelClick(object sender, RoutedEventArgs e)
+ {
+ DialogResult = false;
+ Close();
+ }
+}
\ No newline at end of file
diff --git a/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs
index 1700022f..f777b19c 100644
--- a/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs
+++ b/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs
@@ -2,13 +2,13 @@ using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Logging;
-using System.Windows;
using System.Linq;
using System;
using BetterGenshinImpact.ViewModel.Pages.Component;
using BetterGenshinImpact.Service;
using System.Threading.Tasks;
using System.Collections.Specialized;
+using System.Windows;
using BetterGenshinImpact.View.Windows;
using BetterGenshinImpact.ViewModel.Windows;
using Wpf.Ui.Violeta.Controls;
@@ -26,36 +26,32 @@ public partial class GearTaskListPageViewModel : ViewModel
///
/// 任务定义列表(左侧)
///
- [ObservableProperty]
- private ObservableCollection _taskDefinitions = new();
+ [ObservableProperty] private ObservableCollection _taskDefinitions = new();
///
/// 当前选中的任务定义
///
- [ObservableProperty]
- private GearTaskDefinitionViewModel? _selectedTaskDefinition;
+ [ObservableProperty] private GearTaskDefinitionViewModel? _selectedTaskDefinition;
///
/// 当前任务树根节点(右侧)
///
- [ObservableProperty]
- private GearTaskViewModel _currentTaskTreeRoot = new();
+ [ObservableProperty] private GearTaskViewModel _currentTaskTreeRoot = new();
///
/// 当前选中的任务节点
///
- [ObservableProperty]
- private GearTaskViewModel? _selectedTaskNode;
-
+ [ObservableProperty] private GearTaskViewModel? _selectedTaskNode;
+
public GearTaskListPageViewModel(ILogger logger, GearTaskStorageService storageService)
{
_logger = logger;
_storageService = storageService;
InitializeData();
-
+
// 监听集合变化,实现自动保存
TaskDefinitions.CollectionChanged += OnTaskDefinitionsChanged;
-
+
// 监听当前任务树根节点的子集合变化,用于拖拽后自动保存
CurrentTaskTreeRoot.Children.CollectionChanged += OnCurrentTaskTreeChanged;
}
@@ -77,13 +73,13 @@ public partial class GearTaskListPageViewModel : ViewModel
TaskDefinitions[i].ModifiedTime = DateTime.Now;
}
}
-
+
// 保存所有受影响的任务定义
foreach (var taskDef in TaskDefinitions)
{
await _storageService.SaveTaskDefinitionAsync(taskDef);
}
-
+
_logger.LogInformation("任务定义列表顺序已更新并保存");
}
catch (Exception ex)
@@ -91,7 +87,7 @@ public partial class GearTaskListPageViewModel : ViewModel
_logger.LogError(ex, "保存任务定义列表顺序时发生错误");
}
}
-
+
///
/// 当前任务树集合变化时的处理(用于拖拽后自动保存)
///
@@ -121,17 +117,17 @@ public partial class GearTaskListPageViewModel : ViewModel
{
// 从 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)
{
@@ -145,7 +141,7 @@ public partial class GearTaskListPageViewModel : ViewModel
await CreateSampleTaskAsync();
}
}
-
+
///
/// 创建示例任务
///
@@ -156,16 +152,16 @@ public partial class GearTaskListPageViewModel : ViewModel
{
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);
SetupTaskDefinitionPropertyChanged(sampleTask);
-
+
// 保存示例任务到文件
await _storageService.SaveTaskDefinitionAsync(sampleTask);
}
@@ -180,16 +176,16 @@ public partial class GearTaskListPageViewModel : ViewModel
{
task.IsSelected = false;
}
-
+
// 设置当前选中项
if (value != null)
{
value.IsSelected = true;
}
-
+
// 先解除之前的事件绑定
CurrentTaskTreeRoot.Children.CollectionChanged -= OnCurrentTaskTreeChanged;
-
+
// 设置当前任务树根节点
if (value?.RootTask != null)
{
@@ -199,7 +195,7 @@ public partial class GearTaskListPageViewModel : ViewModel
{
CurrentTaskTreeRoot = new GearTaskViewModel();
}
-
+
// 重新绑定事件
CurrentTaskTreeRoot.Children.CollectionChanged += OnCurrentTaskTreeChanged;
}
@@ -221,17 +217,17 @@ public partial class GearTaskListPageViewModel : ViewModel
{
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);
@@ -240,7 +236,7 @@ public partial class GearTaskListPageViewModel : ViewModel
TaskDefinitions.Add(newTask);
SetupTaskDefinitionPropertyChanged(newTask);
SelectedTaskDefinition = newTask;
-
+
// 自动保存到文件
await _storageService.SaveTaskDefinitionAsync(newTask);
}
@@ -253,10 +249,10 @@ public partial class GearTaskListPageViewModel : ViewModel
private async Task DeleteTaskDefinition(GearTaskDefinitionViewModel? taskDefinition)
{
if (taskDefinition == null) return;
-
- var result = MessageBox.Show($"确定要删除任务定义 '{taskDefinition.Name}' 吗?", "确认删除",
+
+ var result = MessageBox.Show($"确定要删除任务定义 '{taskDefinition.Name}' 吗?", "确认删除",
MessageBoxButton.YesNo, MessageBoxImage.Question);
-
+
if (result == MessageBoxResult.Yes)
{
var taskName = taskDefinition.Name;
@@ -265,7 +261,7 @@ public partial class GearTaskListPageViewModel : ViewModel
{
SelectedTaskDefinition = TaskDefinitions.FirstOrDefault();
}
-
+
// 删除对应的 JSON 文件
await _storageService.DeleteTaskDefinitionAsync(taskName);
}
@@ -278,29 +274,29 @@ public partial class GearTaskListPageViewModel : ViewModel
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);
}
}
@@ -312,12 +308,11 @@ public partial class GearTaskListPageViewModel : ViewModel
private async Task DeleteSelectedTaskDefinition()
{
if (SelectedTaskDefinition == null) return;
-
+
await DeleteTaskDefinition(SelectedTaskDefinition);
}
-
///
/// 添加任务节点
///
@@ -330,22 +325,59 @@ public partial class GearTaskListPageViewModel : ViewModel
return;
}
- var newTask = new GearTaskViewModel($"新任务 {DateTime.Now:HHmmss}")
+ // 如果没有指定任务类型,默认为Javascript
+ taskType ??= "Javascript";
+
+ GearTaskViewModel newTask;
+
+ // 如果是JS脚本类型,使用JS脚本选择窗口
+ if (taskType == "Javascript")
{
- TaskType = "任务类型",
- Description = "新创建的任务"
- };
+ var jsSelectionWindow = new JsScriptSelectionWindow
+ {
+ Owner = Application.Current.MainWindow
+ };
+
+ if (jsSelectionWindow.ShowDialog() == true && jsSelectionWindow.ViewModel.SelectedScript != null)
+ {
+ var selectedScript = jsSelectionWindow.ViewModel.SelectedScript;
+ newTask = new GearTaskViewModel(selectedScript.DisplayName)
+ {
+ TaskType = "Javascript",
+ Description = selectedScript.Description ?? "JS脚本任务"
+ };
+ }
+ else
+ {
+ return; // 用户取消了操作
+ }
+ }
+ else
+ {
+ // 其他类型使用原有的对话框
+ var dialogResult = AddTaskNodeDialog.ShowDialog(taskType, Application.Current.MainWindow);
+ if (dialogResult == null)
+ {
+ return; // 用户取消了操作
+ }
+
+ newTask = new GearTaskViewModel(dialogResult.TaskName)
+ {
+ TaskType = dialogResult.TaskType,
+ Description = dialogResult.TaskDescription
+ };
+ }
// 如果有选中的节点,则在选中节点下新增
// 如果未选择节点,则在根节点下直接新增
var targetParent = SelectedTaskNode ?? SelectedTaskDefinition.RootTask;
targetParent.AddChild(newTask);
-
+
// 展开父节点
targetParent.IsExpanded = true;
SelectedTaskDefinition.ModifiedTime = DateTime.Now;
-
+
// 自动保存到文件
await _storageService.SaveTaskDefinitionAsync(SelectedTaskDefinition);
}
@@ -371,12 +403,12 @@ public partial class GearTaskListPageViewModel : ViewModel
// 如果未选择节点,则在根节点下直接新增
var targetParent = SelectedTaskNode ?? SelectedTaskDefinition.RootTask;
targetParent.AddChild(newGroup);
-
+
// 展开父节点
targetParent.IsExpanded = true;
SelectedTaskDefinition.ModifiedTime = DateTime.Now;
-
+
// 自动保存到文件
await _storageService.SaveTaskDefinitionAsync(SelectedTaskDefinition);
}
@@ -389,14 +421,14 @@ public partial class GearTaskListPageViewModel : ViewModel
{
if (taskNode == null || SelectedTaskDefinition?.RootTask == null) return;
- var result = MessageBox.Show($"确定要删除任务 '{taskNode.Name}' 吗?", "确认删除",
+ 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);
}
@@ -433,13 +465,13 @@ public partial class GearTaskListPageViewModel : ViewModel
{
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)
@@ -467,7 +499,7 @@ public partial class GearTaskListPageViewModel : ViewModel
}
}
};
-
+
// 为根任务及其所有子任务设置监听器
if (taskDefinition.RootTask != null)
{
@@ -492,13 +524,13 @@ public partial class GearTaskListPageViewModel : ViewModel
_logger.LogError(ex, "自动保存任务定义 {TaskName} 时发生错误", parentDefinition.Name);
}
};
-
+
// 为子任务设置监听器
foreach (var child in task.Children)
{
SetupTaskPropertyChangeListener(child, parentDefinition);
}
-
+
// 监听子任务集合变化
task.Children.CollectionChanged += async (sender, e) =>
{
@@ -509,7 +541,7 @@ public partial class GearTaskListPageViewModel : ViewModel
SetupTaskPropertyChangeListener(newTask, parentDefinition);
}
}
-
+
// 任何集合变化都触发保存(包括拖拽重排序)
try
{
@@ -527,5 +559,4 @@ public partial class GearTaskListPageViewModel : ViewModel
///
/// 刷新当前任务树显示
///
-
}
\ No newline at end of file
diff --git a/BetterGenshinImpact/ViewModel/Windows/AddTaskNodeDialogViewModel.cs b/BetterGenshinImpact/ViewModel/Windows/AddTaskNodeDialogViewModel.cs
new file mode 100644
index 00000000..792ce1e7
--- /dev/null
+++ b/BetterGenshinImpact/ViewModel/Windows/AddTaskNodeDialogViewModel.cs
@@ -0,0 +1,67 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+
+namespace BetterGenshinImpact.ViewModel.Windows;
+
+public partial class AddTaskNodeDialogViewModel : ObservableValidator
+{
+ [ObservableProperty]
+ [Required(ErrorMessage = "任务名称不能为空")]
+ private string _taskName = "";
+
+ [ObservableProperty]
+ private string _taskDescription = "";
+
+ [ObservableProperty]
+ private string _taskType = "";
+
+ public event EventHandler? RequestClose;
+
+ public AddTaskNodeDialogViewModel()
+ {
+ }
+
+ public AddTaskNodeDialogViewModel(string taskType)
+ {
+ TaskType = taskType;
+ TaskName = GetDefaultTaskName(taskType);
+ }
+
+ private string GetDefaultTaskName(string taskType)
+ {
+ return taskType switch
+ {
+ "Javascript" => "新建JS脚本",
+ "Pathing" => "新建地图追踪任务",
+ "KeyMouse" => "新建键鼠脚本",
+ "Shell" => "新建Shell脚本",
+ "CSharp" => "新建C#方法",
+ _ => "新建任务"
+ };
+ }
+
+ [RelayCommand]
+ private void Confirm()
+ {
+ ValidateAllProperties();
+ if (HasErrors)
+ {
+ return;
+ }
+
+ if (string.IsNullOrWhiteSpace(TaskName))
+ {
+ return;
+ }
+
+ RequestClose?.Invoke(this, true);
+ }
+
+ [RelayCommand]
+ private void Cancel()
+ {
+ RequestClose?.Invoke(this, false);
+ }
+}
\ No newline at end of file
diff --git a/BetterGenshinImpact/ViewModel/Windows/JsScriptSelectionViewModel.cs b/BetterGenshinImpact/ViewModel/Windows/JsScriptSelectionViewModel.cs
new file mode 100644
index 00000000..06e3916f
--- /dev/null
+++ b/BetterGenshinImpact/ViewModel/Windows/JsScriptSelectionViewModel.cs
@@ -0,0 +1,190 @@
+using System;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using BetterGenshinImpact.Core.Script;
+using BetterGenshinImpact.Core.Script.Project;
+using BetterGenshinImpact.ViewModel;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using Microsoft.Extensions.Logging;
+
+namespace BetterGenshinImpact.ViewModel.Windows;
+
+public partial class JsScriptSelectionViewModel : ViewModel
+{
+ private readonly ILogger _logger = App.GetLogger();
+
+ [ObservableProperty]
+ private ObservableCollection _jsScripts = [];
+
+ [ObservableProperty]
+ private JsScriptInfo? _selectedScript;
+
+ [ObservableProperty]
+ private string _readmeContent = string.Empty;
+
+ [ObservableProperty]
+ private string _mainJsContent = string.Empty;
+
+ [ObservableProperty]
+ private int _selectedTabIndex = 0;
+
+ public JsScriptSelectionViewModel()
+ {
+ LoadJsScripts();
+ }
+
+ private void LoadJsScripts()
+ {
+ try
+ {
+ var jsPath = Path.Combine(ScriptRepoUpdater.CenterRepoPath, "repo", "js");
+ if (!Directory.Exists(jsPath))
+ {
+ _logger.LogWarning($"JS脚本目录不存在: {jsPath}");
+ return;
+ }
+
+ var scriptDirectories = Directory.GetDirectories(jsPath);
+ var scripts = new ObservableCollection();
+
+ foreach (var scriptDir in scriptDirectories)
+ {
+ try
+ {
+ var manifestPath = Path.Combine(scriptDir, "manifest.json");
+ if (File.Exists(manifestPath))
+ {
+ var manifestContent = File.ReadAllText(manifestPath);
+ var manifest = Manifest.FromJson(manifestContent);
+
+ var scriptInfo = new JsScriptInfo
+ {
+ FolderName = Path.GetFileName(scriptDir),
+ FolderPath = scriptDir,
+ Manifest = manifest
+ };
+
+ scripts.Add(scriptInfo);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, $"加载JS脚本失败: {scriptDir}");
+ }
+ }
+
+ JsScripts = scripts;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "加载JS脚本列表失败");
+ }
+ }
+
+ partial void OnSelectedScriptChanged(JsScriptInfo? value)
+ {
+ if (value != null)
+ {
+ // 清空之前的内容
+ ReadmeContent = string.Empty;
+ MainJsContent = string.Empty;
+
+ // 根据当前选中的标签页加载内容
+ LoadCurrentTabContent();
+ }
+ }
+
+ partial void OnSelectedTabIndexChanged(int value)
+ {
+ if (SelectedScript != null)
+ {
+ LoadCurrentTabContent();
+ }
+ }
+
+ private async void LoadCurrentTabContent()
+ {
+ if (SelectedScript == null) return;
+
+ switch (SelectedTabIndex)
+ {
+ case 0: // README.md
+ if (string.IsNullOrEmpty(ReadmeContent))
+ {
+ await Task.Run(LoadReadmeContent);
+ }
+ break;
+ case 1: // main.js
+ if (string.IsNullOrEmpty(MainJsContent))
+ {
+ await Task.Run(LoadMainJsContent);
+ }
+ break;
+ }
+ }
+
+ private void LoadReadmeContent()
+ {
+ if (SelectedScript == null) return;
+
+ try
+ {
+ var readmePath = Path.Combine(SelectedScript.FolderPath, "README.md");
+ if (File.Exists(readmePath))
+ {
+ ReadmeContent = File.ReadAllText(readmePath);
+ }
+ else
+ {
+ ReadmeContent = "README.md 文件不存在";
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "加载README.md失败");
+ ReadmeContent = $"加载README.md失败: {ex.Message}";
+ }
+ }
+
+ private void LoadMainJsContent()
+ {
+ if (SelectedScript == null) return;
+
+ try
+ {
+ var mainJsPath = Path.Combine(SelectedScript.FolderPath, SelectedScript.Manifest.Main);
+ if (File.Exists(mainJsPath))
+ {
+ MainJsContent = File.ReadAllText(mainJsPath);
+ }
+ else
+ {
+ MainJsContent = "main.js 文件不存在";
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "加载main.js失败");
+ MainJsContent = $"加载main.js失败: {ex.Message}";
+ }
+ }
+
+ [RelayCommand]
+ private void RefreshScripts()
+ {
+ LoadJsScripts();
+ }
+}
+
+public class JsScriptInfo
+{
+ public string FolderName { get; set; } = string.Empty;
+ public string FolderPath { get; set; } = string.Empty;
+ public Manifest Manifest { get; set; } = new();
+
+ public string DisplayName => $"{FolderName} - {Manifest.Name}";
+ public string Description => Manifest.ShortDescription;
+}
\ No newline at end of file