Files
FootwearTest-20260602/Footwear Test methodsfor wholeshoe Slipresistanceperformance/ViewModels/MainWindowViewModel.cs

738 lines
26 KiB
C#
Raw Normal View History

2026-06-02 18:14:01 +08:00
using Avalonia.Threading;
2026-06-02 17:41:53 +08:00
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
2026-06-02 18:14:01 +08:00
using Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Models;
using Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services;
2026-06-02 17:41:53 +08:00
using LiveChartsCore;
using LiveChartsCore.Defaults;
using LiveChartsCore.SkiaSharpView;
using LiveChartsCore.SkiaSharpView.Painting;
using SkiaSharp;
2026-06-02 18:14:01 +08:00
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
2026-06-02 17:41:53 +08:00
namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModels
{
2026-06-02 18:14:01 +08:00
public partial class MainWindowViewModel : ViewModelBase, IDisposable
2026-06-02 17:41:53 +08:00
{
2026-06-02 18:14:01 +08:00
private readonly SlipResistanceDeviceService deviceService = new();
private readonly SlipExcelExportService excelExportService = new();
private readonly DispatcherTimer refreshTimer;
private readonly Stopwatch runStopwatch = new();
private readonly List<SlipDataPoint> currentRun = [];
private readonly ObservableCollection<ObservablePoint> verticalLoadPoints = [];
private readonly ObservableCollection<ObservablePoint> horizontalFrictionPoints = [];
private readonly ObservableCollection<ObservablePoint> frictionCoefficientPoints = [];
private readonly ObservableCollection<ObservablePoint> displacementPoints = [];
2026-06-02 17:41:53 +08:00
private bool isLoadingDeviceSettings;
2026-06-02 18:14:01 +08:00
private bool wasRunning;
private List<SlipDataPoint> lastCompletedRun = [];
2026-06-02 17:41:53 +08:00
[ObservableProperty]
private string testNumber = $"SLIP-{DateTime.Now:yyyyMMdd-HHmm}";
[ObservableProperty]
private string operatorName = string.Empty;
[ObservableProperty]
private string methodName = "GB/T 3903.6-2024";
[ObservableProperty]
private string reportName = string.Empty;
[ObservableProperty]
private string sampleFeature = "整鞋样品 / 瓷砖接触面 / 水平测试";
[ObservableProperty]
2026-06-02 18:14:01 +08:00
private string currentStatus = "设备连接中,等待 PLC 与 ADC 实时数据";
2026-06-02 17:41:53 +08:00
[ObservableProperty]
2026-06-02 18:14:01 +08:00
private int uploadProgress;
2026-06-02 17:41:53 +08:00
[ObservableProperty]
private string manualDistance = "0";
[ObservableProperty]
private int selectedSampleIndex;
[ObservableProperty]
private bool isSettingsDialogOpen;
[ObservableProperty]
private string manualSpeed = "0.00";
[ObservableProperty]
private string manualDisplacement = "0.00";
[ObservableProperty]
private string testSpeed = "0.30";
2026-06-02 18:14:01 +08:00
[ObservableProperty]
private string normalPressureZero = "0";
2026-06-02 17:41:53 +08:00
[ObservableProperty]
private string normalPressureCoefficient = "0.00";
2026-06-02 18:14:01 +08:00
[ObservableProperty]
private string frictionZero1 = "0";
2026-06-02 17:41:53 +08:00
[ObservableProperty]
private string frictionCoefficient1 = "0.00";
2026-06-02 18:14:01 +08:00
[ObservableProperty]
private string frictionZero2 = "0";
2026-06-02 17:41:53 +08:00
[ObservableProperty]
private string frictionCoefficient2 = "0.00";
2026-06-02 18:14:01 +08:00
[ObservableProperty]
private string plcPortName = "COM7";
[ObservableProperty]
private string adcPortName = "COM8";
[ObservableProperty]
private int baudRate = 115200;
[ObservableProperty]
private int selectedShoeSizeIndex;
[ObservableProperty]
private int selectedLubricantIndex;
[ObservableProperty]
private int selectedModeIndex = 2;
[ObservableProperty]
private int selectedSurfaceIndex;
[ObservableProperty]
private string targetLoadText = "400 N";
[ObservableProperty]
private string actualLoadText = "0.0 N";
[ObservableProperty]
private string deviceStatus = "离线";
[ObservableProperty]
private string activeMode = "水平测试模式";
[ObservableProperty]
private string resultSummary = "等待 3 次有效试验";
[ObservableProperty]
private string staticCoefficient = "0.000";
[ObservableProperty]
private string dynamicCoefficient = "0.000";
[ObservableProperty]
private string verticalPressure = "0.0";
[ObservableProperty]
private string horizontalForce = "0.0";
[ObservableProperty]
private string frictionCoefficient = "0.000";
[ObservableProperty]
private string distance = "0.0";
2026-06-02 17:41:53 +08:00
public string TestSpeedText => $"{TestSpeed} m/s";
public string SampleRateText { get; } = "30 Hz";
2026-06-02 18:14:01 +08:00
public string BatchNumber { get; } = DateTime.Now.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
2026-06-02 17:41:53 +08:00
public string UploadProgressText => $"{UploadProgress}%";
2026-06-02 18:14:01 +08:00
public string StandardReference { get; } = "GB/T 3903.6-2024 5.1.3、7.3.1.4、8.1-8.3:实时采集、静/动摩擦系数、三次平均与重测判定";
public ObservableCollection<TestSample> Samples { get; } = [];
2026-06-02 17:41:53 +08:00
public DrawMarginFrame ChartFrame { get; } = new()
{
Fill = new SolidColorPaint(SKColor.Parse("#FFFFFF")),
Stroke = new SolidColorPaint(SKColor.Parse("#CBD5E1")) { StrokeThickness = 1.4f }
};
public SolidColorPaint LegendTextPaint { get; } = new(SKColor.Parse("#334155"));
2026-06-02 18:14:01 +08:00
public ISeries[] Series { get; }
2026-06-02 17:41:53 +08:00
public Axis[] XAxes { get; } =
[
new Axis
{
Name = "时间(s)",
2026-06-02 18:14:01 +08:00
MinLimit = 0,
UnitWidth = 0.1,
2026-06-02 17:41:53 +08:00
SeparatorsPaint = new SolidColorPaint(SKColor.Parse("#D7E0EA")) { StrokeThickness = 1 },
SubseparatorsPaint = new SolidColorPaint(SKColor.Parse("#EEF3F8")) { StrokeThickness = 1 },
SubseparatorsCount = 4,
LabelsPaint = new SolidColorPaint(SKColor.Parse("#475569")),
NamePaint = new SolidColorPaint(SKColor.Parse("#334155")),
TextSize = 12,
NameTextSize = 13,
Padding = new LiveChartsCore.Drawing.Padding(4, 3, 4, 3)
}
];
public Axis[] YAxes { get; } =
[
new Axis
{
2026-06-02 18:14:01 +08:00
Name = "压力 / 摩擦力 / 位移",
2026-06-02 17:41:53 +08:00
MinLimit = 0,
SeparatorsPaint = new SolidColorPaint(SKColor.Parse("#D7E0EA")) { StrokeThickness = 1 },
SubseparatorsPaint = new SolidColorPaint(SKColor.Parse("#EEF3F8")) { StrokeThickness = 1 },
SubseparatorsCount = 4,
LabelsPaint = new SolidColorPaint(SKColor.Parse("#475569")),
NamePaint = new SolidColorPaint(SKColor.Parse("#334155")),
TextSize = 11,
NameTextSize = 12,
Padding = new LiveChartsCore.Drawing.Padding(2, 2, 3, 2)
},
new Axis
{
Name = "摩擦系数",
Position = LiveChartsCore.Measure.AxisPosition.End,
MinLimit = 0,
UnitWidth = 0.1,
LabelsPaint = new SolidColorPaint(SKColor.Parse("#7E22CE")),
NamePaint = new SolidColorPaint(SKColor.Parse("#7E22CE")),
SeparatorsPaint = new SolidColorPaint(SKColor.Parse("#F1E7FF")) { StrokeThickness = 1 },
TextSize = 11,
NameTextSize = 12,
Padding = new LiveChartsCore.Drawing.Padding(3, 2, 2, 2)
}
];
public MainWindowViewModel()
{
2026-06-02 18:14:01 +08:00
Series =
[
CreateLineSeries("垂直压力(N)", verticalLoadPoints, "#DC2626", 0, 0.65),
CreateLineSeries("水平摩擦力(N)", horizontalFrictionPoints, "#16A34A", 0, 0.65),
CreateLineSeries("摩擦系数", frictionCoefficientPoints, "#C026D3", 1, 0.65),
CreateLineSeries("位移(mm)", displacementPoints, "#2563EB", 0, 0.35)
];
2026-06-02 17:41:53 +08:00
LoadDeviceSettings();
2026-06-02 18:14:01 +08:00
UpdateTargetLoad();
deviceService.Start(CurrentSettings());
refreshTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(33) };
refreshTimer.Tick += (_, _) => RefreshFromDevice();
refreshTimer.Start();
2026-06-02 17:41:53 +08:00
}
[RelayCommand]
2026-06-02 18:14:01 +08:00
private async Task Clear()
2026-06-02 17:41:53 +08:00
{
2026-06-02 18:14:01 +08:00
await RunDeviceCommand(deviceService.PulseResetAsync(), "已发送复位指令 M90");
2026-06-02 17:41:53 +08:00
}
[RelayCommand]
private void Preload()
{
2026-06-02 18:14:01 +08:00
CurrentStatus = "请在 0.2 s 内施加目标垂直载荷,载荷达到后启动滑动测试";
2026-06-02 17:41:53 +08:00
}
[RelayCommand]
2026-06-02 18:14:01 +08:00
private async Task StartTest()
2026-06-02 17:41:53 +08:00
{
2026-06-02 18:14:01 +08:00
BeginRun();
await RunDeviceCommand(deviceService.PulseStartTestAsync(), "已发送测试启动指令 M80等待 M81 运行状态");
2026-06-02 17:41:53 +08:00
}
[RelayCommand]
2026-06-02 18:14:01 +08:00
private async Task StopTest()
2026-06-02 17:41:53 +08:00
{
2026-06-02 18:14:01 +08:00
await RunDeviceCommand(deviceService.PulseStopTestAsync(), "已发送测试停止指令 M83");
2026-06-02 17:41:53 +08:00
}
[RelayCommand]
private void ExportReport()
{
2026-06-02 18:14:01 +08:00
var points = currentRun.Count > 0 ? currentRun.ToList() : lastCompletedRun;
if (points.Count == 0)
{
CurrentStatus = "没有可导出的实时采样数据,请先完成一次测试";
return;
}
2026-06-02 17:41:53 +08:00
2026-06-02 18:14:01 +08:00
try
{
var report = new SlipReportExport(
TestNumber,
OperatorName,
MethodName,
ReportName,
SampleFeature,
CurrentShoeSize(),
CurrentLubricant(),
CurrentMode(),
CurrentSurface(),
TargetLoadText,
ActualLoadText,
TestSpeedText,
StandardReference,
Samples.ToList(),
points);
var path = excelExportService.Export(report);
UploadProgress = 100;
CurrentStatus = $"Excel 已导出:{path}";
}
catch (Exception ex)
{
CurrentStatus = $"Excel 导出失败:{ex.Message}";
}
}
2026-06-02 17:41:53 +08:00
[RelayCommand]
2026-06-02 18:14:01 +08:00
private async Task Lift() => await RunDeviceCommand(deviceService.LiftAsync(), "垂直架提升指令已发送 M5");
2026-06-02 17:41:53 +08:00
[RelayCommand]
2026-06-02 18:14:01 +08:00
private async Task Lower() => await RunDeviceCommand(deviceService.LowerAsync(), "垂直架下降指令已发送 M4");
2026-06-02 17:41:53 +08:00
[RelayCommand]
2026-06-02 18:14:01 +08:00
private async Task MoveLeft() => await RunDeviceCommand(deviceService.ToggleMoveLeftAsync(), "水平板左移状态已切换 M1");
2026-06-02 17:41:53 +08:00
[RelayCommand]
2026-06-02 18:14:01 +08:00
private async Task MoveRight() => await RunDeviceCommand(deviceService.ToggleMoveRightAsync(), "水平板右移状态已切换 M2");
2026-06-02 17:41:53 +08:00
[RelayCommand]
private void DeleteSelectedSample()
{
var sample = Samples.FirstOrDefault(x => x.Index == SelectedSampleIndex);
if (sample is null)
{
CurrentStatus = $"未找到序号 {SelectedSampleIndex} 的实验数据";
return;
}
Samples.Remove(sample);
2026-06-02 18:14:01 +08:00
UpdateResultSummary();
2026-06-02 17:41:53 +08:00
CurrentStatus = $"已删除序号 {SelectedSampleIndex} 的实验数据";
}
[RelayCommand]
private void ShowSettingsDialog()
{
IsSettingsDialogOpen = true;
}
[RelayCommand]
private void CloseSettingsDialog()
{
IsSettingsDialogOpen = false;
2026-06-02 18:14:01 +08:00
deviceService.UpdateSettings(CurrentSettings());
2026-06-02 17:41:53 +08:00
}
2026-06-02 18:14:01 +08:00
partial void OnUploadProgressChanged(int value) => OnPropertyChanged(nameof(UploadProgressText));
partial void OnManualSpeedChanged(string value)
2026-06-02 17:41:53 +08:00
{
2026-06-02 18:14:01 +08:00
SaveAndApplySettings();
WriteNumericSetting(value, deviceService.WriteManualSpeedAsync, "手动速度");
2026-06-02 17:41:53 +08:00
}
2026-06-02 18:14:01 +08:00
partial void OnManualDisplacementChanged(string value)
{
SaveAndApplySettings();
WriteNumericSetting(value, deviceService.WriteManualDisplacementAsync, "手动位移");
}
2026-06-02 17:41:53 +08:00
partial void OnTestSpeedChanged(string value)
{
OnPropertyChanged(nameof(TestSpeedText));
2026-06-02 18:14:01 +08:00
SaveAndApplySettings();
WriteNumericSetting(value, deviceService.WriteTestSpeedAsync, "测试速度");
}
partial void OnNormalPressureZeroChanged(string value) => SaveAndApplySettings();
partial void OnNormalPressureCoefficientChanged(string value) => SaveAndApplySettings();
partial void OnFrictionZero1Changed(string value) => SaveAndApplySettings();
partial void OnFrictionCoefficient1Changed(string value) => SaveAndApplySettings();
partial void OnFrictionZero2Changed(string value) => SaveAndApplySettings();
partial void OnFrictionCoefficient2Changed(string value) => SaveAndApplySettings();
partial void OnPlcPortNameChanged(string value) => SaveAndApplySettings();
partial void OnAdcPortNameChanged(string value) => SaveAndApplySettings();
partial void OnBaudRateChanged(int value) => SaveAndApplySettings();
partial void OnSelectedShoeSizeIndexChanged(int value) => UpdateTargetLoad();
partial void OnSelectedModeIndexChanged(int value)
{
ActiveMode = CurrentMode();
}
public void Dispose()
{
refreshTimer.Stop();
deviceService.Dispose();
}
private void RefreshFromDevice()
{
var device = deviceService.CurrentSnapshot;
DeviceStatus = device.IsConnected
? device.IsTestRunning ? "联机 / 测试中" : device.IsResetting ? "联机 / 复位中" : "联机 / 待机"
: "离线";
VerticalPressure = device.VerticalLoadN.ToString("F1", CultureInfo.InvariantCulture);
HorizontalForce = device.HorizontalFrictionN.ToString("F1", CultureInfo.InvariantCulture);
FrictionCoefficient = device.FrictionCoefficient.ToString("F3", CultureInfo.InvariantCulture);
Distance = device.DisplacementMm.ToString("F1", CultureInfo.InvariantCulture);
ActualLoadText = $"{VerticalPressure} N";
if (!device.IsConnected && !string.IsNullOrWhiteSpace(device.LastError))
{
CurrentStatus = $"设备离线:{device.LastError}";
}
if (!wasRunning && device.IsTestRunning)
{
BeginRun();
}
if (device.IsTestRunning)
{
RecordPoint(device);
}
if (wasRunning && !device.IsTestRunning)
{
CompleteRun();
}
wasRunning = device.IsTestRunning;
2026-06-02 17:41:53 +08:00
}
2026-06-02 18:14:01 +08:00
private void BeginRun()
{
currentRun.Clear();
verticalLoadPoints.Clear();
horizontalFrictionPoints.Clear();
frictionCoefficientPoints.Clear();
displacementPoints.Clear();
runStopwatch.Restart();
UploadProgress = 0;
CurrentStatus = "测试运行:按标准采集垂直载荷、摩擦力、位移与摩擦系数";
}
2026-06-02 17:41:53 +08:00
2026-06-02 18:14:01 +08:00
private void RecordPoint(SlipDeviceSnapshot device)
{
var time = runStopwatch.Elapsed.TotalSeconds;
if (currentRun.Count > 0 && time - currentRun[^1].TimeSeconds < 1.0 / 30.0)
{
return;
}
var point = new SlipDataPoint(
device.Timestamp,
time,
device.VerticalLoadN,
device.HorizontalFrictionN,
device.DisplacementMm,
device.FrictionCoefficient);
currentRun.Add(point);
verticalLoadPoints.Add(new ObservablePoint(time, point.VerticalLoadN));
horizontalFrictionPoints.Add(new ObservablePoint(time, point.HorizontalFrictionN));
frictionCoefficientPoints.Add(new ObservablePoint(time, point.FrictionCoefficient));
displacementPoints.Add(new ObservablePoint(time, point.DisplacementMm));
UploadProgress = Math.Min(99, currentRun.Count);
}
2026-06-02 17:41:53 +08:00
2026-06-02 18:14:01 +08:00
private void CompleteRun()
{
runStopwatch.Stop();
if (currentRun.Count < 3)
{
CurrentStatus = "测试已停止,但有效采样点不足,未生成结果";
return;
}
lastCompletedRun = currentRun.ToList();
var peak = FindStaticPeak(currentRun);
var dynamicWindow = currentRun
.Where(point => point.TimeSeconds >= 0.3 && point.TimeSeconds <= 0.6)
.ToList();
if (dynamicWindow.Count == 0)
{
dynamicWindow = currentRun.ToList();
}
var staticCoefficientValue = CalculateCoefficient(peak.HorizontalFrictionN, peak.VerticalLoadN);
var dynamicForce = dynamicWindow.Average(point => point.HorizontalFrictionN);
var dynamicLoad = dynamicWindow.Average(point => point.VerticalLoadN);
var dynamicCoefficientValue = CalculateCoefficient(dynamicForce, dynamicLoad);
var verdict = NeedsRetest(staticCoefficientValue, dynamicCoefficientValue) ? "需重测" : "有效";
var nextIndex = Samples.Count == 0 ? 1 : Samples.Max(sample => sample.Index) + 1;
Samples.Insert(0, new TestSample(
nextIndex,
DateTime.Now.ToString("HH:mm:ss", CultureInfo.InvariantCulture),
staticCoefficientValue.ToString("F3", CultureInfo.InvariantCulture),
dynamicCoefficientValue.ToString("F3", CultureInfo.InvariantCulture),
verdict,
staticCoefficientValue,
dynamicCoefficientValue));
StaticCoefficient = staticCoefficientValue.ToString("F3", CultureInfo.InvariantCulture);
DynamicCoefficient = dynamicCoefficientValue.ToString("F3", CultureInfo.InvariantCulture);
UpdateResultSummary();
UploadProgress = 100;
CurrentStatus = verdict == "有效"
? "测试完成:已按标准生成静/动摩擦系数"
: "测试完成:最近三次结果差异超过 10%,建议重新测试";
}
private bool NeedsRetest(double staticCoefficientValue, double dynamicCoefficientValue)
{
var latest = Samples.Take(2).ToList();
if (latest.Count < 2)
{
return false;
}
var staticValues = latest.Select(sample => sample.StaticCoefficientValue).Append(staticCoefficientValue).ToArray();
var dynamicValues = latest.Select(sample => sample.DynamicCoefficientValue).Append(dynamicCoefficientValue).ToArray();
return ExceedsTenPercent(staticValues) || ExceedsTenPercent(dynamicValues);
}
private static bool ExceedsTenPercent(double[] values)
{
var average = values.Average();
if (Math.Abs(average) < 0.0001)
{
return false;
}
return (values.Max() - values.Min()) / Math.Abs(average) > 0.10;
}
private void UpdateResultSummary()
{
var latest = Samples.Take(3).ToList();
if (latest.Count == 0)
{
ResultSummary = "等待 3 次有效试验";
return;
}
var staticAverage = latest.Average(sample => sample.StaticCoefficientValue);
var dynamicAverage = latest.Average(sample => sample.DynamicCoefficientValue);
ResultSummary = $"近 {latest.Count} 次平均 静 {staticAverage:F3} / 动 {dynamicAverage:F3}";
}
private static SlipDataPoint FindStaticPeak(IReadOnlyList<SlipDataPoint> points)
{
for (var index = 1; index < points.Count - 1; index++)
{
var previous = points[index - 1].HorizontalFrictionN;
var current = points[index].HorizontalFrictionN;
var next = points[index + 1].HorizontalFrictionN;
if (current >= previous && current >= next && current > 0)
{
return points[index];
}
}
return points.MaxBy(point => point.HorizontalFrictionN) ?? points[0];
}
private static double CalculateCoefficient(double frictionForce, double verticalLoad) =>
Math.Abs(verticalLoad) > 0.0001 ? frictionForce / verticalLoad : 0;
private async Task RunDeviceCommand(Task command, string successMessage)
{
try
{
await command;
CurrentStatus = successMessage;
}
catch (Exception ex)
{
CurrentStatus = $"设备指令失败:{ex.Message}";
}
}
private void WriteNumericSetting(string value, Func<double, Task> writer, string label)
{
if (isLoadingDeviceSettings || !TryParseDouble(value, out var numericValue))
{
return;
}
_ = RunDeviceCommand(writer(numericValue), $"{label}已写入 PLC");
}
private void SaveAndApplySettings()
{
SaveDeviceSettings();
deviceService.UpdateSettings(CurrentSettings());
}
2026-06-02 17:41:53 +08:00
private void LoadDeviceSettings()
{
if (!File.Exists(DeviceSettingsPath))
{
return;
}
try
{
var json = File.ReadAllText(DeviceSettingsPath);
var settings = JsonSerializer.Deserialize<DeviceSettings>(json);
if (settings is null)
{
return;
}
isLoadingDeviceSettings = true;
ManualSpeed = settings.ManualSpeed ?? ManualSpeed;
ManualDisplacement = settings.ManualDisplacement ?? ManualDisplacement;
TestSpeed = settings.TestSpeed ?? TestSpeed;
2026-06-02 18:14:01 +08:00
NormalPressureZero = settings.NormalPressureZero ?? NormalPressureZero;
2026-06-02 17:41:53 +08:00
NormalPressureCoefficient = settings.NormalPressureCoefficient ?? NormalPressureCoefficient;
2026-06-02 18:14:01 +08:00
FrictionZero1 = settings.FrictionZero1 ?? FrictionZero1;
2026-06-02 17:41:53 +08:00
FrictionCoefficient1 = settings.FrictionCoefficient1 ?? FrictionCoefficient1;
2026-06-02 18:14:01 +08:00
FrictionZero2 = settings.FrictionZero2 ?? FrictionZero2;
2026-06-02 17:41:53 +08:00
FrictionCoefficient2 = settings.FrictionCoefficient2 ?? FrictionCoefficient2;
2026-06-02 18:14:01 +08:00
PlcPortName = settings.PlcPortName ?? PlcPortName;
AdcPortName = settings.AdcPortName ?? AdcPortName;
BaudRate = settings.BaudRate > 0 ? settings.BaudRate : BaudRate;
2026-06-02 17:41:53 +08:00
}
catch
{
}
finally
{
isLoadingDeviceSettings = false;
}
}
private void SaveDeviceSettings()
{
if (isLoadingDeviceSettings)
{
return;
}
try
{
Directory.CreateDirectory(Path.GetDirectoryName(DeviceSettingsPath)!);
2026-06-02 18:14:01 +08:00
var json = JsonSerializer.Serialize(CurrentSettings(), new JsonSerializerOptions { WriteIndented = true });
2026-06-02 17:41:53 +08:00
File.WriteAllText(DeviceSettingsPath, json);
}
catch
{
}
}
2026-06-02 18:14:01 +08:00
private DeviceSettings CurrentSettings() =>
new(
ManualSpeed,
ManualDisplacement,
TestSpeed,
NormalPressureZero,
NormalPressureCoefficient,
FrictionZero1,
FrictionCoefficient1,
FrictionZero2,
FrictionCoefficient2,
PlcPortName,
AdcPortName,
BaudRate);
private void UpdateTargetLoad()
{
TargetLoadText = SelectedShoeSizeIndex switch
{
1 => "350 N",
2 => "160 N",
_ => "400 N"
};
}
private string CurrentShoeSize() => SelectedShoeSizeIndex switch
{
1 => "205-250",
2 => "205以下",
_ => "250(含)以上"
};
private string CurrentLubricant() => SelectedLubricantIndex switch
{
1 => "湿态 - 蒸馏水",
2 => "湿态 - 洗涤剂",
3 => "冰霜",
_ => "干态"
};
private string CurrentMode() => SelectedModeIndex switch
{
0 => "后跟测试模式",
1 => "前掌测试模式",
_ => "水平测试模式"
};
private string CurrentSurface() => SelectedSurfaceIndex switch
{
1 => "木地板",
2 => "石材",
3 => "冰霜表面",
_ => "瓷砖"
};
private static bool TryParseDouble(string value, out double numericValue) =>
double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out numericValue)
|| double.TryParse(value, NumberStyles.Float, CultureInfo.CurrentCulture, out numericValue);
private static LineSeries<ObservablePoint> CreateLineSeries(
string name,
ObservableCollection<ObservablePoint> values,
string color,
int yAxis,
double smoothness) =>
new()
{
Name = name,
Values = values,
MiniatureShapeSize = 8,
MiniatureStrokeThickness = 2,
Stroke = new SolidColorPaint(SKColor.Parse(color)) { StrokeThickness = 3.2f },
Fill = new SolidColorPaint(SKColors.Transparent),
GeometryFill = new SolidColorPaint(SKColors.White),
GeometryStroke = new SolidColorPaint(SKColor.Parse(color)) { StrokeThickness = 2 },
GeometrySize = 4,
LineSmoothness = smoothness,
ScalesYAt = yAxis
};
2026-06-02 17:41:53 +08:00
private static string DeviceSettingsPath =>
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"FootwearSlipResistance",
"device-settings.json");
}
}