feature: HL7 FHIR R4 Integration

This commit is contained in:
voltsrage
2026-06-27 22:23:45 +08:00
parent 756cff332c
commit 5646dfddb4
27 changed files with 2658 additions and 16 deletions
@@ -0,0 +1,83 @@
using Hl7.Fhir.Model;
using FhirPatient = Hl7.Fhir.Model.Patient;
public static class PatientMapper
{
/// <summary>
/// Maps a VigilCare Patient entity to a FHIR R4 Patient resource.
///
/// Mapping decisions:
/// - VigilCare stores full name as a single string; FHIR splits into family/given.
/// We use HumanName.Text for the full string and attempt to split on the last
/// space for family/given when possible.
/// - MRN maps to Identifier with system "urn:oid:2.16.840.1.113883.19.5" (example OID).
/// Facilities should configure their own OID.
/// - BloodType maps to an extension (no standard FHIR element for blood type).
/// - AllergiesJson is NOT mapped here — allergies should use AllergyIntolerance
/// resources, which are out of scope for Phase 11 v1.
/// </summary>
public static FhirPatient ToFhir(Patient entity, string baseUrl)
{
var patient = new FhirPatient
{
Id = entity.Id.ToString(),
Meta = new Meta
{
VersionId = "1",
LastUpdated = entity.UpdatedAt,
},
Active = true,
};
patient.Identifier.Add(new Identifier
{
System = "urn:oid:2.16.840.1.113883.19.5",
Value = entity.Mrn,
Use = Identifier.IdentifierUse.Official,
Type = new CodeableConcept("http://terminology.hl7.org/CodeSystem/v2-0203", "MR", "Medical Record Number"),
});
var name = new HumanName { Text = entity.FullName, Use = HumanName.NameUse.Official };
var parts = entity.FullName.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length >= 2)
{
name.Family = parts[^1];
name.Given = parts[..^1].ToList();
}
else
{
name.Family = entity.FullName;
}
patient.Name.Add(name);
if (entity.DateOfBirth.HasValue)
{
patient.BirthDate = entity.DateOfBirth.Value.ToString("yyyy-MM-dd");
}
if (!string.IsNullOrEmpty(entity.Sex))
{
patient.Gender = entity.Sex.ToLowerInvariant() switch
{
"male" => AdministrativeGender.Male,
"female" => AdministrativeGender.Female,
"other" => AdministrativeGender.Other,
_ => AdministrativeGender.Unknown,
};
}
if (!string.IsNullOrEmpty(entity.EmergencyContact))
{
patient.Contact.Add(new FhirPatient.ContactComponent
{
Relationship = new List<CodeableConcept>
{
new("http://terminology.hl7.org/CodeSystem/v2-0131", "C", "Emergency Contact")
},
Name = new HumanName { Text = entity.EmergencyContact },
});
}
return patient;
}
}