| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- using Prism.Commands;
- using System;
- using System.Collections.ObjectModel;
- using System.Linq;
- using System.Windows.Media;
- using TeamAAS.FlowEditor;
- using TeamAAS.FlowEditor.Execution;
- using TeamAAS.FlowEngine.Execution;
- using TeamAAS.Theme;
- using TeamAAS.Vision;
- namespace TeamAAS.ViewModels
- {
- public class HomeViewModel : TeamAAS.BindableBase
- {
- public ObservableCollection<string> Products { get; } = new ObservableCollection<string>();
- private string _selectedProduct = "";
- public string SelectedProduct
- {
- get => _selectedProduct;
- set => SetProperty(ref _selectedProduct, value);
- }
- public DelegateCommand LoadProductCommand { get; }
- public DelegateCommand ResetStatisticsCommand { get; }
- public DelegateCommand RunCommand { get; }
- public DelegateCommand StopCommand { get; }
- #region 运行状态(总运行/停止按钮)
- public bool IsRunning => FlowRunner.Instance.IsRunning;
- public bool CanRun => !IsRunning && !string.IsNullOrEmpty(FlowRunner.Instance.RunProductName);
- public bool CanStop => IsRunning;
- /// <summary>FlowRunner 运行状态变化后刷新按钮状态</summary>
- public void RefreshRunState()
- {
- RaisePropertyChanged(nameof(IsRunning));
- RaisePropertyChanged(nameof(CanRun));
- RaisePropertyChanged(nameof(CanStop));
- RaisePropertyChanged(nameof(RunProductName));
- }
- private async void RunAll()
- {
- if (string.IsNullOrEmpty(FlowRunner.Instance.RunProductName))
- {
- DialogHelper.ShowWarning("请先加载运行产品");
- return;
- }
- // 循环运行当前产品所有主流程,直到点击停止
- await FlowRunner.Instance.RunLoopAsync();
- }
- private void StopAll()
- {
- FlowRunner.Instance.Stop();
- }
- #endregion
- /// <summary>首页统计数据(真实运行数据,不再是写死的假数据)</summary>
- public RunStatistics Stats => RunStatistics.Instance;
- /// <summary>当前运行产品名(空=未加载)</summary>
- public string RunProductName => FlowRunner.Instance.RunProductName;
- #region 主题与主色(单一数据源:App.SystemConfig,切换后写入 SystemConfiguration.json)
- public bool IsDarkMode =>
- string.Equals(App.SystemConfig?.Theme, "Dark", StringComparison.OrdinalIgnoreCase);
- public string ThemeIcon => IsDarkMode ? "☀️" : "🌙";
- /// <summary>预设主色</summary>
- public ObservableCollection<AccentColorOption> AccentColors { get; }
- = new ObservableCollection<AccentColorOption>();
- /// <summary>当前主色画刷(ColorPicker 与色板联动)</summary>
- public Brush AccentBrush
- {
- get
- {
- try
- {
- var color = (Color)ColorConverter.ConvertFromString(App.SystemConfig?.AccentColor);
- // 规范化为主色不透明版本(配置里可能残留带 alpha 的历史值)
- var brush = new SolidColorBrush(Color.FromRgb(color.R, color.G, color.B));
- brush.Freeze();
- return brush;
- }
- catch { return Brushes.DodgerBlue; }
- }
- set => ApplyAccent(value); // ColorPicker TwoWay 回写:应用并持久化
- }
- public DelegateCommand ToggleThemeCommand { get; }
- public DelegateCommand<string> SetAccentCommand { get; }
- /// <summary>应用主色(色板按钮 / ColorPicker 回调共用)</summary>
- public void ApplyAccent(Brush brush)
- {
- if (!(brush is SolidColorBrush sb)) return;
- // 规范化:只取 RGB、强制不透明。ColorPicker 样式重算时会回写带任意 alpha 的画刷
- // (实测出现过 A=0x0A 的 96% 透明色被存进配置,表现为主色"特别淡、朦了一层"),
- // 统一丢弃 alpha——色相保真,主色永远纯色。
- var color = Color.FromRgb(sb.Color.R, sb.Color.G, sb.Color.B);
- // 按 RGB 去重:同色不同 alpha 的回写(切主题时样式重算触发)完全静默忽略
- var current = TryParseAccentColor();
- if (current.HasValue &&
- current.Value.R == color.R && current.Value.G == color.G && current.Value.B == color.B)
- {
- return;
- }
- App.SystemConfig.AccentColor = color.ToString();
- // 主色系画刷与文字对比色由主题覆盖层派生重建(毫秒级生效,不碰合并字典)
- ThemeManager.UpdateAccent(color);
- App.SaveSystemConfig();
- RaisePropertyChanged(nameof(AccentBrush));
- }
- private static Color? TryParseAccentColor()
- {
- try
- {
- var hex = App.SystemConfig?.AccentColor;
- if (string.IsNullOrWhiteSpace(hex)) return null;
- return (Color)ColorConverter.ConvertFromString(hex);
- }
- catch { return null; }
- }
- /// <summary>主题/主色在别处(顶部栏、设置页)变化后刷新本地状态</summary>
- public void RefreshThemeState()
- {
- RaisePropertyChanged(nameof(IsDarkMode));
- RaisePropertyChanged(nameof(ThemeIcon));
- RaisePropertyChanged(nameof(AccentBrush));
- }
- #endregion
- public HomeViewModel()
- {
- LoadProductCommand = new DelegateCommand(LoadProduct);
- ResetStatisticsCommand = new DelegateCommand(() => RunStatistics.Instance.Reset());
- RunCommand = new DelegateCommand(RunAll);
- StopCommand = new DelegateCommand(StopAll);
- ToggleThemeCommand = new DelegateCommand(() =>
- {
- App.SystemConfig.Theme = IsDarkMode ? "Light" : "Dark";
- ThemeManager.ApplyTheme(!IsDarkMode, App.SystemConfig.AccentColor);
- App.SaveSystemConfig();
- RaisePropertyChanged(nameof(IsDarkMode));
- RaisePropertyChanged(nameof(ThemeIcon));
- });
- SetAccentCommand = new DelegateCommand<string>(hex =>
- {
- if (string.IsNullOrWhiteSpace(hex)) return;
- App.SystemConfig.AccentColor = hex;
- // 主色系画刷与文字对比色由主题覆盖层派生重建(毫秒级生效)
- ThemeManager.UpdateAccent(hex);
- App.SaveSystemConfig();
- RaisePropertyChanged(nameof(AccentBrush));
- });
- InitAccentColors();
- RefreshProducts();
- // 产品管理页新增/删除/重命名产品后,同步刷新首页产品型号下拉
- ProductManager.Instance.ProductListChanged += OnProductListChanged;
- // 产品画面配置(画面数/排列/名称,跟产品走)变化后重建布局
- ProductManager.Instance.HomeFrameConfigChanged += RefreshEngineView;
- RefreshEngineView();
- }
- #region 主页视觉画面(引擎多画面视图 + 画面框注册)
- private object _engineMainView;
- /// <summary>当前视觉引擎的主页多画面视图(无可用引擎时为 null,显示占位提示)</summary>
- public object EngineMainView
- {
- get { return _engineMainView; }
- private set { SetProperty(ref _engineMainView, value); }
- }
- /// <summary>
- /// 按当前产品的画面配置刷新主页画面:应用当前视觉引擎的布局,
- /// 并把各画面框注册到 VisualFrameManager(唯一 ID + 用户可见名称),
- /// 其他页面/插件通过 ID 即可选择往哪个框显示结果。
- /// </summary>
- public void RefreshEngineView()
- {
- var manager = VisualEngineManager.Instance;
- var engine = manager.GetOrLoad(App.SystemConfig?.Vision?.EngineName);
- if (engine == null)
- {
- EngineMainView = null;
- return;
- }
- manager.SetCurrent(engine.EngineName);
- // 画面配置跟产品走(ProductMeta.HomeFrame*)
- // 注意:必须读"运行产品"(主页面刚加载的),而不是编辑态产品——
- // 主页面下拉直接加载某产品时编辑态(CurrentProductName)并未跟随,
- // 若读编辑态产品会导致首次加载的画面数/排列用的是别的产品的配置
- var pm = ProductManager.Instance;
- var configProduct = string.IsNullOrEmpty(pm.RunProductName) ? pm.CurrentProductName : pm.RunProductName;
- var cfg = pm.GetHomeFrameConfig(configProduct);
- // 画面列表(可空):0 个画面 = 主页面不显示画面框
- var count = cfg.HomeFrames?.Count ?? 0;
- engine.ApplyHomeLayout(count, (int)cfg.HomeFrameArrange);
- TeamAAS.Vision.VisualFrameManager.Clear();
- for (int i = 0; i < count; i++)
- {
- var frameId = $"home:{i + 1}";
- var frameName = cfg.GetFrameName(i);
- var showDot = cfg.GetFrameShowDot(i);
- TeamAAS.Vision.VisualFrameManager.Register(frameId, frameName, "Home");
- // 通过引擎抽象接口设置画面框标题与状态圆点显隐
- //(不直接引用引擎插件内部类型——引擎可替换)
- engine.SetFrameCaption(i, frameName);
- engine.SetFrameDotVisible(i, showDot);
- }
- EngineMainView = engine.GetMainView();
- }
- #endregion
- private void OnProductListChanged()
- {
- RefreshProducts();
- }
- private void InitAccentColors()
- {
- var presets = new[]
- {
- ("默认蓝", "#2D6CDF"),
- ("成功绿", "#4CAF50"),
- ("活力橙", "#FF9800"),
- ("警示红", "#F44336"),
- ("优雅紫", "#7B1FA2"),
- ("清新青", "#00BCD4"),
- ("少女粉", "#E91E63"),
- ("中性灰", "#607D8B"),
- };
- foreach (var (name, hex) in presets)
- {
- AccentColors.Add(new AccentColorOption
- {
- Name = name,
- Hex = hex,
- Brush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(hex))
- });
- }
- }
- public void RefreshProducts()
- {
- Products.Clear();
- var list = ProductManager.Instance.GetProductList();
- foreach (var name in list)
- Products.Add(name);
- // 当前选中的产品已被删除 → 清空或切到第一个;否则保留选中状态
- if (!Products.Contains(SelectedProduct))
- SelectedProduct = Products.Count > 0 ? Products.First() : "";
- }
- private void LoadProduct()
- {
- if (string.IsNullOrEmpty(SelectedProduct)) return;
- // 先停掉正在运行的流程(Stop 内部已完全释放 ResultRegistry.Main 的流程数据),再切换运行产品
- FlowRunner.Instance.Stop();
- // 清空视觉画面框注册
- TeamAAS.Vision.VisualFrameManager.Clear();
- // 加载为"运行产品"并复制运行态流程(真正接上运行引擎)
- if (FlowRunner.Instance.LoadRunProduct(SelectedProduct))
- {
- // 加载成功后刷新主页画面布局(应用新产品的画面配置,会重建视觉引擎布局)
- RefreshEngineView();
- RefreshRunState();
- DialogHelper.Success($"运行产品已切换为: {SelectedProduct}");
- }
- else
- {
- DialogHelper.ShowError($"加载运行产品失败: {SelectedProduct}");
- }
- }
- }
- /// <summary>预设主色选项</summary>
- public class AccentColorOption
- {
- public string Name { get; set; }
- public string Hex { get; set; }
- public Brush Brush { get; set; }
- }
- }
|