| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- using Prism.Commands;
- using Prism.Mvvm;
- using System;
- using System.Collections.ObjectModel;
- using System.Linq;
- using System.Windows;
- using System.Windows.Input;
- using System.Windows.Threading;
- using TeamAAS.FlowEditor;
- using TeamAAS.FlowEditor.ProductModels;
- using TeamAAS.FlowEngine.Execution;
- using TeamAAS.Communication;
- using TeamAAS.Communication.Models;
- using TeamAAS.FlowEditor.Execution;
- namespace TeamAAS.ViewModels
- {
- public class ProductViewModel : TeamAAS.BindableBase
- {
- public ObservableCollection<string> Products { get; } = new ObservableCollection<string>();
- private string _selectedProduct = "";
- public string SelectedProduct
- {
- get => _selectedProduct;
- set
- {
- if (_selectedProduct == value) return;
- // 切换产品前:如果有未保存的修改,提示用户(是=保存后切换 / 否=放弃修改切换 / 取消=不切换)
- if (!_isInitializing && !string.IsNullOrEmpty(_selectedProduct) && !ConfirmDiscardOrSave())
- {
- // 取消切换:把 ComboBox 显示还原为当前产品
- RaisePropertyChanged(nameof(SelectedProduct));
- return;
- }
- SetProperty(ref _selectedProduct, value);
- RaisePropertyChanged(nameof(IsProductSelected));
- RaisePropertyChanged(nameof(IsRunProduct));
- RaisePropertyChanged(nameof(IsEditorLocked));
- RaisePropertyChanged(nameof(ShowRunBadge));
- RaisePropertyChanged(nameof(FrameConfig));
- // 切换产品时监控状态由 SwitchProductAsync 末尾 ApplyMonitorAvailability 统一处理
- if (!_isInitializing)
- _ = LoadProductAsync(value);
- }
- }
- /// <summary>选中产品的画面配置(画面数/排列/名称,跟产品走;在产品“属性”窗口中编辑)</summary>
- public ProductMeta FrameConfig
- => ProductManager.Instance.GetHomeFrameConfig(SelectedProduct);
- /// <summary>打开产品属性编辑(通用属性编辑器:画面列表由集合编辑器添加/删除)</summary>
- public void ShowProductProperties(string productName)
- {
- if (string.IsNullOrEmpty(productName)) return;
- // 右键的产品即编辑目标(并同步选中,保证语义一致)
- SelectedProduct = productName;
- var meta = ProductManager.Instance.GetHomeFrameConfig(productName);
- // 直接用通用属性编辑器(PropertyGridDialog):ProductMeta 挂了 Category/DisplayName/
- // CollectionEditor 特性,画面列表在编辑器里可添加/删除/排序
- if (DialogHelper.EditProperties(meta, $"产品属性 - {productName}"))
- {
- // 产品管理页修改产品属性只保存到磁盘,不触发主页刷新
- // (主页刷新由主页面的"加载"按钮触发)
- ProductManager.Instance.SaveProductMeta(meta);
- RaisePropertyChanged(nameof(FrameConfig));
- }
- }
- private DelegateCommand<string> _productPropertiesCommand;
- /// <summary>右键菜单“属性”命令(参数=产品名;未传参数时用当前选中产品)</summary>
- public DelegateCommand<string> ProductPropertiesCommand
- => _productPropertiesCommand ?? (_productPropertiesCommand = new DelegateCommand<string>(
- name => ShowProductProperties(string.IsNullOrEmpty(name) ? SelectedProduct : name)));
- /// <summary>
- /// 打开某产品的“全局变量”弹窗,编辑该产品的 Product 作用域变量。
- /// 直接从该产品快照文件读取(不切换当前产品,规避异步切换竞态);
- /// 确定时写回文件,若正是当前归属产品则同步刷新 live 列表让公式立即生效。
- /// </summary>
- public void ShowProductGlobalVars(string productName)
- {
- if (string.IsNullOrEmpty(productName)) return;
- var gvm = GlobalVariableManager.Instance;
- string path = ProductManager.Instance.GetGlobalVarsPath(productName);
- var vm = new GlobalVarEditorViewModel(VarScope.Product, gvm.ReadSnapshotList(path));
- var view = new Views.GlobalVarEditorView { DataContext = vm };
- if (DialogHelper.ShowPluginView(view, $"全局变量 - {productName}"))
- {
- gvm.WriteSnapshotList(path, vm.Items);
- if (string.Equals(ProductManager.Instance.GlobalVarsOwnerProduct, productName, StringComparison.Ordinal))
- {
- ProductManager.Instance.LoadProductGlobalVars(productName);
- ResultRegistry.RefreshGlobals();
- }
- }
- }
- private DelegateCommand<string> _productGlobalVarsCommand;
- /// <summary>右键菜单“全局变量”命令(参数=产品名;未传时用当前选中产品)。</summary>
- public DelegateCommand<string> ProductGlobalVarsCommand
- => _productGlobalVarsCommand ?? (_productGlobalVarsCommand = new DelegateCommand<string>(
- name => ShowProductGlobalVars(string.IsNullOrEmpty(name) ? SelectedProduct : name)));
- /// <summary>当前编辑的产品是否就是"运行产品"</summary>
- public bool IsRunProduct =>
- !string.IsNullOrEmpty(SelectedProduct)
- && string.Equals(ProductManager.Instance.RunProductName, SelectedProduct, StringComparison.Ordinal);
- /// <summary>运行产品正在执行时编辑器进入只读监控模式(当前产品==运行产品 且 正在运行)</summary>
- public bool IsEditorLocked => IsRunProduct && FlowRunner.Instance.IsRunning;
- /// <summary>运行状态提示文本(当前产品==运行产品时显示)</summary>
-
- /// <summary>顶部运行状态角标(运行产品但未在运行时显示提示)</summary>
- public bool ShowRunBadge => IsRunProduct && !FlowRunner.Instance.IsRunning;
- /// <summary>运行状态变化后刷新锁定状态(由 ProductView 订阅 FlowRunner.RunStateChanged 调用)</summary>
- public void RefreshRunState()
- {
- // 运行开始/停止 → 重新评估监控选项可用性 + 自动进入/退出监控
- ShellVm.ApplyMonitorAvailability();
- RaisePropertyChanged(nameof(IsRunProduct));
- RaisePropertyChanged(nameof(IsEditorLocked));
- RaisePropertyChanged(nameof(ShowRunBadge));
- }
- public bool IsProductSelected => !string.IsNullOrEmpty(SelectedProduct);
- private bool _isSidebarCollapsed;
- public bool IsSidebarCollapsed
- {
- get => _isSidebarCollapsed;
- set => SetProperty(ref _isSidebarCollapsed, value);
- }
- private bool _isProductLoading;
- public bool IsProductLoading
- {
- get => _isProductLoading;
- set => SetProperty(ref _isProductLoading, value);
- }
- public FlowEditorShellViewModel ShellVm { get; }
- public DelegateCommand NewProductCommand { get; }
- public DelegateCommand DeleteProductCommand { get; }
- public DelegateCommand RenameProductCommand { get; }
- public DelegateCommand SaveProductCommand { get; }
- public DelegateCommand ToggleSidebarCommand { get; }
- private bool _isInitializing;
- public ProductViewModel()
- {
- ShellVm = new FlowEditorShellViewModel();
- NewProductCommand = new DelegateCommand(NewProduct);
- DeleteProductCommand = new DelegateCommand(DeleteProduct);
- RenameProductCommand = new DelegateCommand(RenameProduct);
- SaveProductCommand = new DelegateCommand(SaveProduct);
- ToggleSidebarCommand = new DelegateCommand(() => IsSidebarCollapsed = !IsSidebarCollapsed);
- _isInitializing = true;
- RefreshProducts();
- var lastProduct = ProductManager.Instance.CurrentProductName;
- if (!string.IsNullOrEmpty(lastProduct) && Products.Contains(lastProduct))
- SelectedProduct = lastProduct;
- else if (Products.Count > 0)
- SelectedProduct = Products.First();
- _isInitializing = false;
- if (!string.IsNullOrEmpty(SelectedProduct))
- _ = LoadProductAsync(SelectedProduct);
- }
- public void RefreshProducts()
- {
- Products.Clear();
- var list = ProductManager.Instance.GetProductList();
- foreach (var name in list)
- Products.Add(name);
- }
- private async System.Threading.Tasks.Task LoadProductAsync(string productName)
- {
- if (IsProductLoading) return;
- IsProductLoading = true;
- try
- {
- // 让加载遮罩先渲染一帧,再切换产品(文件 IO 在后台,集合变更在 UI 线程)
- await System.Threading.Tasks.Task.Yield();
- await ProductManager.Instance.SwitchProductAsync(productName, ShellVm);
- }
- finally
- {
- IsProductLoading = false;
- }
- }
- /// <summary>切换产品前询问:有未保存修改才提示。true=可以继续切换。</summary>
- private bool ConfirmDiscardOrSave()
- {
- if (!ShellVm.HasUnsavedChanges) return true;
- bool? result = DialogHelper.ConfirmYesNoCancel(
- $"产品 \"{SelectedProduct}\" 的流程有未保存的修改,是否保存?\n\n" +
- "是 = 保存后切换 否 = 不保存直接切换 取消 = 不切换",
- "保存更改");
- if (result == null) return false; // 取消 → 不切换
- if (result == true) SaveProduct(); // 保存后切换
- return true;
- }
- private void NewProduct()
- {
- string name = DialogHelper.Input("产品名称", "新建产品");
- if (string.IsNullOrWhiteSpace(name)) return;
- name = name.Trim();
- if (ProductManager.Instance.CreateProduct(name))
- {
- RefreshProducts();
- SelectedProduct = name;
- }
- else
- {
- DialogHelper.ShowError("创建产品失败,名称可能已存在或无效。");
- }
- }
- private void DeleteProduct()
- {
- if (string.IsNullOrEmpty(SelectedProduct)) return;
- if (!DialogHelper.ConfirmYesNo(
- $"确认删除产品 \"{SelectedProduct}\" 吗?\n该产品的所有流程配置将被删除!",
- "确认删除"))
- {
- return;
- }
- if (ProductManager.Instance.DeleteProduct(SelectedProduct))
- {
- // 产品文件夹已整体删除,未保存的修改随之作废,清掉脏标记避免切换时误弹保存提示
- ShellVm.MarkAllClean();
- RefreshProducts();
- if (Products.Count > 0)
- SelectedProduct = Products.First();
- else
- SelectedProduct = "";
- }
- }
- private void RenameProduct()
- {
- if (string.IsNullOrEmpty(SelectedProduct)) return;
- string newName = DialogHelper.Input("新名称", "重命名产品", SelectedProduct);
- if (string.IsNullOrWhiteSpace(newName)) return;
- newName = newName.Trim();
- if (ProductManager.Instance.RenameProduct(SelectedProduct, newName))
- {
- RefreshProducts();
- SelectedProduct = newName;
- }
- else
- {
- DialogHelper.ShowError("重命名失败,名称可能已存在或无效。");
- }
- }
- /// <summary>点击"保存"才真正落盘;保存成功后清除脏标记并给出反馈</summary>
- private void SaveProduct()
- {
- if (string.IsNullOrEmpty(SelectedProduct)) return;
- if (!ShellVm.HasUnsavedChanges)
- {
- DialogHelper.Info($"产品 \"{SelectedProduct}\" 没有需要保存的更改");
- return;
- }
- bool ok = ProductManager.Instance.SaveAllFlows(SelectedProduct, ShellVm.FlowTabs);
- if (ok)
- {
- ShellVm.MarkAllClean();
- DialogHelper.Success($"产品 \"{SelectedProduct}\" 已保存");
- }
- else
- {
- DialogHelper.ShowError($"产品 \"{SelectedProduct}\" 保存失败,请查看日志");
- }
- }
- }
- }
|