using System; using System.Collections.ObjectModel; using System.Threading; using System.Windows; namespace TeamAAS.FlowEngine.Execution { /// /// 运行统计中心。FlowRunner 每次产品运行结束后调用 AddRun 更新计数; /// 首页 / 统计页直接绑定 Instance 的属性即可获得真实数据(不再写死假数据)。 /// public class RunStatistics : TeamAAS.BindableBase { public static RunStatistics Instance { get; } = new RunStatistics(); private long _totalCount; private long _okCount; private long _ngCount; private long _cycleMs; private RunStatistics() { Logs = new ObservableCollection(); } /// 运行日志(首页"运行信息"面板直接绑定) public ObservableCollection Logs { get; } public long TotalCount => Interlocked.Read(ref _totalCount); public long OkCount => Interlocked.Read(ref _okCount); public long NgCount => Interlocked.Read(ref _ngCount); public long CycleTimeMs => Interlocked.Read(ref _cycleMs); public string YieldText => TotalCount == 0 ? "--" : (OkCount * 100.0 / TotalCount).ToString("F1") + "%"; public string UphText => CycleTimeMs > 0 ? Math.Round(3600000.0 / CycleTimeMs).ToString("F0") : "--"; public string CtText => CycleTimeMs > 0 ? (CycleTimeMs / 1000.0).ToString("F2") + "s" : "--"; /// 记录一次运行结果(后台线程安全,UI 属性自动跨线程刷新) public void AddRun(bool success, long cycleMs) { Interlocked.Increment(ref _totalCount); if (success) Interlocked.Increment(ref _okCount); else Interlocked.Increment(ref _ngCount); Interlocked.Exchange(ref _cycleMs, cycleMs); RaiseCountersChanged(); Log((success ? "OK" : "NG") + $" 周期 {cycleMs}ms"); } public void Reset() { Interlocked.Exchange(ref _totalCount, 0); Interlocked.Exchange(ref _okCount, 0); Interlocked.Exchange(ref _ngCount, 0); Interlocked.Exchange(ref _cycleMs, 0); OnUi(() => Logs.Clear()); RaiseCountersChanged(); Log("统计已清零"); } /// 写一条运行日志(最多保留 200 条) public void Log(string message) { // 并入统一日志流:经 AppLogger 进入公共日志文件 + 实时日志控件 TeamAAS.AppLogger.Info(message, "运行"); OnUi(() => { Logs.Add(new RunLogEntry(DateTime.Now, message ?? "")); while (Logs.Count > 200) Logs.RemoveAt(0); }); } private void RaiseCountersChanged() { RaisePropertyChanged(nameof(TotalCount)); RaisePropertyChanged(nameof(OkCount)); RaisePropertyChanged(nameof(NgCount)); RaisePropertyChanged(nameof(CycleTimeMs)); RaisePropertyChanged(nameof(YieldText)); RaisePropertyChanged(nameof(UphText)); RaisePropertyChanged(nameof(CtText)); } private static void OnUi(Action action) { if (Application.Current?.Dispatcher != null && !Application.Current.Dispatcher.CheckAccess()) Application.Current.Dispatcher.Invoke(action); else action(); } } /// 运行日志条目 public class RunLogEntry { public RunLogEntry(DateTime time, string message) { Time = time; Message = message; } public DateTime Time { get; } public string Message { get; } public string TimeText => Time.ToString("HH:mm:ss"); } }