添加项目文件。

This commit is contained in:
xyy
2026-06-13 14:16:34 +08:00
parent 9df508aa36
commit 3fb35f5814
23 changed files with 1251 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using AciTester.Models;
using AciTester.Services;
using System.Windows;
namespace AciTester.ViewModels
{
public partial class ConfigViewModel : ObservableObject
{
private readonly IPlcService _plcService;
private readonly PlcConfiguration _config;
private readonly CalibrationConfig _calib;
public ConfigViewModel(IPlcService plcService, PlcConfiguration config, CalibrationConfig calib)
{
_plcService = plcService;
_config = config;
_calib = calib;
LoadConfigCommand = new AsyncRelayCommand(LoadConfigAsync);
SaveConfigCommand = new AsyncRelayCommand(SaveConfigAsync);
}
public IAsyncRelayCommand LoadConfigCommand { get; }
public IAsyncRelayCommand SaveConfigCommand { get; }
public CalibrationConfig Calibration => _calib;
private async Task LoadConfigAsync()
{
if (!_plcService.IsConnected)
{
MessageBox.Show("请先连接PLC", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
try
{
_calib.FlowCalibration = await _plcService.ReadFloatAsync(_config.FlowCalibrationReg);
_calib.TemperatureCalibration = await _plcService.ReadFloatAsync(_config.TempCalibrationReg);
_calib.PumpPressureCalibration = await _plcService.ReadFloatAsync(_config.PumpPressureCalibReg);
_calib.ImpactorPressureCalibration = await _plcService.ReadFloatAsync(_config.ImpactorPressureCalibReg);
// 读取流量保护值(假设高限低限分别存储,这里简化)
var protect = await _plcService.ReadFloatAsync(_config.FlowProtectReg);
_calib.FlowLowLimit = protect - 5; // 示例,实际根据协议解析
_calib.FlowHighLimit = protect + 5;
}
catch (System.Exception ex)
{
MessageBox.Show($"读取配置失败: {ex.Message}", "错误");
}
}
private async Task SaveConfigAsync()
{
if (!_plcService.IsConnected)
{
MessageBox.Show("请先连接PLC", "提示");
return;
}
try
{
await _plcService.WriteMultipleRegistersAsync(_config.FlowCalibrationReg, _calib.FlowCalibration);
await _plcService.WriteMultipleRegistersAsync(_config.TempCalibrationReg, _calib.TemperatureCalibration);
await _plcService.WriteMultipleRegistersAsync(_config.PumpPressureCalibReg, _calib.PumpPressureCalibration);
await _plcService.WriteMultipleRegistersAsync(_config.ImpactorPressureCalibReg, _calib.ImpactorPressureCalibration);
// 写入流量保护值(需根据实际协议拆分高低限)
MessageBox.Show("配置保存成功", "提示");
// 可选:触发重新校准
await _plcService.WriteCoilAsync(_config.ImpactorPressureCalibCoil, true);
await Task.Delay(100);
await _plcService.WriteCoilAsync(_config.ImpactorPressureCalibCoil, false);
}
catch (System.Exception ex)
{
MessageBox.Show($"保存失败: {ex.Message}", "错误");
}
}
}
}

305
ViewModels/MainViewModel.cs Normal file
View File

@@ -0,0 +1,305 @@
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<StageData> 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<StageData>
{
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);
}
}
}
}