更新20260606
This commit is contained in:
@@ -1,14 +1,96 @@
|
|||||||
using System.Configuration;
|
using System.IO;
|
||||||
using System.Data;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Events;
|
||||||
|
|
||||||
|
namespace DentistryHandpieces;
|
||||||
|
|
||||||
namespace DentistryHandpieces
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for App.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class App : Application
|
public partial class App : Application
|
||||||
{
|
{
|
||||||
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
|
{
|
||||||
|
ConfigureLogging();
|
||||||
|
DispatcherUnhandledException += OnDispatcherUnhandledException;
|
||||||
|
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
|
||||||
|
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
|
||||||
|
|
||||||
|
Log.Information(
|
||||||
|
"应用启动,版本 {Version},系统 {OperatingSystem}",
|
||||||
|
typeof(App).Assembly.GetName().Version?.ToString() ?? "unknown",
|
||||||
|
Environment.OSVersion.VersionString);
|
||||||
|
|
||||||
|
base.OnStartup(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnExit(ExitEventArgs e)
|
||||||
|
{
|
||||||
|
Log.Information("应用退出,退出代码 {ExitCode}", e.ApplicationExitCode);
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
base.OnExit(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ConfigureLogging()
|
||||||
|
{
|
||||||
|
string logDirectory = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||||
|
"DentistryHandpieces",
|
||||||
|
"Logs");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CreateLogger(logDirectory);
|
||||||
|
Log.Information("日志系统初始化完成,目录 {LogDirectory}", logDirectory);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
string fallbackDirectory = Path.Combine(Path.GetTempPath(), "DentistryHandpieces", "Logs");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CreateLogger(fallbackDirectory);
|
||||||
|
Log.Warning(ex, "主日志目录初始化失败,已切换到临时目录 {LogDirectory}", fallbackDirectory);
|
||||||
|
}
|
||||||
|
catch (Exception fallbackException)
|
||||||
|
{
|
||||||
|
Log.Logger = new LoggerConfiguration().CreateLogger();
|
||||||
|
System.Diagnostics.Debug.WriteLine($"Serilog initialization failed: {ex}; fallback failed: {fallbackException}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CreateLogger(string logDirectory)
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(logDirectory);
|
||||||
|
Log.Logger = new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Information()
|
||||||
|
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.Enrich.WithProperty("Application", "DentistryHandpieces")
|
||||||
|
.WriteTo.File(
|
||||||
|
Path.Combine(logDirectory, "app-.log"),
|
||||||
|
rollingInterval: RollingInterval.Day,
|
||||||
|
retainedFileCountLimit: 30,
|
||||||
|
fileSizeLimitBytes: 20 * 1024 * 1024,
|
||||||
|
rollOnFileSizeLimit: true,
|
||||||
|
shared: true,
|
||||||
|
flushToDiskInterval: TimeSpan.FromSeconds(1),
|
||||||
|
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
|
||||||
|
.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||||
|
{
|
||||||
|
Log.Fatal(e.Exception, "UI线程发生未处理异常");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnUnhandledException(object? sender, UnhandledExceptionEventArgs e)
|
||||||
|
{
|
||||||
|
Log.Fatal(e.ExceptionObject as Exception, "应用域发生未处理异常,IsTerminating={IsTerminating}", e.IsTerminating);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
|
||||||
|
{
|
||||||
|
Log.Error(e.Exception, "后台任务发生未观察异常");
|
||||||
|
e.SetObserved();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,9 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ClosedXML" Version="0.105.0" />
|
<PackageReference Include="ClosedXML" Version="0.105.0" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.7" />
|
|
||||||
<PackageReference Include="NModbusAsync" Version="3.0.2" />
|
<PackageReference Include="NModbusAsync" Version="3.0.2" />
|
||||||
|
<PackageReference Include="Serilog" Version="4.3.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ public sealed class WpfFileDialogService : IFileDialogService
|
|||||||
{
|
{
|
||||||
var dialog = new SaveFileDialog
|
var dialog = new SaveFileDialog
|
||||||
{
|
{
|
||||||
Title = "导出 Excel",
|
Title = "导出报表",
|
||||||
FileName = $"牙科手机验收记录_{createdAt:yyyyMMddHHmmss}.xlsx",
|
FileName = $"牙科手机测试报表_{createdAt:yyyyMMddHHmmss}.xlsx",
|
||||||
Filter = "Excel 工作簿 (*.xlsx)|*.xlsx",
|
Filter = "Excel 工作簿 (*.xlsx)|*.xlsx",
|
||||||
DefaultExt = ".xlsx",
|
DefaultExt = ".xlsx",
|
||||||
AddExtension = true,
|
AddExtension = true,
|
||||||
|
|||||||
@@ -301,10 +301,60 @@
|
|||||||
<Setter Property="CornerRadius" Value="5" />
|
<Setter Property="CornerRadius" Value="5" />
|
||||||
<Setter Property="Padding" Value="12,9" />
|
<Setter Property="Padding" Value="12,9" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="DataStatusBadge" TargetType="Border">
|
||||||
|
<Setter Property="Background" Value="#ECFDF5" />
|
||||||
|
<Setter Property="BorderBrush" Value="#A7DCC8" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
<Setter Property="CornerRadius" Value="12" />
|
||||||
|
<Setter Property="Padding" Value="12,5" />
|
||||||
|
</Style>
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<DockPanel LastChildFill="True">
|
<DockPanel LastChildFill="True">
|
||||||
|
<Border DockPanel.Dock="Top"
|
||||||
|
Style="{StaticResource PanelBorder}"
|
||||||
|
BorderBrush="#AFC8D5"
|
||||||
|
Background="#F8FBFD"
|
||||||
|
Margin="0,0,0,10">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="190" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="测试数据与报表"
|
||||||
|
FontSize="19"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Foreground="#17384D" />
|
||||||
|
<TextBlock x:Name="StatusText"
|
||||||
|
Text="{Binding StatusText}"
|
||||||
|
FontSize="16"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Margin="0,4,0,0"
|
||||||
|
Foreground="#52616F" />
|
||||||
|
<Border Style="{StaticResource DataStatusBadge}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Margin="0,8,0,0">
|
||||||
|
<TextBlock Text="{Binding DataCaptureStatusText}"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="#16624F" />
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Button Grid.Column="1"
|
||||||
|
Content="导出完整报表"
|
||||||
|
Command="{Binding ExportCommand}"
|
||||||
|
Style="{StaticResource StartButtonStyle}"
|
||||||
|
MinHeight="58"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="12,0,0,0" />
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<TabControl x:Name="MainTabs">
|
<TabControl x:Name="MainTabs">
|
||||||
<TabItem Header="轴向位移动量测试">
|
<TabItem Header="轴向位移动量测试">
|
||||||
<Grid>
|
<Grid>
|
||||||
@@ -1168,56 +1218,6 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
<TabItem Header="记录/导出">
|
|
||||||
<Grid Margin="0,14,0,0">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<Border Style="{StaticResource PanelBorder}">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="150" />
|
|
||||||
<ColumnDefinition Width="150" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<TextBlock x:Name="StatusText"
|
|
||||||
Text="{Binding StatusText}"
|
|
||||||
FontSize="20"
|
|
||||||
FontWeight="SemiBold"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Foreground="#52616F" />
|
|
||||||
<Button Grid.Column="1"
|
|
||||||
Content="保存记录"
|
|
||||||
Command="{Binding SaveRecordCommand}"
|
|
||||||
Margin="12,0,6,0" />
|
|
||||||
<Button Grid.Column="2"
|
|
||||||
Content="导出 Excel"
|
|
||||||
Command="{Binding ExportCommand}"
|
|
||||||
Margin="6,0,0,0" />
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<DataGrid Grid.Row="1"
|
|
||||||
x:Name="RecordsGrid"
|
|
||||||
ItemsSource="{Binding Records}"
|
|
||||||
Margin="0,12,0,0"
|
|
||||||
AutoGenerateColumns="False"
|
|
||||||
IsReadOnly="True"
|
|
||||||
CanUserAddRows="False"
|
|
||||||
HeadersVisibility="Column"
|
|
||||||
RowHeight="44"
|
|
||||||
FontSize="15">
|
|
||||||
<DataGrid.Columns>
|
|
||||||
<DataGridTextColumn Header="时间" Binding="{Binding CreatedAtText}" Width="180" />
|
|
||||||
<DataGridTextColumn Header="结果" Binding="{Binding OverallResult}" Width="90" />
|
|
||||||
<DataGridTextColumn Header="Excel文件" Binding="{Binding ExportPathText}" Width="*" />
|
|
||||||
</DataGrid.Columns>
|
|
||||||
</DataGrid>
|
|
||||||
</Grid>
|
|
||||||
</TabItem>
|
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System.Windows;
|
|||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace DentistryHandpieces;
|
namespace DentistryHandpieces;
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ public partial class MainWindow : Window
|
|||||||
};
|
};
|
||||||
_hiddenSettingsPressTimer.Tick += HiddenSettingsPressTimer_Tick;
|
_hiddenSettingsPressTimer.Tick += HiddenSettingsPressTimer_Tick;
|
||||||
Deactivated += (_, _) => ReleaseAllManualMotionTargetsAsync();
|
Deactivated += (_, _) => ReleaseAllManualMotionTargetsAsync();
|
||||||
|
Log.Information("主窗口创建完成");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HiddenSettingsHotspot_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
private void HiddenSettingsHotspot_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
@@ -107,6 +109,7 @@ public partial class MainWindow : Window
|
|||||||
|
|
||||||
if (DataContext is MainWindowViewModel viewModel)
|
if (DataContext is MainWindowViewModel viewModel)
|
||||||
{
|
{
|
||||||
|
Log.Information("打开隐藏速度设置窗口");
|
||||||
var window = new HiddenSpeedSettingsWindow(_plcService, viewModel.GetPlcConnectionConfig())
|
var window = new HiddenSpeedSettingsWindow(_plcService, viewModel.GetPlcConnectionConfig())
|
||||||
{
|
{
|
||||||
Owner = this
|
Owner = this
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace DentistryHandpieces;
|
namespace DentistryHandpieces;
|
||||||
|
|
||||||
@@ -36,15 +37,26 @@ public sealed class ModbusTcpPlcCoilService : IPlcCoilService, IPlcRegisterServi
|
|||||||
private ushort _transactionId;
|
private ushort _transactionId;
|
||||||
|
|
||||||
public async Task PulseCoilAsync(PlcConnectionConfig config, ushort coilAddress, CancellationToken cancellationToken = default)
|
public async Task PulseCoilAsync(PlcConnectionConfig config, ushort coilAddress, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
await ExecuteWriteAsync(
|
||||||
|
config,
|
||||||
|
$"M{coilAddress}",
|
||||||
|
$"脉冲 {config.PulseMilliseconds} ms",
|
||||||
|
async () =>
|
||||||
{
|
{
|
||||||
await WriteSingleCoilAsync(config, coilAddress, true, cancellationToken);
|
await WriteSingleCoilAsync(config, coilAddress, true, cancellationToken);
|
||||||
await Task.Delay(config.PulseMilliseconds, cancellationToken);
|
await Task.Delay(config.PulseMilliseconds, cancellationToken);
|
||||||
await WriteSingleCoilAsync(config, coilAddress, false, cancellationToken);
|
await WriteSingleCoilAsync(config, coilAddress, false, cancellationToken);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task WriteCoilAsync(PlcConnectionConfig config, ushort coilAddress, bool value, CancellationToken cancellationToken = default)
|
public async Task WriteCoilAsync(PlcConnectionConfig config, ushort coilAddress, bool value, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
await WriteSingleCoilAsync(config, coilAddress, value, cancellationToken);
|
await ExecuteWriteAsync(
|
||||||
|
config,
|
||||||
|
$"M{coilAddress}",
|
||||||
|
value ? 1 : 0,
|
||||||
|
() => WriteSingleCoilAsync(config, coilAddress, value, cancellationToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IReadOnlyDictionary<ushort, bool>> ReadCoilValuesAsync(PlcConnectionConfig config, IReadOnlyCollection<ushort> coilAddresses, CancellationToken cancellationToken = default)
|
public async Task<IReadOnlyDictionary<ushort, bool>> ReadCoilValuesAsync(PlcConnectionConfig config, IReadOnlyCollection<ushort> coilAddresses, CancellationToken cancellationToken = default)
|
||||||
@@ -118,12 +130,20 @@ public sealed class ModbusTcpPlcCoilService : IPlcCoilService, IPlcRegisterServi
|
|||||||
? [highWord, lowWord]
|
? [highWord, lowWord]
|
||||||
: [lowWord, highWord];
|
: [lowWord, highWord];
|
||||||
|
|
||||||
await WriteMultipleRegistersAsync(config, registerAddress, registers, cancellationToken);
|
await ExecuteWriteAsync(
|
||||||
|
config,
|
||||||
|
$"D{registerAddress}",
|
||||||
|
value,
|
||||||
|
() => WriteMultipleRegistersAsync(config, registerAddress, registers, cancellationToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task WriteUInt16Async(PlcConnectionConfig config, ushort registerAddress, ushort value, CancellationToken cancellationToken = default)
|
public async Task WriteUInt16Async(PlcConnectionConfig config, ushort registerAddress, ushort value, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
await WriteMultipleRegistersAsync(config, registerAddress, [value], cancellationToken);
|
await ExecuteWriteAsync(
|
||||||
|
config,
|
||||||
|
$"D{registerAddress}",
|
||||||
|
value,
|
||||||
|
() => WriteMultipleRegistersAsync(config, registerAddress, [value], cancellationToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task WriteInt32Async(PlcConnectionConfig config, ushort registerAddress, int value, CancellationToken cancellationToken = default)
|
public async Task WriteInt32Async(PlcConnectionConfig config, ushort registerAddress, int value, CancellationToken cancellationToken = default)
|
||||||
@@ -136,7 +156,38 @@ public sealed class ModbusTcpPlcCoilService : IPlcCoilService, IPlcRegisterServi
|
|||||||
? [highWord, lowWord]
|
? [highWord, lowWord]
|
||||||
: [lowWord, highWord];
|
: [lowWord, highWord];
|
||||||
|
|
||||||
await WriteMultipleRegistersAsync(config, registerAddress, registers, cancellationToken);
|
await ExecuteWriteAsync(
|
||||||
|
config,
|
||||||
|
$"D{registerAddress}",
|
||||||
|
value,
|
||||||
|
() => WriteMultipleRegistersAsync(config, registerAddress, registers, cancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task ExecuteWriteAsync(PlcConnectionConfig config, string target, object value, Func<Task> writeAction)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await writeAction();
|
||||||
|
Log.Information(
|
||||||
|
"PLC写入成功,地址 {IpAddress}:{Port},站号 {UnitId},目标 {Target},值 {Value}",
|
||||||
|
config.IpAddress,
|
||||||
|
config.Port,
|
||||||
|
config.UnitId,
|
||||||
|
target,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(
|
||||||
|
ex,
|
||||||
|
"PLC写入失败,地址 {IpAddress}:{Port},站号 {UnitId},目标 {Target},值 {Value}",
|
||||||
|
config.IpAddress,
|
||||||
|
config.Port,
|
||||||
|
config.UnitId,
|
||||||
|
target,
|
||||||
|
value);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task WriteSingleCoilAsync(PlcConnectionConfig config, ushort coilAddress, bool value, CancellationToken cancellationToken)
|
private async Task WriteSingleCoilAsync(PlcConnectionConfig config, ushort coilAddress, bool value, CancellationToken cancellationToken)
|
||||||
|
|||||||
@@ -142,36 +142,27 @@ public sealed class TestPointRow : INotifyPropertyChanged
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class TestRecordRow
|
|
||||||
{
|
|
||||||
public int Id { get; init; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; init; }
|
|
||||||
|
|
||||||
public string CreatedAtText => CreatedAt.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
|
|
||||||
|
|
||||||
public string SampleCode { get; init; } = string.Empty;
|
|
||||||
|
|
||||||
public string OperatorName { get; init; } = string.Empty;
|
|
||||||
|
|
||||||
public string OverallResult { get; init; } = string.Empty;
|
|
||||||
|
|
||||||
public string ExportPath { get; init; } = string.Empty;
|
|
||||||
|
|
||||||
public string ExportPathText => string.IsNullOrWhiteSpace(ExportPath) ? "未导出" : ExportPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class AcceptancePayload
|
public sealed class AcceptancePayload
|
||||||
{
|
{
|
||||||
|
public int SchemaVersion { get; init; } = 2;
|
||||||
|
|
||||||
|
public string SessionId { get; init; } = string.Empty;
|
||||||
|
|
||||||
public DateTime CreatedAt { get; init; }
|
public DateTime CreatedAt { get; init; }
|
||||||
|
|
||||||
|
public DateTime LastUpdatedAt { get; init; }
|
||||||
|
|
||||||
public string SampleCode { get; init; } = string.Empty;
|
public string SampleCode { get; init; } = string.Empty;
|
||||||
|
|
||||||
public string OperatorName { get; init; } = string.Empty;
|
public string OperatorName { get; init; } = string.Empty;
|
||||||
|
|
||||||
public string OverallResult { get; init; } = string.Empty;
|
public string OverallResult { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
public TestParameterConfig ParameterSnapshot { get; init; } = TestParameterConfig.CreateDefault();
|
||||||
|
|
||||||
public List<ProjectPayload> Projects { get; init; } = [];
|
public List<ProjectPayload> Projects { get; init; } = [];
|
||||||
|
|
||||||
|
public List<TestRunPayload> Runs { get; init; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ProjectPayload
|
public sealed class ProjectPayload
|
||||||
@@ -234,6 +225,82 @@ public sealed class TorqueCurvePayload
|
|||||||
public List<TorqueSamplePayload> Samples { get; init; } = [];
|
public List<TorqueSamplePayload> Samples { get; init; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class TestRunPayload
|
||||||
|
{
|
||||||
|
public string RunId { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
public string TestType { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
public DateTime StartedAt { get; init; }
|
||||||
|
|
||||||
|
public DateTime? CompletedAt { get; set; }
|
||||||
|
|
||||||
|
public string CompletionStatus { get; set; } = "测试中";
|
||||||
|
|
||||||
|
public TestParameterConfig ParameterSnapshot { get; init; } = TestParameterConfig.CreateDefault();
|
||||||
|
|
||||||
|
public double? FinalDisplacementMm { get; set; }
|
||||||
|
|
||||||
|
public double? FinalAxialForceN { get; set; }
|
||||||
|
|
||||||
|
public double? FinalSpeedRpm { get; set; }
|
||||||
|
|
||||||
|
public double? FinalTorqueMilliNewtonMeters { get; set; }
|
||||||
|
|
||||||
|
public double? NoLoadSpeedRpm { get; set; }
|
||||||
|
|
||||||
|
public double? NoLoadSpeedErrorRatePercent { get; set; }
|
||||||
|
|
||||||
|
public List<RealtimeSamplePayload> Samples { get; init; } = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class RealtimeSamplePayload
|
||||||
|
{
|
||||||
|
public long Sequence { get; init; }
|
||||||
|
|
||||||
|
public DateTime SampledAt { get; init; }
|
||||||
|
|
||||||
|
public double DialIndicatorMm { get; init; }
|
||||||
|
|
||||||
|
public double RelativeDisplacementMm { get; init; }
|
||||||
|
|
||||||
|
public double AxialAxisPositionMm { get; init; }
|
||||||
|
|
||||||
|
public double AxialSampleStartMm { get; init; }
|
||||||
|
|
||||||
|
public double AxialSampleEndMm { get; init; }
|
||||||
|
|
||||||
|
public double AxialSampleDifferenceMm { get; init; }
|
||||||
|
|
||||||
|
public double AxialForceN { get; init; }
|
||||||
|
|
||||||
|
public double SpeedTorqueAxisPositionMm { get; init; }
|
||||||
|
|
||||||
|
public double SpeedTorqueDisplacementMm { get; init; }
|
||||||
|
|
||||||
|
public double SpeedTorquePeakTorqueMilliNewtonMeters { get; init; }
|
||||||
|
|
||||||
|
public double RealtimeTorqueMilliNewtonMeters { get; init; }
|
||||||
|
|
||||||
|
public double RealtimeSpeedRpm { get; init; }
|
||||||
|
|
||||||
|
public double RealtimePressureMpa { get; init; }
|
||||||
|
|
||||||
|
public double NoLoadSpeedRpm { get; init; }
|
||||||
|
|
||||||
|
public double NoLoadSpeedErrorRatePercent { get; init; }
|
||||||
|
|
||||||
|
public bool SpeedTorqueDone { get; init; }
|
||||||
|
|
||||||
|
public bool SpeedTorqueResetEnabled { get; init; }
|
||||||
|
|
||||||
|
public bool SpeedTorqueResetDone { get; init; }
|
||||||
|
|
||||||
|
public bool AxialResetEnabled { get; init; }
|
||||||
|
|
||||||
|
public bool AxialResetDone { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class TestParameterConfig
|
public sealed class TestParameterConfig
|
||||||
{
|
{
|
||||||
public double AxialDisplacementLimit { get; init; }
|
public double AxialDisplacementLimit { get; init; }
|
||||||
@@ -278,6 +345,8 @@ public sealed class TestParameterConfig
|
|||||||
|
|
||||||
public double PressureCoefficient { get; init; }
|
public double PressureCoefficient { get; init; }
|
||||||
|
|
||||||
|
public double NoLoadSpeedSetting { get; init; }
|
||||||
|
|
||||||
public string PlcIpAddress { get; init; } = "192.168.1.10";
|
public string PlcIpAddress { get; init; } = "192.168.1.10";
|
||||||
|
|
||||||
public int PlcPort { get; init; } = 502;
|
public int PlcPort { get; init; } = 502;
|
||||||
@@ -328,6 +397,7 @@ public sealed class TestParameterConfig
|
|||||||
SpeedCoefficient = 1,
|
SpeedCoefficient = 1,
|
||||||
SpeedStopThreshold = 0,
|
SpeedStopThreshold = 0,
|
||||||
PressureCoefficient = 1,
|
PressureCoefficient = 1,
|
||||||
|
NoLoadSpeedSetting = 0,
|
||||||
PlcIpAddress = "192.168.1.10",
|
PlcIpAddress = "192.168.1.10",
|
||||||
PlcPort = 502,
|
PlcPort = 502,
|
||||||
PlcUnitId = 1,
|
PlcUnitId = 1,
|
||||||
|
|||||||
Reference in New Issue
Block a user