初始化
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:models="clr-namespace:Cardiopulmonarybypasssystems.Models"
|
||||
mc:Ignorable="d"
|
||||
Title="心肺转流检验"
|
||||
Title="心肺转流检测"
|
||||
Width="1024"
|
||||
Height="768"
|
||||
MinWidth="960"
|
||||
@@ -27,13 +27,13 @@
|
||||
<StackPanel>
|
||||
<TextBlock Text="{Binding PageTitle}" FontSize="28" FontWeight="Bold" Foreground="White" TextWrapping="Wrap" />
|
||||
<TextBlock Margin="0,8,0,0" Foreground="#EFFAFC" FontSize="15" TextWrapping="Wrap"
|
||||
Text="再循环率由实时流量传感器计算,其他结果人工记录,实验结束后导出报表。" />
|
||||
Text="再循环率由实时流量传感器计算,其他结果由人工填写,检测完成后导出报表。" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="1" Margin="0,12,0,0">
|
||||
<WrapPanel>
|
||||
<Button Command="{Binding ToggleAcquisitionCommand}" Content="采集" Background="#FFFFFFFF" Foreground="{StaticResource HeaderBrush}" />
|
||||
<Button Command="{Binding AcknowledgeAlarmCommand}" Content="消警" Background="#33FFFFFF" />
|
||||
<Button Command="{Binding CompleteExperimentCommand}" Content="结束" Background="#FFF0B145" />
|
||||
<Button Command="{Binding CompleteDetectionCommand}" Content="完成检测" Background="#FFF0B145" />
|
||||
<Button Command="{Binding ExportReportCommand}" Content="导出 PDF" Background="#FFEA7E3C" />
|
||||
</WrapPanel>
|
||||
<TextBlock Margin="0,2,0,0" Foreground="#EFFAFC" FontSize="14" Text="{Binding ExportStateText}" TextWrapping="Wrap" />
|
||||
@@ -53,7 +53,7 @@
|
||||
<StackPanel>
|
||||
<Border Style="{StaticResource CardBorderStyle}" Margin="0,0,0,12">
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource SectionTitleStyle}" Text="实验总览" />
|
||||
<TextBlock Style="{StaticResource SectionTitleStyle}" Text="检测总览" />
|
||||
<UniformGrid Columns="1">
|
||||
<Border Margin="0,0,0,8" Padding="14" Background="#FFE7F5F3" CornerRadius="14">
|
||||
<StackPanel>
|
||||
@@ -111,7 +111,7 @@
|
||||
|
||||
<Border Grid.Column="2" Style="{StaticResource CardBorderStyle}" Margin="0">
|
||||
<TabControl>
|
||||
<TabItem Header="检验单">
|
||||
<TabItem Header="项目检测">
|
||||
<ScrollViewer Margin="0,6,0,0" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel>
|
||||
<Border Style="{StaticResource CardBorderStyle}">
|
||||
@@ -123,16 +123,27 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox Grid.Column="0" Margin="0" MinHeight="40" Text="{Binding RequirementSearchText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<Button Grid.Column="1" Margin="8,0,0,0" MinWidth="90" Padding="14,8" Command="{Binding ClearRequirementSearchCommand}" Content="清空" Background="#FF6B8791" />
|
||||
<TextBox Grid.Column="0" Margin="0" MinHeight="40" Text="{Binding ItemSearchText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<Button Grid.Column="1" Margin="8,0,0,0" MinWidth="90" Padding="14,8" Command="{Binding ClearItemSearchCommand}" Content="清空" Background="#FF6B8791" />
|
||||
</Grid>
|
||||
<TextBlock Margin="0,8,0,0" Style="{StaticResource CaptionStyle}" Text="{Binding FilteredRequirementSummary}" />
|
||||
<TextBlock Margin="0,8,0,0" FontSize="14" Foreground="{StaticResource WarningBrush}" Text="未匹配到测试项。">
|
||||
<Grid Margin="0,8,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="220" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock VerticalAlignment="Center" Style="{StaticResource CaptionStyle}" Text="快速筛选" />
|
||||
<ComboBox Grid.Column="1"
|
||||
Margin="12,0,0,8"
|
||||
ItemsSource="{Binding ItemFilterOptions}"
|
||||
SelectedItem="{Binding ActiveFilter, Mode=TwoWay}" />
|
||||
</Grid>
|
||||
<TextBlock Margin="0,8,0,0" Style="{StaticResource CaptionStyle}" Text="{Binding FilteredItemSummary}" />
|
||||
<TextBlock Margin="0,8,0,0" FontSize="14" Foreground="{StaticResource WarningBrush}" Text="未匹配到项目。">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding HasFilteredRequirements}" Value="False">
|
||||
<DataTrigger Binding="{Binding HasFilteredItems}" Value="False">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
@@ -169,8 +180,8 @@
|
||||
<Border Style="{StaticResource CardBorderStyle}">
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource SectionTitleStyle}" Text="项目清单" />
|
||||
<DataGrid ItemsSource="{Binding FilteredRequirements}"
|
||||
SelectedItem="{Binding SelectedRequirement, Mode=TwoWay}"
|
||||
<DataGrid ItemsSource="{Binding FilteredItems}"
|
||||
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
|
||||
CanUserSortColumns="False"
|
||||
IsReadOnly="True"
|
||||
CanUserAddRows="False"
|
||||
@@ -180,8 +191,26 @@
|
||||
MinHeight="240">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="项目" Binding="{Binding Item}" Width="180" />
|
||||
<DataGridTextColumn Header="采集方式" Binding="{Binding CaptureModeText}" Width="150" />
|
||||
<DataGridTemplateColumn Header="采集方式" Width="170">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Border Margin="0,4" Padding="10,4" Background="{Binding CaptureModeBadgeBackground}" CornerRadius="999">
|
||||
<TextBlock HorizontalAlignment="Center" Foreground="{Binding CaptureModeBadgeForeground}" FontWeight="Bold" Text="{Binding CaptureModeText}" />
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTextColumn Header="当前状态" Binding="{Binding StatusText}" Width="90" />
|
||||
<DataGridTemplateColumn Header="完成情况" Width="130">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Margin="0,2">
|
||||
<TextBlock FontWeight="Bold" Text="{Binding CompletionText}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="{Binding CompletionHint}" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTextColumn Header="结果/说明" Binding="{Binding Measured}" Width="*" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
@@ -191,33 +220,34 @@
|
||||
<UniformGrid Columns="4" Margin="0,0,0,12">
|
||||
<Border Margin="0,0,8,8" Style="{StaticResource PanelSectionStyle}">
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="当前测试项" />
|
||||
<TextBlock FontSize="18" FontWeight="Bold" Text="{Binding SelectedRequirementTitle}" TextWrapping="Wrap" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="当前项目" />
|
||||
<TextBlock FontSize="18" FontWeight="Bold" Text="{Binding SelectedItemTitle}" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Margin="0,0,8,8" Style="{StaticResource PanelSectionStyle}">
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="采集方式" />
|
||||
<TextBlock Style="{StaticResource MetricValueStyle}" FontSize="20" Text="{Binding SelectedRequirementCaptureModeText}" TextWrapping="Wrap" />
|
||||
<TextBlock Style="{StaticResource MetricValueStyle}" FontSize="20" Text="{Binding SelectedItemCaptureModeText}" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Margin="0,0,8,8" Style="{StaticResource PanelSectionStyle}">
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="状态" />
|
||||
<TextBlock Style="{StaticResource MetricValueStyle}" FontSize="20" Text="{Binding SelectedRequirementStatusText}" />
|
||||
<TextBlock Style="{StaticResource MetricValueStyle}" FontSize="20" Text="{Binding SelectedItemStatusText}" />
|
||||
<TextBlock Margin="0,6,0,0" Style="{StaticResource CaptionStyle}" Text="{Binding SelectedItem.CompletionHint}" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Margin="0,0,0,8" Style="{StaticResource PanelSectionStyle}">
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="记录时间" />
|
||||
<TextBlock FontSize="16" FontWeight="Bold" Text="{Binding SelectedRequirement.RecordedAtText}" TextWrapping="Wrap" />
|
||||
<TextBlock FontSize="16" FontWeight="Bold" Text="{Binding SelectedItem.RecordedAtText}" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</UniformGrid>
|
||||
|
||||
<Border Style="{StaticResource CardBorderStyle}">
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource SectionTitleStyle}" Text="条款详情与录入" />
|
||||
<TextBlock Style="{StaticResource SectionTitleStyle}" Text="项目详情与结果填写" />
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1.12*" />
|
||||
@@ -226,43 +256,43 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="类别" />
|
||||
<TextBlock FontSize="16" FontWeight="SemiBold" Margin="0,0,0,10" Text="{Binding SelectedRequirement.Category}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="要求" />
|
||||
<TextBlock FontSize="15" Margin="0,0,0,10" TextWrapping="Wrap" Text="{Binding SelectedRequirement.Requirement}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="方法" />
|
||||
<TextBlock FontSize="15" Margin="0,0,0,10" TextWrapping="Wrap" Text="{Binding SelectedRequirement.Method}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="控制点" />
|
||||
<TextBlock FontSize="15" Margin="0,0,0,10" TextWrapping="Wrap" Text="{Binding SelectedRequirement.ControlPoint}" />
|
||||
<TextBlock FontSize="16" FontWeight="SemiBold" Margin="0,0,0,10" Text="{Binding SelectedItem.Category}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="判定要求" />
|
||||
<TextBlock FontSize="15" Margin="0,0,0,10" TextWrapping="Wrap" Text="{Binding SelectedItem.AcceptanceCriteria}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="检测方法" />
|
||||
<TextBlock FontSize="15" Margin="0,0,0,10" TextWrapping="Wrap" Text="{Binding SelectedItem.TestMethod}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="记录要点" />
|
||||
<TextBlock FontSize="15" Margin="0,0,0,10" TextWrapping="Wrap" Text="{Binding SelectedItem.RecordFocus}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="数据来源" />
|
||||
<TextBlock FontSize="15" Margin="0,0,0,10" TextWrapping="Wrap" Text="{Binding SelectedRequirementMeasurementSource}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="实时预览" />
|
||||
<TextBlock FontSize="15" Margin="0,0,0,10" TextWrapping="Wrap" Text="{Binding SelectedItemMeasurementSource}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="实时数据预览" />
|
||||
<Border Padding="12" Background="#FFF4F8FA" CornerRadius="14" Margin="0,0,0,10">
|
||||
<StackPanel>
|
||||
<TextBlock FontSize="16" FontWeight="SemiBold" Text="{Binding SelectedRequirementLiveDisplay}" TextWrapping="Wrap" />
|
||||
<TextBlock Margin="0,6,0,0" Style="{StaticResource CaptionStyle}" Text="{Binding SelectedRequirementLiveHint}" TextWrapping="Wrap" />
|
||||
<TextBlock FontSize="16" FontWeight="SemiBold" Text="{Binding SelectedItemLiveDisplay}" TextWrapping="Wrap" />
|
||||
<TextBlock Margin="0,6,0,0" Style="{StaticResource CaptionStyle}" Text="{Binding SelectedItemLiveHint}" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="录入要求" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="填写说明" />
|
||||
<TextBlock Margin="0,0,0,6" Foreground="{StaticResource MutedTextBrush}" FontSize="13" Text="{Binding RealtimeMeasurementHint}" TextWrapping="Wrap" />
|
||||
<TextBox Text="{Binding ManualMeasuredValue, UpdateSourceTrigger=PropertyChanged}" MinHeight="104" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" IsReadOnly="{Binding SelectedRequirementUsesRealtimeValue}" />
|
||||
<TextBox Text="{Binding ResultValue, UpdateSourceTrigger=PropertyChanged}" MinHeight="104" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" IsReadOnly="{Binding SelectedItemUsesRealtimeValue}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="判定" />
|
||||
<ComboBox ItemsSource="{Binding ManualStatusOptions}" SelectedItem="{Binding SelectedManualStatusText, Mode=TwoWay}" />
|
||||
<ComboBox ItemsSource="{Binding ResultStatusOptions}" SelectedItem="{Binding SelectedResultStatusText, Mode=TwoWay}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="记录人" />
|
||||
<TextBox Text="{Binding ManualOperator, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBox Text="{Binding ResultOperator, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="复核人" />
|
||||
<TextBox Text="{Binding ReviewerName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="批准人" />
|
||||
<TextBox Text="{Binding ApproverName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="备注" />
|
||||
<TextBox Text="{Binding ManualNote, UpdateSourceTrigger=PropertyChanged}" MinHeight="104" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" IsReadOnly="{Binding SelectedRequirementUsesRealtimeValue}" />
|
||||
<TextBox Text="{Binding ResultNote, UpdateSourceTrigger=PropertyChanged}" MinHeight="104" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" IsReadOnly="{Binding SelectedItemUsesRealtimeValue}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<WrapPanel Margin="0,8,0,0">
|
||||
<Button Command="{Binding SelectPreviousRequirementCommand}" Content="上一项" Background="#FF6B8791" />
|
||||
<Button Command="{Binding SelectNextRequirementCommand}" Content="下一项" Background="#FF6B8791" />
|
||||
<Button Command="{Binding ApplyManualResultCommand}" Content="保存" />
|
||||
<Button Command="{Binding SelectPreviousItemCommand}" Content="上一项" Background="#FF6B8791" />
|
||||
<Button Command="{Binding SelectNextItemCommand}" Content="下一项" Background="#FF6B8791" />
|
||||
<Button Command="{Binding ApplyResultCommand}" Content="保存" />
|
||||
</WrapPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
@@ -270,7 +300,7 @@
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="实时工况">
|
||||
<TabItem Header="实时数据">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Margin="0,6,0,0">
|
||||
<UniformGrid Columns="4" Margin="0,0,0,12">
|
||||
@@ -331,7 +361,7 @@
|
||||
<Border Margin="0,0,8,0" Style="{StaticResource PanelSectionStyle}">
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="入口/出口压力" />
|
||||
<TextBlock FontSize="18" FontWeight="Bold" Text="{Binding SelectedRequirementLiveDisplay}" TextWrapping="Wrap" />
|
||||
<TextBlock FontSize="18" FontWeight="Bold" Text="{Binding SelectedItemLiveDisplay}" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Margin="0,0,8,0" Style="{StaticResource PanelSectionStyle}">
|
||||
@@ -343,8 +373,8 @@
|
||||
<Border Style="{StaticResource PanelSectionStyle}">
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="当前选中条款策略" />
|
||||
<TextBlock Style="{StaticResource MetricValueStyle}" FontSize="20" Text="{Binding SelectedRequirementCaptureModeText}" TextWrapping="Wrap" />
|
||||
<TextBlock Margin="0,6,0,0" Style="{StaticResource CaptionStyle}" Text="{Binding SelectedRequirementMeasurementSource}" TextWrapping="Wrap" />
|
||||
<TextBlock Style="{StaticResource MetricValueStyle}" FontSize="20" Text="{Binding SelectedItemCaptureModeText}" TextWrapping="Wrap" />
|
||||
<TextBlock Margin="0,6,0,0" Style="{StaticResource CaptionStyle}" Text="{Binding SelectedItemMeasurementSource}" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</UniformGrid>
|
||||
|
||||
73
Cardiopulmonarybypasssystems/Models/InspectionItem.cs
Normal file
73
Cardiopulmonarybypasssystems/Models/InspectionItem.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Cardiopulmonarybypasssystems.Models;
|
||||
|
||||
public partial class InspectionItem : ObservableObject
|
||||
{
|
||||
public required string Clause { get; init; }
|
||||
public required string Category { get; init; }
|
||||
public required string Item { get; init; }
|
||||
public required string AcceptanceCriteria { get; init; }
|
||||
public required string TestMethod { get; init; }
|
||||
public required string RecordFocus { get; init; }
|
||||
public InspectionItemCaptureMode CaptureMode { get; init; } = InspectionItemCaptureMode.ManualEntry;
|
||||
public string MeasurementSource { get; init; } = "人工观察 / 检测记录";
|
||||
public string ManualEntryHint { get; init; } = "按标准方法完成检测后,由检测员手动填写结果。";
|
||||
public string LiveDisplayHint { get; init; } = "当前项目无实时信号接入。";
|
||||
|
||||
[ObservableProperty]
|
||||
private string measured = "待检测";
|
||||
|
||||
[ObservableProperty]
|
||||
private InspectionItemStatus status = InspectionItemStatus.Pending;
|
||||
|
||||
[ObservableProperty]
|
||||
private string notes = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private string recordedBy = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private DateTime? recordedAt;
|
||||
|
||||
public string StatusText => Status switch
|
||||
{
|
||||
InspectionItemStatus.Qualified => "合格",
|
||||
InspectionItemStatus.Warning => "预警",
|
||||
InspectionItemStatus.Critical => "不合格",
|
||||
_ => "待检"
|
||||
};
|
||||
public bool RequiresManualEntry => CaptureMode != InspectionItemCaptureMode.RealtimeMonitor;
|
||||
public string CaptureModeText => CaptureMode switch
|
||||
{
|
||||
InspectionItemCaptureMode.RealtimeMonitor => "实时监控",
|
||||
InspectionItemCaptureMode.RealtimeAssist => "实时显示+手动录入",
|
||||
_ => "手动录入"
|
||||
};
|
||||
public string CaptureModeBadgeBackground => CaptureMode switch
|
||||
{
|
||||
InspectionItemCaptureMode.RealtimeMonitor => "#FFE3F6EF",
|
||||
InspectionItemCaptureMode.RealtimeAssist => "#FFEAF0FB",
|
||||
_ => "#FFFDF0E5"
|
||||
};
|
||||
public string CaptureModeBadgeForeground => CaptureMode switch
|
||||
{
|
||||
InspectionItemCaptureMode.RealtimeMonitor => "#FF0E6C58",
|
||||
InspectionItemCaptureMode.RealtimeAssist => "#FF2A5DA8",
|
||||
_ => "#FFA45A12"
|
||||
};
|
||||
public string CompletionText => Status == InspectionItemStatus.Pending ? "待填写" : "已完成";
|
||||
public string CompletionHint => Status == InspectionItemStatus.Pending
|
||||
? CaptureMode == InspectionItemCaptureMode.RealtimeMonitor ? "等待实时数据" : "等待填写结果"
|
||||
: $"状态:{StatusText}";
|
||||
|
||||
public string RecordedAtText => RecordedAt?.ToString("yyyy-MM-dd HH:mm") ?? "未记录";
|
||||
|
||||
partial void OnStatusChanged(InspectionItemStatus value)
|
||||
{
|
||||
OnPropertyChanged(nameof(StatusText));
|
||||
OnPropertyChanged(nameof(CompletionText));
|
||||
OnPropertyChanged(nameof(CompletionHint));
|
||||
}
|
||||
partial void OnRecordedAtChanged(DateTime? value) => OnPropertyChanged(nameof(RecordedAtText));
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Cardiopulmonarybypasssystems.Models;
|
||||
|
||||
public enum RequirementCaptureMode
|
||||
public enum InspectionItemCaptureMode
|
||||
{
|
||||
ManualEntry,
|
||||
RealtimeAssist,
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Cardiopulmonarybypasssystems.Models;
|
||||
|
||||
public enum RequirementStatus
|
||||
public enum InspectionItemStatus
|
||||
{
|
||||
Pending,
|
||||
Qualified,
|
||||
@@ -1,52 +0,0 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Cardiopulmonarybypasssystems.Models;
|
||||
|
||||
public partial class TestRequirement : ObservableObject
|
||||
{
|
||||
public required string Clause { get; init; }
|
||||
public required string Category { get; init; }
|
||||
public required string Item { get; init; }
|
||||
public required string Requirement { get; init; }
|
||||
public required string Method { get; init; }
|
||||
public required string ControlPoint { get; init; }
|
||||
public RequirementCaptureMode CaptureMode { get; init; } = RequirementCaptureMode.ManualEntry;
|
||||
public string MeasurementSource { get; init; } = "人工观察 / 试验记录";
|
||||
public string ManualEntryHint { get; init; } = "按标准方法完成试验后,由检验员手动录入结果。";
|
||||
public string LiveDisplayHint { get; init; } = "当前条款无实时信号接入。";
|
||||
|
||||
[ObservableProperty]
|
||||
private string measured = "待检测";
|
||||
|
||||
[ObservableProperty]
|
||||
private RequirementStatus status = RequirementStatus.Pending;
|
||||
|
||||
[ObservableProperty]
|
||||
private string notes = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private string recordedBy = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private DateTime? recordedAt;
|
||||
|
||||
public string StatusText => Status switch
|
||||
{
|
||||
RequirementStatus.Qualified => "合格",
|
||||
RequirementStatus.Warning => "预警",
|
||||
RequirementStatus.Critical => "不合格",
|
||||
_ => "待检"
|
||||
};
|
||||
public bool RequiresManualEntry => CaptureMode != RequirementCaptureMode.RealtimeMonitor;
|
||||
public string CaptureModeText => CaptureMode switch
|
||||
{
|
||||
RequirementCaptureMode.RealtimeMonitor => "实时监控",
|
||||
RequirementCaptureMode.RealtimeAssist => "实时显示+手动录入",
|
||||
_ => "手动录入"
|
||||
};
|
||||
|
||||
public string RecordedAtText => RecordedAt?.ToString("yyyy-MM-dd HH:mm") ?? "未记录";
|
||||
|
||||
partial void OnStatusChanged(RequirementStatus value) => OnPropertyChanged(nameof(StatusText));
|
||||
partial void OnRecordedAtChanged(DateTime? value) => OnPropertyChanged(nameof(RecordedAtText));
|
||||
}
|
||||
@@ -4,6 +4,6 @@ namespace Cardiopulmonarybypasssystems.Services;
|
||||
|
||||
public interface IStandardRepository
|
||||
{
|
||||
IReadOnlyList<TestRequirement> GetRequirements();
|
||||
IReadOnlyList<InspectionItem> GetInspectionItems();
|
||||
IReadOnlyList<TraceEvent> GetSeedTraceEvents();
|
||||
}
|
||||
|
||||
@@ -4,31 +4,31 @@ namespace Cardiopulmonarybypasssystems.Services;
|
||||
|
||||
public sealed class StandardRepository : IStandardRepository
|
||||
{
|
||||
public IReadOnlyList<TestRequirement> GetRequirements() =>
|
||||
public IReadOnlyList<InspectionItem> GetInspectionItems() =>
|
||||
[
|
||||
new() { Clause = "4.1.1", Category = "生物性能", Item = "无菌", Requirement = "插管应无菌", Method = "对灭菌后样品进行无菌培养观察,确认无菌生长", ControlPoint = "灭菌批次放行" },
|
||||
new() { Clause = "4.1.2", Category = "生物性能", Item = "细菌内毒素", Requirement = "内毒素不超过 20 EU/件", Method = "提取样液后进行细菌内毒素检测,确认每件结果不超过限值", ControlPoint = "内毒素检测记录" },
|
||||
new() { Clause = "4.1.3", Category = "生物性能", Item = "生物相容性", Requirement = "符合预期用途生物学评价", Method = "结合预期用途完成生物学评价并审查评价结论", ControlPoint = "生物学评价记录" },
|
||||
new() { Clause = "4.2.1", Category = "物理性能", Item = "血液通道密合性", Requirement = "血液通道不应泄漏", Method = "封闭血液通道并加压至最大工作压力 1.5 倍,保压观察是否泄漏", ControlPoint = "人工保压观察" },
|
||||
new() { Clause = "4.2.2", Category = "物理性能", Item = "接头", Requirement = "连接牢固,辅助接头同样满足要求", Method = "对接头和辅助接头施加规定拉力,检查是否松动或脱开", ControlPoint = "人工拉脱力记录" },
|
||||
new() { Clause = "4.2.3", Category = "物理性能", Item = "抗扭结抗性", Requirement = "流量降低不超过 50%", Method = "将插管弯折至规定状态,比较弯折前后流量变化", ControlPoint = "人工填写弯折流量" },
|
||||
new() { Clause = "4.2.4", Category = "物理性能", Item = "抗拉强度", Requirement = "承受持续最小拉力且不分离", Method = "对连接部位持续施加预期使用力 1.5 倍拉力,观察是否分离", ControlPoint = "拉力试验记录" },
|
||||
new() { Clause = "4.2.5", Category = "物理性能", Item = "外观", Requirement = "无毛刺、裂纹、异物、色斑,远端无锐角", Method = "在正常照明下目视检查管体表面、接口和远端外观", ControlPoint = "人工外观复核" },
|
||||
new() { Clause = "4.2.6", Category = "物理性能", Item = "完整性", Requirement = "模拟使用后无腐蚀、磨损、塌陷", Method = "完成模拟使用后,对管体和组件进行放大检查", ControlPoint = "使用后检查" },
|
||||
new() { Clause = "4.2.7", Category = "物理性能", Item = "射线可探测性", Requirement = "需具备可探测性时应满足要求", Method = "在影像条件下观察插管显影情况和可识别性", ControlPoint = "影像记录" },
|
||||
new() { Clause = "4.2.8", Category = "物理性能", Item = "距离标记", Requirement = "标记应指示至远端距离,间隔不超过 10 mm 或风评值", Method = "目视检查距离标记的位置、间距和清晰度", ControlPoint = "人工核对标记" },
|
||||
new() { Clause = "4.2.9", Category = "物理性能", Item = "管腔标记", Requirement = "端口和血流方向可肉眼识别", Method = "目视检查端口标识和血流方向标识是否清晰可辨", ControlPoint = "人工核对流向" },
|
||||
new() { Clause = "4.1.1", Category = "生物性能", Item = "无菌", AcceptanceCriteria = "应无菌。", TestMethod = "进行无菌培养观察;判定无菌生长。", RecordFocus = "记录无菌培养结果" },
|
||||
new() { Clause = "4.1.2", Category = "生物性能", Item = "细菌内毒素", AcceptanceCriteria = "每件内毒素不超过 20 EU。", TestMethod = "对提取液进行内毒素检测;判定结果不超过 20 EU/件。", RecordFocus = "记录内毒素检测值" },
|
||||
new() { Clause = "4.1.3", Category = "生物性能", Item = "生物相容性", AcceptanceCriteria = "生物学评价应符合预期用途。", TestMethod = "按预期用途完成生物学评价;判定评价结论符合使用要求。", RecordFocus = "记录生物学评价结论" },
|
||||
new() { Clause = "4.2.1", Category = "物理性能", Item = "血液通道密合性", AcceptanceCriteria = "血液通道应无泄漏。", TestMethod = "封闭通道并加压保压观察;判定血液通道无泄漏。", RecordFocus = "观察并记录保压结果" },
|
||||
new() { Clause = "4.2.2", Category = "物理性能", Item = "接头", AcceptanceCriteria = "各接头连接应牢固。", TestMethod = "对接头施加规定拉力;判定连接不松动、不脱开。", RecordFocus = "记录接头拉脱结果" },
|
||||
new() { Clause = "4.2.3", Category = "物理性能", Item = "抗扭结抗性", AcceptanceCriteria = "弯折后流量降低不超过 50%。", TestMethod = "将插管弯折后测量流量变化;判定流量降低不超过 50%。", RecordFocus = "填写弯折前后流量" },
|
||||
new() { Clause = "4.2.4", Category = "物理性能", Item = "抗拉强度", AcceptanceCriteria = "受力后部件不应分离。", TestMethod = "对连接部位持续施加拉力;判定部件不分离。", RecordFocus = "记录拉力试验结果" },
|
||||
new() { Clause = "4.2.5", Category = "物理性能", Item = "外观", AcceptanceCriteria = "外观应完整、洁净、无明显缺陷。", TestMethod = "在正常照明下目视检查外观;判定无毛刺、裂纹、异物和锐角。", RecordFocus = "核对并记录外观结果" },
|
||||
new() { Clause = "4.2.6", Category = "物理性能", Item = "完整性", AcceptanceCriteria = "模拟使用后应保持完整。", TestMethod = "模拟使用后检查管体和组件;判定无腐蚀、磨损和塌陷。", RecordFocus = "记录使用后检查结果" },
|
||||
new() { Clause = "4.2.7", Category = "物理性能", Item = "射线可探测性", AcceptanceCriteria = "需要时应具备射线可探测性。", TestMethod = "在影像条件下观察显影情况;判定插管可被清晰识别。", RecordFocus = "记录影像观察结果" },
|
||||
new() { Clause = "4.2.8", Category = "物理性能", Item = "距离标记", AcceptanceCriteria = "距离标记应清晰且间隔符合要求。", TestMethod = "检查距离标记位置和间距;判定标记清晰且间隔符合要求。", RecordFocus = "核对距离标记" },
|
||||
new() { Clause = "4.2.9", Category = "物理性能", Item = "管腔标记", AcceptanceCriteria = "端口和流向标识应清晰可辨。", TestMethod = "检查端口和流向标识;判定标识肉眼清晰可辨。", RecordFocus = "核对端口和流向标识" },
|
||||
new()
|
||||
{
|
||||
Clause = "4.3.1",
|
||||
Category = "性能特征",
|
||||
Item = "压力降",
|
||||
Requirement = "应在制造商声明范围内",
|
||||
Method = "在额定流量点同步测量入口与出口压力,计算压差",
|
||||
ControlPoint = "入口/出口压差",
|
||||
CaptureMode = RequirementCaptureMode.RealtimeMonitor,
|
||||
AcceptanceCriteria = "压力降应在声明范围内。",
|
||||
TestMethod = "在额定流量点测量入口和出口压力;判定压差在声明范围内。",
|
||||
RecordFocus = "实时监控压差",
|
||||
CaptureMode = InspectionItemCaptureMode.RealtimeMonitor,
|
||||
MeasurementSource = "入口/出口压力传感器",
|
||||
ManualEntryHint = "该条款由实时压力信号自动采集,无需人工重复录入。",
|
||||
ManualEntryHint = "该项目由实时压力信号自动采集,无需人工重复填写。",
|
||||
LiveDisplayHint = "实时显示入口压力、出口压力和压差,用于直接判定压力降。"
|
||||
},
|
||||
new()
|
||||
@@ -36,12 +36,12 @@ public sealed class StandardRepository : IStandardRepository
|
||||
Clause = "4.3.2",
|
||||
Category = "性能特征",
|
||||
Item = "抗塌陷",
|
||||
Requirement = "引流管负压后压降增量不超过 40%",
|
||||
Method = "施加负压后比较压差增量和流量变化,判断是否塌陷",
|
||||
ControlPoint = "负压后人工判定",
|
||||
CaptureMode = RequirementCaptureMode.RealtimeAssist,
|
||||
AcceptanceCriteria = "负压后压降增量不超过 40%。",
|
||||
TestMethod = "施加负压后比较压差增量和流量变化;判定压降增量不超过限值。",
|
||||
RecordFocus = "记录负压与压差变化",
|
||||
CaptureMode = InspectionItemCaptureMode.RealtimeAssist,
|
||||
MeasurementSource = "负压辅助引流、入口/出口压差趋势",
|
||||
ManualEntryHint = "系统实时显示负压与压差趋势,最终结论仍由检验员按试验工况手动录入。",
|
||||
ManualEntryHint = "系统实时显示负压与压差趋势,最终结论仍由检测员根据检测记录手动填写。",
|
||||
LiveDisplayHint = "建议结合负压、压差增量和流量变化综合判定是否塌陷。"
|
||||
},
|
||||
new()
|
||||
@@ -49,12 +49,12 @@ public sealed class StandardRepository : IStandardRepository
|
||||
Clause = "4.3.3",
|
||||
Category = "性能特征",
|
||||
Item = "再循环",
|
||||
Requirement = "再循环百分比在声明值范围内",
|
||||
Method = "在双腔回路模型中测量引流与回输流量,计算再循环比例",
|
||||
ControlPoint = "三路流量实时计算",
|
||||
CaptureMode = RequirementCaptureMode.RealtimeMonitor,
|
||||
AcceptanceCriteria = "再循环比例应在声明范围内。",
|
||||
TestMethod = "在双腔回路中测量引流和回输流量;判定再循环比例在声明范围内。",
|
||||
RecordFocus = "实时监控再循环率",
|
||||
CaptureMode = InspectionItemCaptureMode.RealtimeMonitor,
|
||||
MeasurementSource = "主泵 / 静脉引流 / 动脉回输流量传感器",
|
||||
ManualEntryHint = "该条款由三路流量实时计算,无需人工重复录入。",
|
||||
ManualEntryHint = "该项目由三路流量实时计算,无需人工重复填写。",
|
||||
LiveDisplayHint = "实时显示主泵、引流、回输流量及再循环率。"
|
||||
},
|
||||
new()
|
||||
@@ -62,12 +62,12 @@ public sealed class StandardRepository : IStandardRepository
|
||||
Clause = "4.3.4",
|
||||
Category = "性能特征",
|
||||
Item = "血细胞破坏",
|
||||
Requirement = "游离血红蛋白增量在声明值范围内",
|
||||
Method = "进行体外循环试验,检测循环前后游离血红蛋白增量",
|
||||
ControlPoint = "人工填写 fHb",
|
||||
CaptureMode = RequirementCaptureMode.RealtimeAssist,
|
||||
AcceptanceCriteria = "游离血红蛋白增量应在声明范围内。",
|
||||
TestMethod = "进行体外循环试验并检测游离血红蛋白;判定增量在声明范围内。",
|
||||
RecordFocus = "填写游离血红蛋白结果",
|
||||
CaptureMode = InspectionItemCaptureMode.RealtimeAssist,
|
||||
MeasurementSource = "游离血红蛋白在线趋势 + 实验室结果",
|
||||
ManualEntryHint = "系统仅实时显示趋势,最终结果应以试验室检测值手动录入。",
|
||||
ManualEntryHint = "系统仅实时显示趋势,最终结果应以实验室检测值手动填写。",
|
||||
LiveDisplayHint = "关注游离血红蛋白上升趋势,避免仅用在线值替代正式记录。"
|
||||
},
|
||||
new()
|
||||
@@ -75,29 +75,29 @@ public sealed class StandardRepository : IStandardRepository
|
||||
Clause = "4.3.4",
|
||||
Category = "性能特征",
|
||||
Item = "血小板/白细胞减少率",
|
||||
Requirement = "应在声明值范围内",
|
||||
Method = "进行体外循环试验,比较循环前后血小板和白细胞计数变化",
|
||||
ControlPoint = "人工填写血常规",
|
||||
CaptureMode = RequirementCaptureMode.RealtimeAssist,
|
||||
AcceptanceCriteria = "血细胞减少率应在声明范围内。",
|
||||
TestMethod = "进行体外循环试验并比较血细胞计数;判定减少率在声明范围内。",
|
||||
RecordFocus = "填写血细胞计数结果",
|
||||
CaptureMode = InspectionItemCaptureMode.RealtimeAssist,
|
||||
MeasurementSource = "白细胞减少率趋势 + 血常规结果",
|
||||
ManualEntryHint = "系统用于实时显示趋势,最终血常规结果仍需人工录入。",
|
||||
LiveDisplayHint = "实时观察白细胞减少率趋势,最终以检验报告为准。"
|
||||
ManualEntryHint = "系统用于实时显示趋势,最终血常规结果仍需人工填写。",
|
||||
LiveDisplayHint = "实时观察白细胞减少率趋势,最终以检测报告为准。"
|
||||
},
|
||||
new() { Clause = "4.3.5", Category = "性能特征", Item = "有效期", Requirement = "有效期内应符合标准", Method = "对实时或加速老化样品复测关键性能,评价有效期内是否仍满足要求", ControlPoint = "老化记录" },
|
||||
new() { Clause = "4.4.1", Category = "化学性能", Item = "还原物质", Requirement = "高锰酸钾消耗差值 < 2.0 mL", Method = "制备检验液后比较高锰酸钾消耗量与空白液差值", ControlPoint = "人工填写化学结果" },
|
||||
new() { Clause = "4.4.2", Category = "化学性能", Item = "金属离子", Requirement = "Ba、Cr、Cu、Pb 总量符合限值", Method = "制备浸提液后测定钡、铬、铜、铅总量", ControlPoint = "人工填写金属离子" },
|
||||
new() { Clause = "4.4.3", Category = "化学性能", Item = "酸碱度", Requirement = "检验液与空白差值不超过 4.0", Method = "测量检验液与空白液的 pH 差值", ControlPoint = "人工填写 pH" },
|
||||
new() { Clause = "4.4.4", Category = "化学性能", Item = "蒸发残渣", Requirement = "不超过规定值", Method = "蒸干检验液并称量残渣,确认结果不超过限值", ControlPoint = "人工填写残渣" },
|
||||
new() { Clause = "4.4.5", Category = "化学性能", Item = "紫外吸光度", Requirement = "应小于 0.1", Method = "测量检验液在规定波长下的紫外吸光度", ControlPoint = "人工填写 UV" },
|
||||
new() { Clause = "4.4.5", Category = "化学性能", Item = "色泽", Requirement = "应无色透明", Method = "目视观察检验液颜色和澄清度", ControlPoint = "人工外观确认" },
|
||||
new() { Clause = "4.5", Category = "残留", Item = "环氧乙烷残留量", Requirement = "EO 残留量不大于 10 mg/kg", Method = "对样品提取后测定环氧乙烷残留量,确认不超过限值", ControlPoint = "人工填写 EO" },
|
||||
new() { Clause = "4.6", Category = "耐蚀性", Item = "金属部件耐蚀性", Requirement = "直接接触血液部位不超过 1 级", Method = "对金属部件进行耐蚀性试验并按腐蚀等级判定", ControlPoint = "耐蚀性记录" },
|
||||
new() { Clause = "4.7", Category = "清洁度", Item = "污染指数", Requirement = "污染指数不超过 90", Method = "收集样品污染物并计算污染指数", ControlPoint = "人工填写污染指数" }
|
||||
new() { Clause = "4.3.5", Category = "性能特征", Item = "有效期", AcceptanceCriteria = "有效期内应持续符合要求。", TestMethod = "对老化后样品复测关键性能;判定有效期内仍符合要求。", RecordFocus = "记录老化复测结果" },
|
||||
new() { Clause = "4.4.1", Category = "化学性能", Item = "还原物质", AcceptanceCriteria = "高锰酸钾消耗差值小于 2.0 mL。", TestMethod = "测定检验液与空白液的高锰酸钾消耗差值;判定差值小于 2.0 mL。", RecordFocus = "填写还原物质结果" },
|
||||
new() { Clause = "4.4.2", Category = "化学性能", Item = "金属离子", AcceptanceCriteria = "金属离子总量应符合限值。", TestMethod = "测定浸提液中金属离子总量;判定结果符合限值要求。", RecordFocus = "填写金属离子结果" },
|
||||
new() { Clause = "4.4.3", Category = "化学性能", Item = "酸碱度", AcceptanceCriteria = "检验液与空白液 pH 差值不超过 4.0。", TestMethod = "测量检验液与空白液的 pH 差值;判定差值不超过 4.0。", RecordFocus = "填写 pH 差值" },
|
||||
new() { Clause = "4.4.4", Category = "化学性能", Item = "蒸发残渣", AcceptanceCriteria = "蒸发残渣量不超过规定值。", TestMethod = "蒸干检验液并称量残渣;判定残渣量不超过规定值。", RecordFocus = "填写残渣称量结果" },
|
||||
new() { Clause = "4.4.5", Category = "化学性能", Item = "紫外吸光度", AcceptanceCriteria = "紫外吸光度应小于 0.1。", TestMethod = "测量检验液的紫外吸光度;判定吸光度小于 0.1。", RecordFocus = "填写紫外吸光度" },
|
||||
new() { Clause = "4.4.5", Category = "化学性能", Item = "色泽", AcceptanceCriteria = "检验液应无色透明。", TestMethod = "目视观察检验液色泽和澄清度;判定应无色透明。", RecordFocus = "记录色泽观察结果" },
|
||||
new() { Clause = "4.5", Category = "残留", Item = "环氧乙烷残留量", AcceptanceCriteria = "环氧乙烷残留量不大于 10 mg/kg。", TestMethod = "测定样品的环氧乙烷残留量;判定结果不大于 10 mg/kg。", RecordFocus = "填写 EO 残留量" },
|
||||
new() { Clause = "4.6", Category = "耐蚀性", Item = "金属部件耐蚀性", AcceptanceCriteria = "金属部件腐蚀等级不超过 1 级。", TestMethod = "进行耐蚀性试验并评定腐蚀等级;判定结果不超过 1 级。", RecordFocus = "记录腐蚀等级" },
|
||||
new() { Clause = "4.7", Category = "清洁度", Item = "污染指数", AcceptanceCriteria = "污染指数不超过 90。", TestMethod = "收集污染物并计算污染指数;判定结果不超过 90。", RecordFocus = "填写污染指数" }
|
||||
];
|
||||
|
||||
public IReadOnlyList<TraceEvent> GetSeedTraceEvents() =>
|
||||
[
|
||||
new() { Timestamp = DateTime.Today.AddHours(8.2), Stage = "批次建档", Detail = "创建一次性使用动静脉插管检验任务", Operator = "张工" },
|
||||
new() { Timestamp = DateTime.Today.AddHours(8.2), Stage = "批次建档", Detail = "创建一次性使用动静脉插管检测任务", Operator = "张工" },
|
||||
new() { Timestamp = DateTime.Today.AddHours(8.6), Stage = "样品登记", Detail = "录入规格 24Fr/32Fr、双腔、EO 灭菌", Operator = "张工" },
|
||||
new() { Timestamp = DateTime.Today.AddHours(9.1), Stage = "回路预充", Detail = "实时通道仅做辅助显示,最终结果由试验员手动录入", Operator = "王工" }
|
||||
];
|
||||
|
||||
@@ -16,10 +16,10 @@ public partial class MainViewModel : ObservableObject
|
||||
private readonly DispatcherTimer _timer;
|
||||
|
||||
[ObservableProperty]
|
||||
private string pageTitle = "心肺转流系统一次性使用动静脉插管";
|
||||
private string pageTitle = "心肺转流系统一次性使用动静脉插管检测";
|
||||
|
||||
[ObservableProperty]
|
||||
private string currentStage = "试验执行中";
|
||||
private string currentStage = "检测进行中";
|
||||
|
||||
[ObservableProperty]
|
||||
private string operatorName = "张工";
|
||||
@@ -40,7 +40,7 @@ public partial class MainViewModel : ObservableObject
|
||||
private bool acquisitionRunning = true;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool experimentCompleted;
|
||||
private bool detectionCompleted;
|
||||
|
||||
[ObservableProperty]
|
||||
private double complianceRate;
|
||||
@@ -58,42 +58,42 @@ public partial class MainViewModel : ObservableObject
|
||||
private double deltaPressure;
|
||||
|
||||
[ObservableProperty]
|
||||
private string latestAction = "系统已载入标准条款,等待试验员录入结果。";
|
||||
private string latestAction = "系统已载入标准项目,等待填写检测结果。";
|
||||
|
||||
[ObservableProperty]
|
||||
private TestRequirement? selectedRequirement;
|
||||
private InspectionItem? selectedItem;
|
||||
|
||||
[ObservableProperty]
|
||||
private string manualMeasuredValue = "";
|
||||
private string resultValue = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private string manualNote = "";
|
||||
private string resultNote = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private string manualOperator = "张工";
|
||||
private string resultOperator = "张工";
|
||||
|
||||
[ObservableProperty]
|
||||
private string selectedManualStatusText = "合格";
|
||||
private string selectedResultStatusText = "合格";
|
||||
|
||||
[ObservableProperty]
|
||||
private string experimentSummary = "";
|
||||
private string detectionSummary = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private string requirementSearchText = "";
|
||||
private string itemSearchText = "";
|
||||
|
||||
public MainViewModel(IStandardRepository repository, IModbusTelemetryService telemetryService)
|
||||
{
|
||||
_telemetryService = telemetryService;
|
||||
Requirements = new ObservableCollection<TestRequirement>(repository.GetRequirements());
|
||||
InspectionItems = new ObservableCollection<InspectionItem>(repository.GetInspectionItems());
|
||||
Channels = new ObservableCollection<DeviceChannel>(telemetryService.GetChannels());
|
||||
TraceEvents = new ObservableCollection<TraceEvent>(repository.GetSeedTraceEvents());
|
||||
AlarmMessages = new ObservableCollection<AlarmMessage>();
|
||||
ManualStatusOptions = new ObservableCollection<string>(["待检", "合格", "预警", "不合格"]);
|
||||
ResultStatusOptions = new ObservableCollection<string>(["待检", "合格", "预警", "不合格"]);
|
||||
|
||||
SelectedRequirement = Requirements.FirstOrDefault();
|
||||
if (SelectedRequirement is not null)
|
||||
SelectedItem = InspectionItems.FirstOrDefault();
|
||||
if (SelectedItem is not null)
|
||||
{
|
||||
LoadSelectedRequirementDraft(SelectedRequirement);
|
||||
LoadSelectedItemDraft(SelectedItem);
|
||||
}
|
||||
|
||||
RefreshTelemetryPanel();
|
||||
@@ -104,21 +104,21 @@ public partial class MainViewModel : ObservableObject
|
||||
_timer.Start();
|
||||
}
|
||||
|
||||
public ObservableCollection<TestRequirement> Requirements { get; }
|
||||
public ObservableCollection<InspectionItem> InspectionItems { get; }
|
||||
public ObservableCollection<DeviceChannel> Channels { get; }
|
||||
public ObservableCollection<TraceEvent> TraceEvents { get; }
|
||||
public ObservableCollection<AlarmMessage> AlarmMessages { get; }
|
||||
public ObservableCollection<string> ManualStatusOptions { get; }
|
||||
public IEnumerable<TestRequirement> FilteredRequirements => Requirements.Where(MatchesRequirementSearch);
|
||||
public bool HasFilteredRequirements => FilteredRequirements.Any();
|
||||
public ObservableCollection<string> ResultStatusOptions { get; }
|
||||
public IEnumerable<InspectionItem> FilteredItems => InspectionItems.Where(MatchesItemSearch);
|
||||
public bool HasFilteredItems => FilteredItems.Any();
|
||||
public IEnumerable<DeviceChannel> FlowSensorChannels => Channels.Where(IsFlowSensorChannel);
|
||||
public IEnumerable<DeviceChannel> OtherChannels => Channels.Where(channel => !IsFlowSensorChannel(channel));
|
||||
|
||||
public string ComplianceDisplay => $"{ComplianceRate:F0}%";
|
||||
public string DeltaPressureDisplay => $"{DeltaPressure:F1} mmHg";
|
||||
public string ExportStateText => ExperimentCompleted ? "实验已结束,可导出 PDF 正式报表" : "实验进行中,完成后导出 PDF 正式报表";
|
||||
public string SelectedRequirementTitle => SelectedRequirement?.Item ?? "未选择测试项";
|
||||
public string SelectedRequirementStatusText => SelectedRequirement?.StatusText ?? "待检";
|
||||
public string ExportStateText => DetectionCompleted ? "检测已完成,可导出 PDF 正式报表" : "检测进行中,完成后导出 PDF 正式报表";
|
||||
public string SelectedItemTitle => SelectedItem?.Item ?? "未选择项目";
|
||||
public string SelectedItemStatusText => SelectedItem?.StatusText ?? "待检";
|
||||
public string RealtimeRecirculationDisplay => $"{RecirculationRate:F1}%";
|
||||
public string PumpFlowDisplay => $"{PumpFlow:F2} L/min";
|
||||
public string DrainageFlowDisplay => $"{DrainageFlow:F2} L/min";
|
||||
@@ -130,19 +130,19 @@ public partial class MainViewModel : ObservableObject
|
||||
public double PumpFlowNormalizedValue => ChannelNormalizedValue("主泵流量");
|
||||
public double DrainageFlowNormalizedValue => ChannelNormalizedValue("静脉引流流量");
|
||||
public double ReturnFlowNormalizedValue => ChannelNormalizedValue("动脉回输流量");
|
||||
public string FilteredRequirementSummary => $"{FilteredRequirements.Count()} / {Requirements.Count} 条";
|
||||
public bool HasRequirementSearchText => !string.IsNullOrWhiteSpace(RequirementSearchText);
|
||||
public int RealtimeMonitorCount => Requirements.Count(requirement => requirement.CaptureMode == RequirementCaptureMode.RealtimeMonitor);
|
||||
public int RealtimeAssistCount => Requirements.Count(requirement => requirement.CaptureMode == RequirementCaptureMode.RealtimeAssist);
|
||||
public int ManualEntryCount => Requirements.Count(requirement => requirement.CaptureMode == RequirementCaptureMode.ManualEntry);
|
||||
public string SelectedRequirementCaptureModeText => SelectedRequirement?.CaptureModeText ?? "未选择";
|
||||
public string SelectedRequirementMeasurementSource => SelectedRequirement?.MeasurementSource ?? "-";
|
||||
public bool SelectedRequirementUsesRealtimeValue => SelectedRequirement?.CaptureMode == RequirementCaptureMode.RealtimeMonitor;
|
||||
public string RealtimeMeasurementHint => SelectedRequirementUsesRealtimeValue
|
||||
? "当前条款取实时工况计算值,不再手动录入。"
|
||||
: SelectedRequirement?.ManualEntryHint ?? "当前条款保持人工录入。";
|
||||
public string SelectedRequirementLiveDisplay => BuildSelectedRequirementLiveDisplay();
|
||||
public string SelectedRequirementLiveHint => SelectedRequirement?.LiveDisplayHint ?? "当前条款无实时映射。";
|
||||
public string FilteredItemSummary => $"{FilteredItems.Count()} / {InspectionItems.Count} 项";
|
||||
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 string SelectedItemCaptureModeText => SelectedItem?.CaptureModeText ?? "未选择";
|
||||
public string SelectedItemMeasurementSource => SelectedItem?.MeasurementSource ?? "-";
|
||||
public bool SelectedItemUsesRealtimeValue => SelectedItem?.CaptureMode == InspectionItemCaptureMode.RealtimeMonitor;
|
||||
public string RealtimeMeasurementHint => SelectedItemUsesRealtimeValue
|
||||
? "当前项目使用实时数据自动判定,无需手动填写。"
|
||||
: SelectedItem?.ManualEntryHint ?? "当前项目需要人工填写结果。";
|
||||
public string SelectedItemLiveDisplay => BuildSelectedItemLiveDisplay();
|
||||
public string SelectedItemLiveHint => SelectedItem?.LiveDisplayHint ?? "当前项目无实时映射。";
|
||||
public string NegativeAssistPressureDisplay => $"{ChannelValue("负压辅助引流"):F1} kPa";
|
||||
public string TemperatureDisplay => $"{ChannelValue("模拟血液温度"):F1} °C";
|
||||
public string FreeHemoglobinDisplay => $"{ChannelValue("游离血红蛋白"):F3} g/L";
|
||||
@@ -155,57 +155,57 @@ public partial class MainViewModel : ObservableObject
|
||||
|
||||
partial void OnComplianceRateChanged(double value) => OnPropertyChanged(nameof(ComplianceDisplay));
|
||||
partial void OnDeltaPressureChanged(double value) => OnPropertyChanged(nameof(DeltaPressureDisplay));
|
||||
partial void OnExperimentCompletedChanged(bool value) => OnPropertyChanged(nameof(ExportStateText));
|
||||
partial void OnRequirementSearchTextChanged(string value)
|
||||
partial void OnDetectionCompletedChanged(bool value) => OnPropertyChanged(nameof(ExportStateText));
|
||||
partial void OnItemSearchTextChanged(string value)
|
||||
{
|
||||
OnPropertyChanged(nameof(FilteredRequirements));
|
||||
OnPropertyChanged(nameof(FilteredRequirementSummary));
|
||||
OnPropertyChanged(nameof(HasFilteredRequirements));
|
||||
OnPropertyChanged(nameof(HasRequirementSearchText));
|
||||
OnPropertyChanged(nameof(FilteredItems));
|
||||
OnPropertyChanged(nameof(FilteredItemSummary));
|
||||
OnPropertyChanged(nameof(HasFilteredItems));
|
||||
OnPropertyChanged(nameof(HasItemSearchText));
|
||||
|
||||
var filtered = FilteredRequirements.ToList();
|
||||
var filtered = FilteredItems.ToList();
|
||||
if (filtered.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SelectedRequirement is null || !filtered.Contains(SelectedRequirement))
|
||||
if (SelectedItem is null || !filtered.Contains(SelectedItem))
|
||||
{
|
||||
SelectedRequirement = filtered[0];
|
||||
SelectedItem = filtered[0];
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnSelectedRequirementChanged(TestRequirement? value)
|
||||
partial void OnSelectedItemChanged(InspectionItem? value)
|
||||
{
|
||||
OnPropertyChanged(nameof(SelectedRequirementTitle));
|
||||
OnPropertyChanged(nameof(SelectedRequirementStatusText));
|
||||
OnPropertyChanged(nameof(SelectedRequirementCaptureModeText));
|
||||
OnPropertyChanged(nameof(SelectedRequirementMeasurementSource));
|
||||
OnPropertyChanged(nameof(SelectedRequirementUsesRealtimeValue));
|
||||
OnPropertyChanged(nameof(SelectedItemTitle));
|
||||
OnPropertyChanged(nameof(SelectedItemStatusText));
|
||||
OnPropertyChanged(nameof(SelectedItemCaptureModeText));
|
||||
OnPropertyChanged(nameof(SelectedItemMeasurementSource));
|
||||
OnPropertyChanged(nameof(SelectedItemUsesRealtimeValue));
|
||||
OnPropertyChanged(nameof(RealtimeMeasurementHint));
|
||||
OnPropertyChanged(nameof(SelectedRequirementLiveDisplay));
|
||||
OnPropertyChanged(nameof(SelectedRequirementLiveHint));
|
||||
OnPropertyChanged(nameof(SelectedItemLiveDisplay));
|
||||
OnPropertyChanged(nameof(SelectedItemLiveHint));
|
||||
if (value is not null)
|
||||
{
|
||||
LoadSelectedRequirementDraft(value);
|
||||
LoadSelectedItemDraft(value);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SelectRequirement(TestRequirement? requirement)
|
||||
private void SelectItem(InspectionItem? item)
|
||||
{
|
||||
if (requirement is null)
|
||||
if (item is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SelectedRequirement = requirement;
|
||||
SelectedItem = item;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ClearRequirementSearch()
|
||||
private void ClearItemSearch()
|
||||
{
|
||||
RequirementSearchText = string.Empty;
|
||||
ItemSearchText = string.Empty;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -213,7 +213,7 @@ public partial class MainViewModel : ObservableObject
|
||||
{
|
||||
AcquisitionRunning = !AcquisitionRunning;
|
||||
DeviceStatus = AcquisitionRunning ? "Modbus 在线" : "采集暂停";
|
||||
LatestAction = AcquisitionRunning ? "继续采集实时工况,供试验员参考。" : "已暂停实时采集。";
|
||||
LatestAction = AcquisitionRunning ? "继续采集实时数据,供检测参考。" : "已暂停实时采集。";
|
||||
|
||||
if (AcquisitionRunning)
|
||||
{
|
||||
@@ -228,95 +228,95 @@ public partial class MainViewModel : ObservableObject
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SelectPreviousRequirement()
|
||||
private void SelectPreviousItem()
|
||||
{
|
||||
var scope = ActiveRequirementScope();
|
||||
if (SelectedRequirement is null)
|
||||
var scope = ActiveItemScope();
|
||||
if (SelectedItem is null)
|
||||
{
|
||||
SelectedRequirement = scope.FirstOrDefault();
|
||||
SelectedItem = scope.FirstOrDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
var index = scope.IndexOf(SelectedRequirement);
|
||||
var index = scope.IndexOf(SelectedItem);
|
||||
if (index > 0)
|
||||
{
|
||||
SelectedRequirement = scope[index - 1];
|
||||
SelectedItem = scope[index - 1];
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SelectNextRequirement()
|
||||
private void SelectNextItem()
|
||||
{
|
||||
var scope = ActiveRequirementScope();
|
||||
if (SelectedRequirement is null)
|
||||
var scope = ActiveItemScope();
|
||||
if (SelectedItem is null)
|
||||
{
|
||||
SelectedRequirement = scope.FirstOrDefault();
|
||||
SelectedItem = scope.FirstOrDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
var index = scope.IndexOf(SelectedRequirement);
|
||||
var index = scope.IndexOf(SelectedItem);
|
||||
if (index >= 0 && index < scope.Count - 1)
|
||||
{
|
||||
SelectedRequirement = scope[index + 1];
|
||||
SelectedItem = scope[index + 1];
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ApplyManualResult()
|
||||
private void ApplyResult()
|
||||
{
|
||||
if (SelectedRequirement is null)
|
||||
if (SelectedItem is null)
|
||||
{
|
||||
LatestAction = "请先选择条款项。";
|
||||
LatestAction = "请先选择项目。";
|
||||
return;
|
||||
}
|
||||
|
||||
if (SelectedRequirementUsesRealtimeValue)
|
||||
if (SelectedItemUsesRealtimeValue)
|
||||
{
|
||||
LatestAction = "当前条款已改为实时工况计算值,无需手动录入。";
|
||||
LatestAction = "当前项目使用实时数据自动判定,无需手动填写。";
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ManualMeasuredValue))
|
||||
if (string.IsNullOrWhiteSpace(ResultValue))
|
||||
{
|
||||
LatestAction = "请先输入测量结果或人工结论。";
|
||||
LatestAction = "请先填写检测结果或判定结论。";
|
||||
return;
|
||||
}
|
||||
|
||||
SelectedRequirement.Measured = ManualMeasuredValue.Trim();
|
||||
SelectedRequirement.Notes = ManualNote.Trim();
|
||||
SelectedRequirement.RecordedBy = string.IsNullOrWhiteSpace(ManualOperator) ? OperatorName : ManualOperator.Trim();
|
||||
SelectedRequirement.RecordedAt = DateTime.Now;
|
||||
SelectedRequirement.Status = SelectedManualStatusText switch
|
||||
SelectedItem.Measured = ResultValue.Trim();
|
||||
SelectedItem.Notes = ResultNote.Trim();
|
||||
SelectedItem.RecordedBy = string.IsNullOrWhiteSpace(ResultOperator) ? OperatorName : ResultOperator.Trim();
|
||||
SelectedItem.RecordedAt = DateTime.Now;
|
||||
SelectedItem.Status = SelectedResultStatusText switch
|
||||
{
|
||||
"待检" => RequirementStatus.Pending,
|
||||
"合格" => RequirementStatus.Qualified,
|
||||
"预警" => RequirementStatus.Warning,
|
||||
"不合格" => RequirementStatus.Critical,
|
||||
_ => RequirementStatus.Pending
|
||||
"待检" => InspectionItemStatus.Pending,
|
||||
"合格" => InspectionItemStatus.Qualified,
|
||||
"预警" => InspectionItemStatus.Warning,
|
||||
"不合格" => InspectionItemStatus.Critical,
|
||||
_ => InspectionItemStatus.Pending
|
||||
};
|
||||
|
||||
LatestAction = $"已记录 {SelectedRequirement.Item} 的人工测试结果。";
|
||||
LatestAction = $"已填写 {SelectedItem.Item} 的检测结果。";
|
||||
TraceEvents.Insert(0, new TraceEvent
|
||||
{
|
||||
Timestamp = DateTime.Now,
|
||||
Stage = "人工录入",
|
||||
Detail = $"{SelectedRequirement.Item}: {SelectedRequirement.Measured}",
|
||||
Operator = SelectedRequirement.RecordedBy
|
||||
Stage = "结果填写",
|
||||
Detail = $"{SelectedItem.Item}: {SelectedItem.Measured}",
|
||||
Operator = SelectedItem.RecordedBy
|
||||
});
|
||||
|
||||
RefreshComputedState();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CompleteExperiment()
|
||||
private void CompleteDetection()
|
||||
{
|
||||
ExperimentCompleted = true;
|
||||
CurrentStage = "实验结束";
|
||||
DetectionCompleted = true;
|
||||
CurrentStage = "检测完成";
|
||||
AcquisitionRunning = false;
|
||||
_timer.Stop();
|
||||
DeviceStatus = "采集停止";
|
||||
LatestAction = PendingCount == 0 ? "实验结束,全部条款已录入,可导出 PDF 报表。" : $"实验结束,但仍有 {PendingCount} 项待检,请确认后导出 PDF 报表。";
|
||||
TraceEvents.Insert(0, NewTrace("实验结束", "实验员结束本次检测任务"));
|
||||
LatestAction = PendingCount == 0 ? "检测完成,全部项目已填写,可导出 PDF 报表。" : $"检测完成,但仍有 {PendingCount} 项待处理,请确认后导出 PDF 报表。";
|
||||
TraceEvents.Insert(0, NewTrace("检测完成", "检测员结束本次检测任务"));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -339,8 +339,8 @@ public partial class MainViewModel : ObservableObject
|
||||
{
|
||||
var outputDirectory = AppContext.BaseDirectory;
|
||||
var timestamp = DateTime.Now.ToString("yyyyMMdd-HHmmss");
|
||||
var htmlPath = Path.Combine(outputDirectory, $"实验报表-{BatchNumber}-{timestamp}.html");
|
||||
var pdfPath = Path.Combine(outputDirectory, $"实验报表-{BatchNumber}-{timestamp}.pdf");
|
||||
var htmlPath = Path.Combine(outputDirectory, $"检测报表-{BatchNumber}-{timestamp}.html");
|
||||
var pdfPath = Path.Combine(outputDirectory, $"检测报表-{BatchNumber}-{timestamp}.pdf");
|
||||
|
||||
File.WriteAllText(htmlPath, BuildHtmlReport(), Encoding.UTF8);
|
||||
|
||||
@@ -416,43 +416,45 @@ public partial class MainViewModel : ObservableObject
|
||||
OnPropertyChanged(nameof(ReturnFlowNormalizedValue));
|
||||
OnPropertyChanged(nameof(FlowSensorChannels));
|
||||
OnPropertyChanged(nameof(OtherChannels));
|
||||
OnPropertyChanged(nameof(SelectedRequirementLiveDisplay));
|
||||
OnPropertyChanged(nameof(SelectedRequirementLiveHint));
|
||||
OnPropertyChanged(nameof(SelectedItemLiveDisplay));
|
||||
OnPropertyChanged(nameof(SelectedItemLiveHint));
|
||||
|
||||
SyncRealtimeRequirements();
|
||||
SyncRealtimeItems();
|
||||
}
|
||||
|
||||
private void RefreshComputedState()
|
||||
{
|
||||
QualifiedCount = Requirements.Count(r => r.Status == RequirementStatus.Qualified);
|
||||
WarningCount = Requirements.Count(r => r.Status == RequirementStatus.Warning || r.Status == RequirementStatus.Critical);
|
||||
PendingCount = Requirements.Count(r => r.Status == RequirementStatus.Pending);
|
||||
ComplianceRate = Requirements.Count == 0 ? 0 : QualifiedCount * 100d / Requirements.Count;
|
||||
QualifiedCount = InspectionItems.Count(r => r.Status == InspectionItemStatus.Qualified);
|
||||
WarningCount = InspectionItems.Count(r => r.Status == InspectionItemStatus.Warning || r.Status == InspectionItemStatus.Critical);
|
||||
PendingCount = InspectionItems.Count(r => r.Status == InspectionItemStatus.Pending);
|
||||
ComplianceRate = InspectionItems.Count == 0 ? 0 : QualifiedCount * 100d / InspectionItems.Count;
|
||||
}
|
||||
|
||||
private void LoadSelectedRequirementDraft(TestRequirement requirement)
|
||||
private void LoadSelectedItemDraft(InspectionItem item)
|
||||
{
|
||||
ManualMeasuredValue = SelectedRequirementUsesRealtimeValue
|
||||
? requirement.Measured
|
||||
: requirement.Measured == "待检测" ? string.Empty : requirement.Measured;
|
||||
ManualNote = requirement.Notes;
|
||||
ManualOperator = string.IsNullOrWhiteSpace(requirement.RecordedBy) ? OperatorName : requirement.RecordedBy;
|
||||
SelectedManualStatusText = requirement.Status switch
|
||||
ResultValue = SelectedItemUsesRealtimeValue
|
||||
? item.Measured
|
||||
: item.Measured == "待检测" ? string.Empty : item.Measured;
|
||||
ResultNote = item.Notes;
|
||||
ResultOperator = string.IsNullOrWhiteSpace(item.RecordedBy) ? OperatorName : item.RecordedBy;
|
||||
SelectedResultStatusText = item.Status switch
|
||||
{
|
||||
RequirementStatus.Warning => "预警",
|
||||
RequirementStatus.Critical => "不合格",
|
||||
RequirementStatus.Pending => "待检",
|
||||
InspectionItemStatus.Warning => "预警",
|
||||
InspectionItemStatus.Critical => "不合格",
|
||||
InspectionItemStatus.Pending => "待检",
|
||||
_ => "合格"
|
||||
};
|
||||
}
|
||||
|
||||
private string BuildHtmlReport()
|
||||
{
|
||||
var rows = string.Join(Environment.NewLine, Requirements.Select(r => $@"
|
||||
var rows = string.Join(Environment.NewLine, InspectionItems.Select(r => $@"
|
||||
<tr>
|
||||
<td>{Html(r.Clause)}</td>
|
||||
<td>{Html(r.Category)}</td>
|
||||
<td>{Html(r.Item)}</td>
|
||||
<td>{Html(r.AcceptanceCriteria)}</td>
|
||||
<td>{Html(r.TestMethod)}</td>
|
||||
<td>{Html(r.RecordFocus)}</td>
|
||||
<td>{Html(r.Measured)}</td>
|
||||
<td>{Html(r.StatusText)}</td>
|
||||
<td>{Html(r.RecordedBy)}</td>
|
||||
@@ -493,10 +495,10 @@ ul {{ padding-left: 20px; }}
|
||||
<div><strong>合格率:</strong>{Html(ComplianceDisplay)}</div>
|
||||
<div><strong>压差:</strong>{Html(DeltaPressureDisplay)}</div>
|
||||
</div>
|
||||
<div class='card'><strong>实验结论:</strong>{Html(ExperimentSummary)}</div>
|
||||
<h2>条款记录</h2>
|
||||
<div class='card'><strong>检测结论:</strong>{Html(DetectionSummary)}</div>
|
||||
<h2>项目记录</h2>
|
||||
<table>
|
||||
<thead><tr><th>条款</th><th>类别</th><th>项目</th><th>结果</th><th>状态</th><th>记录人</th><th>记录时间</th><th>备注</th></tr></thead>
|
||||
<thead><tr><th>类别</th><th>项目</th><th>判定要求</th><th>检测方法</th><th>记录要点</th><th>结果</th><th>状态</th><th>记录人</th><th>记录时间</th><th>备注</th></tr></thead>
|
||||
<tbody>{rows}</tbody>
|
||||
</table>
|
||||
<h2>追溯事件</h2>
|
||||
@@ -537,72 +539,72 @@ ul {{ padding-left: 20px; }}
|
||||
Timestamp = DateTime.Now,
|
||||
Stage = stage,
|
||||
Detail = detail,
|
||||
Operator = string.IsNullOrWhiteSpace(ManualOperator) ? OperatorName : ManualOperator
|
||||
Operator = string.IsNullOrWhiteSpace(ResultOperator) ? OperatorName : ResultOperator
|
||||
};
|
||||
|
||||
private void SyncRealtimeRequirements()
|
||||
private void SyncRealtimeItems()
|
||||
{
|
||||
var pressureRequirement = Requirements.FirstOrDefault(requirement => requirement.Clause == "4.3.1");
|
||||
if (pressureRequirement is not null)
|
||||
var pressureItem = InspectionItems.FirstOrDefault(item => item.Clause == "4.3.1");
|
||||
if (pressureItem is not null)
|
||||
{
|
||||
var pressureStatus = DeltaPressure switch
|
||||
{
|
||||
<= 20 => RequirementStatus.Qualified,
|
||||
<= 24 => RequirementStatus.Warning,
|
||||
_ => RequirementStatus.Critical
|
||||
<= 20 => InspectionItemStatus.Qualified,
|
||||
<= 24 => InspectionItemStatus.Warning,
|
||||
_ => InspectionItemStatus.Critical
|
||||
};
|
||||
|
||||
pressureRequirement.Measured = $"实时压差 {DeltaPressure:F1} mmHg";
|
||||
pressureRequirement.Notes =
|
||||
pressureItem.Measured = $"实时压差 {DeltaPressure:F1} mmHg";
|
||||
pressureItem.Notes =
|
||||
$"入口 {ChannelValue("入口压力"):F1} mmHg,出口 {ChannelValue("出口压力"):F1} mmHg,按额定流量点连续监控。";
|
||||
pressureRequirement.RecordedBy = "实时工况";
|
||||
pressureRequirement.RecordedAt = DateTime.Now;
|
||||
pressureRequirement.Status = pressureStatus;
|
||||
pressureItem.RecordedBy = "实时数据";
|
||||
pressureItem.RecordedAt = DateTime.Now;
|
||||
pressureItem.Status = pressureStatus;
|
||||
}
|
||||
|
||||
var recirculationRequirement = Requirements.FirstOrDefault(requirement => requirement.Clause == "4.3.3");
|
||||
if (recirculationRequirement is null)
|
||||
var recirculationItem = InspectionItems.FirstOrDefault(item => item.Clause == "4.3.3");
|
||||
if (recirculationItem is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var status = RecirculationRate switch
|
||||
{
|
||||
<= 8 => RequirementStatus.Qualified,
|
||||
<= 12 => RequirementStatus.Warning,
|
||||
_ => RequirementStatus.Critical
|
||||
<= 8 => InspectionItemStatus.Qualified,
|
||||
<= 12 => InspectionItemStatus.Warning,
|
||||
_ => InspectionItemStatus.Critical
|
||||
};
|
||||
|
||||
recirculationRequirement.Measured =
|
||||
recirculationItem.Measured =
|
||||
$"实时计算值 {RecirculationRate:F1}% (回输 {ReturnFlow:F2} / 引流 {DrainageFlow:F2} L/min)";
|
||||
recirculationRequirement.Notes =
|
||||
recirculationItem.Notes =
|
||||
$"由 3 路流量传感器实时计算;主泵 {PumpFlow:F2} L/min,流量差 {Math.Abs(PumpFlow - ReturnFlow):F2} L/min。";
|
||||
recirculationRequirement.RecordedBy = "实时工况";
|
||||
recirculationRequirement.RecordedAt = DateTime.Now;
|
||||
recirculationRequirement.Status = status;
|
||||
recirculationItem.RecordedBy = "实时数据";
|
||||
recirculationItem.RecordedAt = DateTime.Now;
|
||||
recirculationItem.Status = status;
|
||||
|
||||
if (SelectedRequirement == recirculationRequirement)
|
||||
if (SelectedItem == recirculationItem)
|
||||
{
|
||||
ManualMeasuredValue = recirculationRequirement.Measured;
|
||||
ManualNote = recirculationRequirement.Notes;
|
||||
SelectedManualStatusText = recirculationRequirement.Status switch
|
||||
ResultValue = recirculationItem.Measured;
|
||||
ResultNote = recirculationItem.Notes;
|
||||
SelectedResultStatusText = recirculationItem.Status switch
|
||||
{
|
||||
RequirementStatus.Pending => "待检",
|
||||
RequirementStatus.Warning => "预警",
|
||||
RequirementStatus.Critical => "不合格",
|
||||
InspectionItemStatus.Pending => "待检",
|
||||
InspectionItemStatus.Warning => "预警",
|
||||
InspectionItemStatus.Critical => "不合格",
|
||||
_ => "合格"
|
||||
};
|
||||
}
|
||||
|
||||
if (pressureRequirement is not null && SelectedRequirement == pressureRequirement)
|
||||
if (pressureItem is not null && SelectedItem == pressureItem)
|
||||
{
|
||||
ManualMeasuredValue = pressureRequirement.Measured;
|
||||
ManualNote = pressureRequirement.Notes;
|
||||
SelectedManualStatusText = pressureRequirement.Status switch
|
||||
ResultValue = pressureItem.Measured;
|
||||
ResultNote = pressureItem.Notes;
|
||||
SelectedResultStatusText = pressureItem.Status switch
|
||||
{
|
||||
RequirementStatus.Pending => "待检",
|
||||
RequirementStatus.Warning => "预警",
|
||||
RequirementStatus.Critical => "不合格",
|
||||
InspectionItemStatus.Pending => "待检",
|
||||
InspectionItemStatus.Warning => "预警",
|
||||
InspectionItemStatus.Critical => "不合格",
|
||||
_ => "合格"
|
||||
};
|
||||
}
|
||||
@@ -610,21 +612,21 @@ ul {{ padding-left: 20px; }}
|
||||
|
||||
private double ChannelValue(string name) => Channels.First(channel => channel.Name == name).Value;
|
||||
private double ChannelNormalizedValue(string name) => Channels.First(channel => channel.Name == name).NormalizedValue;
|
||||
private List<TestRequirement> ActiveRequirementScope() => FilteredRequirements.ToList();
|
||||
private List<InspectionItem> ActiveItemScope() => FilteredItems.ToList();
|
||||
|
||||
private bool MatchesRequirementSearch(TestRequirement requirement)
|
||||
private bool MatchesItemSearch(InspectionItem item)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(RequirementSearchText))
|
||||
if (string.IsNullOrWhiteSpace(ItemSearchText))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var keyword = RequirementSearchText.Trim();
|
||||
return MatchesKeyword(requirement.Clause, keyword)
|
||||
|| MatchesKeyword(requirement.Item, keyword)
|
||||
|| MatchesKeyword(requirement.Category, keyword)
|
||||
|| MatchesKeyword(requirement.Requirement, keyword)
|
||||
|| MatchesKeyword(requirement.Method, keyword);
|
||||
var keyword = ItemSearchText.Trim();
|
||||
return MatchesKeyword(item.Clause, keyword)
|
||||
|| MatchesKeyword(item.Item, keyword)
|
||||
|| MatchesKeyword(item.Category, keyword)
|
||||
|| MatchesKeyword(item.AcceptanceCriteria, keyword)
|
||||
|| MatchesKeyword(item.TestMethod, keyword);
|
||||
}
|
||||
|
||||
private static bool MatchesKeyword(string source, string keyword)
|
||||
@@ -653,21 +655,21 @@ ul {{ padding-left: 20px; }}
|
||||
private static bool IsFlowSensorChannel(DeviceChannel channel) =>
|
||||
channel.Name is "主泵流量" or "静脉引流流量" or "动脉回输流量";
|
||||
|
||||
private string BuildSelectedRequirementLiveDisplay()
|
||||
private string BuildSelectedItemLiveDisplay()
|
||||
{
|
||||
if (SelectedRequirement is null)
|
||||
if (SelectedItem is null)
|
||||
{
|
||||
return "未选择条款";
|
||||
return "未选择项目";
|
||||
}
|
||||
|
||||
return (SelectedRequirement.Clause, SelectedRequirement.Item) switch
|
||||
return (SelectedItem.Clause, SelectedItem.Item) switch
|
||||
{
|
||||
("4.3.1", _) => $"入口 {ChannelValue("入口压力"):F1} mmHg / 出口 {ChannelValue("出口压力"):F1} mmHg / 压差 {DeltaPressure:F1} mmHg",
|
||||
("4.3.2", _) => $"负压 {ChannelValue("负压辅助引流"):F1} kPa / 压差 {DeltaPressure:F1} mmHg / 流量差 {Math.Abs(PumpFlow - ReturnFlow):F2} L/min",
|
||||
("4.3.3", _) => $"再循环率 {RecirculationRate:F1}% / 引流 {DrainageFlow:F2} / 回输 {ReturnFlow:F2} L/min",
|
||||
("4.3.4", "血细胞破坏") => $"游离血红蛋白 {ChannelValue("游离血红蛋白"):F3} g/L / 温度 {ChannelValue("模拟血液温度"):F1} °C",
|
||||
("4.3.4", "血小板/白细胞减少率") => $"白细胞减少率 {ChannelValue("白细胞减少率"):F1}% / 温度 {ChannelValue("模拟血液温度"):F1} °C",
|
||||
_ => "当前条款无实时信号,按试验原始记录手动录入。"
|
||||
_ => "当前项目无实时信号,按检测原始记录手动填写。"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user