Files
CSI-Z420-Tablet-Multi-Funct…/App.xaml.cs
GukSang.Jin 69557bc108 更新122
2026-05-19 20:33:16 +08:00

262 lines
9.5 KiB
C#

using Microsoft.Extensions.Configuration;
using Microsoft.Data.Sqlite;
using OfficeOpenXml;
using System;
using System.IO;
using System.Text.Json;
using System.Windows;
using TabletTester2025.Data;
using TabletTester2025.Models;
using TabletTester2025.Services;
using TabletTester2025.ViewModels;
namespace TabletTester2025
{
public partial class App : Application
{
public static IPlcService PlcService { get; private set; }
public static PlcConfiguration PlcConfig { get; private set; }
public static PharmaParameters CurrentPharmaParams { get; set; } = new PharmaParameters();
private static readonly JsonSerializerOptions PharmaJsonOptions = new() { WriteIndented = true };
public static string PharmaParametersFilePath
{
get
{
string directory = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"CSI-Z420-Tablet-Multi-Function-Tester");
return Path.Combine(directory, "pharma-standard.json");
}
}
protected override void OnStartup(StartupEventArgs e)
{
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
base.OnStartup(e);
// 读取配置
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
var configuration = builder.Build();
// 数据库初始化(手动建表)
var connectionString = configuration.GetConnectionString("DefaultConnection") ?? "Data Source=TabletTests.db";
using (var connection = new Microsoft.Data.Sqlite.SqliteConnection(connectionString))
{
connection.Open();
var cmd = connection.CreateCommand();
cmd.CommandText = @"
CREATE TABLE IF NOT EXISTS TestBatches (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
TestTime TEXT NOT NULL,
StationId INTEGER NOT NULL,
SampleName TEXT,
-- 硬度
HardnessAvg REAL,
HardnessAverageDeviation REAL,
HardnessRSD REAL,
HardnessMax REAL,
HardnessMin REAL,
HardnessTestCount INTEGER,
HardnessInternalMin REAL,
HardnessInternalMax REAL,
-- 脆碎度
FriabilityLoss REAL,
FriabilityTargetRpm REAL,
FriabilityTargetTimeSec INTEGER,
FriabilityTargetRounds INTEGER,
FriabilityClockwise INTEGER, -- bool 存储为 0/1
FriabilityRemainingRounds INTEGER,
WeightBefore REAL,
WeightAfter REAL,
-- 崩解
DisintegrationTimeSec REAL,
RemainingTubesAtEnd INTEGER,
DisintegrationTargetFreq REAL,
DisintegrationTemp REAL,
DisintegrationDosageForm TEXT,
DisintegrationLimitSeconds INTEGER,
-- 溶出
DissolutionChannel TEXT,
DissolutionRate30Min REAL,
DissolutionTargetRpm REAL,
DissolutionRSquared REAL,
DissolutionSampleInterval INTEGER,
Dissolution1SampleInterval REAL,
Dissolution2SampleInterval REAL,
DissolutionUpDownFreq REAL,
-- 综合
IsQualified INTEGER,
-- 各项目单独合格标志
HardnessPass INTEGER,
FriabilityPass INTEGER,
DisintegrationPass INTEGER,
DissolutionPass INTEGER,
-- 测试类型(用于区分报表)
TestType TEXT
);
";
cmd.ExecuteNonQuery();
var hardnessSampleCmd = connection.CreateCommand();
hardnessSampleCmd.CommandText = @"
CREATE TABLE IF NOT EXISTS HardnessSamplePoints (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
TestBatchId INTEGER NOT NULL,
SequenceNo INTEGER NOT NULL,
Value REAL NOT NULL,
DeviationFromAverage REAL NOT NULL,
RecordedAt TEXT NOT NULL,
FOREIGN KEY(TestBatchId) REFERENCES TestBatches(Id) ON DELETE CASCADE
);
";
hardnessSampleCmd.ExecuteNonQuery();
var sampleCmd = connection.CreateCommand();
sampleCmd.CommandText = @"
CREATE TABLE IF NOT EXISTS DissolutionSamplePoints (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
TestBatchId INTEGER NOT NULL,
Channel INTEGER NOT NULL,
ScheduledTimeMin REAL NOT NULL,
ActualTimeMin REAL,
Percent REAL,
RecordedAt TEXT,
FOREIGN KEY(TestBatchId) REFERENCES TestBatches(Id) ON DELETE CASCADE
);
";
sampleCmd.ExecuteNonQuery();
}
EnsureColumnsExist(connectionString);
// 绑定药典参数
configuration.GetSection("PharmaStandard").Bind(CurrentPharmaParams);
LoadLocalPharmaParameters();
// PLC配置
PlcConfig = configuration.GetSection("Plc").Get<PlcConfiguration>();
if (PlcConfig == null)
throw new InvalidOperationException("PLC配置缺失");
PlcService = new ModbusTcpPlcService(PlcConfig);
// 业务服务
var dbService = new DatabaseService(connectionString);
var excelService = new ExcelExportService();
var alarmService = new AlarmService();
// 主窗口
var mainWindow = new MainWindow();
mainWindow.DataContext = new MainViewModel(PlcService, dbService, excelService, alarmService, PlcConfig);
MainWindow = mainWindow;
mainWindow.Show();
}
public static void SaveCurrentPharmaParameters()
{
string path = PharmaParametersFilePath;
string? directory = Path.GetDirectoryName(path);
if (!string.IsNullOrWhiteSpace(directory))
Directory.CreateDirectory(directory);
File.WriteAllText(path, JsonSerializer.Serialize(CurrentPharmaParams, PharmaJsonOptions));
}
private static void LoadLocalPharmaParameters()
{
string path = PharmaParametersFilePath;
if (!File.Exists(path))
return;
try
{
var local = JsonSerializer.Deserialize<PharmaParameters>(File.ReadAllText(path));
if (local != null)
CurrentPharmaParams = local;
}
catch
{
// Keep appsettings defaults if the local parameter file is damaged.
}
}
private void EnsureColumnsExist(string connectionString)
{
var requiredColumns = new[]
{
("TestBatches", "HardnessMax", "REAL", "0"),
("TestBatches", "HardnessMin", "REAL", "0"),
("TestBatches", "HardnessAverageDeviation", "REAL", "0"),
("TestBatches", "HardnessTestCount", "INTEGER", "6"),
("TestBatches", "HardnessInternalMin", "REAL", "40"),
("TestBatches", "HardnessInternalMax", "REAL", "60"),
("TestBatches", "FriabilityTargetRpm", "REAL", "25"),
("TestBatches", "FriabilityTargetTimeSec", "INTEGER", "240"),
("TestBatches", "FriabilityTargetRounds", "INTEGER", "100"),
("TestBatches", "FriabilityClockwise", "INTEGER", "1"),
("TestBatches", "FriabilityRemainingRounds", "INTEGER", "100"),
("TestBatches", "WeightBefore", "REAL", "0"),
("TestBatches", "WeightAfter", "REAL", "0"),
("TestBatches", "DisintegrationTargetFreq", "REAL", "31"),
("TestBatches", "DisintegrationTemp", "REAL", "37"),
("TestBatches", "DisintegrationDosageForm", "TEXT", "'普通片'"),
("TestBatches", "DisintegrationLimitSeconds", "INTEGER", "900"),
("TestBatches", "DissolutionChannel", "TEXT", "''"),
("TestBatches", "DissolutionTargetRpm", "REAL", "50"),
("TestBatches", "DissolutionRSquared", "REAL", "0"),
("TestBatches", "DissolutionSampleInterval", "INTEGER", "5"),
("TestBatches", "Dissolution1SampleInterval", "REAL", "5"),
("TestBatches", "Dissolution2SampleInterval", "REAL", "5"),
("TestBatches", "DissolutionUpDownFreq", "REAL", "32"),
("TestBatches", "HardnessRSD", "REAL", "0"), // 已存在但确保
("TestBatches", "RemainingTubesAtEnd", "INTEGER", "0"),
// 新增合格列
("TestBatches", "HardnessPass", "INTEGER", "0"),
("TestBatches", "FriabilityPass", "INTEGER", "0"),
("TestBatches", "DisintegrationPass", "INTEGER", "0"),
("TestBatches", "DissolutionPass", "INTEGER", "0"),
("TestBatches", "TestType", "TEXT", "")
};
using var connection = new SqliteConnection(connectionString);
connection.Open();
foreach (var (table, column, colType, defaultValue) in requiredColumns)
{
// 检查列是否存在
var pragmaCmd = connection.CreateCommand();
pragmaCmd.CommandText = $"PRAGMA table_info({table})";
using var reader = pragmaCmd.ExecuteReader();
bool columnExists = false;
while (reader.Read())
{
if (reader.GetString(1) == column)
{
columnExists = true;
break;
}
}
if (!columnExists)
{
// 添加缺失的列
var alterCmd = connection.CreateCommand();
alterCmd.CommandText = $"ALTER TABLE {table} ADD COLUMN {column} {colType} DEFAULT {defaultValue}";
alterCmd.ExecuteNonQuery();
System.Diagnostics.Debug.WriteLine($"已添加缺失的列: {table}.{column}");
}
}
}
}
}