更新
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -198,6 +198,11 @@ public partial class PumpControlChannel : ObservableObject
|
||||
: PendingRs485RunningState == true || IsRunning
|
||||
? "停止"
|
||||
: "启动";
|
||||
public string ToggleButtonText => IsRs485Busy
|
||||
? $"{Name}处理中"
|
||||
: PendingRs485RunningState == true || IsRunning
|
||||
? $"停止{Name}"
|
||||
: $"启动{Name}";
|
||||
public bool CanStartRs485Action => !IsRs485Busy
|
||||
&& PendingRs485RunningState != true
|
||||
&& !IsRunning
|
||||
@@ -228,6 +233,7 @@ public partial class PumpControlChannel : ObservableObject
|
||||
OnPropertyChanged(nameof(StateHint));
|
||||
OnPropertyChanged(nameof(IndicatorColor));
|
||||
OnPropertyChanged(nameof(ActionText));
|
||||
OnPropertyChanged(nameof(ToggleButtonText));
|
||||
OnPropertyChanged(nameof(CanStartRs485Action));
|
||||
OnPropertyChanged(nameof(CanStopRs485Action));
|
||||
OnPropertyChanged(nameof(StartActionHint));
|
||||
@@ -252,6 +258,7 @@ public partial class PumpControlChannel : ObservableObject
|
||||
OnPropertyChanged(nameof(StateText));
|
||||
OnPropertyChanged(nameof(StateHint));
|
||||
OnPropertyChanged(nameof(IndicatorColor));
|
||||
OnPropertyChanged(nameof(ToggleButtonText));
|
||||
OnPropertyChanged(nameof(CardPrimaryDisplay));
|
||||
}
|
||||
|
||||
@@ -342,6 +349,7 @@ public partial class PumpControlChannel : ObservableObject
|
||||
OnPropertyChanged(nameof(StateText));
|
||||
OnPropertyChanged(nameof(StateHint));
|
||||
OnPropertyChanged(nameof(ActionText));
|
||||
OnPropertyChanged(nameof(ToggleButtonText));
|
||||
OnPropertyChanged(nameof(CanStartRs485Action));
|
||||
OnPropertyChanged(nameof(CanStopRs485Action));
|
||||
OnPropertyChanged(nameof(StartActionHint));
|
||||
@@ -354,6 +362,7 @@ public partial class PumpControlChannel : ObservableObject
|
||||
{
|
||||
OnPropertyChanged(nameof(StateHint));
|
||||
OnPropertyChanged(nameof(ActionText));
|
||||
OnPropertyChanged(nameof(ToggleButtonText));
|
||||
OnPropertyChanged(nameof(CanStartRs485Action));
|
||||
OnPropertyChanged(nameof(CanStopRs485Action));
|
||||
OnPropertyChanged(nameof(StartActionHint));
|
||||
|
||||
@@ -16,6 +16,12 @@ public partial class ValveControlChannel : ObservableObject
|
||||
|
||||
public string StateText => !StateAvailable ? "未知" : IsOpen ? "开启" : "关闭";
|
||||
public string ActionText => IsOpen ? "关闭" : "开启";
|
||||
public string ToggleButtonText => Key == "CirculatingWaterTemperature"
|
||||
? (IsOpen ? "停止循环水温" : "启动循环水温")
|
||||
: IsOpen
|
||||
? $"停止{Name}"
|
||||
: $"启动{Name}";
|
||||
public string CirculatingWaterToggleText => IsOpen ? "停止循环水温" : "启动循环水温";
|
||||
public string IndicatorColor => !StateAvailable ? "#FF94A6AE" : IsOpen ? "#FF32B06A" : "#FFC8D4DA";
|
||||
public string StateHint => !StateAvailable ? "未取得 PLC 状态" : $"{Name}已{StateText}";
|
||||
public bool HideRealtimeCardStateDescription => Key is "TestLoopValve1" or "TestLoopValve2" or "CirculatingWaterTemperature";
|
||||
@@ -24,6 +30,8 @@ public partial class ValveControlChannel : ObservableObject
|
||||
{
|
||||
OnPropertyChanged(nameof(StateText));
|
||||
OnPropertyChanged(nameof(ActionText));
|
||||
OnPropertyChanged(nameof(ToggleButtonText));
|
||||
OnPropertyChanged(nameof(CirculatingWaterToggleText));
|
||||
OnPropertyChanged(nameof(IndicatorColor));
|
||||
OnPropertyChanged(nameof(StateHint));
|
||||
}
|
||||
@@ -31,6 +39,8 @@ public partial class ValveControlChannel : ObservableObject
|
||||
partial void OnStateAvailableChanged(bool value)
|
||||
{
|
||||
OnPropertyChanged(nameof(StateText));
|
||||
OnPropertyChanged(nameof(ToggleButtonText));
|
||||
OnPropertyChanged(nameof(CirculatingWaterToggleText));
|
||||
OnPropertyChanged(nameof(IndicatorColor));
|
||||
OnPropertyChanged(nameof(StateHint));
|
||||
}
|
||||
|
||||
@@ -41,6 +41,20 @@ public partial class MainViewModel
|
||||
private const double DefaultRs485RawPerLitrePerMinute = 100d;
|
||||
private const double DefaultRs485RawOffset = 0d;
|
||||
private const int MaxRs485MotorCommand = short.MaxValue;
|
||||
private const string PressureDropRs485PumpKey = "PressureDropPump";
|
||||
private const string KinkResistanceRs485PumpKey = "KinkResistancePump";
|
||||
private static readonly string[] HemolysisRs485PumpKeys =
|
||||
[
|
||||
"HemolysisDrainageSinglePump",
|
||||
"HemolysisReturnSinglePump",
|
||||
"HemolysisDualLumenPump"
|
||||
];
|
||||
private static readonly string[] RecirculationRs485PumpKeys =
|
||||
[
|
||||
"RecirculationMainPump",
|
||||
"RecirculationReturnPump",
|
||||
"RecirculationDrainagePump"
|
||||
];
|
||||
private static readonly TimeSpan Rs485RuntimeRefreshInterval = TimeSpan.FromSeconds(4);
|
||||
private DateTime _lastRs485RuntimeRefreshUtc = DateTime.MinValue;
|
||||
private string _lastRs485RuntimeRefreshFailureMessage = string.Empty;
|
||||
@@ -78,14 +92,28 @@ public partial class MainViewModel
|
||||
[ObservableProperty]
|
||||
private bool rs485AdvancedSettingsVisible;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool realtimeActuatorControlsVisible = true;
|
||||
|
||||
[ObservableProperty]
|
||||
private string rs485StatusText = "RS485 待确认";
|
||||
|
||||
public ObservableCollection<string> Rs485ParityOptions { get; } = new(["Even", "Odd", "None"]);
|
||||
public ObservableCollection<PumpControlChannel> Rs485FlowPumpControls { get; } = [];
|
||||
public ObservableCollection<PumpControlChannel> ActiveRs485FlowPumpControls { get; } = [];
|
||||
public ObservableCollection<PumpControlChannel> RealtimeRs485FlowPumpControls { get; } = [];
|
||||
public ObservableCollection<PumpControlChannel> PressureDropRs485FlowPumpControls { get; } = [];
|
||||
public ObservableCollection<PumpControlChannel> KinkResistanceRs485FlowPumpControls { get; } = [];
|
||||
public ObservableCollection<PumpControlChannel> HemolysisRs485FlowPumpControls { get; } = [];
|
||||
public ObservableCollection<PumpControlChannel> RecirculationRs485FlowPumpControls { get; } = [];
|
||||
public bool HasRealtimeRs485FlowPumpControls => RealtimeRs485FlowPumpControls.Count > 0;
|
||||
public bool HasPressureDropRs485FlowPumpControls => PressureDropRs485FlowPumpControls.Count > 0;
|
||||
public bool HasKinkResistanceRs485FlowPumpControls => KinkResistanceRs485FlowPumpControls.Count > 0;
|
||||
public bool HasHemolysisRs485FlowPumpControls => HemolysisRs485FlowPumpControls.Count > 0;
|
||||
public bool HasRecirculationRs485FlowPumpControls => RecirculationRs485FlowPumpControls.Count > 0;
|
||||
public int SelectedRs485PumpCount => ActiveRs485FlowPumpControls.Count(item => item.IsBatchSelected);
|
||||
public string Rs485AdvancedSettingsToggleText => Rs485AdvancedSettingsVisible ? "收起高级维护" : "展开高级维护";
|
||||
public string RealtimeActuatorControlsToggleText => RealtimeActuatorControlsVisible ? "隐藏执行机构控制" : "显示执行机构控制";
|
||||
public string Rs485ConnectionSummary =>
|
||||
$"{Rs485PortName} / {Rs485BaudRate}bps / {Rs485Parity} / {Rs485DataBits}-{Rs485StopBits}";
|
||||
public int Rs485EnabledPumpCount => Rs485FlowPumpControls.Count(item => item.Rs485Enabled);
|
||||
@@ -121,6 +149,13 @@ public partial class MainViewModel
|
||||
partial void OnRs485PersistPresetAfterWriteChanged(bool value) => UpdateAndPersistRs485Settings();
|
||||
partial void OnRs485AutoStartPumpAfterWriteChanged(bool value) => UpdateAndPersistRs485Settings();
|
||||
partial void OnRs485AdvancedSettingsVisibleChanged(bool value) => OnPropertyChanged(nameof(Rs485AdvancedSettingsToggleText));
|
||||
partial void OnRealtimeActuatorControlsVisibleChanged(bool value) => OnPropertyChanged(nameof(RealtimeActuatorControlsToggleText));
|
||||
|
||||
[RelayCommand]
|
||||
private void ToggleRealtimeActuatorControls()
|
||||
{
|
||||
RealtimeActuatorControlsVisible = !RealtimeActuatorControlsVisible;
|
||||
}
|
||||
|
||||
private void InitializeRs485FlowControl()
|
||||
{
|
||||
@@ -290,14 +325,130 @@ public partial class MainViewModel
|
||||
private void RefreshActiveRs485FlowPumpControls()
|
||||
{
|
||||
ActiveRs485FlowPumpControls.Clear();
|
||||
RealtimeRs485FlowPumpControls.Clear();
|
||||
PressureDropRs485FlowPumpControls.Clear();
|
||||
KinkResistanceRs485FlowPumpControls.Clear();
|
||||
HemolysisRs485FlowPumpControls.Clear();
|
||||
RecirculationRs485FlowPumpControls.Clear();
|
||||
foreach (var pump in Rs485FlowPumpControls.Where(item => item.Rs485Enabled))
|
||||
{
|
||||
ActiveRs485FlowPumpControls.Add(pump);
|
||||
if (string.Equals(pump.Key, PressureDropRs485PumpKey, StringComparison.Ordinal))
|
||||
{
|
||||
PressureDropRs485FlowPumpControls.Add(pump);
|
||||
}
|
||||
else if (string.Equals(pump.Key, KinkResistanceRs485PumpKey, StringComparison.Ordinal))
|
||||
{
|
||||
KinkResistanceRs485FlowPumpControls.Add(pump);
|
||||
}
|
||||
else if (HemolysisRs485PumpKeys.Contains(pump.Key, StringComparer.Ordinal))
|
||||
{
|
||||
HemolysisRs485FlowPumpControls.Add(pump);
|
||||
}
|
||||
else if (RecirculationRs485PumpKeys.Contains(pump.Key, StringComparer.Ordinal))
|
||||
{
|
||||
RecirculationRs485FlowPumpControls.Add(pump);
|
||||
}
|
||||
else
|
||||
{
|
||||
RealtimeRs485FlowPumpControls.Add(pump);
|
||||
}
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(HasRealtimeRs485FlowPumpControls));
|
||||
OnPropertyChanged(nameof(HasPressureDropRs485FlowPumpControls));
|
||||
OnPropertyChanged(nameof(HasKinkResistanceRs485FlowPumpControls));
|
||||
OnPropertyChanged(nameof(HasHemolysisRs485FlowPumpControls));
|
||||
OnPropertyChanged(nameof(HasRecirculationRs485FlowPumpControls));
|
||||
RaiseRs485CalibrationSummaryChanges();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task StartRecirculationRs485Pumps()
|
||||
{
|
||||
if (!EnsureSessionEditable("再循环三泵统一启动"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var pumps = RecirculationRs485FlowPumpControls.ToList();
|
||||
if (pumps.Count == 0)
|
||||
{
|
||||
Rs485StatusText = "当前未配置再循环 RS485 泵。";
|
||||
LatestAction = Rs485StatusText;
|
||||
return;
|
||||
}
|
||||
|
||||
var issuedCount = 0;
|
||||
var confirmedCount = 0;
|
||||
var skippedCount = 0;
|
||||
var failedCount = 0;
|
||||
foreach (var pump in pumps)
|
||||
{
|
||||
var effectiveRunning = pump.PendingRs485RunningState ?? pump.IsRunning;
|
||||
if (effectiveRunning)
|
||||
{
|
||||
skippedCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
var startResult = await TryWriteAndStartPumpCore(pump, "再循环三泵统一启动");
|
||||
if (startResult is Rs485StartExecutionResult.PendingConfirmation or Rs485StartExecutionResult.Confirmed)
|
||||
{
|
||||
issuedCount++;
|
||||
if (startResult == Rs485StartExecutionResult.Confirmed)
|
||||
{
|
||||
confirmedCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
var summary = $"再循环三泵启动完成:已下发 {issuedCount} 台,已确认运行 {confirmedCount} 台,跳过 {skippedCount} 台,失败 {failedCount} 台。";
|
||||
Rs485StatusText = summary;
|
||||
LatestAction = summary;
|
||||
TraceEvents.Insert(0, NewTrace("再循环三泵启动", summary));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task StopRecirculationRs485Pumps()
|
||||
{
|
||||
if (!EnsureSessionEditable("再循环三泵统一停止"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var pumps = RecirculationRs485FlowPumpControls.ToList();
|
||||
if (pumps.Count == 0)
|
||||
{
|
||||
Rs485StatusText = "当前未配置再循环 RS485 泵。";
|
||||
LatestAction = Rs485StatusText;
|
||||
return;
|
||||
}
|
||||
|
||||
var stoppedCount = 0;
|
||||
var failedCount = 0;
|
||||
foreach (var pump in pumps)
|
||||
{
|
||||
if (await TryTogglePumpControlViaRs485(pump, nextState: false) == Rs485ToggleExecutionResult.Succeeded)
|
||||
{
|
||||
stoppedCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
var summary = $"再循环三泵停止完成:已下发停止 {stoppedCount} 台,失败 {failedCount} 台。";
|
||||
Rs485StatusText = summary;
|
||||
LatestAction = summary;
|
||||
TraceEvents.Insert(0, NewTrace("再循环三泵停止", summary));
|
||||
}
|
||||
|
||||
private async Task RefreshRs485RuntimeStateSilentlyAsync()
|
||||
{
|
||||
if (DateTime.UtcNow - _lastRs485RuntimeRefreshUtc < Rs485RuntimeRefreshInterval)
|
||||
|
||||
@@ -353,6 +353,45 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
||||
public ObservableCollection<DeviceChannel> Channels { get; }
|
||||
public ObservableCollection<PumpControlChannel> PumpControls { get; }
|
||||
public ObservableCollection<ValveControlChannel> ValveControls { get; }
|
||||
public IEnumerable<ValveControlChannel> RealtimeValveControls =>
|
||||
ValveControls.Where(item =>
|
||||
!string.Equals(item.Key, "CirculatingWaterTemperature", StringComparison.Ordinal)
|
||||
&& !string.Equals(item.Key, "TestLoopValve1", StringComparison.Ordinal)
|
||||
&& !string.Equals(item.Key, "TestLoopValve2", StringComparison.Ordinal));
|
||||
public ValveControlChannel? CirculatingWaterControl =>
|
||||
ValveControls.FirstOrDefault(item => string.Equals(item.Key, "CirculatingWaterTemperature", StringComparison.Ordinal));
|
||||
public bool HasCirculatingWaterControl => CirculatingWaterControl is not null;
|
||||
public IEnumerable<ValveControlChannel> PressureDropAuxiliaryValveControls =>
|
||||
ValveControls.Where(item =>
|
||||
string.Equals(item.Key, "CirculatingWaterTemperature", StringComparison.Ordinal)
|
||||
|| string.Equals(item.Key, "TestLoopValve1", StringComparison.Ordinal))
|
||||
.OrderBy(item => string.Equals(item.Key, "CirculatingWaterTemperature", StringComparison.Ordinal) ? 0 : 1);
|
||||
public bool HasPressureDropAuxiliaryValveControls => PressureDropAuxiliaryValveControls.Any();
|
||||
public IEnumerable<ValveControlChannel> PressureDropSecondaryValveControls =>
|
||||
ValveControls.Where(item => string.Equals(item.Key, "TestLoopValve1", StringComparison.Ordinal));
|
||||
public bool HasPressureDropSecondaryValveControls => PressureDropSecondaryValveControls.Any();
|
||||
public ValveControlChannel? RecirculationCirculatingWaterControl =>
|
||||
ValveControls.FirstOrDefault(item => string.Equals(item.Key, "CirculatingWaterTemperature", StringComparison.Ordinal));
|
||||
public bool HasRecirculationCirculatingWaterControl => RecirculationCirculatingWaterControl is not null;
|
||||
public PumpControlChannel? AntiCollapseNegativeAssistPumpControl =>
|
||||
NegativeAssistPumpControls.FirstOrDefault();
|
||||
public bool HasAntiCollapseNegativeAssistPumpControl => AntiCollapseNegativeAssistPumpControl is not null;
|
||||
public ValveControlChannel? AntiCollapseCirculatingWaterControl =>
|
||||
ValveControls.FirstOrDefault(item => string.Equals(item.Key, "CirculatingWaterTemperature", StringComparison.Ordinal));
|
||||
public bool HasAntiCollapseCirculatingWaterControl => AntiCollapseCirculatingWaterControl is not null;
|
||||
public ValveControlChannel? AntiCollapseTestLoopValve2Control =>
|
||||
ValveControls.FirstOrDefault(item => string.Equals(item.Key, "TestLoopValve2", StringComparison.Ordinal));
|
||||
public bool HasAntiCollapseTestLoopValve2Control => AntiCollapseTestLoopValve2Control is not null;
|
||||
public IEnumerable<ValveControlChannel> AntiCollapseAuxiliaryValveControls =>
|
||||
ValveControls.Where(item =>
|
||||
string.Equals(item.Key, "CirculatingWaterTemperature", StringComparison.Ordinal)
|
||||
|| string.Equals(item.Key, "TestLoopValve2", StringComparison.Ordinal))
|
||||
.OrderBy(item => string.Equals(item.Key, "CirculatingWaterTemperature", StringComparison.Ordinal) ? 0 : 1);
|
||||
public bool HasAntiCollapseAuxiliaryValveControls => AntiCollapseAuxiliaryValveControls.Any();
|
||||
public IEnumerable<ValveControlChannel> AntiCollapseSecondaryValveControls =>
|
||||
ValveControls.Where(item => string.Equals(item.Key, "TestLoopValve2", StringComparison.Ordinal));
|
||||
public bool HasAntiCollapseSecondaryValveControls => AntiCollapseSecondaryValveControls.Any();
|
||||
public bool HasAntiCollapsePumpControls => NegativeAssistPumpControls.Any();
|
||||
public IEnumerable<PumpControlChannel> NegativeAssistPumpControls => PumpControlsFor("NegativeAssistPump");
|
||||
public IEnumerable<PumpControlChannel> PressureDropPumpControls => PumpControlsFor("NegativeAssistPump", "PressureDropPump");
|
||||
public IEnumerable<PumpControlChannel> RecirculationPumpControls => PumpControlsFor("RecirculationMainPump", "RecirculationReturnPump", "RecirculationDrainagePump");
|
||||
@@ -559,7 +598,7 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
||||
public string PressureTrendCurrentSummary => $"近端 {ProximalPressureDisplay} / 远端 {DistalPressureDisplay} / ΔP {DeltaPressureDisplay}";
|
||||
public string FlowTrendCurrentSummary => BuildFlowTrendCurrentSummary();
|
||||
public string HemolysisRecordTemplate =>
|
||||
"3.2 试验血液准备\n" +
|
||||
"1. 试验血液准备\n" +
|
||||
$"- 依据 GB/T 16886.4 进行血液预处理。\n" +
|
||||
$"- 血液来源:{HemolysisTestParameters.BloodSource}\n" +
|
||||
$"- 采血日期:{FormatHemolysisDate(HemolysisTestParameters.CollectionDate)}\n" +
|
||||
@@ -569,13 +608,13 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
||||
$"- 血中葡萄糖:{FormatHemolysisValue(HemolysisTestParameters.Glucose, "F1")} mmol/L\n" +
|
||||
$"- 血红蛋白:{FormatHemolysisValue(HemolysisTestParameters.TotalHemoglobin, "F1")} g/dL\n" +
|
||||
$"- 初始游离血红蛋白 fHb:{FormatHemolysisValue(GetHemolysisInitialFreeHemoglobin(), "F1")} mg/dL\n\n" +
|
||||
"3.3 测试回路说明\n" +
|
||||
"2. 测试回路说明\n" +
|
||||
$"- 回路总充盈量:{FormatHemolysisValue(HemolysisTestParameters.CircuitPrimingVolume, "F0")} mL\n" +
|
||||
$"- 回路初始血液通道试验液容积差:{FormatHemolysisValue(HemolysisTestParameters.CircuitVolumeDifference, "F2")} %(应 ≤ 1%)\n" +
|
||||
$"- 设定流量:{FormatHemolysisValue(HemolysisTestParameters.SetFlow, "F2")} L/min\n" +
|
||||
$"- 设定运行时间:{FormatHemolysisValue(HemolysisTestParameters.RunTimeMinutes, "F0")} min\n" +
|
||||
$"- 温度控制:{FormatHemolysisValue(HemolysisTestParameters.TargetTemperature, "F1")} ℃ ± 2 ℃\n\n" +
|
||||
"4. 试验运行与取样记录";
|
||||
"3. 试验运行与取样记录";
|
||||
public string HemolysisRecordNoteTemplate => BuildHemolysisRecordNoteText();
|
||||
public bool HasAntiCollapseBaseline => _antiCollapseBaselinePressureDrop.HasValue && _antiCollapseBaselineFlow.HasValue;
|
||||
public string AntiCollapseBaselineDisplay => HasAntiCollapseBaseline
|
||||
@@ -778,11 +817,35 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
||||
}
|
||||
|
||||
var nextState = !valve.IsOpen;
|
||||
ValveControlChannel? pairedValve = null;
|
||||
if (nextState)
|
||||
{
|
||||
pairedValve = valve.Key switch
|
||||
{
|
||||
"TestLoopValve1" => ValveControls.FirstOrDefault(item => string.Equals(item.Key, "TestLoopValve2", StringComparison.Ordinal)),
|
||||
"TestLoopValve2" => ValveControls.FirstOrDefault(item => string.Equals(item.Key, "TestLoopValve1", StringComparison.Ordinal)),
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (pairedValve?.IsOpen == true)
|
||||
{
|
||||
_telemetryService.SetValveOpen(pairedValve.Key, false);
|
||||
}
|
||||
}
|
||||
|
||||
_telemetryService.SetValveOpen(valve.Key, nextState);
|
||||
var traceDetail = $"{valve.Name} => {(nextState ? "开启" : "关闭")}";
|
||||
if (pairedValve?.IsOpen == true)
|
||||
{
|
||||
traceDetail += $" / {pairedValve.Name} => 关闭";
|
||||
}
|
||||
|
||||
LatestAction = IsTelemetryOnline
|
||||
? $"{valve.Name} 已发送{(nextState ? "开启" : "关闭")}指令。"
|
||||
? pairedValve?.IsOpen == true
|
||||
? $"{valve.Name} 已发送{(nextState ? "开启" : "关闭")}指令,并自动关闭 {pairedValve.Name}。"
|
||||
: $"{valve.Name} 已发送{(nextState ? "开启" : "关闭")}指令。"
|
||||
: $"{valve.Name} 指令未下发,PLC 当前离线。";
|
||||
TraceEvents.Insert(0, NewTrace("阀控", $"{valve.Name} => {(nextState ? "开启" : "关闭")}"));
|
||||
TraceEvents.Insert(0, NewTrace("阀控", traceDetail));
|
||||
_ = RefreshTelemetryAsync();
|
||||
}
|
||||
|
||||
@@ -1349,7 +1412,6 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
||||
RefreshTelemetryPanel();
|
||||
RefreshDeviceStatus();
|
||||
RefreshComputedState();
|
||||
RefreshFilteredItemsView();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -1760,7 +1822,7 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
||||
var calculationHematocrit = GetHemolysisCalculationHematocrit();
|
||||
|
||||
return
|
||||
"5. 结果计算\n" +
|
||||
"4. 结果计算\n" +
|
||||
$"- 标准取样点完成情况:{BuildHemolysisSamplingCompletionSummary()}\n" +
|
||||
$"- ΔfHb (T360 - T0):{FormatHemolysisDisplay(GetHemolysisDeltaFreeHemoglobin(), "F1", "mg/dL")}\n" +
|
||||
"- NIH = ΔfHb × V(L) × (1-Hct) / (Q×T)\n" +
|
||||
|
||||
Reference in New Issue
Block a user