Files
HeadgearViewingRange3M/ViewModels/PoreDistributionViewModel.cs
2026-03-24 20:40:26 +08:00

409 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using MembranePoreTester.Communication;
using MembranePoreTester.Helpers;
using MembranePoreTester.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
namespace MembranePoreTester.ViewModels
{
public class PoreDistributionViewModel : ViewModelBase, IStationViewModel
{
private PoreDistributionRecord _record = new();
private TestLiquid _selectedLiquid;
private bool _isCustomLiquid;
private double _customSurfaceTension = 30.0;
private double _lowerPore = 0.2;
private double _upperPore = 0.8;
private double _rangePercentage;
// 添加字段
private readonly IPlcService _plcService;
private readonly PlcConfiguration _plcConfig;
private DataPoint _selectedDataPoint;
// 添加属性
public DataPoint SelectedDataPoint
{
get => _selectedDataPoint;
set => SetProperty(ref _selectedDataPoint, value);
}
public ICommand ReadPlcCommand { get; }
public PoreDistributionRecord Record
{
get => _record;
set => SetProperty(ref _record, value);
}
public List<TestLiquid> Liquids => TestLiquid.Predefined;
public List<string> PressureUnits => new() { "Pa", "cmHg", "psi" };
public List<string> MembraneTypes => new() { "平板膜", "中空纤维膜" };
public TestLiquid SelectedLiquid
{
get => _selectedLiquid;
set
{
if (SetProperty(ref _selectedLiquid, value))
{
Record.Liquid = value;
}
}
}
public bool IsCustomLiquid
{
get => _isCustomLiquid;
set
{
if (SetProperty(ref _isCustomLiquid, value))
{
UpdateCustomLiquid();
}
}
}
public double CustomSurfaceTension
{
get => _customSurfaceTension;
set
{
if (SetProperty(ref _customSurfaceTension, value))
{
UpdateCustomLiquid();
}
}
}
public double LowerPore
{
get => _lowerPore;
set => SetProperty(ref _lowerPore, value);
}
public double UpperPore
{
get => _upperPore;
set => SetProperty(ref _upperPore, value);
}
public double RangePercentage
{
get => _rangePercentage;
set => SetProperty(ref _rangePercentage, value);
}
public ICommand AddDataPointCommand { get; }
public ICommand RemoveDataPointCommand { get; }
public ICommand CalculateCommand { get; }
public ICommand GenerateReportCommand { get; }
public PoreDistributionViewModel()
{
_plcService = App.PlcService;
_plcConfig = App.PlcConfig;
AddDataPointCommand = new RelayCommand(AddDataPoint);
RemoveDataPointCommand = new RelayCommand(RemoveDataPoint, () => Record.DataPoints.Any());
CalculateCommand = new RelayCommand(Calculate);
GenerateReportCommand = new RelayCommand(GenerateReport);
SelectedLiquid = Liquids[0];
Record.PressureUnit = PressureUnits[0]; // 默认 "Pa"
ReadPlcCommand = new RelayCommand(async () => await ReadPlcAsync());
SaveCommand = new RelayCommand(SaveToDatabase);
ExportCommand = new RelayCommand(ExportToExcel);
OpenFlowCalibCommand = new RelayCommand(OpenFlowCalibration);
Record.DataPoints.CollectionChanged += (s, e) => UpdatePlot();
}
private async Task ReadPlcAsync()
{
try
{
// 始终读取压力
float rawPressure = await _plcService.ReadPressureAsync(StationId);
double pressure = rawPressure * _plcConfig.PressureFactor;
if (SelectedDataPoint != null)
{
// 更新选中行
SelectedDataPoint.Pressure = pressure;
if (TestMode == "湿膜")
{
float rawWet = await _plcService.ReadWetFlowAsync();
SelectedDataPoint.WetFlow = rawWet * _plcConfig.WetFlowFactor;
}
else
{
float rawDry = await _plcService.ReadDryFlowAsync();
SelectedDataPoint.DryFlow = rawDry * _plcConfig.DryFlowFactor;
}
}
else
{
// 新增一行
var newPoint = new DataPoint { Pressure = pressure };
if (TestMode == "湿膜")
{
float rawWet = await _plcService.ReadWetFlowAsync();
newPoint.WetFlow = rawWet * _plcConfig.WetFlowFactor;
}
else
{
float rawDry = await _plcService.ReadDryFlowAsync();
newPoint.DryFlow = rawDry * _plcConfig.DryFlowFactor;
}
Record.DataPoints.Add(newPoint);
}
}
catch (Exception ex)
{
MessageBox.Show($"读取PLC失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void AddDataPoint()
{
Record.DataPoints.Add(new DataPoint());
}
private void RemoveDataPoint()
{
if (Record.DataPoints.Any())
Record.DataPoints.RemoveAt(Record.DataPoints.Count - 1);
}
private void UpdateCustomLiquid()
{
if (IsCustomLiquid)
{
Record.Liquid = new TestLiquid
{
Name = "自定义",
SurfaceTension = CustomSurfaceTension
};
}
}
// 添加私有字段和公共属性
private double _averagePoreSize;
public double AveragePoreSize
{
get => _averagePoreSize;
set => SetProperty(ref _averagePoreSize, value);
}
// 修改 Calculate 方法:
private void Calculate()
{
if (Record.DataPoints.Count < 2) return;
AveragePoreSize = PoreDistributionAnalysis.CalculateAveragePore(
Record.DataPoints, Record.PressureUnit, Record.Liquid);
RangePercentage = PoreDistributionAnalysis.CalculatePoreRangePercentage(
Record.DataPoints, Record.PressureUnit, Record.Liquid, LowerPore, UpperPore);
}
private void GenerateReport()
{
ReportGenerator.GeneratePoreDistributionReport(Record);
}
private void OpenFlowCalibration()
{
string zeroStr = Microsoft.VisualBasic.Interaction.InputBox("请输入流量零点系数", "流量校准", "0");
string spanStr = Microsoft.VisualBasic.Interaction.InputBox("请输入流量量程系数", "流量校准", "1");
if (float.TryParse(zeroStr, out float zero) && float.TryParse(spanStr, out float span))
{
Task.Run(async () =>
{
await WriteFloatAsync(_plcConfig.FlowCalibZero, zero);
await WriteFloatAsync(_plcConfig.FlowCalibSpan, span);
MessageBox.Show("流量校准系数已写入", "完成");
});
}
}
private int _stationId;
public int StationId
{
get => _stationId;
set => SetProperty(ref _stationId, value);
}
public void SaveToDatabase()
{
var entity = new PoreDistributionEntity
{
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 ?? 0,
LiquidManufacturer = Record.LiquidManufacturer,
PressureUnit = Record.PressureUnit,
BubblePointPressure = Record.BubblePointPressure,
AveragePoreSize = AveragePoreSize, // 使用计算后的属性
DataPoints = Record.DataPoints.Select(dp => new DataPointEntity
{
Pressure = dp.Pressure,
WetFlow = dp.WetFlow,
DryFlow = dp.DryFlow
}).ToList()
};
using var db = new AppDbContext();
db.PoreDistributionRecords.Add(entity);
db.SaveChanges();
MessageBox.Show("保存成功!", "提示");
}
public void LoadFromDatabase(int recordId)
{
using var db = new AppDbContext();
var entity = db.PoreDistributionRecords
.Include(p => p.DataPoints)
.FirstOrDefault(p => p.Id == recordId);
if (entity == null) return;
Record.SampleType = entity.SampleType;
Record.SampleSpec = entity.SampleSpec;
Record.RoomTemperature = entity.RoomTemperature;
Record.SoakingTime = entity.SoakingTime;
Record.Liquid = TestLiquid.Predefined.FirstOrDefault(l => l.Name == entity.LiquidName)
?? new TestLiquid { Name = entity.LiquidName, SurfaceTension = entity.LiquidSurfaceTension };
Record.LiquidManufacturer = entity.LiquidManufacturer;
Record.PressureUnit = entity.PressureUnit;
Record.BubblePointPressure = entity.BubblePointPressure;
Record.TestDate = entity.TestDate;
Record.Tester = entity.Tester;
Record.DataPoints.Clear();
foreach (var dp in entity.DataPoints)
{
Record.DataPoints.Add(new DataPoint
{
Pressure = dp.Pressure,
WetFlow = dp.WetFlow,
DryFlow = dp.DryFlow
});
}
// 重新计算平均孔径和分布(触发计算命令)
Calculate();
}
public ICommand SaveCommand { get; }
public ICommand OpenFlowCalibCommand { get; }
public ICommand ExportCommand { get; }
private void ExportToExcel()
{
var saveFileDialog = new SaveFileDialog
{
Filter = "Excel文件|*.xlsx",
FileName = $"泡点法_工位{StationId}_{DateTime.Now:yyyyMMddHHmmss}.xlsx"
};
if (saveFileDialog.ShowDialog() == true)
{
// 转换为Entity后导出
var entity = new BubblePointEntity { /* 从Record复制 */ };
ExportHelper.ExportBubblePoint(entity, saveFileDialog.FileName);
MessageBox.Show("导出成功");
}
}
private string _testMode = "湿膜";
public string TestMode
{
get => _testMode;
set => SetProperty(ref _testMode, value);
}
private int _selectedFlowModeIndex; // 0=大流量1=小流量
public int SelectedFlowModeIndex
{
get => _selectedFlowModeIndex;
set
{
if (SetProperty(ref _selectedFlowModeIndex, value))
{
ushort reg = StationId switch
{
1 => _plcConfig.FlowModeRegister1,
2 => _plcConfig.FlowModeRegister2,
3 => _plcConfig.FlowModeRegister3,
_ => 0
};
Task.Run(async () => await _plcService.WriteSingleRegisterAsync(reg, (ushort)value));
}
}
}
private OxyPlot.PlotModel _plotModel;
public OxyPlot.PlotModel PlotModel
{
get => _plotModel;
set => SetProperty(ref _plotModel, value);
}
private void UpdatePlot()
{
var sorted = Record.DataPoints.OrderBy(p => p.Pressure).ToList();
if (sorted.Count == 0)
{
PlotModel = null;
return;
}
var model = new OxyPlot.PlotModel { Title = "流量-压力曲线" };
model.Axes.Add(new OxyPlot.Axes.LinearAxis { Position = OxyPlot.Axes.AxisPosition.Bottom, Title = "压力" });
model.Axes.Add(new OxyPlot.Axes.LinearAxis { Position = OxyPlot.Axes.AxisPosition.Left, Title = "流量 (L/min)" });
var wetSeries = new OxyPlot.Series.LineSeries { Title = "湿膜流量", Color = OxyPlot.OxyColors.Blue, MarkerType = OxyPlot.MarkerType.Circle };
var drySeries = new OxyPlot.Series.LineSeries { Title = "干膜流量", Color = OxyPlot.OxyColors.Red, MarkerType = OxyPlot.MarkerType.Circle };
foreach (var dp in sorted)
{
wetSeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.WetFlow));
drySeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.DryFlow));
}
model.Series.Add(wetSeries);
model.Series.Add(drySeries);
PlotModel = model;
}
}
}