✨ feat(*): 重构PCB放行流程并接入双扫码校验

- 将流程改为 OMRON FINS + TCP 双扫码 + SFTP 文件校验
- 新增文件校验与扫码结果汇总实现,补充对应单测
- 同步更新流程设计文档、配置和系统设置页面文案
This commit is contained in:
2026-05-17 14:08:05 +08:00
parent 9a2211ccaa
commit ce356bffff
37 changed files with 4443 additions and 2436 deletions

View File

@@ -11,58 +11,58 @@ using Xunit;
namespace AxiOmron.PcbCheck.Tests;
/// <summary>
/// 验证系统设置页视图模型中的 SFTP 测试连接行为。
/// 验证系统设置页视图模型中的文件校验通道测试行为。
/// </summary>
public sealed class SystemSettingViewModelTests
{
/// <summary>
/// 当 SFTP 测试成功时,应更新成功状态文本。
/// 当文件校验通道测试成功时,应更新成功状态文本。
/// </summary>
/// <returns>异步测试任务。</returns>
[Fact]
public async Task TestSftpConnectionAsync_ShouldReportSuccess_WhenConnectionSucceeds()
public async Task TestFileCheckConnectionAsync_ShouldReportSuccess_WhenConnectionSucceeds()
{
var configService = new FakeAppConfigService();
var stateStore = new AppStateStore();
var dispatcherService = new ImmediateDispatcherService();
var sftpLookupService = new FakeSftpLookupService
var fileCheckService = new FakeFileCheckService
{
TestOutcome = new SftpConnectionTestOutcome
TestOutcome = new FileCheckTestOutcome
{
IsSuccess = true,
RootPathAccessible = true,
StatusMessage = "SFTP 连接成功,根目录可访问。"
}
};
var viewModel = new SystemSettingViewModel(configService, sftpLookupService, stateStore, dispatcherService);
var viewModel = new SystemSettingViewModel(configService, fileCheckService, stateStore, dispatcherService);
await viewModel.TestSftpConnectionCommand.ExecuteAsync(null);
await viewModel.TestFileCheckConnectionCommand.ExecuteAsync(null);
Assert.Equal("SFTP 连接成功,根目录可访问。", viewModel.StatusMessage);
}
/// <summary>
/// 当 SFTP 测试失败时,应将失败原因展示到状态文本。
/// 当文件校验通道测试失败时,应将失败原因展示到状态文本。
/// </summary>
/// <returns>异步测试任务。</returns>
[Fact]
public async Task TestSftpConnectionAsync_ShouldReportFailure_WhenConnectionFails()
public async Task TestFileCheckConnectionAsync_ShouldReportFailure_WhenConnectionFails()
{
var configService = new FakeAppConfigService();
var stateStore = new AppStateStore();
var dispatcherService = new ImmediateDispatcherService();
var sftpLookupService = new FakeSftpLookupService
var fileCheckService = new FakeFileCheckService
{
TestOutcome = new SftpConnectionTestOutcome
TestOutcome = new FileCheckTestOutcome
{
IsSuccess = false,
IsSystemError = true,
StatusMessage = "SFTP 连接失败: timeout"
}
};
var viewModel = new SystemSettingViewModel(configService, sftpLookupService, stateStore, dispatcherService);
var viewModel = new SystemSettingViewModel(configService, fileCheckService, stateStore, dispatcherService);
await viewModel.TestSftpConnectionCommand.ExecuteAsync(null);
await viewModel.TestFileCheckConnectionCommand.ExecuteAsync(null);
Assert.Equal("SFTP 连接失败: timeout", viewModel.StatusMessage);
}
@@ -87,7 +87,7 @@ public sealed class SystemSettingViewModelTests
});
});
var viewModel = new SystemSettingViewModel(configService, new FakeSftpLookupService(), stateStore, dispatcherService);
var viewModel = new SystemSettingViewModel(configService, new FakeFileCheckService(), stateStore, dispatcherService);
Assert.Single(viewModel.PlcMonitorItems);
Assert.Equal("PcbArrived", viewModel.PlcMonitorItems[0].Name);
@@ -104,7 +104,7 @@ public sealed class SystemSettingViewModelTests
var configService = new FakeAppConfigService();
var stateStore = new AppStateStore();
var dispatcherService = new CapturedDispatcherService(Dispatcher.CurrentDispatcher);
var viewModel = new SystemSettingViewModel(configService, new FakeSftpLookupService(), stateStore, dispatcherService);
var viewModel = new SystemSettingViewModel(configService, new FakeFileCheckService(), stateStore, dispatcherService);
_ = CollectionViewSource.GetDefaultView(viewModel.PlcMonitorItems);
Exception? capturedException = null;
@@ -158,7 +158,7 @@ public sealed class SystemSettingViewModelTests
var stateStore = new AppStateStore();
var viewModel = new SystemSettingViewModel(
configService,
new FakeSftpLookupService(),
new FakeFileCheckService(),
stateStore,
new CanceledDispatcherService());
var synchronizationContext = new ExceptionCapturingSynchronizationContext();
@@ -281,16 +281,16 @@ public sealed class SystemSettingViewModelTests
}
}
private sealed class FakeSftpLookupService : ISftpLookupService
private sealed class FakeFileCheckService : IFileCheckService
{
public SftpConnectionTestOutcome TestOutcome { get; set; } = new();
public FileCheckTestOutcome TestOutcome { get; set; } = new();
public Task<SftpCheckOutcome> CheckFileAsync(string barcode, CancellationToken cancellationToken)
public Task<FileCheckOutcome> CheckFileAsync(string barcode, CancellationToken cancellationToken)
{
throw new NotSupportedException();
}
public Task<SftpConnectionTestOutcome> TestConnectionAsync(SftpOptions? options, CancellationToken cancellationToken)
public Task<FileCheckTestOutcome> TestConnectionAsync(AppConfig? config, CancellationToken cancellationToken)
{
return Task.FromResult(TestOutcome);
}