更新202659
This commit is contained in:
@@ -14,6 +14,85 @@
|
||||
<Window.Resources>
|
||||
<converters:TrendPointCollectionConverter x:Key="TrendPointCollectionConverter" />
|
||||
<converters:TrendLastPointCoordinateConverter x:Key="TrendLastPointCoordinateConverter" />
|
||||
<DataTemplate x:Key="ProjectRs485PumpCardTemplate" DataType="{x:Type models:PumpControlChannel}">
|
||||
<Grid Margin="0,0,10,6"
|
||||
VerticalAlignment="Center">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="112" />
|
||||
<ColumnDefinition Width="6" />
|
||||
<ColumnDefinition Width="82" />
|
||||
<ColumnDefinition Width="44" />
|
||||
<ColumnDefinition Width="6" />
|
||||
<ColumnDefinition Width="54" />
|
||||
<ColumnDefinition Width="6" />
|
||||
<ColumnDefinition Width="54" />
|
||||
<ColumnDefinition Width="8" />
|
||||
<ColumnDefinition Width="52" />
|
||||
<ColumnDefinition Width="6" />
|
||||
<ColumnDefinition Width="96" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="13"
|
||||
FontWeight="Bold"
|
||||
Foreground="{StaticResource HeaderBrush}"
|
||||
Text="{Binding Name}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
ToolTip="{Binding Name}" />
|
||||
<TextBox Grid.Column="2"
|
||||
Height="32"
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Text="{Binding PendingSetpointText, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsReadOnly="True"
|
||||
Cursor="Hand"
|
||||
ToolTip="目标流量 L/min"
|
||||
PreviewMouseLeftButtonDown="PumpSetpointTextBox_OnPreviewMouseLeftButtonDown"
|
||||
GotKeyboardFocus="PumpSetpointTextBox_OnGotKeyboardFocus" />
|
||||
<TextBlock Grid.Column="3"
|
||||
Margin="4,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionStyle}"
|
||||
Text="L/min" />
|
||||
<Button Grid.Column="5"
|
||||
Height="32"
|
||||
MinWidth="0"
|
||||
Padding="6,2"
|
||||
Command="{Binding DataContext.StartSingleRs485PumpCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
CommandParameter="{Binding}"
|
||||
Content="启动"
|
||||
IsEnabled="{Binding CanStartRs485Action}"
|
||||
Background="#FF2B8F6A"
|
||||
ToolTipService.ShowOnDisabled="True"
|
||||
ToolTip="{Binding StartActionHint}" />
|
||||
<Button Grid.Column="7"
|
||||
Height="32"
|
||||
MinWidth="0"
|
||||
Padding="6,2"
|
||||
Command="{Binding DataContext.StopSingleRs485PumpCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
CommandParameter="{Binding}"
|
||||
Content="停止"
|
||||
IsEnabled="{Binding CanStopRs485Action}"
|
||||
Background="#FFB85C38"
|
||||
ToolTipService.ShowOnDisabled="True"
|
||||
ToolTip="{Binding StopActionHint}" />
|
||||
<CheckBox Grid.Column="9"
|
||||
VerticalAlignment="Center"
|
||||
Content="稳流"
|
||||
IsChecked="{Binding IsFlowStabilizationEnabled, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding CanUseFlowStabilization}"
|
||||
ToolTip="{Binding FlowStabilizationToggleHint}" />
|
||||
<TextBlock Grid.Column="11"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="11"
|
||||
Foreground="{StaticResource MutedTextBrush}"
|
||||
Text="{Binding FlowStabilizationStateText}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
ToolTip="{Binding FlowStabilizationStateText}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</Window.Resources>
|
||||
<Grid Margin="12">
|
||||
<Grid.RowDefinitions>
|
||||
@@ -202,6 +281,16 @@
|
||||
Cursor="Hand"
|
||||
PreviewMouseLeftButtonDown="PumpSetpointTextBox_OnPreviewMouseLeftButtonDown"
|
||||
GotKeyboardFocus="PumpSetpointTextBox_OnGotKeyboardFocus" />
|
||||
<CheckBox Margin="0,8,0,0"
|
||||
Content="稳流"
|
||||
IsChecked="{Binding IsFlowStabilizationEnabled, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding CanUseFlowStabilization}"
|
||||
ToolTip="{Binding FlowStabilizationToggleHint}" />
|
||||
<TextBlock Margin="0,4,0,0"
|
||||
FontSize="11"
|
||||
Foreground="{StaticResource MutedTextBrush}"
|
||||
Text="{Binding FlowStabilizationStateText}"
|
||||
TextWrapping="Wrap" />
|
||||
<Border Margin="0,10,0,0"
|
||||
Padding="10,6"
|
||||
Background="{Binding SetpointStatusBackground}"
|
||||
@@ -939,6 +1028,105 @@
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<TabItem x:Name="TightnessTestTab" Header="密合性">
|
||||
<ScrollViewer Margin="0,6,0,0" VerticalScrollBarVisibility="Auto" CanContentScroll="False">
|
||||
<StackPanel>
|
||||
<Border Style="{StaticResource CardBorderStyle}" Padding="14">
|
||||
<ItemsControl ItemsSource="{Binding PressureDropRs485FlowPumpControls}"
|
||||
ItemTemplate="{StaticResource ProjectRs485PumpCardTemplate}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
|
||||
<Border Style="{StaticResource CardBorderStyle}" Padding="14">
|
||||
<StackPanel IsEnabled="{Binding HasTightnessInspectionItem}">
|
||||
<Grid Margin="0,0,0,8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="12" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource SectionTitleStyle}"
|
||||
Text="{Binding SelectedItemTitle}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
<Button Grid.Column="2"
|
||||
MinWidth="112"
|
||||
MinHeight="32"
|
||||
Padding="12,5"
|
||||
Click="OpenProjectInfoDialogButton_OnClick"
|
||||
Background="#FFE3F6EF"
|
||||
Foreground="{StaticResource HeaderBrush}"
|
||||
BorderBrush="#FF9CCBBF"
|
||||
Content="查看项目说明" />
|
||||
</Grid>
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="结果记录" />
|
||||
<TextBox Margin="0,4,0,0"
|
||||
Text="{Binding ResultValue, UpdateSourceTrigger=PropertyChanged}"
|
||||
MinHeight="118"
|
||||
AcceptsReturn="True"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
IsReadOnly="{Binding SelectedItemUsesRealtimeValue}" />
|
||||
|
||||
<Grid Margin="0,10,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="12" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="判定" />
|
||||
<ComboBox Grid.Row="1"
|
||||
ItemsSource="{Binding ResultStatusOptions}"
|
||||
SelectedItem="{Binding SelectedResultStatusText, Mode=TwoWay}" />
|
||||
<TextBlock Grid.Column="2" Style="{StaticResource CaptionStyle}" Text="记录人" />
|
||||
<TextBox Grid.Row="1" Grid.Column="2" Text="{Binding ResultOperator, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBlock Grid.Row="2" Style="{StaticResource CaptionStyle}" Text="复核人" />
|
||||
<TextBox Grid.Row="3" Text="{Binding ReviewerName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBlock Grid.Row="2" Grid.Column="2" Style="{StaticResource CaptionStyle}" Text="批准人" />
|
||||
<TextBox Grid.Row="3" Grid.Column="2" Text="{Binding ApproverName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock Margin="0,10,0,0" Style="{StaticResource CaptionStyle}" Text="复核备注" />
|
||||
<TextBox Margin="0,4,0,0"
|
||||
Text="{Binding ResultNote, UpdateSourceTrigger=PropertyChanged}"
|
||||
MinHeight="96"
|
||||
AcceptsReturn="True"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
IsReadOnly="{Binding SelectedItemUsesRealtimeValue}" />
|
||||
|
||||
<DockPanel Margin="0,12,0,0" LastChildFill="True">
|
||||
<Button DockPanel.Dock="Right"
|
||||
MinWidth="112"
|
||||
Height="34"
|
||||
Padding="12,4"
|
||||
Command="{Binding ApplyResultCommand}"
|
||||
Content="保存结果"
|
||||
Background="#FF4D8C72"
|
||||
IsEnabled="{Binding CanModifySession}" />
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionStyle}"
|
||||
Text="{Binding LatestAction}"
|
||||
TextWrapping="Wrap" />
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<TabItem x:Name="ManualSupplementTab" Header="项目补充">
|
||||
<ScrollViewer Margin="0,6,0,0" VerticalScrollBarVisibility="Auto" CanContentScroll="False">
|
||||
<StackPanel>
|
||||
@@ -1070,34 +1258,8 @@
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<Border.Resources>
|
||||
<DataTemplate x:Key="KinkResistanceRs485PumpCardTemplate" DataType="{x:Type models:PumpControlChannel}">
|
||||
<Border MinWidth="640"
|
||||
Margin="0,0,10,10"
|
||||
Padding="0">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150" />
|
||||
<ColumnDefinition Width="116" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Column="0" VerticalAlignment="Center" FontSize="14" FontWeight="Bold" Text="{Binding Name}" TextWrapping="Wrap" />
|
||||
<TextBox Grid.Column="1" Width="108" Height="32" Margin="8,0,0,0" VerticalContentAlignment="Center" Text="{Binding PendingSetpointText, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True" Cursor="Hand" PreviewMouseLeftButtonDown="PumpSetpointTextBox_OnPreviewMouseLeftButtonDown" GotKeyboardFocus="PumpSetpointTextBox_OnGotKeyboardFocus" />
|
||||
<Button Grid.Column="2" MinWidth="66" Height="32" Margin="8,0,0,0" Padding="8,2" Command="{Binding DataContext.StartSingleRs485PumpCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" Content="启动" IsEnabled="{Binding CanStartRs485Action}" Background="#FF2B8F6A" ToolTipService.ShowOnDisabled="True" ToolTip="{Binding StartActionHint}" />
|
||||
<Button Grid.Column="3" MinWidth="66" Height="32" Margin="8,0,0,0" Padding="8,2" Command="{Binding DataContext.StopSingleRs485PumpCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" Content="停止" IsEnabled="{Binding CanStopRs485Action}" Background="#FFB85C38" ToolTipService.ShowOnDisabled="True" ToolTip="{Binding StopActionHint}" />
|
||||
<TextBlock Grid.Column="4" Margin="10,0,0,0" VerticalAlignment="Center" FontSize="12" FontWeight="Bold" Foreground="{Binding SetpointStatusForeground}" Text="{Binding Rs485RunStateText}" TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</Border.Resources>
|
||||
<StackPanel>
|
||||
<Grid Margin="0,8,0,0">
|
||||
<Grid Margin="0,4,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="12" />
|
||||
@@ -1105,7 +1267,7 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<ItemsControl Grid.Column="0"
|
||||
ItemsSource="{Binding KinkResistanceRs485FlowPumpControls}"
|
||||
ItemTemplate="{StaticResource KinkResistanceRs485PumpCardTemplate}">
|
||||
ItemTemplate="{StaticResource ProjectRs485PumpCardTemplate}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
@@ -1133,30 +1295,6 @@
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<Border.Resources>
|
||||
<DataTemplate x:Key="PressureDropRs485QuickPumpCardTemplate" DataType="{x:Type models:PumpControlChannel}">
|
||||
<Border MinWidth="640"
|
||||
Margin="0,0,10,10"
|
||||
Padding="0">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150" />
|
||||
<ColumnDefinition Width="116" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Column="0" VerticalAlignment="Center" FontSize="14" FontWeight="Bold" Text="{Binding Name}" TextWrapping="Wrap" />
|
||||
<TextBox Grid.Column="1" Width="108" Height="32" Margin="8,0,0,0" VerticalContentAlignment="Center" Text="{Binding PendingSetpointText, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True" Cursor="Hand" PreviewMouseLeftButtonDown="PumpSetpointTextBox_OnPreviewMouseLeftButtonDown" GotKeyboardFocus="PumpSetpointTextBox_OnGotKeyboardFocus" />
|
||||
<Button Grid.Column="2" MinWidth="66" Height="32" Margin="8,0,0,0" Padding="8,2" Command="{Binding DataContext.StartSingleRs485PumpCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" Content="启动" IsEnabled="{Binding CanStartRs485Action}" Background="#FF2B8F6A" ToolTipService.ShowOnDisabled="True" ToolTip="{Binding StartActionHint}" />
|
||||
<Button Grid.Column="3" MinWidth="66" Height="32" Margin="8,0,0,0" Padding="8,2" Command="{Binding DataContext.StopSingleRs485PumpCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" Content="停止" IsEnabled="{Binding CanStopRs485Action}" Background="#FFB85C38" ToolTipService.ShowOnDisabled="True" ToolTip="{Binding StopActionHint}" />
|
||||
<TextBlock Grid.Column="4" Margin="10,0,0,0" VerticalAlignment="Center" FontSize="12" FontWeight="Bold" Foreground="{Binding SetpointStatusForeground}" Text="{Binding Rs485RunStateText}" TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="PressureDropValveControlCardTemplate" DataType="{x:Type models:ValveControlChannel}">
|
||||
<Button MinWidth="132"
|
||||
Height="34"
|
||||
@@ -1170,7 +1308,7 @@
|
||||
ToolTip="{Binding StateText}" />
|
||||
</DataTemplate>
|
||||
</Border.Resources>
|
||||
<Grid Margin="0,8,0,0">
|
||||
<Grid Margin="0,4,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="12" />
|
||||
@@ -1178,7 +1316,7 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<ItemsControl Grid.Column="0"
|
||||
ItemsSource="{Binding PressureDropRs485FlowPumpControls}"
|
||||
ItemTemplate="{StaticResource PressureDropRs485QuickPumpCardTemplate}">
|
||||
ItemTemplate="{StaticResource ProjectRs485PumpCardTemplate}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
@@ -1224,70 +1362,38 @@
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<Border.Resources>
|
||||
<DataTemplate x:Key="RecirculationRs485PumpCardTemplate" DataType="{x:Type models:PumpControlChannel}">
|
||||
<Border MinWidth="640"
|
||||
Margin="0,0,10,10"
|
||||
Padding="0">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150" />
|
||||
<ColumnDefinition Width="116" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Column="0" VerticalAlignment="Center" FontSize="14" FontWeight="Bold" Text="{Binding Name}" TextWrapping="Wrap" />
|
||||
<TextBox Grid.Column="1" Width="108" Height="32" Margin="8,0,0,0" VerticalContentAlignment="Center" Text="{Binding PendingSetpointText, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True" Cursor="Hand" PreviewMouseLeftButtonDown="PumpSetpointTextBox_OnPreviewMouseLeftButtonDown" GotKeyboardFocus="PumpSetpointTextBox_OnGotKeyboardFocus" />
|
||||
<Button Grid.Column="2" MinWidth="66" Height="32" Margin="8,0,0,0" Padding="8,2" Command="{Binding DataContext.StartSingleRs485PumpCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" Content="启动" IsEnabled="{Binding CanStartRs485Action}" Background="#FF2B8F6A" ToolTipService.ShowOnDisabled="True" ToolTip="{Binding StartActionHint}" />
|
||||
<Button Grid.Column="3" MinWidth="66" Height="32" Margin="8,0,0,0" Padding="8,2" Command="{Binding DataContext.StopSingleRs485PumpCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" Content="停止" IsEnabled="{Binding CanStopRs485Action}" Background="#FFB85C38" ToolTipService.ShowOnDisabled="True" ToolTip="{Binding StopActionHint}" />
|
||||
<TextBlock Grid.Column="4" Margin="10,0,0,0" VerticalAlignment="Center" FontSize="12" FontWeight="Bold" Foreground="{Binding SetpointStatusForeground}" Text="{Binding Rs485RunStateText}" TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</Border.Resources>
|
||||
<StackPanel>
|
||||
<DockPanel LastChildFill="False">
|
||||
<StackPanel DockPanel.Dock="Left">
|
||||
</StackPanel>
|
||||
<WrapPanel DockPanel.Dock="Right" Margin="12,0,0,0">
|
||||
<Button MinWidth="120"
|
||||
Height="34"
|
||||
Padding="12,4"
|
||||
Margin="0,0,8,8"
|
||||
Command="{Binding StartRecirculationRs485PumpsCommand}"
|
||||
Content="统一启动三泵"
|
||||
Background="#FF2B8F6A" />
|
||||
<Button MinWidth="120"
|
||||
Height="34"
|
||||
Padding="12,4"
|
||||
Margin="0,0,8,8"
|
||||
Command="{Binding StopRecirculationRs485PumpsCommand}"
|
||||
Content="统一停止三泵"
|
||||
Background="#FFB85C38" />
|
||||
</WrapPanel>
|
||||
</DockPanel>
|
||||
<Grid Margin="0,8,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="12" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ItemsControl Grid.Column="0"
|
||||
ItemsSource="{Binding RecirculationRs485FlowPumpControls}"
|
||||
ItemTemplate="{StaticResource RecirculationRs485PumpCardTemplate}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<Grid Margin="0,4,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="12" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ItemsControl Grid.Column="0"
|
||||
ItemsSource="{Binding RecirculationRs485FlowPumpControls}"
|
||||
ItemTemplate="{StaticResource ProjectRs485PumpCardTemplate}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
<WrapPanel Grid.Column="2" VerticalAlignment="Top">
|
||||
<Button MinWidth="112"
|
||||
Height="34"
|
||||
Padding="10,4"
|
||||
Margin="0,0,8,6"
|
||||
Command="{Binding StartRecirculationRs485PumpsCommand}"
|
||||
Content="统一启动"
|
||||
Background="#FF2B8F6A" />
|
||||
<Button MinWidth="112"
|
||||
Height="34"
|
||||
Padding="10,4"
|
||||
Margin="0,0,0,6"
|
||||
Command="{Binding StopRecirculationRs485PumpsCommand}"
|
||||
Content="统一停止"
|
||||
Background="#FFB85C38" />
|
||||
</WrapPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Border>
|
||||
<Border.Style>
|
||||
@@ -1312,30 +1418,6 @@
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<Border.Resources>
|
||||
<DataTemplate x:Key="AntiCollapseRs485QuickPumpCardTemplate" DataType="{x:Type models:PumpControlChannel}">
|
||||
<Border MinWidth="640"
|
||||
Margin="0,0,10,10"
|
||||
Padding="0">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150" />
|
||||
<ColumnDefinition Width="116" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Column="0" VerticalAlignment="Center" FontSize="14" FontWeight="Bold" Text="{Binding Name}" TextWrapping="Wrap" />
|
||||
<TextBox Grid.Column="1" Width="108" Height="32" Margin="8,0,0,0" VerticalContentAlignment="Center" Text="{Binding PendingSetpointText, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True" Cursor="Hand" PreviewMouseLeftButtonDown="PumpSetpointTextBox_OnPreviewMouseLeftButtonDown" GotKeyboardFocus="PumpSetpointTextBox_OnGotKeyboardFocus" />
|
||||
<Button Grid.Column="2" MinWidth="66" Height="32" Margin="8,0,0,0" Padding="8,2" Command="{Binding DataContext.StartSingleRs485PumpCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" Content="启动" IsEnabled="{Binding CanStartRs485Action}" Background="#FF2B8F6A" ToolTipService.ShowOnDisabled="True" ToolTip="{Binding StartActionHint}" />
|
||||
<Button Grid.Column="3" MinWidth="66" Height="32" Margin="8,0,0,0" Padding="8,2" Command="{Binding DataContext.StopSingleRs485PumpCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" Content="停止" IsEnabled="{Binding CanStopRs485Action}" Background="#FFB85C38" ToolTipService.ShowOnDisabled="True" ToolTip="{Binding StopActionHint}" />
|
||||
<TextBlock Grid.Column="4" Margin="10,0,0,0" VerticalAlignment="Center" FontSize="12" FontWeight="Bold" Foreground="{Binding SetpointStatusForeground}" Text="{Binding Rs485RunStateText}" TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="AntiCollapsePumpControlCardTemplate" DataType="{x:Type models:PumpControlChannel}">
|
||||
<Button MinWidth="132"
|
||||
Height="34"
|
||||
@@ -1362,9 +1444,9 @@
|
||||
</DataTemplate>
|
||||
</Border.Resources>
|
||||
<StackPanel>
|
||||
<WrapPanel Margin="0,8,0,0">
|
||||
<WrapPanel Margin="0,4,0,0">
|
||||
<ItemsControl ItemsSource="{Binding PressureDropRs485FlowPumpControls}"
|
||||
ItemTemplate="{StaticResource AntiCollapseRs485QuickPumpCardTemplate}">
|
||||
ItemTemplate="{StaticResource ProjectRs485PumpCardTemplate}">
|
||||
<ItemsControl.Style>
|
||||
<Style TargetType="ItemsControl">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
@@ -1377,7 +1459,7 @@
|
||||
</ItemsControl.Style>
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" />
|
||||
<WrapPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
@@ -1437,34 +1519,8 @@
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<Border.Resources>
|
||||
<DataTemplate x:Key="HemolysisRs485PumpCardTemplate" DataType="{x:Type models:PumpControlChannel}">
|
||||
<Border MinWidth="640"
|
||||
Margin="0,0,10,10"
|
||||
Padding="0">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150" />
|
||||
<ColumnDefinition Width="116" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Column="0" VerticalAlignment="Center" FontSize="14" FontWeight="Bold" Text="{Binding Name}" TextWrapping="Wrap" />
|
||||
<TextBox Grid.Column="1" Width="108" Height="32" Margin="8,0,0,0" VerticalContentAlignment="Center" Text="{Binding PendingSetpointText, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True" Cursor="Hand" PreviewMouseLeftButtonDown="PumpSetpointTextBox_OnPreviewMouseLeftButtonDown" GotKeyboardFocus="PumpSetpointTextBox_OnGotKeyboardFocus" />
|
||||
<Button Grid.Column="2" MinWidth="66" Height="32" Margin="8,0,0,0" Padding="8,2" Command="{Binding DataContext.StartSingleRs485PumpCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" Content="启动" IsEnabled="{Binding CanStartRs485Action}" Background="#FF2B8F6A" ToolTipService.ShowOnDisabled="True" ToolTip="{Binding StartActionHint}" />
|
||||
<Button Grid.Column="3" MinWidth="66" Height="32" Margin="8,0,0,0" Padding="8,2" Command="{Binding DataContext.StopSingleRs485PumpCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" Content="停止" IsEnabled="{Binding CanStopRs485Action}" Background="#FFB85C38" ToolTipService.ShowOnDisabled="True" ToolTip="{Binding StopActionHint}" />
|
||||
<TextBlock Grid.Column="4" Margin="10,0,0,0" VerticalAlignment="Center" FontSize="12" FontWeight="Bold" Foreground="{Binding SetpointStatusForeground}" Text="{Binding Rs485RunStateText}" TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</Border.Resources>
|
||||
<StackPanel>
|
||||
<Grid Margin="0,8,0,0">
|
||||
<Grid Margin="0,4,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="12" />
|
||||
@@ -1472,7 +1528,7 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<ItemsControl Grid.Column="0"
|
||||
ItemsSource="{Binding HemolysisRs485FlowPumpControls}"
|
||||
ItemTemplate="{StaticResource HemolysisRs485PumpCardTemplate}">
|
||||
ItemTemplate="{StaticResource ProjectRs485PumpCardTemplate}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
@@ -1495,18 +1551,27 @@
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<StackPanel>
|
||||
<DockPanel LastChildFill="False">
|
||||
<Button DockPanel.Dock="Right"
|
||||
<Grid Margin="0,0,0,8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="12" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource SectionTitleStyle}"
|
||||
Text="{Binding SelectedItemTitle}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
<Button Grid.Column="2"
|
||||
MinWidth="112"
|
||||
MinHeight="32"
|
||||
Padding="12,5"
|
||||
Margin="12,0,0,8"
|
||||
Click="OpenProjectInfoDialogButton_OnClick"
|
||||
Background="#FFE3F6EF"
|
||||
Foreground="{StaticResource HeaderBrush}"
|
||||
BorderBrush="#FF9CCBBF"
|
||||
Content="查看项目说明" />
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
<Grid Margin="0,2,0,0">
|
||||
<StackPanel Margin="0,0,0,4" IsEnabled="{Binding CanModifySession}">
|
||||
<Border Margin="0,0,0,16" Padding="0">
|
||||
@@ -1983,13 +2048,21 @@
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid Margin="0,8,0,0">
|
||||
<Grid Margin="0,4,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="12" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" VerticalAlignment="Center" Style="{StaticResource CaptionStyle}" Text="{Binding LatestAction}" TextWrapping="Wrap" />
|
||||
<Button Grid.Column="2"
|
||||
MinWidth="112"
|
||||
Height="34"
|
||||
Padding="12,4"
|
||||
Command="{Binding ApplyResultCommand}"
|
||||
Content="保存结果"
|
||||
Background="#FF4D8C72"
|
||||
IsEnabled="{Binding CanModifySession}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
@@ -21,6 +21,7 @@ public partial class MainWindow : Window
|
||||
private readonly List<Button> _projectInspectionButtons = [];
|
||||
private object? _projectInspectionContent;
|
||||
private object? _realtimeContent;
|
||||
private object? _tightnessTestContent;
|
||||
private object? _manualSupplementContent;
|
||||
private object? _configurationContent;
|
||||
private object? _traceContent;
|
||||
@@ -85,6 +86,7 @@ public partial class MainWindow : Window
|
||||
{
|
||||
_realtimeContent = ExtractTabContent(RealtimeDataTab);
|
||||
_projectInspectionContent = ExtractTabContent(ProjectListTab);
|
||||
_tightnessTestContent = ExtractTabContent(TightnessTestTab);
|
||||
_manualSupplementContent = ExtractTabContent(ManualSupplementTab);
|
||||
_configurationContent = ExtractTabContent(ConfigurationTab);
|
||||
_traceContent = ExtractTabContent(TraceTab);
|
||||
@@ -126,6 +128,7 @@ public partial class MainWindow : Window
|
||||
_projectInspectionButtons.Add(button);
|
||||
}
|
||||
|
||||
AddNavigationButton("密合性", new NavigationTarget(NavigationPage.TightnessTest, null));
|
||||
AddNavigationButton("项目补充", new NavigationTarget(NavigationPage.ManualSupplement, null));
|
||||
AddNavigationButton("配置", new NavigationTarget(NavigationPage.Configuration, null));
|
||||
AddNavigationButton("追溯", new NavigationTarget(NavigationPage.Trace, null));
|
||||
@@ -188,9 +191,19 @@ public partial class MainWindow : Window
|
||||
{
|
||||
_currentPage = page;
|
||||
_currentProjectItem = null;
|
||||
|
||||
if (page == NavigationPage.TightnessTest
|
||||
&& DataContext is MainViewModel viewModel
|
||||
&& viewModel.TightnessInspectionItem is not null
|
||||
&& !ReferenceEquals(viewModel.SelectedItem, viewModel.TightnessInspectionItem))
|
||||
{
|
||||
viewModel.SelectedItem = viewModel.TightnessInspectionItem;
|
||||
}
|
||||
|
||||
MainContentHost.Content = page switch
|
||||
{
|
||||
NavigationPage.RealtimeData => _realtimeContent,
|
||||
NavigationPage.TightnessTest => _tightnessTestContent,
|
||||
NavigationPage.ManualSupplement => _manualSupplementContent,
|
||||
NavigationPage.Configuration => _configurationContent,
|
||||
NavigationPage.Trace => _traceContent,
|
||||
@@ -254,6 +267,7 @@ public partial class MainWindow : Window
|
||||
{
|
||||
RealtimeData,
|
||||
ProjectItem,
|
||||
TightnessTest,
|
||||
ManualSupplement,
|
||||
Configuration,
|
||||
Trace
|
||||
|
||||
@@ -109,6 +109,18 @@ public partial class PumpControlChannel : ObservableObject
|
||||
[ObservableProperty]
|
||||
private bool isBatchSelected;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool isFlowStabilizationEnabled;
|
||||
|
||||
[ObservableProperty]
|
||||
private DateTime lastFlowStabilizationAdjustmentUtc = DateTime.MinValue;
|
||||
|
||||
[ObservableProperty]
|
||||
private int flowStabilizationRawSetpoint;
|
||||
|
||||
[ObservableProperty]
|
||||
private string flowStabilizationStatusText = "稳流未启用";
|
||||
|
||||
public string StartAddressDisplay => $"M{StartAddress}";
|
||||
public string FlowAddressDisplay => FlowAddress.HasValue ? $"D{FlowAddress.Value}" : "-";
|
||||
public bool HasFlowTelemetry => FlowAddress.HasValue;
|
||||
@@ -224,6 +236,15 @@ public partial class PumpControlChannel : ObservableObject
|
||||
: "未配置流量换算系数";
|
||||
public string Rs485ReadActionText => IsRs485Busy ? "处理中" : "读取";
|
||||
public string Rs485WriteActionText => IsRs485Busy ? "处理中" : "写入";
|
||||
public bool CanUseFlowStabilization => SupportsRs485DirectControl && Key != "KinkResistancePump";
|
||||
public string FlowStabilizationToggleHint => CanUseFlowStabilization
|
||||
? "按实际流量小步调节泵速"
|
||||
: "抗扭结采样要求保持固定转速";
|
||||
public string FlowStabilizationStateText => !CanUseFlowStabilization
|
||||
? "固定转速"
|
||||
: IsFlowStabilizationEnabled
|
||||
? FlowStabilizationStatusText
|
||||
: "稳流未启用";
|
||||
public string SetpointStatusForeground => ResolveSetpointStatusForeground();
|
||||
public string SetpointStatusBackground => ResolveSetpointStatusBackground();
|
||||
|
||||
@@ -241,6 +262,7 @@ public partial class PumpControlChannel : ObservableObject
|
||||
OnPropertyChanged(nameof(CanToggleRs485Action));
|
||||
OnPropertyChanged(nameof(ToggleActionHint));
|
||||
OnPropertyChanged(nameof(CardPrimaryDisplay));
|
||||
OnPropertyChanged(nameof(FlowStabilizationStateText));
|
||||
}
|
||||
|
||||
partial void OnFlowValueChanged(double value)
|
||||
@@ -251,6 +273,7 @@ public partial class PumpControlChannel : ObservableObject
|
||||
OnPropertyChanged(nameof(StateHint));
|
||||
OnPropertyChanged(nameof(IndicatorColor));
|
||||
OnPropertyChanged(nameof(CardPrimaryDisplay));
|
||||
OnPropertyChanged(nameof(FlowStabilizationStateText));
|
||||
}
|
||||
|
||||
partial void OnStateAvailableChanged(bool value)
|
||||
@@ -260,6 +283,7 @@ public partial class PumpControlChannel : ObservableObject
|
||||
OnPropertyChanged(nameof(IndicatorColor));
|
||||
OnPropertyChanged(nameof(ToggleButtonText));
|
||||
OnPropertyChanged(nameof(CardPrimaryDisplay));
|
||||
OnPropertyChanged(nameof(FlowStabilizationStateText));
|
||||
}
|
||||
|
||||
partial void OnFlowAvailableChanged(bool value)
|
||||
@@ -270,6 +294,7 @@ public partial class PumpControlChannel : ObservableObject
|
||||
OnPropertyChanged(nameof(StateHint));
|
||||
OnPropertyChanged(nameof(IndicatorColor));
|
||||
OnPropertyChanged(nameof(CardPrimaryDisplay));
|
||||
OnPropertyChanged(nameof(FlowStabilizationStateText));
|
||||
}
|
||||
|
||||
partial void OnRs485EnabledChanged(bool value)
|
||||
@@ -280,11 +305,33 @@ public partial class PumpControlChannel : ObservableObject
|
||||
OnPropertyChanged(nameof(CalibrationStatusText));
|
||||
OnPropertyChanged(nameof(SetpointReadbackDisplay));
|
||||
OnPropertyChanged(nameof(RawSetpointDisplay));
|
||||
OnPropertyChanged(nameof(CanUseFlowStabilization));
|
||||
OnPropertyChanged(nameof(FlowStabilizationToggleHint));
|
||||
OnPropertyChanged(nameof(FlowStabilizationStateText));
|
||||
}
|
||||
|
||||
partial void OnRs485SlaveAddressChanged(byte value) => OnPropertyChanged(nameof(Rs485SlaveAddressDisplay));
|
||||
|
||||
partial void OnRs485MotorControlRegisterChanged(ushort value) => OnPropertyChanged(nameof(SupportsRs485DirectControl));
|
||||
partial void OnRs485MotorControlRegisterChanged(ushort value)
|
||||
{
|
||||
OnPropertyChanged(nameof(SupportsRs485DirectControl));
|
||||
OnPropertyChanged(nameof(CanUseFlowStabilization));
|
||||
OnPropertyChanged(nameof(FlowStabilizationToggleHint));
|
||||
OnPropertyChanged(nameof(FlowStabilizationStateText));
|
||||
}
|
||||
|
||||
partial void OnIsFlowStabilizationEnabledChanged(bool value)
|
||||
{
|
||||
if (!value)
|
||||
{
|
||||
FlowStabilizationStatusText = "稳流未启用";
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(FlowStabilizationStateText));
|
||||
}
|
||||
|
||||
partial void OnFlowStabilizationStatusTextChanged(string value) =>
|
||||
OnPropertyChanged(nameof(FlowStabilizationStateText));
|
||||
|
||||
partial void OnRs485RawPerLitrePerMinuteChanged(double value)
|
||||
{
|
||||
@@ -327,6 +374,7 @@ public partial class PumpControlChannel : ObservableObject
|
||||
ConfirmedSetpointAvailable = false;
|
||||
ConfirmedRawSetpointValue = 0;
|
||||
ConfirmedSetpointFlowValue = 0;
|
||||
FlowStabilizationRawSetpoint = 0;
|
||||
}
|
||||
|
||||
partial void OnSetpointAvailableChanged(bool value)
|
||||
|
||||
@@ -16,5 +16,5 @@ public sealed class Rs485PumpBindingSettings
|
||||
public double RawPerLitrePerMinute { get; set; }
|
||||
public double RawOffset { get; set; }
|
||||
public double MinFlowLpm { get; set; }
|
||||
public double MaxFlowLpm { get; set; } = 7.0;
|
||||
public double MaxFlowLpm { get; set; } = 20.0;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ public interface IRs485PumpFlowService
|
||||
Rs485PumpFlowOperationResult ReadPumpPreset(Rs485PumpFlowRequest request);
|
||||
IReadOnlyList<Rs485PumpRuntimeSnapshot> ReadPumpRuntimeStates(IReadOnlyList<Rs485PumpFlowRequest> requests);
|
||||
Rs485PumpFlowOperationResult WritePumpPreset(Rs485PumpFlowRequest request, ushort rawForwardSpeed);
|
||||
Rs485PumpFlowOperationResult WritePumpMotorCommand(Rs485PumpFlowRequest request, short rawMotorSpeed);
|
||||
Rs485PumpFlowOperationResult StartPump(Rs485PumpFlowRequest request, short rawMotorSpeed);
|
||||
Rs485PumpFlowOperationResult StopPump(Rs485PumpFlowRequest request);
|
||||
}
|
||||
|
||||
@@ -278,6 +278,48 @@ public sealed class Rs485PumpFlowService : IRs485PumpFlowService
|
||||
});
|
||||
}
|
||||
|
||||
public Rs485PumpFlowOperationResult WritePumpMotorCommand(Rs485PumpFlowRequest request, short rawMotorSpeed)
|
||||
{
|
||||
return Execute(request, master =>
|
||||
{
|
||||
var slave = request.PumpSettings.SlaveAddress;
|
||||
if (rawMotorSpeed <= 0)
|
||||
{
|
||||
return Failure("RS485 稳流调节失败:控制值必须大于 0");
|
||||
}
|
||||
|
||||
if (!TryWriteSignedRegister(master, slave, request.PumpSettings.MotorControlRegister, rawMotorSpeed, out var writeError))
|
||||
{
|
||||
return Failure($"RS485 稳流调节失败:{writeError}");
|
||||
}
|
||||
|
||||
if (PostCommandVerifyDelayMs > 0)
|
||||
{
|
||||
Thread.Sleep(PostCommandVerifyDelayMs);
|
||||
}
|
||||
|
||||
if (TryReadRegister(master, slave, request.PumpSettings.MotorControlRegister, out var motorCommandReadback, out _)
|
||||
&& motorCommandReadback != unchecked((ushort)rawMotorSpeed))
|
||||
{
|
||||
return Failure($"RS485 稳流调节失败:控制寄存器回读 {motorCommandReadback},目标 {rawMotorSpeed}");
|
||||
}
|
||||
|
||||
ushort? runStatus = null;
|
||||
if (TryReadRegister(master, slave, request.PumpSettings.RunStatusRegister, out var runStatusValue, out _))
|
||||
{
|
||||
runStatus = runStatusValue;
|
||||
}
|
||||
|
||||
return new Rs485PumpFlowOperationResult
|
||||
{
|
||||
Success = true,
|
||||
Message = $"RS485 稳流调节成功,控制值 {rawMotorSpeed}",
|
||||
RunStatus = runStatus,
|
||||
RawForwardSpeed = (ushort)rawMotorSpeed
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public Rs485PumpFlowOperationResult StopPump(Rs485PumpFlowRequest request)
|
||||
{
|
||||
return Execute(request, master =>
|
||||
|
||||
@@ -41,8 +41,12 @@ public partial class MainViewModel
|
||||
private const double DefaultRs485RawPerLitrePerMinute = 100d;
|
||||
private const double DefaultRs485RawOffset = 0d;
|
||||
private const int MaxRs485MotorCommand = short.MaxValue;
|
||||
private const double FlowStabilizationDeadbandLpm = 0.05d;
|
||||
private const int FlowStabilizationMaxRawStep = 5;
|
||||
private const double FlowStabilizationMaxRelativeTrim = 0.20d;
|
||||
private const string PressureDropRs485PumpKey = "PressureDropPump";
|
||||
private const string KinkResistanceRs485PumpKey = "KinkResistancePump";
|
||||
private static readonly TimeSpan FlowStabilizationAdjustmentInterval = TimeSpan.FromSeconds(2);
|
||||
private static readonly string[] HemolysisRs485PumpKeys =
|
||||
[
|
||||
"HemolysisDrainageSinglePump",
|
||||
@@ -220,7 +224,7 @@ public partial class MainViewModel
|
||||
RawPerLitrePerMinute = DefaultRs485RawPerLitrePerMinute,
|
||||
RawOffset = DefaultRs485RawOffset,
|
||||
MinFlowLpm = 0,
|
||||
MaxFlowLpm = 7.0
|
||||
MaxFlowLpm = 20.0
|
||||
});
|
||||
}
|
||||
|
||||
@@ -249,7 +253,7 @@ public partial class MainViewModel
|
||||
? binding.RawOffset
|
||||
: DefaultRs485RawOffset;
|
||||
pump.Rs485MinFlowLpm = binding.MinFlowLpm;
|
||||
pump.Rs485MaxFlowLpm = binding.MaxFlowLpm <= 0 ? Math.Max(RatedMaxFlow, 7.0) : binding.MaxFlowLpm;
|
||||
pump.Rs485MaxFlowLpm = binding.MaxFlowLpm <= 0 ? Math.Max(RatedMaxFlow, 20.0) : binding.MaxFlowLpm;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(pump.PendingSetpointText))
|
||||
{
|
||||
@@ -552,6 +556,132 @@ public partial class MainViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private async Task MaintainRs485FlowStabilizationAsync()
|
||||
{
|
||||
var adjustablePumps = ActiveRs485FlowPumpControls
|
||||
.Where(ShouldMaintainFlowStabilization)
|
||||
.OrderBy(item => item.Rs485SlaveAddress)
|
||||
.ToList();
|
||||
|
||||
foreach (var pump in adjustablePumps)
|
||||
{
|
||||
await TryAdjustRs485FlowStabilizationAsync(pump);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldMaintainFlowStabilization(PumpControlChannel pump)
|
||||
{
|
||||
if (!pump.IsFlowStabilizationEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pump.CanUseFlowStabilization)
|
||||
{
|
||||
pump.FlowStabilizationStatusText = "当前项目要求固定转速";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pump.IsRs485Busy)
|
||||
{
|
||||
pump.FlowStabilizationStatusText = "等待当前 RS485 操作完成";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pump.IsRunning || pump.PendingRs485RunningState == false)
|
||||
{
|
||||
pump.FlowStabilizationStatusText = "等待泵运行";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pump.FlowAvailable)
|
||||
{
|
||||
pump.FlowStabilizationStatusText = "等待流量反馈";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pump.ConfirmedSetpointAvailable || pump.ConfirmedSetpointFlowValue <= 0)
|
||||
{
|
||||
pump.FlowStabilizationStatusText = "等待确认目标流量";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DateTime.UtcNow - pump.LastFlowStabilizationAdjustmentUtc < FlowStabilizationAdjustmentInterval)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task TryAdjustRs485FlowStabilizationAsync(PumpControlChannel pump)
|
||||
{
|
||||
var targetFlow = pump.ConfirmedSetpointFlowValue;
|
||||
var flowError = targetFlow - pump.FlowValue;
|
||||
if (Math.Abs(flowError) <= FlowStabilizationDeadbandLpm)
|
||||
{
|
||||
pump.FlowStabilizationStatusText = $"稳流保持:目标 {targetFlow:F2} / 当前 {pump.FlowValue:F2} L/min";
|
||||
pump.LastFlowStabilizationAdjustmentUtc = DateTime.UtcNow;
|
||||
return;
|
||||
}
|
||||
|
||||
var targetRaw = pump.ConfirmedRawSetpointValue > 0
|
||||
? pump.ConfirmedRawSetpointValue
|
||||
: ConvertFlowToRawSpeed(pump, targetFlow);
|
||||
if (targetRaw <= 0)
|
||||
{
|
||||
pump.FlowStabilizationStatusText = "目标流量换算值无效";
|
||||
pump.LastFlowStabilizationAdjustmentUtc = DateTime.UtcNow;
|
||||
return;
|
||||
}
|
||||
|
||||
var currentRaw = pump.FlowStabilizationRawSetpoint > 0
|
||||
? pump.FlowStabilizationRawSetpoint
|
||||
: pump.RawSetpointValue > 0
|
||||
? pump.RawSetpointValue
|
||||
: targetRaw;
|
||||
var maxTrim = Math.Max(FlowStabilizationMaxRawStep, (int)Math.Round(targetRaw * FlowStabilizationMaxRelativeTrim, MidpointRounding.AwayFromZero));
|
||||
var minRaw = Math.Max(1, targetRaw - maxTrim);
|
||||
var maxRaw = Math.Min(MaxRs485MotorCommand, targetRaw + maxTrim);
|
||||
var rawStep = Math.Sign(flowError) * FlowStabilizationMaxRawStep;
|
||||
var nextRaw = Math.Clamp(currentRaw + rawStep, minRaw, maxRaw);
|
||||
|
||||
if (nextRaw == currentRaw)
|
||||
{
|
||||
pump.FlowStabilizationStatusText = $"稳流已到调节限幅:目标 {targetFlow:F2} / 当前 {pump.FlowValue:F2} L/min";
|
||||
pump.LastFlowStabilizationAdjustmentUtc = DateTime.UtcNow;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryBeginRs485PumpOperation(pump, "稳流调节"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var request = BuildRs485Request(pump);
|
||||
var result = await Task.Run(() => _rs485PumpFlowService.WritePumpMotorCommand(request, (short)nextRaw));
|
||||
if (!result.Success)
|
||||
{
|
||||
pump.FlowStabilizationStatusText = result.Message;
|
||||
Rs485StatusText = result.Message;
|
||||
TraceEvents.Insert(0, NewTrace("RS485 稳流调节失败", $"{pump.Name} / {result.Message}"));
|
||||
return;
|
||||
}
|
||||
|
||||
pump.FlowStabilizationRawSetpoint = nextRaw;
|
||||
CacheResolvedRs485Setpoint(pump, nextRaw);
|
||||
ApplyPostCommandPumpState(pump, result, expectedRunning: true);
|
||||
pump.FlowStabilizationStatusText = $"稳流调节:目标 {targetFlow:F2} / 当前 {pump.FlowValue:F2} L/min / 控制值 {nextRaw}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
pump.LastFlowStabilizationAdjustmentUtc = DateTime.UtcNow;
|
||||
EndRs485PumpOperation(pump);
|
||||
}
|
||||
}
|
||||
|
||||
private void RaiseRs485CalibrationSummaryChanges()
|
||||
{
|
||||
OnPropertyChanged(nameof(Rs485EnabledPumpCount));
|
||||
@@ -1349,6 +1479,7 @@ public partial class MainViewModel
|
||||
pump.ConfirmedSetpointAvailable = true;
|
||||
pump.ConfirmedRawSetpointValue = rawMotorSpeed;
|
||||
pump.ConfirmedSetpointFlowValue = flowLpm;
|
||||
pump.FlowStabilizationRawSetpoint = rawMotorSpeed;
|
||||
}
|
||||
|
||||
private bool TryBeginRs485PumpOperation(PumpControlChannel pump, string operationName)
|
||||
|
||||
@@ -423,6 +423,8 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
||||
public bool HasFilteredItems => !FilteredItemsView.IsEmpty;
|
||||
public bool HasManualSupplementItems => !ManualSupplementItemsView.IsEmpty;
|
||||
public bool HasSelectedItem => SelectedItem is not null;
|
||||
public InspectionItem? TightnessInspectionItem => InspectionItems.FirstOrDefault(IsTightnessInspectionItem);
|
||||
public bool HasTightnessInspectionItem => TightnessInspectionItem is not null;
|
||||
public IEnumerable<DeviceChannel> FlowSensorChannels => Channels.Where(IsFlowSensorChannel);
|
||||
public IEnumerable<DeviceChannel> OtherChannels => Channels.Where(channel => !IsFlowSensorChannel(channel));
|
||||
public bool IsTelemetryOnline => _isTelemetryOnline;
|
||||
@@ -544,7 +546,7 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
||||
public bool HasItemSearchText => !string.IsNullOrWhiteSpace(ItemSearchText);
|
||||
public int RealtimeMonitorCount => InspectionItems.Count(item => item.CaptureMode == InspectionItemCaptureMode.RealtimeMonitor);
|
||||
public int RealtimeAssistCount => InspectionItems.Count(item => item.CaptureMode == InspectionItemCaptureMode.RealtimeAssist);
|
||||
public int ManualEntryCount => InspectionItems.Count(item => item.CaptureMode == InspectionItemCaptureMode.ManualEntry);
|
||||
public int ManualEntryCount => InspectionItems.Count(item => item.CaptureMode == InspectionItemCaptureMode.ManualEntry && !IsTightnessInspectionItem(item));
|
||||
public string SelectedItemCaptureModeText => SelectedItem?.CaptureModeText ?? "未选择";
|
||||
public string SelectedItemMeasurementSource => SelectedItem?.MeasurementSource ?? "-";
|
||||
public bool SelectedItemUsesRealtimeValue => SelectedItem?.CaptureMode == InspectionItemCaptureMode.RealtimeMonitor;
|
||||
@@ -566,6 +568,7 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
||||
public string KinkResistanceMandrelDiameterDisplay => $"圆角模板直径:{Math.Max(KinkResistanceOuterDiameter, 0d) * 4d:F1} mm(外径 {KinkResistanceOuterDiameter:F1} mm × 4)";
|
||||
public bool IsPressureDropSelected => SelectedItem?.Clause == "4.3.1";
|
||||
public string PressureDropSamplingSummary => BuildPressureDropSamplingSummary();
|
||||
public bool IsTightnessSelected => SelectedItem is not null && IsTightnessInspectionItem(SelectedItem);
|
||||
public bool IsKinkResistanceSelected => SelectedItem?.Clause == "4.2.3";
|
||||
public string KinkResistanceSamplingSummary => BuildKinkResistanceSamplingSummary();
|
||||
public bool IsAntiCollapseSelected => SelectedItem?.Clause == "4.3.2";
|
||||
@@ -692,6 +695,7 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
||||
OnPropertyChanged(nameof(SelectedItemUsesRealtimeValue));
|
||||
OnPropertyChanged(nameof(IsPressureDropSelected));
|
||||
OnPropertyChanged(nameof(PressureDropSamplingSummary));
|
||||
OnPropertyChanged(nameof(IsTightnessSelected));
|
||||
OnPropertyChanged(nameof(IsKinkResistanceSelected));
|
||||
OnPropertyChanged(nameof(KinkResistanceFlowPointDisplay));
|
||||
OnPropertyChanged(nameof(KinkResistanceMandrelDiameterDisplay));
|
||||
@@ -1408,6 +1412,7 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
||||
var snapshot = await Task.Run(_telemetryService.UpdateChannels);
|
||||
ApplyTelemetrySnapshot(snapshot);
|
||||
await RefreshRs485RuntimeStateSilentlyAsync();
|
||||
await MaintainRs485FlowStabilizationAsync();
|
||||
_lastTelemetryRefreshFailureMessage = string.Empty;
|
||||
RefreshTelemetryPanel();
|
||||
RefreshDeviceStatus();
|
||||
@@ -1635,7 +1640,8 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
||||
var projectCheckItems = FilteredItemsView.Cast<InspectionItem>().ToList();
|
||||
var manualSupplementItems = ManualSupplementItemsView.Cast<InspectionItem>().ToList();
|
||||
var selectedItemStillVisible = SelectedItem is not null
|
||||
&& ((SelectedItem.CaptureMode == InspectionItemCaptureMode.ManualEntry && manualSupplementItems.Contains(SelectedItem))
|
||||
&& ((IsTightnessInspectionItem(SelectedItem))
|
||||
|| (SelectedItem.CaptureMode == InspectionItemCaptureMode.ManualEntry && manualSupplementItems.Contains(SelectedItem))
|
||||
|| (SelectedItem.CaptureMode != InspectionItemCaptureMode.ManualEntry && projectCheckItems.Contains(SelectedItem)));
|
||||
|
||||
if (selectedItemStillVisible)
|
||||
@@ -2132,8 +2138,13 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
||||
private bool MatchesManualSupplementItem(object item) =>
|
||||
item is InspectionItem inspectionItem
|
||||
&& inspectionItem.CaptureMode == InspectionItemCaptureMode.ManualEntry
|
||||
&& !IsTightnessInspectionItem(inspectionItem)
|
||||
&& MatchesItemSearch(inspectionItem);
|
||||
|
||||
private static bool IsTightnessInspectionItem(InspectionItem item) =>
|
||||
string.Equals(item.Clause, "4.2.1", StringComparison.Ordinal)
|
||||
&& string.Equals(item.Item, "血液通道密合性", StringComparison.Ordinal);
|
||||
|
||||
private bool MatchesItemSearch(InspectionItem item)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ItemSearchText))
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"RawPerLitrePerMinute": 100,
|
||||
"RawOffset": 0,
|
||||
"MinFlowLpm": 0,
|
||||
"MaxFlowLpm": 7
|
||||
"MaxFlowLpm": 20
|
||||
},
|
||||
{
|
||||
"PumpKey": "RecirculationMainPump",
|
||||
@@ -54,7 +54,7 @@
|
||||
"RawPerLitrePerMinute": 100,
|
||||
"RawOffset": 0,
|
||||
"MinFlowLpm": 0,
|
||||
"MaxFlowLpm": 7
|
||||
"MaxFlowLpm": 20
|
||||
},
|
||||
{
|
||||
"PumpKey": "RecirculationReturnPump",
|
||||
@@ -71,7 +71,7 @@
|
||||
"RawPerLitrePerMinute": 100,
|
||||
"RawOffset": 0,
|
||||
"MinFlowLpm": 0,
|
||||
"MaxFlowLpm": 7
|
||||
"MaxFlowLpm": 20
|
||||
},
|
||||
{
|
||||
"PumpKey": "RecirculationDrainagePump",
|
||||
@@ -88,7 +88,7 @@
|
||||
"RawPerLitrePerMinute": 100,
|
||||
"RawOffset": 0,
|
||||
"MinFlowLpm": 0,
|
||||
"MaxFlowLpm": 7
|
||||
"MaxFlowLpm": 20
|
||||
},
|
||||
{
|
||||
"PumpKey": "KinkResistancePump",
|
||||
@@ -105,7 +105,7 @@
|
||||
"RawPerLitrePerMinute": 100,
|
||||
"RawOffset": 0,
|
||||
"MinFlowLpm": 0,
|
||||
"MaxFlowLpm": 7
|
||||
"MaxFlowLpm": 20
|
||||
},
|
||||
{
|
||||
"PumpKey": "HemolysisDrainageSinglePump",
|
||||
@@ -122,7 +122,7 @@
|
||||
"RawPerLitrePerMinute": 100,
|
||||
"RawOffset": 0,
|
||||
"MinFlowLpm": 0,
|
||||
"MaxFlowLpm": 7
|
||||
"MaxFlowLpm": 20
|
||||
},
|
||||
{
|
||||
"PumpKey": "HemolysisReturnSinglePump",
|
||||
@@ -139,7 +139,7 @@
|
||||
"RawPerLitrePerMinute": 100,
|
||||
"RawOffset": 0,
|
||||
"MinFlowLpm": 0,
|
||||
"MaxFlowLpm": 7
|
||||
"MaxFlowLpm": 20
|
||||
},
|
||||
{
|
||||
"PumpKey": "HemolysisDualLumenPump",
|
||||
@@ -156,7 +156,7 @@
|
||||
"RawPerLitrePerMinute": 100,
|
||||
"RawOffset": 0,
|
||||
"MinFlowLpm": 0,
|
||||
"MaxFlowLpm": 7
|
||||
"MaxFlowLpm": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user