using Prism.Mvvm;
using Prism.Commands;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using TeamAAS.FlowEditor.Models;
using TeamAAS.FlowEngine.Execution;
using TeamAAS.Dialogs;
using TeamAAS.FlowEngine;
using TeamAAS.FlowEditor.Execution;
namespace TeamAAS.FlowEditor
{
///
/// 流程编辑器外壳 ViewModel:管理多 Tab 流程
///
public class FlowEditorShellViewModel : TeamAAS.BindableBase
{
public ObservableCollection FlowTabs => PluginLoader.Instance.FlowTabs;
private FlowTabItem _activeTab;
public FlowTabItem ActiveTab
{
get => _activeTab;
set
{
if (_activeTab != null) _activeTab.IsActive = false;
if (SetProperty(ref _activeTab, value))
{
if (_activeTab != null) _activeTab.IsActive = true;
RaisePropertyChanged(nameof(ActiveEditorVm));
}
}
}
public FlowEditorViewModel ActiveEditorVm => ActiveTab?.EditorVm;
// 流程结构变化(新建/删除/重命名 Tab)——关闭的 Tab 不再参与 per-tab 脏检查,需单独记录
private bool _structureChanged;
private bool _isReadOnly;
/// 只读监控模式(运行产品运行中):由 ProductManager/ProductViewModel 设置并传播到所有 Tab
public bool IsReadOnly
{
get => _isReadOnly;
set
{
if (SetProperty(ref _isReadOnly, value))
ApplyReadOnlyToTabs();
}
}
private bool _isMonitorMode;
/// 是否监控运行中流程(勾选后挂接 RunTabs,否则独立编辑)
public bool IsMonitorMode
{
get => _isMonitorMode;
private set => SetProperty(ref _isMonitorMode, value);
}
/// 切换监控模式(开/关)
public DelegateCommand ToggleMonitorCommand { get; }
private bool _isMonitorOptionAvailable;
/// 「监控当前流程」选项是否可用(当前产品==运行产品且正在运行)
public bool IsMonitorOptionAvailable
{
get => _isMonitorOptionAvailable;
private set => SetProperty(ref _isMonitorOptionAvailable, value);
}
/// 把当前只读状态应用到所有流程 Tab(切换产品/新增 Tab 后调用)
public void ApplyReadOnlyToTabs()
{
foreach (var tab in FlowTabs)
tab.EditorVm?.SetReadOnly(_isReadOnly);
}
/// 是否存在未保存的修改(流程内容修改 + 流程增删/改名)
public bool HasUnsavedChanges =>
_structureChanged || FlowTabs.Any(t => t.EditorVm != null && t.EditorVm.IsDirty);
/// 保存后清除所有流程的修改标记
public void MarkAllClean()
{
_structureChanged = false;
foreach (var tab in FlowTabs)
tab.EditorVm?.MarkClean();
}
public DelegateCommand AddFlowCommand { get; }
public DelegateCommand CloseFlowCommand { get; }
public DelegateCommand RenameFlowCommand { get; }
public DelegateCommand OpenTabPropertiesCommand { get; }
public DelegateCommand ImportFlowCommand { get; }
public DelegateCommand ExportFlowCommand { get; }
public FlowEditorShellViewModel()
{
if (FlowTabs.Count == 0)
{
var defaultTab = new FlowTabItem("流程1");
FlowTabs.Add(defaultTab);
ActiveTab = defaultTab;
}
else
{
ActiveTab = FlowTabs[0];
}
AddFlowCommand = new DelegateCommand(AddFlow);
CloseFlowCommand = new DelegateCommand(CloseFlow);
RenameFlowCommand = new DelegateCommand(tab => RenameFlow(tab));
OpenTabPropertiesCommand = new DelegateCommand(OpenTabProperties);
// 导入/导出逻辑统一在 FlowEditorViewModel 的命令里,Shell 只做转发(只读模式下禁用导入)
ImportFlowCommand = new DelegateCommand(
() => ActiveEditorVm?.ImportFlowCommand?.Execute(),
() => ActiveEditorVm != null && !IsReadOnly);
ExportFlowCommand = new DelegateCommand(() => ActiveEditorVm?.ExportFlowCommand?.Execute());
ToggleMonitorCommand = new DelegateCommand(ToggleMonitor);
// 订阅运行态重载事件:监控中主界面重载流程时自动同步显示
FlowRunner.Instance.RunTabsRefreshed += OnRunTabsRefreshed;
}
/// 切换监控模式入口
private void ToggleMonitor()
{
if (IsMonitorMode) ExitMonitor();
else EnterMonitor();
}
/// 进入监控模式:必要时提示保存当前编辑,再挂接运行态 RunTabs
private void EnterMonitor()
{
// 运行态未启动 → 提示并 return
if (!FlowRunner.Instance.IsRunning || FlowRunner.Instance.RunTabs.Count == 0)
{
DialogHelper.Info("当前没有正在运行的流程,无法监控");
return;
}
// 当前产品 != 运行产品 → 提示保存后切换(点否不保存但仍然切到运行产品监控)
if (!string.Equals(ProductManager.Instance.CurrentProductName,
FlowRunner.Instance.RunProductName, StringComparison.Ordinal))
{
if (HasUnsavedChanges)
{
bool save = DialogHelper.ConfirmYesNo("切换到运行产品需先保存当前方案,是否保存?", "保存确认");
if (save) SaveAllModifiedTabs();
}
ProductManager.Instance.SwitchProduct(FlowRunner.Instance.RunProductName, this);
}
else if (HasUnsavedChanges)
{
// 当前产品 == 运行产品:点否也进入监控,但不保存
bool save = DialogHelper.ConfirmYesNo("进入监控前是否保存当前修改?", "保存确认");
if (save) SaveAllModifiedTabs();
}
AttachRunTabs();
IsMonitorMode = true;
IsReadOnly = true;
}
/// 退出监控模式:恢复编辑态(从磁盘重载副本)
private void ExitMonitor()
{
IsMonitorMode = false;
IsReadOnly = false;
DetachAndReloadFromDisk();
}
///
/// 根据"当前产品 == 运行产品 且 正在运行"刷新监控选项可用性,并自动同步监控状态:
/// - 满足条件 → 选项可用;若当前不在监控则自动进入监控
/// - 不满足 → 选项禁用;若当前在监控则自动退出
/// 该方法由 ProductManager.SwitchProduct/SwitchProductAsync、ProductViewModel.RefreshRunState 调用。
/// 注意:本方法不直接调 EnterMonitor(避免与 EnterMonitor 内部的 SwitchProduct 互相递归),
/// 而是设置 IsMonitorMode 标志后再调,让 EnterMonitor 看到 IsMonitorMode=true 时跳过自动调用。
///
public void ApplyMonitorAvailability()
{
bool available = !string.IsNullOrEmpty(ProductManager.Instance.CurrentProductName)
&& string.Equals(ProductManager.Instance.CurrentProductName,
FlowRunner.Instance.RunProductName, StringComparison.Ordinal)
&& FlowRunner.Instance.IsRunning;
IsMonitorOptionAvailable = available;
try
{
if (!available && IsMonitorMode)
{
// 当前产品不再是运行产品或运行已停止 → 退出监控
ExitMonitor();
}
else if (available && !IsMonitorMode)
{
// 切到运行产品且正在运行 → 默认进入监控模式。
// 先置 IsMonitorMode=true 防止 EnterMonitor 内部调 SwitchProduct 时
// 其末尾的 ApplyMonitorAvailability 再次触发 EnterMonitor(无限递归)。
IsMonitorMode = true;
EnterMonitor();
}
}
catch (Exception ex)
{
// 监控自动切换失败不应导致整个应用闪退
IsMonitorMode = false;
IsReadOnly = false;
TeamAAS.AppLogger.Error("ApplyMonitorAvailability 自动监控失败", ex, nameof(FlowEditorShellViewModel));
}
}
/// 保存所有已修改的流程 tab 到磁盘
private void SaveAllModifiedTabs()
{
foreach (var tab in FlowTabs)
if (tab.EditorVm != null && tab.EditorVm.IsDirty)
ProductManager.Instance.SaveFlow(ProductManager.Instance.CurrentProductName, tab);
MarkAllClean();
}
///
/// 释放当前集合中的编辑态 Tab(插件 Dispose + Debug 注册表清理)。
/// 跳过 FlowRunner.RunTabs 中的运行态 Tab——它们由 FlowRunner 拥有,可能正在执行,不能在此释放。
///
private void DisposeEditTabs()
{
try
{
var runTabs = FlowRunner.Instance.RunTabs;
var editTabs = FlowTabs.Where(t => t != null && !runTabs.Contains(t)).ToList();
if (editTabs.Count > 0)
ProductManager.DisposeFlowTabs(editTabs);
}
catch (Exception ex)
{
TeamAAS.AppLogger.Error("释放编辑态流程 Tab 失败", ex, nameof(FlowEditorShellViewModel));
}
}
/// 挂接运行态 RunTabs 到当前编辑器(监控模式核心)
private void AttachRunTabs()
{
// 释放被替换的编辑态 Tab,否则插件与 Debug 注册表引用会随每次进入监控持续泄漏
DisposeEditTabs();
// 进入监控=换对象:完全清空 Debug 之前的编辑态集合(含子流程残留),
// 此后编辑器挂的是 Main 的 RunTabs,看到的就是运行态数据
ResultRegistry.Debug.ClearAllFlows();
FlowTabs.Clear();
foreach (var t in FlowRunner.Instance.RunTabs.ToList())
FlowTabs.Add(t);
if (FlowTabs.Count > 0) ActiveTab = FlowTabs[0];
}
/// 从磁盘重载当前产品的编辑副本(退出监控时恢复编辑态)
private void DetachAndReloadFromDisk()
{
var productName = ProductManager.Instance.CurrentProductName;
// 退出监控时 FlowTabs 挂的是 RunTabs(由 FlowRunner 拥有),只解除引用不释放;
// 非监控状态下的残留编辑 Tab 则正常释放
DisposeEditTabs();
// 退出监控=换回编辑态对象:完全清空 Debug(含监控期与子流程残留),再从磁盘重载干净副本
ResultRegistry.Debug.ClearAllFlows();
FlowTabs.Clear();
if (!string.IsNullOrEmpty(productName))
{
foreach (var t in ProductManager.Instance.LoadAllFlows(productName))
FlowTabs.Add(t);
}
if (FlowTabs.Count == 0)
{
var defaultTab = new FlowTabItem("流程1");
FlowTabs.Add(defaultTab);
}
ActiveTab = FlowTabs.FirstOrDefault();
}
/// FlowRunner.RunTabsRefreshed 回调:监控模式下自动同步新运行态
private void OnRunTabsRefreshed()
{
if (!IsMonitorMode) return;
Application.Current?.Dispatcher.Invoke(AttachRunTabs);
}
public void AddFlow()
{
if (IsReadOnly) return; // 运行监控中禁止新增流程
var name = GetUniqueFlowName("流程");
var tab = new FlowTabItem(name);
tab.EditorVm?.SetReadOnly(IsReadOnly);
FlowTabs.Add(tab);
ActiveTab = tab;
_structureChanged = true; // 新增流程属于未保存修改
}
private string GetUniqueFlowName(string baseName)
{
int suffix = 1;
var name = baseName + suffix;
while (FlowTabs.Any(t => t.Name == name))
{
suffix++;
name = baseName + suffix;
}
return name;
}
public void CloseFlow(FlowTabItem tab)
{
if (tab == null || FlowTabs.Count <= 1) return;
if (IsReadOnly)
{
DialogHelper.Info("运行产品监控中,无法关闭流程");
return;
}
// 关闭的流程如果有未保存修改,先确认是否放弃
if (tab.EditorVm != null && tab.EditorVm.IsDirty)
{
bool discard = DialogHelper.ConfirmYesNo(
$"流程 \"{tab.Name}\" 有未保存的修改,关闭后将丢失这些修改,确定关闭吗?",
"关闭流程");
if (!discard) return;
}
int idx = FlowTabs.IndexOf(tab);
FlowTabs.Remove(tab);
if (ActiveTab == tab)
{
int newIdx = Math.Min(idx, FlowTabs.Count - 1);
ActiveTab = FlowTabs[newIdx];
}
_structureChanged = true; // 删除流程:保存时需要同步删除磁盘上的对应 .aas
}
public void RenameFlow(FlowTabItem tab, string newName = null)
{
if (tab == null) return;
if (IsReadOnly)
{
DialogHelper.Info("运行产品监控中,无法重命名流程");
return;
}
if (newName == null)
{
newName = ShowRenameDialog(tab.Name);
if (string.IsNullOrWhiteSpace(newName)) return;
}
// 重名加序号(排除自身)
if (FlowTabs.Any(t => t != tab && t.Name == newName))
newName = GetUniqueFlowName(newName);
tab.Name = newName;
tab.Graph.GraphName = newName;
// 同步所有节点的 FlowName
foreach (var node in tab.Graph.Nodes)
{
node.FlowName = newName;
}
tab.EditorVm?.MarkDirty(); // 流程改名也属于未保存修改
}
public void OpenTabProperties(FlowTabItem tab)
{
if (tab == null) return;
if (IsReadOnly)
{
DialogHelper.Info("运行产品监控中,无法修改流程属性");
return;
}
// 调试:记录打开属性前的 TriggerType 值
TeamAAS.AppLogger.Info($"OpenTabProperties: {tab.Name} 当前 TriggerType={tab.TriggerType}", "OpenTabProperties");
if (DialogHelper.EditProperties(tab, $"流程属性 - {tab.Name}"))
{
// 调试:记录关闭对话框后的 TriggerType 值
TeamAAS.AppLogger.Info($"OpenTabProperties: {tab.Name} 修改后 TriggerType={tab.TriggerType}", "OpenTabProperties");
DialogHelper.Info($"已更新流程属性: {tab.Name}");
}
}
private string ShowRenameDialog(string currentName)
{
return DialogHelper.Input("流程名称", "重命名流程", currentName);
}
}
}