更新
This commit is contained in:
@@ -477,6 +477,38 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
<Border Style="{StaticResource CardBorderStyle}">
|
||||||
|
<Border.Resources>
|
||||||
|
<DataTemplate x:Key="ValveControlCardTemplate" DataType="{x:Type models:ValveControlChannel}">
|
||||||
|
<Border Width="220" Margin="0,0,10,0" Padding="14" Background="#FFF4F8FA" CornerRadius="14">
|
||||||
|
<StackPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<Ellipse Width="12" Height="12" Margin="0,3,8,0" Fill="{Binding IndicatorColor}" DockPanel.Dock="Left" />
|
||||||
|
<TextBlock FontSize="16" FontWeight="SemiBold" Text="{Binding Name}" TextWrapping="Wrap" />
|
||||||
|
</DockPanel>
|
||||||
|
<TextBlock Margin="0,10,0,0" Style="{StaticResource MetricValueStyle}" FontSize="20" Text="{Binding StateText}" />
|
||||||
|
<TextBlock Margin="0,4,0,0" Style="{StaticResource CaptionStyle}" Text="{Binding StateHint}" />
|
||||||
|
<Button Margin="0,10,0,0"
|
||||||
|
Command="{Binding DataContext.ToggleValveControlCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||||
|
CommandParameter="{Binding}"
|
||||||
|
Content="{Binding ActionText}"
|
||||||
|
Background="#FF4D8C72" />
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</Border.Resources>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Style="{StaticResource SectionTitleStyle}" Text="测试回路阀" />
|
||||||
|
<ItemsControl Margin="0,10,0,0" ItemsSource="{Binding ValveControls}" ItemTemplate="{StaticResource ValveControlCardTemplate}">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<WrapPanel />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
</ItemsControl>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<Border Style="{StaticResource CardBorderStyle}">
|
<Border Style="{StaticResource CardBorderStyle}">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock Style="{StaticResource SectionTitleStyle}" Text="关键实时读数" />
|
<TextBlock Style="{StaticResource SectionTitleStyle}" Text="关键实时读数" />
|
||||||
|
|||||||
26
Cardiopulmonarybypasssystems/Models/ValveControlChannel.cs
Normal file
26
Cardiopulmonarybypasssystems/Models/ValveControlChannel.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
|
namespace Cardiopulmonarybypasssystems.Models;
|
||||||
|
|
||||||
|
public partial class ValveControlChannel : ObservableObject
|
||||||
|
{
|
||||||
|
public required string Key { get; init; }
|
||||||
|
public required string Name { get; init; }
|
||||||
|
public int StartAddress { get; init; }
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool isOpen;
|
||||||
|
|
||||||
|
public string StateText => IsOpen ? "开启" : "关闭";
|
||||||
|
public string ActionText => IsOpen ? "关闭阀门" : "开启阀门";
|
||||||
|
public string IndicatorColor => IsOpen ? "#FF32B06A" : "#FFC8D4DA";
|
||||||
|
public string StateHint => IsOpen ? "测试回路已导通" : "测试回路已关闭";
|
||||||
|
|
||||||
|
partial void OnIsOpenChanged(bool value)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(StateText));
|
||||||
|
OnPropertyChanged(nameof(ActionText));
|
||||||
|
OnPropertyChanged(nameof(IndicatorColor));
|
||||||
|
OnPropertyChanged(nameof(StateHint));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,8 @@ public interface IModbusTelemetryService
|
|||||||
{
|
{
|
||||||
IReadOnlyList<DeviceChannel> GetChannels();
|
IReadOnlyList<DeviceChannel> GetChannels();
|
||||||
IReadOnlyList<PumpControlChannel> GetPumpControls();
|
IReadOnlyList<PumpControlChannel> GetPumpControls();
|
||||||
|
IReadOnlyList<ValveControlChannel> GetValveControls();
|
||||||
IReadOnlyList<AlarmMessage> UpdateChannels();
|
IReadOnlyList<AlarmMessage> UpdateChannels();
|
||||||
void SetPumpRunning(string pumpKey, bool isRunning);
|
void SetPumpRunning(string pumpKey, bool isRunning);
|
||||||
|
void SetValveOpen(string valveKey, bool isOpen);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,11 @@ public sealed class MockModbusTelemetryService : IModbusTelemetryService, IDispo
|
|||||||
new() { Key = "HemolysisReturnSinglePump", Name = "血细胞破坏-单腔回输泵", StartAddress = 7, FlowAddress = 1060 },
|
new() { Key = "HemolysisReturnSinglePump", Name = "血细胞破坏-单腔回输泵", StartAddress = 7, FlowAddress = 1060 },
|
||||||
new() { Key = "HemolysisDualLumenPump", Name = "血细胞破坏-双腔泵", StartAddress = 8, FlowAddress = 1070 }
|
new() { Key = "HemolysisDualLumenPump", Name = "血细胞破坏-双腔泵", StartAddress = 8, FlowAddress = 1070 }
|
||||||
];
|
];
|
||||||
|
private readonly List<ValveControlChannel> _valveControls =
|
||||||
|
[
|
||||||
|
new() { Key = "TestLoopValve1", Name = "测试回路阀 1", StartAddress = 10 },
|
||||||
|
new() { Key = "TestLoopValve2", Name = "测试回路阀 2", StartAddress = 11 }
|
||||||
|
];
|
||||||
|
|
||||||
private TcpClient? _tcpClient;
|
private TcpClient? _tcpClient;
|
||||||
private IModbusMaster? _master;
|
private IModbusMaster? _master;
|
||||||
@@ -95,6 +100,12 @@ public sealed class MockModbusTelemetryService : IModbusTelemetryService, IDispo
|
|||||||
return _pumpControls;
|
return _pumpControls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<ValveControlChannel> GetValveControls()
|
||||||
|
{
|
||||||
|
EnsureConnectionScheduled();
|
||||||
|
return _valveControls;
|
||||||
|
}
|
||||||
|
|
||||||
public IReadOnlyList<AlarmMessage> UpdateChannels()
|
public IReadOnlyList<AlarmMessage> UpdateChannels()
|
||||||
{
|
{
|
||||||
EnsureConnectionScheduled();
|
EnsureConnectionScheduled();
|
||||||
@@ -138,6 +149,35 @@ public sealed class MockModbusTelemetryService : IModbusTelemetryService, IDispo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetValveOpen(string valveKey, bool isOpen)
|
||||||
|
{
|
||||||
|
lock (_syncRoot)
|
||||||
|
{
|
||||||
|
var valve = _valveControls.FirstOrDefault(item => item.Key == valveKey);
|
||||||
|
if (valve is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
valve.IsOpen = isOpen;
|
||||||
|
|
||||||
|
if (_master is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_master.WriteSingleCoil(SlaveId, (ushort)valve.StartAddress, isOpen);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
ReleaseConnection();
|
||||||
|
_nextConnectionAttemptUtc = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
lock (_syncRoot)
|
lock (_syncRoot)
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ public partial class MainViewModel : ObservableObject
|
|||||||
FilteredItemsView.Filter = MatchesFilteredItem;
|
FilteredItemsView.Filter = MatchesFilteredItem;
|
||||||
Channels = new ObservableCollection<DeviceChannel>(telemetryService.GetChannels());
|
Channels = new ObservableCollection<DeviceChannel>(telemetryService.GetChannels());
|
||||||
PumpControls = new ObservableCollection<PumpControlChannel>(telemetryService.GetPumpControls());
|
PumpControls = new ObservableCollection<PumpControlChannel>(telemetryService.GetPumpControls());
|
||||||
|
ValveControls = new ObservableCollection<ValveControlChannel>(telemetryService.GetValveControls());
|
||||||
TraceEvents = new ObservableCollection<TraceEvent>(repository.GetSeedTraceEvents());
|
TraceEvents = new ObservableCollection<TraceEvent>(repository.GetSeedTraceEvents());
|
||||||
AlarmMessages = new ObservableCollection<AlarmMessage>();
|
AlarmMessages = new ObservableCollection<AlarmMessage>();
|
||||||
ResultStatusOptions = new ObservableCollection<string>(["待检", "合格", "预警", "不合格"]);
|
ResultStatusOptions = new ObservableCollection<string>(["待检", "合格", "预警", "不合格"]);
|
||||||
@@ -190,6 +191,7 @@ public partial class MainViewModel : ObservableObject
|
|||||||
public ICollectionView FilteredItemsView { get; }
|
public ICollectionView FilteredItemsView { get; }
|
||||||
public ObservableCollection<DeviceChannel> Channels { get; }
|
public ObservableCollection<DeviceChannel> Channels { get; }
|
||||||
public ObservableCollection<PumpControlChannel> PumpControls { get; }
|
public ObservableCollection<PumpControlChannel> PumpControls { get; }
|
||||||
|
public ObservableCollection<ValveControlChannel> ValveControls { get; }
|
||||||
public IEnumerable<PumpControlChannel> PressureDropPumpControls => PumpControlsFor("NegativeAssistPump", "PressureDropPump");
|
public IEnumerable<PumpControlChannel> PressureDropPumpControls => PumpControlsFor("NegativeAssistPump", "PressureDropPump");
|
||||||
public IEnumerable<PumpControlChannel> RecirculationPumpControls => PumpControlsFor("RecirculationMainPump", "RecirculationReturnPump", "RecirculationDrainagePump");
|
public IEnumerable<PumpControlChannel> RecirculationPumpControls => PumpControlsFor("RecirculationMainPump", "RecirculationReturnPump", "RecirculationDrainagePump");
|
||||||
public IEnumerable<PumpControlChannel> KinkResistancePumpControls => PumpControlsFor("KinkResistancePump");
|
public IEnumerable<PumpControlChannel> KinkResistancePumpControls => PumpControlsFor("KinkResistancePump");
|
||||||
@@ -451,6 +453,21 @@ public partial class MainViewModel : ObservableObject
|
|||||||
RefreshTelemetry();
|
RefreshTelemetry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void ToggleValveControl(ValveControlChannel? valve)
|
||||||
|
{
|
||||||
|
if (valve is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextState = !valve.IsOpen;
|
||||||
|
_telemetryService.SetValveOpen(valve.Key, nextState);
|
||||||
|
valve.IsOpen = nextState;
|
||||||
|
LatestAction = $"{valve.Name} 已{(nextState ? "开启" : "关闭")}。";
|
||||||
|
TraceEvents.Insert(0, NewTrace("阀控", $"{valve.Name} => {(nextState ? "开启" : "关闭")}"));
|
||||||
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void ClearTrendData()
|
private void ClearTrendData()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user