更新最新版20260604
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.Threading;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
@@ -32,6 +35,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
||||
private const string DefaultAdcPortName = "COM4";
|
||||
private const string LegacyPlcPortName = "COM7";
|
||||
private const string LegacyAdcPortName = "COM8";
|
||||
private static readonly TimeSpan ResetButtonPendingTimeout = TimeSpan.FromMilliseconds(800);
|
||||
|
||||
private readonly SlipResistanceDeviceService deviceService = new();
|
||||
private readonly SlipExcelExportService excelExportService = new();
|
||||
@@ -45,6 +49,9 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
||||
|
||||
private bool isLoadingDeviceSettings;
|
||||
private bool wasRunning;
|
||||
private bool isResetButtonPending;
|
||||
private bool hasObservedResetDeviceBusy;
|
||||
private DateTime resetButtonPendingStartedAt = DateTime.MinValue;
|
||||
private string activePlcPortName = string.Empty;
|
||||
private string activeAdcPortName = string.Empty;
|
||||
private int activeBaudRate;
|
||||
@@ -258,7 +265,20 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
||||
private async Task Clear()
|
||||
{
|
||||
ApplyConnectionSettings();
|
||||
await RunDeviceCommand(deviceService.PulseResetAsync(), "已按老代码逻辑发送复位指令 M90");
|
||||
BeginResetButtonFeedback();
|
||||
|
||||
try
|
||||
{
|
||||
await deviceService.PulseResetAsync();
|
||||
CurrentStatus = "已按老代码逻辑发送复位指令 M90";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "设备指令失败:已按老代码逻辑发送复位指令 M90");
|
||||
CurrentStatus = $"设备指令失败:{ex.Message}";
|
||||
ClearResetButtonFeedback();
|
||||
UpdateResetButtonText(deviceService.CurrentSnapshot);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -293,7 +313,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ExportReport()
|
||||
private async Task ExportReport()
|
||||
{
|
||||
var points = currentRun.Count > 0 ? currentRun.ToList() : lastCompletedRun;
|
||||
if (points.Count == 0)
|
||||
@@ -305,6 +325,15 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
||||
|
||||
try
|
||||
{
|
||||
CurrentStatus = "请选择 Excel 报告保存目录";
|
||||
var exportDirectory = await SelectExportDirectoryAsync();
|
||||
if (exportDirectory is null)
|
||||
{
|
||||
Log.Information("用户取消 Excel 导出目录选择:TestNumber={TestNumber}, PointCount={PointCount}", TestNumber, points.Count);
|
||||
CurrentStatus = "已取消 Excel 导出";
|
||||
return;
|
||||
}
|
||||
|
||||
var report = new SlipReportExport(
|
||||
TestNumber,
|
||||
OperatorName,
|
||||
@@ -322,7 +351,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
||||
Samples.ToList(),
|
||||
points);
|
||||
|
||||
var path = excelExportService.Export(report);
|
||||
var path = excelExportService.Export(report, exportDirectory);
|
||||
UploadProgress = 100;
|
||||
CurrentStatus = $"Excel 已导出:{path}";
|
||||
}
|
||||
@@ -333,6 +362,79 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string?> SelectExportDirectoryAsync()
|
||||
{
|
||||
var storageProvider = GetStorageProvider();
|
||||
if (storageProvider is null || !storageProvider.CanPickFolder)
|
||||
{
|
||||
var defaultDirectory = SlipExcelExportService.GetDefaultExportDirectory();
|
||||
Log.Warning("当前平台无法打开 Excel 导出目录选择器,将使用默认目录:Path={Path}", defaultDirectory);
|
||||
return defaultDirectory;
|
||||
}
|
||||
|
||||
var folders = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = "选择报告保存目录",
|
||||
AllowMultiple = false,
|
||||
SuggestedStartLocation = await TryGetSuggestedExportFolderAsync(storageProvider)
|
||||
});
|
||||
|
||||
var selectedFolder = folders.FirstOrDefault();
|
||||
if (selectedFolder is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var localPath = selectedFolder.TryGetLocalPath();
|
||||
if (string.IsNullOrWhiteSpace(localPath) && selectedFolder.Path.IsFile)
|
||||
{
|
||||
localPath = selectedFolder.Path.LocalPath;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(localPath))
|
||||
{
|
||||
throw new InvalidOperationException("选择的目录不是本地文件夹,无法保存 Excel");
|
||||
}
|
||||
|
||||
return localPath;
|
||||
}
|
||||
|
||||
private static async Task<IStorageFolder?> TryGetSuggestedExportFolderAsync(IStorageProvider storageProvider)
|
||||
{
|
||||
try
|
||||
{
|
||||
var defaultDirectory = SlipExcelExportService.GetDefaultExportDirectory();
|
||||
if (Directory.Exists(defaultDirectory))
|
||||
{
|
||||
return await storageProvider.TryGetFolderFromPathAsync(defaultDirectory);
|
||||
}
|
||||
|
||||
var parentDirectory = Path.GetDirectoryName(defaultDirectory);
|
||||
if (!string.IsNullOrWhiteSpace(parentDirectory) && Directory.Exists(parentDirectory))
|
||||
{
|
||||
return await storageProvider.TryGetFolderFromPathAsync(parentDirectory);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "准备 Excel 默认导出目录失败,将不设置目录选择初始位置");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static IStorageProvider? GetStorageProvider()
|
||||
{
|
||||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop
|
||||
&& desktop.MainWindow is not null)
|
||||
{
|
||||
return desktop.MainWindow.StorageProvider;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private Task LiftMotion() => RunDeviceCommand(deviceService.ApplyOldLiftAsync(), "提升按老代码逻辑执行:M4=0, M5=1");
|
||||
|
||||
@@ -478,7 +580,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
||||
{
|
||||
DeviceStatus = device.IsTestRunning ? "联机 / 测试中" : device.IsResetting ? "联机 / 复位中" : "联机 / 待机";
|
||||
TestButtonText = device.IsTestRunning ? "停止" : "测试";
|
||||
ResetButtonText = device.IsResetting ? "复位中" : "复位";
|
||||
UpdateResetButtonText(device);
|
||||
VerticalPressure = device.VerticalLoadN.ToString("F1", CultureInfo.InvariantCulture);
|
||||
HorizontalForce = device.HorizontalFrictionN.ToString("F1", CultureInfo.InvariantCulture);
|
||||
FrictionCoefficient = device.FrictionCoefficient.ToString("F3", CultureInfo.InvariantCulture);
|
||||
@@ -489,7 +591,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
||||
{
|
||||
DeviceStatus = IsAdcCalibrationError(device.LastError) ? "数据无效" : "离线";
|
||||
TestButtonText = device.IsTestRunning ? "停止" : "测试";
|
||||
ResetButtonText = device.IsResetting ? "复位中" : "复位";
|
||||
UpdateResetButtonText(device);
|
||||
VerticalPressure = "--";
|
||||
HorizontalForce = "--";
|
||||
FrictionCoefficient = "--";
|
||||
@@ -530,6 +632,37 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
||||
wasRunning = isRecording;
|
||||
}
|
||||
|
||||
private void BeginResetButtonFeedback()
|
||||
{
|
||||
isResetButtonPending = true;
|
||||
hasObservedResetDeviceBusy = false;
|
||||
resetButtonPendingStartedAt = DateTime.UtcNow;
|
||||
ResetButtonText = "复位中";
|
||||
}
|
||||
|
||||
private void ClearResetButtonFeedback()
|
||||
{
|
||||
isResetButtonPending = false;
|
||||
hasObservedResetDeviceBusy = false;
|
||||
resetButtonPendingStartedAt = DateTime.MinValue;
|
||||
}
|
||||
|
||||
private void UpdateResetButtonText(SlipDeviceSnapshot device)
|
||||
{
|
||||
if (device.IsResetting)
|
||||
{
|
||||
hasObservedResetDeviceBusy = true;
|
||||
}
|
||||
else if (!device.IsConnected
|
||||
|| hasObservedResetDeviceBusy
|
||||
|| (isResetButtonPending && DateTime.UtcNow - resetButtonPendingStartedAt >= ResetButtonPendingTimeout))
|
||||
{
|
||||
ClearResetButtonFeedback();
|
||||
}
|
||||
|
||||
ResetButtonText = device.IsResetting || isResetButtonPending ? "复位中" : "复位";
|
||||
}
|
||||
|
||||
private void BeginRun()
|
||||
{
|
||||
currentRun.Clear();
|
||||
|
||||
Reference in New Issue
Block a user