using MembranePoreTester.Communication; using MembranePoreTester.Helpers; using MembranePoreTester.Models; using Microsoft.Win32; using System.Collections.Generic; using System.Windows; using System.Windows.Input; namespace MembranePoreTester.ViewModels { public class BubblePointViewModel : ViewModelBase { private BubblePointRecord _record = new(); private TestLiquid _selectedLiquid; private bool _isCustomLiquid; private double _customSurfaceTension = 30.0; // 添加字段 private readonly IPlcService _plcService; private readonly PlcConfiguration _plcConfig; public ICommand ReadPlcCommand { get; } public BubblePointRecord Record { get => _record; set => SetProperty(ref _record, value); } // 初始化,确保 StationId 在读取PLC前已设置 public void Initialize(int stationId) { StationId = stationId; // 延迟读取当前PLC值以确保连接稳定 Task.Run(async () => { await Task.Delay(200); await ReadCurrentPlcAsync(); await ReadSpeedRateAsync(); }); } public List Liquids => TestLiquid.Predefined; public List PressureUnits => new() { "Pa", "cmHg", "psi" }; public List MembraneTypes => new() { "平板膜", "中空纤维膜" }; public TestLiquid SelectedLiquid { get => _selectedLiquid; set { if (SetProperty(ref _selectedLiquid, value)) { Record.Liquid = value; OnPropertyChanged(nameof(Record.MaxPoreSize)); } } } public bool IsCustomLiquid { get => _isCustomLiquid; set { if (SetProperty(ref _isCustomLiquid, value)) { UpdateCustomLiquid(); } } } public double CustomSurfaceTension { get => _customSurfaceTension; set { if (SetProperty(ref _customSurfaceTension, value)) { UpdateCustomLiquid(); } } } private void UpdateCustomLiquid() { if (IsCustomLiquid) { Record.Liquid = new TestLiquid { Name = "自定义", SurfaceTension = CustomSurfaceTension }; OnPropertyChanged(nameof(Record.MaxPoreSize)); } } public ICommand CalculateCommand { get; } public ICommand GenerateReportCommand { get; } public ICommand OpenPressureCalibCommand { get; } public ICommand OpenPressureCalibCommand2 { get; } private System.Windows.Threading.DispatcherTimer _timer; // 添加定时器字段 public BubblePointViewModel() { if (IsInDesignMode()) { return; // 设计时跳过PLC初始化 } _plcService = App.PlcService; _plcConfig = App.PlcConfig; CalculateCommand = new RelayCommand(Calculate); GenerateReportCommand = new RelayCommand(GenerateReport); SelectedLiquid = Liquids[0]; ReadPlcCommand = new RelayCommand(async () => await ReadPlcAsync()); SaveCommand = new RelayCommand(SaveToDatabase); ExportCommand = new RelayCommand(ExportToExcel); OpenPressureCalibCommand = new RelayCommand(OpenPressureCalibration); OpenPressureCalibCommand2 = new RelayCommand(OpenPressureCalibration2); // 启动定时器,每秒读取一次 _timer = new System.Windows.Threading.DispatcherTimer(); _timer.Interval = TimeSpan.FromSeconds(1); _timer.Tick += async (s, e) => { if (StationId > 0 && !IsDisposed) { await ReadCurrentPlcAsync(); await ReadSpeedRateAsync(); // 新增:读取加压速率 } }; _timer.Start(); //// 立即读取一次 //Task.Run(async () => //{ // await Task.Delay(1000); // 等待2秒确保PLC连接稳定 // await ReadCurrentPlcAsync(); //} //); } // 新增:读取加压速率并赋值给 Record.SpeedRate1 private async Task ReadSpeedRateAsync() { try { float speedRate = 0; ushort address = 0; switch (StationId) { case 1: address = _plcConfig.HPCoeff11; speedRate = await _plcService.ReadFloatAsync(address); Record.SpeedRate1 = speedRate.ToString("F3"); break; case 2: address = _plcConfig.HPCoeff12; speedRate = await _plcService.ReadFloatAsync(address); Record.SpeedRate1 = speedRate.ToString("F3"); break; case 3: address = _plcConfig.HPCoeff13; speedRate = await _plcService.ReadFloatAsync(address); Record.SpeedRate1 = speedRate.ToString("F3"); break; } OnPropertyChanged(nameof(Record)); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"读取加压速率失败: {ex.Message}"); } } public override void Dispose() { _timer?.Stop(); base.Dispose(); } private async Task ReadCurrentPlcAsync() { await SafeExecuteAsync("ReadCurrentPressure", async () => { if (IsDisposed || _plcService == null) return; await Task.Delay(100); // 小延迟避免过快读取 float rawPressure = await _plcService.ReadPressureAsync(StationId); Record.BubbleCurrentPressure = Math.Round(rawPressure, 2); OnPropertyChanged(nameof(Record.BubbleCurrentPressure)); }); } private async Task ReadPlcAsync() { try { double rawPressure = await _plcService.ReadPressureAsync(StationId); rawPressure = Math.Round((double)rawPressure, 2); double pressure = rawPressure * _plcConfig.PressureFactor; // 更新当前压力显示 Record.BubbleCurrentPressure = pressure; // 同时将泡点压力设为该值(符合涨破测试逻辑) Record.BubblePointPressure = pressure; OnPropertyChanged(nameof(Record.BubblePointPressure)); OnPropertyChanged(nameof(Record.BubbleCurrentPressure)); } catch (Exception ex) { MessageBox.Show($"读取PLC失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } public double MaxPoreSize => Record.MaxPoreSize; private void Calculate() { // 触发最大孔径重新计算(通过绑定已自动刷新) OnPropertyChanged(nameof(Record.MaxPoreSize)); } private void GenerateReport() { ReportGenerator.GenerateBubblePointReport(Record); } public void UpdateBubblePointPressure(double pressure) { Record.BubblePointPressure = pressure; OnPropertyChanged(nameof(Record.BubblePointPressure)); OnPropertyChanged(nameof(MaxPoreSize)); // 最大孔径依赖于压力 } private int _stationId; public int StationId { get => _stationId; set => SetProperty(ref _stationId, value); } // 保存当前记录到数据库 public void SaveToDatabase() { var entity = new BubblePointEntity { StationId = StationId, TestDate = Record.TestDate, Tester = Record.Tester ?? "系统操作员", SampleType = Record.SampleType ?? "缺省值", SampleSpec = Record.SampleSpec ?? "缺省值", RoomTemperature = Record.RoomTemperature, SoakingTime = Record.SoakingTime, LiquidName = Record.Liquid?.Name ?? "缺省值", LiquidSurfaceTension = Record.Liquid?.SurfaceTension ?? 0, LiquidManufacturer = Record.LiquidManufacturer, BubblePointPressure = Record.BubblePointPressure, PressureUnit = Record.PressureUnit, MaxPoreSize = Record.MaxPoreSize }; using var db = new AppDbContext(); db.BubblePointRecords.Add(entity); db.SaveChanges(); } public void LoadFromDatabase(int recordId) { using var db = new AppDbContext(); var entity = db.BubblePointRecords.Find(recordId); if (entity == null) return; Record.SampleType = entity.SampleType; Record.SampleSpec = entity.SampleSpec; Record.RoomTemperature = entity.RoomTemperature ?? 0; Record.SoakingTime = entity.SoakingTime ?? 0; Record.Liquid = TestLiquid.Predefined.FirstOrDefault(l => l.Name == entity.LiquidName) ?? new TestLiquid { Name = entity.LiquidName, SurfaceTension = entity.LiquidSurfaceTension ?? 0 }; Record.LiquidManufacturer = entity.LiquidManufacturer; Record.BubblePointPressure = entity.BubblePointPressure ?? 0; Record.PressureUnit = entity.PressureUnit; Record.TestDate = entity.TestDate; Record.Tester = entity.Tester; OnPropertyChanged(nameof(Record)); OnPropertyChanged(nameof(MaxPoreSize)); // 触发界面更新 } public ICommand SaveCommand { get; } public ICommand ExportCommand { get; } private void OpenPressureCalibration() { ushort address = new ushort(); switch (StationId) { case 1: { address = _plcConfig.High1; break; } case 2: { address = _plcConfig.High2; break; } case 3: { address = _plcConfig.High3; break; } } Task.Run(async () => { await _plcService.WriteCoilAsync(address, true); }); } private void OpenPressureCalibration2() { ushort address = new ushort(); switch (StationId) { case 1: { address = _plcConfig.Low1; break; } case 2: { address = _plcConfig.Low2; break; } case 3: { address = _plcConfig.Low3; break; } } Task.Run(async () => { await _plcService.WriteCoilAsync(address, true); }); } private void ExportToExcel() { var saveFileDialog = new SaveFileDialog { Filter = "Excel文件|*.xlsx", FileName = $"泡点法_工位{StationId}_{DateTime.Now:yyyyMMddHHmmss}.xlsx" }; if (saveFileDialog.ShowDialog() == true) { // 将 Record 转换为 Entity var entity = new BubblePointEntity { StationId = this.StationId, TestDate = Record.TestDate, Tester = Record.Tester, SampleType = Record.SampleType, SampleSpec = Record.SampleSpec, RoomTemperature = Record.RoomTemperature, SoakingTime = Record.SoakingTime, LiquidName = Record.Liquid?.Name, LiquidSurfaceTension = Record.Liquid?.SurfaceTension, LiquidManufacturer = Record.LiquidManufacturer, BubblePointPressure = Record.BubblePointPressure, PressureUnit = Record.PressureUnit, MaxPoreSize = Record.MaxPoreSize }; ExportHelper.ExportBubblePoint(entity, saveFileDialog.FileName); MessageBox.Show("导出成功"); } } } }