✨ feat: 初始化 PCB 检测 WPF 应用程序

* 创建 AxiOmron.PcbCheck 项目主框架及解决方案
* 添加 Dashboard 和系统设置页面
* 实现 Modbus TCP PLC、扫码枪、SFTP 查询等核心服务
* 集成 Andon 报警、工作流托管服务与日志配置
* 补充项目文档和 UI 设计规范
This commit is contained in:
2026-04-17 10:43:51 +08:00
parent 660ee99442
commit 49f113dcf3
46 changed files with 8042 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
using System.IO;
using System.Text;
using System.Windows;
using AxiOmron.PcbCheck.Options;
using AxiOmron.PcbCheck.Services.Implementations;
using AxiOmron.PcbCheck.Services.Interfaces;
using AxiOmron.PcbCheck.ViewModels;
using AxiOmron.PcbCheck.Views.Pages;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
namespace AxiOmron.PcbCheck;
/// <summary>
/// 表示 WPF 应用入口,负责 Host/DI、配置和日志初始化。
/// </summary>
public partial class App : Application
{
private IHost? _host;
/// <summary>
/// 获取当前应用服务容器。
/// </summary>
public static IServiceProvider Services { get; private set; } = null!;
/// <summary>
/// 应用启动入口。
/// </summary>
/// <param name="e">启动事件参数。</param>
protected override async void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
try
{
Console.OutputEncoding = Encoding.UTF8;
}
catch (IOException)
{
// WinExe 在没有控制台句柄时忽略
}
try
{
_host = BuildHost();
await _host.StartAsync().ConfigureAwait(true);
Services = _host.Services;
var mainWindow = Services.GetRequiredService<MainWindow>();
MainWindow = mainWindow;
mainWindow.Show();
}
catch (Exception ex)
{
MessageBox.Show($"应用启动失败: {ex.Message}", "Axi Omron PCB Check", MessageBoxButton.OK, MessageBoxImage.Error);
Shutdown(-1);
}
}
/// <summary>
/// 应用退出入口。
/// </summary>
/// <param name="e">退出事件参数。</param>
protected override async void OnExit(ExitEventArgs e)
{
if (_host is not null)
{
try
{
await _host.StopAsync(TimeSpan.FromSeconds(2)).ConfigureAwait(false);
}
finally
{
_host.Dispose();
}
}
base.OnExit(e);
}
/// <summary>
/// 构建应用 Host 与依赖注入容器。
/// </summary>
/// <returns>已构建的 Host 实例。</returns>
private static IHost BuildHost()
{
return Host.CreateDefaultBuilder()
.ConfigureAppConfiguration((context, configurationBuilder) =>
{
configurationBuilder.SetBasePath(AppContext.BaseDirectory);
configurationBuilder.AddJsonFile("appConfig.json", optional: true, reloadOnChange: false);
configurationBuilder.AddJsonFile($"appConfig.{context.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: false);
})
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Information);
logging.AddNLog();
})
.ConfigureServices((context, services) =>
{
var appConfig = new AppConfig();
context.Configuration.Bind(appConfig);
services.AddSingleton<IConfiguration>(context.Configuration);
services.AddSingleton<IAppConfigService, AppConfigService>();
services.AddSingleton(appConfig);
services.AddSingleton<IAppStateStore, AppStateStore>();
services.AddSingleton(typeof(IAppLogger<>), typeof(AppLogger<>));
services.AddSingleton<IDispatcherService, DispatcherService>();
services.AddHttpClient(nameof(AndonService));
services.AddSingleton<IPlcService, ModbusTcpPlcService>();
services.AddSingleton<IScannerService, SerialScannerService>();
services.AddSingleton<ISftpLookupService, SftpLookupService>();
services.AddSingleton<IAndonService, AndonService>();
services.AddSingleton<WorkflowHostedService>();
services.AddSingleton<IWorkflowControlService>(sp => sp.GetRequiredService<WorkflowHostedService>());
services.AddHostedService(sp => sp.GetRequiredService<WorkflowHostedService>());
services.AddSingleton<MainWindowViewModel>();
services.AddSingleton<SystemSettingViewModel>();
services.AddSingleton<DashboardPage>();
services.AddSingleton<SystemSettingsPage>();
services.AddSingleton<MainWindow>();
})
.Build();
}
}