using System; using System.Collections.ObjectModel; using System.Threading; using System.Threading.Tasks; using System.Windows; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using AciTester.Models; using AciTester.Services; using AciTester.Views; namespace AciTester.ViewModels { public partial class MainViewModel : ObservableObject { public readonly IPlcService _plcService; private readonly IReportService _reportService; public readonly PlcConfiguration _config; private CancellationTokenSource _testCts; [ObservableProperty] private bool isConnected; [ObservableProperty] private string connectionStatus = "未连接"; [ObservableProperty] private float currentFlow; [ObservableProperty] private bool isPumpRunning; [ObservableProperty] private bool isTesting; [ObservableProperty] private int sampleTimeSeconds = 60; // 默认采样60秒 [ObservableProperty] private int remainingSeconds; [ObservableProperty] private ObservableCollection stages; [ObservableProperty] private TestResult currentResult; // 在 MainViewModel 中添加 [ObservableProperty] private RealTimeData realTime; [ObservableProperty] private CalibrationConfig calibration; private Timer _dataTimer; public MainViewModel() { _config = new PlcConfiguration(); _plcService = new ModbusTcpPlcService(_config); _reportService = new ExcelReportService(); // 初始化ACI 8级 + 滤膜 Stages = new ObservableCollection { new StageData { StageName = "Stage 0", CutoffDiameter = 9.0 }, new StageData { StageName = "Stage 1", CutoffDiameter = 5.8 }, new StageData { StageName = "Stage 2", CutoffDiameter = 4.7 }, new StageData { StageName = "Stage 3", CutoffDiameter = 3.3 }, new StageData { StageName = "Stage 4", CutoffDiameter = 2.1 }, new StageData { StageName = "Stage 5", CutoffDiameter = 1.1 }, new StageData { StageName = "Stage 6", CutoffDiameter = 0.7 }, new StageData { StageName = "Stage 7", CutoffDiameter = 0.4 }, new StageData { StageName = "Filter", CutoffDiameter = 0.0 } }; ConnectCommand = new AsyncRelayCommand(ConnectAsync); DisconnectCommand = new RelayCommand(Disconnect); StartTestCommand = new AsyncRelayCommand(StartTestAsync); CalculateCommand = new RelayCommand(CalculateResult); ExportReportCommand = new AsyncRelayCommand(ExportReportAsync); // 在构造函数中初始化 RealTime = new RealTimeData(); Calibration = new CalibrationConfig(); //this.Loaded += (s, e) => //{ // var keyGesture = new KeyGesture(Key.P, ModifierKeys.Control); // var inputBinding = new InputBinding(new RelayCommand(OpenConfigWindow), keyGesture); // this.InputBindings.Add(inputBinding); //}; } public IAsyncRelayCommand ConnectCommand { get; } public IRelayCommand DisconnectCommand { get; } public IAsyncRelayCommand StartTestCommand { get; } public IRelayCommand CalculateCommand { get; } public IAsyncRelayCommand ExportReportCommand { get; } private async Task ConnectAsync() { try { await _plcService.EnsureConnectedAsync(); IsConnected = true; ConnectionStatus = "已连接"; _ = Task.Run(ReadFlowLoop); _ = Task.Run(ReadRealTimeLoop); // 新增 } catch (Exception ex) { MessageBox.Show($"连接失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); IsConnected = false; ConnectionStatus = "连接失败"; } } private void Disconnect() { _plcService.Dispose(); IsConnected = false; ConnectionStatus = "未连接"; } private async Task ReadFlowLoop() { while (IsConnected) { try { var flow = await _plcService.ReadFloatAsync(_config.FlowRegister); Application.Current.Dispatcher.Invoke(() => CurrentFlow = flow); await Task.Delay(1000); } catch { break; } } } private async Task StartTestAsync() { if (!IsConnected) { await ConnectAsync(); if (!IsConnected) return; } if (IsTesting) return; IsTesting = true; _testCts = new CancellationTokenSource(); try { // 启动真空泵 await _plcService.WriteCoilAsync(_config.PumpCoil, true); IsPumpRunning = true; // 倒计时 RemainingSeconds = SampleTimeSeconds; for (int i = 0; i < SampleTimeSeconds; i++) { if (_testCts.Token.IsCancellationRequested) break; await Task.Delay(1000); RemainingSeconds--; } // 停止泵 await _plcService.WriteCoilAsync(_config.PumpCoil, false); IsPumpRunning = false; MessageBox.Show($"采样完成!\n实际采样时间: {SampleTimeSeconds} 秒\n请进行称重并录入数据。", "提示", MessageBoxButton.OK, MessageBoxImage.Information); } catch (Exception ex) { MessageBox.Show($"测试异常: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); // 尝试停止泵 try { await _plcService.WriteCoilAsync(_config.PumpCoil, false); } catch { } IsPumpRunning = false; } finally { IsTesting = false; _testCts?.Dispose(); } } private void CalculateResult() { double totalMass = 0; foreach (var stage in Stages) totalMass += stage.NetWeight; if (totalMass <= 0) { MessageBox.Show("总质量为零,无法计算", "警告", MessageBoxButton.OK, MessageBoxImage.Warning); return; } // 微细粒子剂量:截止直径 ≤ 5μm 的级 + 滤膜 double fineMass = 0; foreach (var stage in Stages) { if (stage.CutoffDiameter <= 5.0 && stage.CutoffDiameter > 0) fineMass += stage.NetWeight; } fineMass += Stages[8].NetWeight; // 滤膜 double fpd = fineMass * 1000; // mg double fpf = (fineMass / totalMass) * 100; CurrentResult = new TestResult { TestTime = DateTime.Now, TotalMass = totalMass, FineParticleDose = fpd, FineParticleFraction = fpf, Stages = Stages.ToList(), FlowRate = CurrentFlow, Temperature = RealTime.Temperature, // 新增 DifferentialPressure = RealTime.DifferentialPressure // 新增 }; MessageBox.Show($"计算完成\n总质量: {totalMass:F4} g\n微细粒子剂量: {fpd:F2} mg\n微细粒子分数: {fpf:F2}%", "计算结果", MessageBoxButton.OK, MessageBoxImage.Information); } private async Task ExportReportAsync() { if (CurrentResult == null) { MessageBox.Show("请先计算测试结果", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; } var saveDialog = new Microsoft.Win32.SaveFileDialog { Filter = "Excel文件|*.xlsx", FileName = $"ACI_Test_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx" }; if (saveDialog.ShowDialog() == true) { await _reportService.GenerateReportAsync(CurrentResult, saveDialog.FileName); MessageBox.Show("报告已保存", "完成", MessageBoxButton.OK, MessageBoxImage.Information); } } // 启动定时读取(连接成功后) private async Task ReadRealTimeLoop() { while (IsConnected) { try { // 读取原始流量 var rawFlow = await _plcService.ReadFloatAsync(_config.FlowRegister); // 校准流量 = 原始流量 * 流量系数 var calibrated = rawFlow * Calibration.FlowCalibration; Application.Current.Dispatcher.Invoke(() => { RealTime.RawFlow = rawFlow; RealTime.CalibratedFlow = calibrated; }); // 温度 var temp = await _plcService.ReadFloatAsync(_config.TemperatureReg); var calibratedTemp = temp * Calibration.TemperatureCalibration; Application.Current.Dispatcher.Invoke(() => RealTime.Temperature = calibratedTemp); // 泵端压力 var pumpPres = await _plcService.ReadFloatAsync(_config.PumpPressureReg); var calibratedPump = pumpPres * Calibration.PumpPressureCalibration; Application.Current.Dispatcher.Invoke(() => RealTime.PumpPressure = calibratedPump); // 撞击器端压力 var impPres = await _plcService.ReadFloatAsync(_config.ImpactorPressureReg); var calibratedImp = impPres * Calibration.ImpactorPressureCalibration; Application.Current.Dispatcher.Invoke(() => { RealTime.ImpactorPressure = calibratedImp; RealTime.DifferentialPressure = calibratedImp - calibratedPump; }); // 流量报警检查 if (calibrated < Calibration.FlowLowLimit || calibrated > Calibration.FlowHighLimit) { // 可触发界面警告 Application.Current.Dispatcher.Invoke(() => MessageBox.Show($"流量异常: {calibrated:F2} L/min", "警告", MessageBoxButton.OK, MessageBoxImage.Warning)); } } catch { } await Task.Delay(1000); } } } }