feature: qSOFA Scoring & Sepsis Bundle Compliance

This commit is contained in:
voltsrage
2026-06-18 22:52:43 +08:00
parent 3c54feb38a
commit 4b46c09f90
34 changed files with 2351 additions and 18 deletions
@@ -13,6 +13,8 @@ public class AppDbContext : DbContext
public DbSet<OutboxEvent> OutboxEvents => Set<OutboxEvent>();
public DbSet<ReconciliationAlert> ReconciliationAlerts => Set<ReconciliationAlert>();
public DbSet<News2Score> News2Scores => Set<News2Score>();
public DbSet<SepsisBundle> SepsisBundles => Set<SepsisBundle>();
public DbSet<SepsisBundleElement> SepsisBundleElements => Set<SepsisBundleElement>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
@@ -0,0 +1,47 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
public class SepsisBundleConfiguration : IEntityTypeConfiguration<SepsisBundle>
{
public void Configure(EntityTypeBuilder<SepsisBundle> builder)
{
builder.ToTable("sepsis_bundles", t =>
{
t.HasCheckConstraint("chk_sepsis_bundles_compliance_status",
"compliance_status IN ('IN_PROGRESS', 'COMPLIANT', 'NON_COMPLIANT')");
});
builder.HasKey(b => b.Id);
builder.Property(b => b.Id).HasColumnName("id").HasDefaultValueSql("gen_random_uuid()");
builder.Property(b => b.EncounterId).HasColumnName("encounter_id").IsRequired();
builder.Property(b => b.TriggeringAlertId).HasColumnName("triggering_alert_id").IsRequired();
builder.Property(b => b.TriggeringAlertType)
.HasColumnName("triggering_alert_type")
.HasMaxLength(50)
.IsRequired();
builder.Property(b => b.RecognizedAt).HasColumnName("recognized_at").IsRequired();
builder.Property(b => b.DeadlineAt).HasColumnName("deadline_at").IsRequired();
builder.Property(b => b.ComplianceStatus)
.HasColumnName("compliance_status")
.HasMaxLength(20)
.HasConversion(
v => v.ToDbString(),
v => SepsisBundleComplianceStatusExtensions.FromDbString(v))
.HasDefaultValueSql("'IN_PROGRESS'")
.HasSentinel((SepsisBundleComplianceStatus)(-1));
builder.Property(b => b.CompletedAt).HasColumnName("completed_at");
builder.HasOne(b => b.Encounter)
.WithMany()
.HasForeignKey(b => b.EncounterId)
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne(b => b.TriggeringAlert)
.WithMany()
.HasForeignKey(b => b.TriggeringAlertId)
.OnDelete(DeleteBehavior.Restrict);
builder.HasIndex(b => new { b.EncounterId, b.RecognizedAt });
builder.HasIndex(b => b.ComplianceStatus);
}
}
@@ -0,0 +1,50 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
public class SepsisBundleElementConfiguration : IEntityTypeConfiguration<SepsisBundleElement>
{
public void Configure(EntityTypeBuilder<SepsisBundleElement> builder)
{
builder.ToTable("sepsis_bundle_elements", t =>
{
t.HasCheckConstraint("chk_sepsis_bundle_elements_element_type",
"element_type IN ('BLOOD_CULTURES', 'SERUM_LACTATE', " +
"'BROAD_SPECTRUM_ANTIBIOTICS', 'IV_FLUID_RESUSCITATION')");
t.HasCheckConstraint("chk_sepsis_bundle_elements_status",
"status IN ('PENDING', 'COMPLETED')");
});
builder.HasKey(e => e.Id);
builder.Property(e => e.Id).HasColumnName("id").HasDefaultValueSql("gen_random_uuid()");
builder.Property(e => e.BundleId).HasColumnName("bundle_id").IsRequired();
builder.Property(e => e.ElementType)
.HasColumnName("element_type")
.HasMaxLength(40)
.HasConversion(
v => v.ToDbString(),
v => SepsisBundleElementTypeExtensions.FromDbString(v))
.IsRequired();
builder.Property(e => e.Status)
.HasColumnName("status")
.HasMaxLength(20)
.HasConversion(
v => v.ToDbString(),
v => SepsisBundleElementStatusExtensions.FromDbString(v))
.HasDefaultValueSql("'PENDING'")
.HasSentinel((SepsisBundleElementStatus)(-1));
builder.Property(e => e.OrderId).HasColumnName("order_id");
builder.Property(e => e.CompletedAt).HasColumnName("completed_at");
builder.HasOne(e => e.Bundle)
.WithMany(b => b.Elements)
.HasForeignKey(e => e.BundleId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne(e => e.Order)
.WithMany()
.HasForeignKey(e => e.OrderId)
.OnDelete(DeleteBehavior.SetNull);
builder.HasIndex(e => new { e.BundleId, e.ElementType }).IsUnique();
}
}