@imranq2/fhirpatientsummary 1.0.23 → 1.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +448 -1
- package/dist/index.js +448 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -155,7 +155,9 @@ var IPSSectionSummaryCompositionFilter = {
|
|
|
155
155
|
["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "vital_summary_document"),
|
|
156
156
|
["PlanOfCareSection" /* CARE_PLAN */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "careplan_summary_document"),
|
|
157
157
|
["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "immunization_summary_document"),
|
|
158
|
-
["MedicationSummarySection" /* MEDICATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "medication_summary_document")
|
|
158
|
+
["MedicationSummarySection" /* MEDICATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "medication_summary_document"),
|
|
159
|
+
["ResultsSection" /* DIAGNOSTIC_REPORTS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && ["lab_summary_document", "diagnosticreportlab_summary_document"].includes(c.code)),
|
|
160
|
+
["HistoryOfProceduresSection" /* PROCEDURES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "procedure_summary_document")
|
|
159
161
|
};
|
|
160
162
|
var IPSSectionResourceHelper = class {
|
|
161
163
|
static getResourceFilterForSection(section) {
|
|
@@ -2088,6 +2090,400 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
2088
2090
|
generateNarrative(resources, timezone) {
|
|
2089
2091
|
return _DiagnosticResultsTemplate.generateStaticNarrative(resources, timezone);
|
|
2090
2092
|
}
|
|
2093
|
+
/**
|
|
2094
|
+
* Helper function to format observation data fields
|
|
2095
|
+
* @param obsData - Record containing observation data fields
|
|
2096
|
+
*/
|
|
2097
|
+
formatSummaryObservationData(obsData) {
|
|
2098
|
+
const valueType = obsData["valueType"];
|
|
2099
|
+
switch (valueType) {
|
|
2100
|
+
case "valueQuantity":
|
|
2101
|
+
if (obsData["value"] && obsData["unit"]) {
|
|
2102
|
+
obsData["formattedValue"] = `${obsData["value"]} ${obsData["unit"]}`;
|
|
2103
|
+
} else if (obsData["value"]) {
|
|
2104
|
+
obsData["formattedValue"] = obsData["value"];
|
|
2105
|
+
}
|
|
2106
|
+
break;
|
|
2107
|
+
case "valueCodeableConcept":
|
|
2108
|
+
case "valueString":
|
|
2109
|
+
case "valueBoolean":
|
|
2110
|
+
case "valueInteger":
|
|
2111
|
+
case "valueDateTime":
|
|
2112
|
+
case "valueTime":
|
|
2113
|
+
obsData["formattedValue"] = obsData["value"] ?? "";
|
|
2114
|
+
break;
|
|
2115
|
+
case "valuePeriod":
|
|
2116
|
+
if (obsData["valuePeriodStart"] && obsData["valuePeriodEnd"]) {
|
|
2117
|
+
obsData["formattedValue"] = `${obsData["valuePeriodStart"]} - ${obsData["valuePeriodEnd"]}`;
|
|
2118
|
+
} else if (obsData["valuePeriodStart"]) {
|
|
2119
|
+
obsData["formattedValue"] = `From ${obsData["valuePeriodStart"]}`;
|
|
2120
|
+
} else if (obsData["valuePeriodEnd"]) {
|
|
2121
|
+
obsData["formattedValue"] = `Until ${obsData["valuePeriodEnd"]}`;
|
|
2122
|
+
}
|
|
2123
|
+
break;
|
|
2124
|
+
case "valueSampledData": {
|
|
2125
|
+
const sampledParts = [];
|
|
2126
|
+
if (obsData["sampledDataOriginValue"]) {
|
|
2127
|
+
sampledParts.push(`Origin: ${obsData["sampledDataOriginValue"]}${obsData["sampledDataOriginUnit"] ? " " + obsData["sampledDataOriginUnit"] : ""}`);
|
|
2128
|
+
}
|
|
2129
|
+
if (obsData["sampledDataPeriod"]) {
|
|
2130
|
+
sampledParts.push(`Period: ${obsData["sampledDataPeriod"]}`);
|
|
2131
|
+
}
|
|
2132
|
+
if (obsData["sampledDataFactor"]) {
|
|
2133
|
+
sampledParts.push(`Factor: ${obsData["sampledDataFactor"]}`);
|
|
2134
|
+
}
|
|
2135
|
+
if (obsData["sampledDataLowerLimit"]) {
|
|
2136
|
+
sampledParts.push(`Lower: ${obsData["sampledDataLowerLimit"]}`);
|
|
2137
|
+
}
|
|
2138
|
+
if (obsData["sampledDataUpperLimit"]) {
|
|
2139
|
+
sampledParts.push(`Upper: ${obsData["sampledDataUpperLimit"]}`);
|
|
2140
|
+
}
|
|
2141
|
+
if (obsData["sampledDataData"]) {
|
|
2142
|
+
sampledParts.push(`Data: ${obsData["sampledDataData"]}`);
|
|
2143
|
+
}
|
|
2144
|
+
obsData["formattedValue"] = sampledParts.join(", ");
|
|
2145
|
+
break;
|
|
2146
|
+
}
|
|
2147
|
+
case "valueRange": {
|
|
2148
|
+
const rangeParts = [];
|
|
2149
|
+
if (obsData["valueRangeLowValue"]) {
|
|
2150
|
+
rangeParts.push(`${obsData["valueRangeLowValue"]}${obsData["valueRangeLowUnit"] ? " " + obsData["valueRangeLowUnit"] : ""}`);
|
|
2151
|
+
}
|
|
2152
|
+
if (obsData["valueRangeHighValue"]) {
|
|
2153
|
+
rangeParts.push(`${obsData["valueRangeHighValue"]}${obsData["valueRangeHighUnit"] ? " " + obsData["valueRangeHighUnit"] : ""}`);
|
|
2154
|
+
}
|
|
2155
|
+
obsData["formattedValue"] = rangeParts.join(" - ");
|
|
2156
|
+
break;
|
|
2157
|
+
}
|
|
2158
|
+
case "valueRatio": {
|
|
2159
|
+
const numerator = obsData["valueRatioNumeratorValue"] ? `${obsData["valueRatioNumeratorValue"]}${obsData["valueRatioNumeratorUnit"] ? " " + obsData["valueRatioNumeratorUnit"] : ""}` : "";
|
|
2160
|
+
const denominator = obsData["valueRatioDenominatorValue"] ? `${obsData["valueRatioDenominatorValue"]}${obsData["valueRatioDenominatorUnit"] ? " " + obsData["valueRatioDenominatorUnit"] : ""}` : "";
|
|
2161
|
+
if (numerator && denominator) {
|
|
2162
|
+
obsData["formattedValue"] = `${numerator} / ${denominator}`;
|
|
2163
|
+
} else if (numerator) {
|
|
2164
|
+
obsData["formattedValue"] = numerator;
|
|
2165
|
+
}
|
|
2166
|
+
break;
|
|
2167
|
+
}
|
|
2168
|
+
default:
|
|
2169
|
+
obsData["formattedValue"] = obsData["value"] ?? "";
|
|
2170
|
+
break;
|
|
2171
|
+
}
|
|
2172
|
+
if (obsData["referenceRangeLow"]) {
|
|
2173
|
+
obsData["referenceRange"] = obsData["referenceRangeLow"] + " " + obsData["referenceRangeLowUnit"];
|
|
2174
|
+
}
|
|
2175
|
+
if (obsData["referenceRangeHigh"]) {
|
|
2176
|
+
if (obsData["referenceRange"]) {
|
|
2177
|
+
obsData["referenceRange"] += " - ";
|
|
2178
|
+
} else {
|
|
2179
|
+
obsData["referenceRange"] = "";
|
|
2180
|
+
}
|
|
2181
|
+
obsData["referenceRange"] += obsData["referenceRangeHigh"] + " " + obsData["referenceRangeHighUnit"];
|
|
2182
|
+
}
|
|
2183
|
+
if (obsData["referenceRangeAgeLowValue"] || obsData["referenceRangeAgeHighValue"]) {
|
|
2184
|
+
const ageParts = [];
|
|
2185
|
+
if (obsData["referenceRangeAgeLowValue"]) {
|
|
2186
|
+
ageParts.push(`${obsData["referenceRangeAgeLowValue"]}${obsData["referenceRangeAgeLowUnit"] ? " " + obsData["referenceRangeAgeLowUnit"] : ""}`);
|
|
2187
|
+
}
|
|
2188
|
+
if (obsData["referenceRangeAgeHighValue"]) {
|
|
2189
|
+
ageParts.push(`${obsData["referenceRangeAgeHighValue"]}${obsData["referenceRangeAgeHighUnit"] ? " " + obsData["referenceRangeAgeHighUnit"] : ""}`);
|
|
2190
|
+
}
|
|
2191
|
+
if (obsData["referenceRange"]) {
|
|
2192
|
+
obsData["referenceRange"] += ` (Age: ${ageParts.join(" - ")})`;
|
|
2193
|
+
} else {
|
|
2194
|
+
obsData["referenceRange"] = `Age: ${ageParts.join(" - ")}`;
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
/**
|
|
2199
|
+
* Helper function to extract observation field data
|
|
2200
|
+
* @param column - Column data from the summary
|
|
2201
|
+
* @param targetData - Record to populate with extracted data
|
|
2202
|
+
*/
|
|
2203
|
+
extractSummaryObservationFields(column, targetData) {
|
|
2204
|
+
switch (column.title) {
|
|
2205
|
+
case "Labs Name":
|
|
2206
|
+
targetData["code"] = column.text?.div ?? "";
|
|
2207
|
+
break;
|
|
2208
|
+
case "effectiveDateTime":
|
|
2209
|
+
targetData["effectiveDateTime"] = column.text?.div ?? "";
|
|
2210
|
+
break;
|
|
2211
|
+
case "effectivePeriod.start":
|
|
2212
|
+
targetData["effectivePeriodStart"] = column.text?.div ?? "";
|
|
2213
|
+
break;
|
|
2214
|
+
case "effectivePeriod.end":
|
|
2215
|
+
targetData["effectivePeriodEnd"] = column.text?.div ?? "";
|
|
2216
|
+
break;
|
|
2217
|
+
// valueQuantity
|
|
2218
|
+
case "valueQuantity.value":
|
|
2219
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2220
|
+
targetData["valueType"] = "valueQuantity";
|
|
2221
|
+
break;
|
|
2222
|
+
case "valueQuantity.unit":
|
|
2223
|
+
targetData["unit"] = column.text?.div ?? "";
|
|
2224
|
+
break;
|
|
2225
|
+
// valueCodeableConcept
|
|
2226
|
+
case "valueCodeableConcept.text":
|
|
2227
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2228
|
+
targetData["valueType"] = "valueCodeableConcept";
|
|
2229
|
+
break;
|
|
2230
|
+
case "valueCodeableConcept.coding.display":
|
|
2231
|
+
if (!targetData["value"]) {
|
|
2232
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2233
|
+
targetData["valueType"] = "valueCodeableConcept";
|
|
2234
|
+
}
|
|
2235
|
+
break;
|
|
2236
|
+
// valueString
|
|
2237
|
+
case "valueString":
|
|
2238
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2239
|
+
targetData["valueType"] = "valueString";
|
|
2240
|
+
break;
|
|
2241
|
+
// valueBoolean
|
|
2242
|
+
case "valueBoolean":
|
|
2243
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2244
|
+
targetData["valueType"] = "valueBoolean";
|
|
2245
|
+
break;
|
|
2246
|
+
// valueInteger
|
|
2247
|
+
case "valueInteger":
|
|
2248
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2249
|
+
targetData["valueType"] = "valueInteger";
|
|
2250
|
+
break;
|
|
2251
|
+
// valueDateTime
|
|
2252
|
+
case "valueDateTime":
|
|
2253
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2254
|
+
targetData["valueType"] = "valueDateTime";
|
|
2255
|
+
break;
|
|
2256
|
+
// valuePeriod
|
|
2257
|
+
case "valuePeriod.start":
|
|
2258
|
+
targetData["valuePeriodStart"] = column.text?.div ?? "";
|
|
2259
|
+
targetData["valueType"] = "valuePeriod";
|
|
2260
|
+
break;
|
|
2261
|
+
case "valuePeriod.end":
|
|
2262
|
+
targetData["valuePeriodEnd"] = column.text?.div ?? "";
|
|
2263
|
+
targetData["valueType"] = "valuePeriod";
|
|
2264
|
+
break;
|
|
2265
|
+
// valueTime
|
|
2266
|
+
case "valueTime":
|
|
2267
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2268
|
+
targetData["valueType"] = "valueTime";
|
|
2269
|
+
break;
|
|
2270
|
+
// valueSampledData
|
|
2271
|
+
case "valueSampledData.origin.value":
|
|
2272
|
+
targetData["sampledDataOriginValue"] = column.text?.div ?? "";
|
|
2273
|
+
targetData["valueType"] = "valueSampledData";
|
|
2274
|
+
break;
|
|
2275
|
+
case "valueSampledData.origin.unit":
|
|
2276
|
+
targetData["sampledDataOriginUnit"] = column.text?.div ?? "";
|
|
2277
|
+
break;
|
|
2278
|
+
case "valueSampledData.period":
|
|
2279
|
+
targetData["sampledDataPeriod"] = column.text?.div ?? "";
|
|
2280
|
+
break;
|
|
2281
|
+
case "valueSampledData.factor":
|
|
2282
|
+
targetData["sampledDataFactor"] = column.text?.div ?? "";
|
|
2283
|
+
break;
|
|
2284
|
+
case "valueSampledData.lowerLimit":
|
|
2285
|
+
targetData["sampledDataLowerLimit"] = column.text?.div ?? "";
|
|
2286
|
+
break;
|
|
2287
|
+
case "valueSampledData.upperLimit":
|
|
2288
|
+
targetData["sampledDataUpperLimit"] = column.text?.div ?? "";
|
|
2289
|
+
break;
|
|
2290
|
+
case "valueSampledData.data":
|
|
2291
|
+
targetData["sampledDataData"] = column.text?.div ?? "";
|
|
2292
|
+
break;
|
|
2293
|
+
// valueRange
|
|
2294
|
+
case "valueRange.low.value":
|
|
2295
|
+
targetData["valueRangeLowValue"] = column.text?.div ?? "";
|
|
2296
|
+
targetData["valueType"] = "valueRange";
|
|
2297
|
+
break;
|
|
2298
|
+
case "valueRange.low.unit":
|
|
2299
|
+
targetData["valueRangeLowUnit"] = column.text?.div ?? "";
|
|
2300
|
+
break;
|
|
2301
|
+
case "valueRange.high.value":
|
|
2302
|
+
targetData["valueRangeHighValue"] = column.text?.div ?? "";
|
|
2303
|
+
break;
|
|
2304
|
+
case "valueRange.high.unit":
|
|
2305
|
+
targetData["valueRangeHighUnit"] = column.text?.div ?? "";
|
|
2306
|
+
break;
|
|
2307
|
+
// valueRatio
|
|
2308
|
+
case "valueRatio.numerator.value":
|
|
2309
|
+
targetData["valueRatioNumeratorValue"] = column.text?.div ?? "";
|
|
2310
|
+
targetData["valueType"] = "valueRatio";
|
|
2311
|
+
break;
|
|
2312
|
+
case "valueRatio.numerator.unit":
|
|
2313
|
+
targetData["valueRatioNumeratorUnit"] = column.text?.div ?? "";
|
|
2314
|
+
break;
|
|
2315
|
+
case "valueRatio.denominator.value":
|
|
2316
|
+
targetData["valueRatioDenominatorValue"] = column.text?.div ?? "";
|
|
2317
|
+
break;
|
|
2318
|
+
case "valueRatio.denominator.unit":
|
|
2319
|
+
targetData["valueRatioDenominatorUnit"] = column.text?.div ?? "";
|
|
2320
|
+
break;
|
|
2321
|
+
// referenceRange
|
|
2322
|
+
case "referenceRange.low.value":
|
|
2323
|
+
targetData["referenceRangeLow"] = column.text?.div ?? "";
|
|
2324
|
+
break;
|
|
2325
|
+
case "referenceRange.low.unit":
|
|
2326
|
+
targetData["referenceRangeLowUnit"] = column.text?.div ?? "";
|
|
2327
|
+
break;
|
|
2328
|
+
case "referenceRange.high.value":
|
|
2329
|
+
targetData["referenceRangeHigh"] = column.text?.div ?? "";
|
|
2330
|
+
break;
|
|
2331
|
+
case "referenceRange.high.unit":
|
|
2332
|
+
targetData["referenceRangeHighUnit"] = column.text?.div ?? "";
|
|
2333
|
+
break;
|
|
2334
|
+
case "referenceRange.age.low.value":
|
|
2335
|
+
targetData["referenceRangeAgeLowValue"] = column.text?.div ?? "";
|
|
2336
|
+
break;
|
|
2337
|
+
case "referenceRange.age.low.unit":
|
|
2338
|
+
targetData["referenceRangeAgeLowUnit"] = column.text?.div ?? "";
|
|
2339
|
+
break;
|
|
2340
|
+
case "referenceRange.age.high.value":
|
|
2341
|
+
targetData["referenceRangeAgeHighValue"] = column.text?.div ?? "";
|
|
2342
|
+
break;
|
|
2343
|
+
case "referenceRange.age.high.unit":
|
|
2344
|
+
targetData["referenceRangeAgeHighUnit"] = column.text?.div ?? "";
|
|
2345
|
+
break;
|
|
2346
|
+
default:
|
|
2347
|
+
break;
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
/**
|
|
2351
|
+
* Generate HTML narrative for Diagnostic Results & Observation resources using summary
|
|
2352
|
+
* @param resources - FHIR Composition resources
|
|
2353
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2354
|
+
* @returns HTML string for rendering
|
|
2355
|
+
*/
|
|
2356
|
+
generateSummaryNarrative(resources, timezone) {
|
|
2357
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
2358
|
+
let html = `
|
|
2359
|
+
<div>`;
|
|
2360
|
+
let observationhtml = `
|
|
2361
|
+
<div>
|
|
2362
|
+
<h3>Observations</h3>
|
|
2363
|
+
<table>
|
|
2364
|
+
<thead>
|
|
2365
|
+
<tr>
|
|
2366
|
+
<th>Code</th>
|
|
2367
|
+
<th>Result</th>
|
|
2368
|
+
<th>Reference Range</th>
|
|
2369
|
+
<th>Date</th>
|
|
2370
|
+
</tr>
|
|
2371
|
+
</thead>
|
|
2372
|
+
<tbody>`;
|
|
2373
|
+
let diagnosticReporthtml = `
|
|
2374
|
+
<div>
|
|
2375
|
+
<h3>Diagnostic Reports</h3>
|
|
2376
|
+
<table>
|
|
2377
|
+
<thead>
|
|
2378
|
+
<tr>
|
|
2379
|
+
<th>Report</th>
|
|
2380
|
+
<th>Performer</th>
|
|
2381
|
+
<th>Issued</th>
|
|
2382
|
+
</tr>
|
|
2383
|
+
</thead>
|
|
2384
|
+
<tbody>`;
|
|
2385
|
+
let observationExists = false;
|
|
2386
|
+
let diagnosticReportExists = false;
|
|
2387
|
+
for (const resourceItem of resources) {
|
|
2388
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
2389
|
+
const data = {};
|
|
2390
|
+
const components = [];
|
|
2391
|
+
for (const columnData of rowData.section ?? []) {
|
|
2392
|
+
if (resourceItem.title === "Observation|Labs Summary Grouped by Lab Code") {
|
|
2393
|
+
if (columnData.text?.div === "Observation.component" && columnData.section) {
|
|
2394
|
+
for (const componentSection of columnData.section) {
|
|
2395
|
+
const componentData = {};
|
|
2396
|
+
for (const nestedColumn of componentSection.section ?? []) {
|
|
2397
|
+
this.extractSummaryObservationFields(nestedColumn, componentData);
|
|
2398
|
+
}
|
|
2399
|
+
if (Object.keys(componentData).length > 0) {
|
|
2400
|
+
components.push(componentData);
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
} else {
|
|
2404
|
+
this.extractSummaryObservationFields(columnData, data);
|
|
2405
|
+
}
|
|
2406
|
+
} else if (resourceItem.title === "DiagnosticReportLab Summary Grouped by DiagnosticReport|Lab Code") {
|
|
2407
|
+
switch (columnData.title) {
|
|
2408
|
+
case "Diagnostic Report Name":
|
|
2409
|
+
data["report"] = columnData.text?.div ?? "";
|
|
2410
|
+
break;
|
|
2411
|
+
case "Performer":
|
|
2412
|
+
data["performer"] = columnData.text?.div ?? "";
|
|
2413
|
+
break;
|
|
2414
|
+
case "Issued Date":
|
|
2415
|
+
data["issued"] = columnData.text?.div ?? "";
|
|
2416
|
+
break;
|
|
2417
|
+
case "Status":
|
|
2418
|
+
data["status"] = columnData.text?.div ?? "";
|
|
2419
|
+
break;
|
|
2420
|
+
default:
|
|
2421
|
+
break;
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
if (resourceItem.title === "Observation|Labs Summary Grouped by Lab Code") {
|
|
2426
|
+
observationExists = true;
|
|
2427
|
+
let date = data["effectiveDateTime"] ? templateUtilities.renderTime(data["effectiveDateTime"], timezone) : "";
|
|
2428
|
+
if (!date && data["effectivePeriodStart"]) {
|
|
2429
|
+
date = templateUtilities.renderTime(data["effectivePeriodStart"], timezone);
|
|
2430
|
+
if (data["effectivePeriodEnd"]) {
|
|
2431
|
+
date += " - " + templateUtilities.renderTime(data["effectivePeriodEnd"], timezone);
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
if (components.length > 0) {
|
|
2435
|
+
const groupName = data["code"] ?? "";
|
|
2436
|
+
for (const component of components) {
|
|
2437
|
+
this.formatSummaryObservationData(component);
|
|
2438
|
+
observationhtml += `
|
|
2439
|
+
<tr>
|
|
2440
|
+
<td>${groupName ? groupName + " - " : ""}${component["code"] ?? "-"}</td>
|
|
2441
|
+
<td>${component["formattedValue"] ?? "-"}</td>
|
|
2442
|
+
<td>${component["referenceRange"]?.trim() ?? "-"}</td>
|
|
2443
|
+
<td>${date ?? "-"}</td>
|
|
2444
|
+
</tr>`;
|
|
2445
|
+
}
|
|
2446
|
+
} else {
|
|
2447
|
+
this.formatSummaryObservationData(data);
|
|
2448
|
+
observationhtml += `
|
|
2449
|
+
<tr>
|
|
2450
|
+
<td>${data["code"] ?? "-"}</td>
|
|
2451
|
+
<td>${data["formattedValue"] ?? "-"}</td>
|
|
2452
|
+
<td>${data["referenceRange"]?.trim() ?? "-"}</td>
|
|
2453
|
+
<td>${date ?? "-"}</td>
|
|
2454
|
+
</tr>`;
|
|
2455
|
+
}
|
|
2456
|
+
} else if (resourceItem.title === "DiagnosticReportLab Summary Grouped by DiagnosticReport|Lab Code") {
|
|
2457
|
+
if (data["status"] === "final") {
|
|
2458
|
+
diagnosticReportExists = true;
|
|
2459
|
+
diagnosticReporthtml += `
|
|
2460
|
+
<tr>
|
|
2461
|
+
<td>${data["report"] ?? "-"}</td>
|
|
2462
|
+
<td>${data["performer"] ?? "-"}</td>
|
|
2463
|
+
<td>${templateUtilities.renderTime(data["issued"], timezone) ?? "-"}</td>
|
|
2464
|
+
</tr>`;
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
if (observationExists) {
|
|
2470
|
+
html += observationhtml;
|
|
2471
|
+
html += `
|
|
2472
|
+
</tbody>
|
|
2473
|
+
</table>
|
|
2474
|
+
</div>`;
|
|
2475
|
+
}
|
|
2476
|
+
if (diagnosticReportExists) {
|
|
2477
|
+
html += diagnosticReporthtml;
|
|
2478
|
+
html += `
|
|
2479
|
+
</tbody>
|
|
2480
|
+
</table>
|
|
2481
|
+
</div>`;
|
|
2482
|
+
}
|
|
2483
|
+
html += `
|
|
2484
|
+
</div>`;
|
|
2485
|
+
return html;
|
|
2486
|
+
}
|
|
2091
2487
|
/**
|
|
2092
2488
|
* Internal static implementation that actually generates the narrative
|
|
2093
2489
|
* @param resources - FHIR resources array containing Observation and DiagnosticReport resources
|
|
@@ -2229,6 +2625,57 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
|
|
|
2229
2625
|
});
|
|
2230
2626
|
return _HistoryOfProceduresTemplate.generateStaticNarrative(resources, timezone);
|
|
2231
2627
|
}
|
|
2628
|
+
/**
|
|
2629
|
+
* Generate HTML narrative for Procedure resources using summary
|
|
2630
|
+
* @param resources - FHIR Composition resources
|
|
2631
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2632
|
+
* @returns HTML string for rendering
|
|
2633
|
+
*/
|
|
2634
|
+
generateSummaryNarrative(resources, timezone) {
|
|
2635
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
2636
|
+
let html = `
|
|
2637
|
+
<div>
|
|
2638
|
+
<table>
|
|
2639
|
+
<thead>
|
|
2640
|
+
<tr>
|
|
2641
|
+
<th>Procedure</th>
|
|
2642
|
+
<th>Performer</th>
|
|
2643
|
+
<th>Date</th>
|
|
2644
|
+
</tr>
|
|
2645
|
+
</thead>
|
|
2646
|
+
<tbody>`;
|
|
2647
|
+
for (const resourceItem of resources) {
|
|
2648
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
2649
|
+
const data = {};
|
|
2650
|
+
for (const columnData of rowData.section ?? []) {
|
|
2651
|
+
switch (columnData.title) {
|
|
2652
|
+
case "Procedure Name":
|
|
2653
|
+
data["procedure"] = columnData.text?.div ?? "";
|
|
2654
|
+
break;
|
|
2655
|
+
case "Performer":
|
|
2656
|
+
data["performer"] = columnData.text?.div ?? "";
|
|
2657
|
+
break;
|
|
2658
|
+
case "Performed Date":
|
|
2659
|
+
data["date"] = columnData.text?.div ?? "";
|
|
2660
|
+
break;
|
|
2661
|
+
default:
|
|
2662
|
+
break;
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
html += `
|
|
2666
|
+
<tr>
|
|
2667
|
+
<td>${data["procedure"] ?? "-"}</td>
|
|
2668
|
+
<td>${data["performer"] ?? "-"}</td>
|
|
2669
|
+
<td>${templateUtilities.renderTime(data["date"], timezone) ?? "-"}</td>
|
|
2670
|
+
</tr>`;
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
html += `
|
|
2674
|
+
</tbody>
|
|
2675
|
+
</table>
|
|
2676
|
+
</div>`;
|
|
2677
|
+
return html;
|
|
2678
|
+
}
|
|
2232
2679
|
/**
|
|
2233
2680
|
* Internal static implementation that actually generates the narrative
|
|
2234
2681
|
* @param resources - FHIR Procedure resources
|
package/dist/index.js
CHANGED
|
@@ -127,7 +127,9 @@ var IPSSectionSummaryCompositionFilter = {
|
|
|
127
127
|
["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "vital_summary_document"),
|
|
128
128
|
["PlanOfCareSection" /* CARE_PLAN */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "careplan_summary_document"),
|
|
129
129
|
["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "immunization_summary_document"),
|
|
130
|
-
["MedicationSummarySection" /* MEDICATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "medication_summary_document")
|
|
130
|
+
["MedicationSummarySection" /* MEDICATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "medication_summary_document"),
|
|
131
|
+
["ResultsSection" /* DIAGNOSTIC_REPORTS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && ["lab_summary_document", "diagnosticreportlab_summary_document"].includes(c.code)),
|
|
132
|
+
["HistoryOfProceduresSection" /* PROCEDURES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "procedure_summary_document")
|
|
131
133
|
};
|
|
132
134
|
var IPSSectionResourceHelper = class {
|
|
133
135
|
static getResourceFilterForSection(section) {
|
|
@@ -2060,6 +2062,400 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
2060
2062
|
generateNarrative(resources, timezone) {
|
|
2061
2063
|
return _DiagnosticResultsTemplate.generateStaticNarrative(resources, timezone);
|
|
2062
2064
|
}
|
|
2065
|
+
/**
|
|
2066
|
+
* Helper function to format observation data fields
|
|
2067
|
+
* @param obsData - Record containing observation data fields
|
|
2068
|
+
*/
|
|
2069
|
+
formatSummaryObservationData(obsData) {
|
|
2070
|
+
const valueType = obsData["valueType"];
|
|
2071
|
+
switch (valueType) {
|
|
2072
|
+
case "valueQuantity":
|
|
2073
|
+
if (obsData["value"] && obsData["unit"]) {
|
|
2074
|
+
obsData["formattedValue"] = `${obsData["value"]} ${obsData["unit"]}`;
|
|
2075
|
+
} else if (obsData["value"]) {
|
|
2076
|
+
obsData["formattedValue"] = obsData["value"];
|
|
2077
|
+
}
|
|
2078
|
+
break;
|
|
2079
|
+
case "valueCodeableConcept":
|
|
2080
|
+
case "valueString":
|
|
2081
|
+
case "valueBoolean":
|
|
2082
|
+
case "valueInteger":
|
|
2083
|
+
case "valueDateTime":
|
|
2084
|
+
case "valueTime":
|
|
2085
|
+
obsData["formattedValue"] = obsData["value"] ?? "";
|
|
2086
|
+
break;
|
|
2087
|
+
case "valuePeriod":
|
|
2088
|
+
if (obsData["valuePeriodStart"] && obsData["valuePeriodEnd"]) {
|
|
2089
|
+
obsData["formattedValue"] = `${obsData["valuePeriodStart"]} - ${obsData["valuePeriodEnd"]}`;
|
|
2090
|
+
} else if (obsData["valuePeriodStart"]) {
|
|
2091
|
+
obsData["formattedValue"] = `From ${obsData["valuePeriodStart"]}`;
|
|
2092
|
+
} else if (obsData["valuePeriodEnd"]) {
|
|
2093
|
+
obsData["formattedValue"] = `Until ${obsData["valuePeriodEnd"]}`;
|
|
2094
|
+
}
|
|
2095
|
+
break;
|
|
2096
|
+
case "valueSampledData": {
|
|
2097
|
+
const sampledParts = [];
|
|
2098
|
+
if (obsData["sampledDataOriginValue"]) {
|
|
2099
|
+
sampledParts.push(`Origin: ${obsData["sampledDataOriginValue"]}${obsData["sampledDataOriginUnit"] ? " " + obsData["sampledDataOriginUnit"] : ""}`);
|
|
2100
|
+
}
|
|
2101
|
+
if (obsData["sampledDataPeriod"]) {
|
|
2102
|
+
sampledParts.push(`Period: ${obsData["sampledDataPeriod"]}`);
|
|
2103
|
+
}
|
|
2104
|
+
if (obsData["sampledDataFactor"]) {
|
|
2105
|
+
sampledParts.push(`Factor: ${obsData["sampledDataFactor"]}`);
|
|
2106
|
+
}
|
|
2107
|
+
if (obsData["sampledDataLowerLimit"]) {
|
|
2108
|
+
sampledParts.push(`Lower: ${obsData["sampledDataLowerLimit"]}`);
|
|
2109
|
+
}
|
|
2110
|
+
if (obsData["sampledDataUpperLimit"]) {
|
|
2111
|
+
sampledParts.push(`Upper: ${obsData["sampledDataUpperLimit"]}`);
|
|
2112
|
+
}
|
|
2113
|
+
if (obsData["sampledDataData"]) {
|
|
2114
|
+
sampledParts.push(`Data: ${obsData["sampledDataData"]}`);
|
|
2115
|
+
}
|
|
2116
|
+
obsData["formattedValue"] = sampledParts.join(", ");
|
|
2117
|
+
break;
|
|
2118
|
+
}
|
|
2119
|
+
case "valueRange": {
|
|
2120
|
+
const rangeParts = [];
|
|
2121
|
+
if (obsData["valueRangeLowValue"]) {
|
|
2122
|
+
rangeParts.push(`${obsData["valueRangeLowValue"]}${obsData["valueRangeLowUnit"] ? " " + obsData["valueRangeLowUnit"] : ""}`);
|
|
2123
|
+
}
|
|
2124
|
+
if (obsData["valueRangeHighValue"]) {
|
|
2125
|
+
rangeParts.push(`${obsData["valueRangeHighValue"]}${obsData["valueRangeHighUnit"] ? " " + obsData["valueRangeHighUnit"] : ""}`);
|
|
2126
|
+
}
|
|
2127
|
+
obsData["formattedValue"] = rangeParts.join(" - ");
|
|
2128
|
+
break;
|
|
2129
|
+
}
|
|
2130
|
+
case "valueRatio": {
|
|
2131
|
+
const numerator = obsData["valueRatioNumeratorValue"] ? `${obsData["valueRatioNumeratorValue"]}${obsData["valueRatioNumeratorUnit"] ? " " + obsData["valueRatioNumeratorUnit"] : ""}` : "";
|
|
2132
|
+
const denominator = obsData["valueRatioDenominatorValue"] ? `${obsData["valueRatioDenominatorValue"]}${obsData["valueRatioDenominatorUnit"] ? " " + obsData["valueRatioDenominatorUnit"] : ""}` : "";
|
|
2133
|
+
if (numerator && denominator) {
|
|
2134
|
+
obsData["formattedValue"] = `${numerator} / ${denominator}`;
|
|
2135
|
+
} else if (numerator) {
|
|
2136
|
+
obsData["formattedValue"] = numerator;
|
|
2137
|
+
}
|
|
2138
|
+
break;
|
|
2139
|
+
}
|
|
2140
|
+
default:
|
|
2141
|
+
obsData["formattedValue"] = obsData["value"] ?? "";
|
|
2142
|
+
break;
|
|
2143
|
+
}
|
|
2144
|
+
if (obsData["referenceRangeLow"]) {
|
|
2145
|
+
obsData["referenceRange"] = obsData["referenceRangeLow"] + " " + obsData["referenceRangeLowUnit"];
|
|
2146
|
+
}
|
|
2147
|
+
if (obsData["referenceRangeHigh"]) {
|
|
2148
|
+
if (obsData["referenceRange"]) {
|
|
2149
|
+
obsData["referenceRange"] += " - ";
|
|
2150
|
+
} else {
|
|
2151
|
+
obsData["referenceRange"] = "";
|
|
2152
|
+
}
|
|
2153
|
+
obsData["referenceRange"] += obsData["referenceRangeHigh"] + " " + obsData["referenceRangeHighUnit"];
|
|
2154
|
+
}
|
|
2155
|
+
if (obsData["referenceRangeAgeLowValue"] || obsData["referenceRangeAgeHighValue"]) {
|
|
2156
|
+
const ageParts = [];
|
|
2157
|
+
if (obsData["referenceRangeAgeLowValue"]) {
|
|
2158
|
+
ageParts.push(`${obsData["referenceRangeAgeLowValue"]}${obsData["referenceRangeAgeLowUnit"] ? " " + obsData["referenceRangeAgeLowUnit"] : ""}`);
|
|
2159
|
+
}
|
|
2160
|
+
if (obsData["referenceRangeAgeHighValue"]) {
|
|
2161
|
+
ageParts.push(`${obsData["referenceRangeAgeHighValue"]}${obsData["referenceRangeAgeHighUnit"] ? " " + obsData["referenceRangeAgeHighUnit"] : ""}`);
|
|
2162
|
+
}
|
|
2163
|
+
if (obsData["referenceRange"]) {
|
|
2164
|
+
obsData["referenceRange"] += ` (Age: ${ageParts.join(" - ")})`;
|
|
2165
|
+
} else {
|
|
2166
|
+
obsData["referenceRange"] = `Age: ${ageParts.join(" - ")}`;
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
/**
|
|
2171
|
+
* Helper function to extract observation field data
|
|
2172
|
+
* @param column - Column data from the summary
|
|
2173
|
+
* @param targetData - Record to populate with extracted data
|
|
2174
|
+
*/
|
|
2175
|
+
extractSummaryObservationFields(column, targetData) {
|
|
2176
|
+
switch (column.title) {
|
|
2177
|
+
case "Labs Name":
|
|
2178
|
+
targetData["code"] = column.text?.div ?? "";
|
|
2179
|
+
break;
|
|
2180
|
+
case "effectiveDateTime":
|
|
2181
|
+
targetData["effectiveDateTime"] = column.text?.div ?? "";
|
|
2182
|
+
break;
|
|
2183
|
+
case "effectivePeriod.start":
|
|
2184
|
+
targetData["effectivePeriodStart"] = column.text?.div ?? "";
|
|
2185
|
+
break;
|
|
2186
|
+
case "effectivePeriod.end":
|
|
2187
|
+
targetData["effectivePeriodEnd"] = column.text?.div ?? "";
|
|
2188
|
+
break;
|
|
2189
|
+
// valueQuantity
|
|
2190
|
+
case "valueQuantity.value":
|
|
2191
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2192
|
+
targetData["valueType"] = "valueQuantity";
|
|
2193
|
+
break;
|
|
2194
|
+
case "valueQuantity.unit":
|
|
2195
|
+
targetData["unit"] = column.text?.div ?? "";
|
|
2196
|
+
break;
|
|
2197
|
+
// valueCodeableConcept
|
|
2198
|
+
case "valueCodeableConcept.text":
|
|
2199
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2200
|
+
targetData["valueType"] = "valueCodeableConcept";
|
|
2201
|
+
break;
|
|
2202
|
+
case "valueCodeableConcept.coding.display":
|
|
2203
|
+
if (!targetData["value"]) {
|
|
2204
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2205
|
+
targetData["valueType"] = "valueCodeableConcept";
|
|
2206
|
+
}
|
|
2207
|
+
break;
|
|
2208
|
+
// valueString
|
|
2209
|
+
case "valueString":
|
|
2210
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2211
|
+
targetData["valueType"] = "valueString";
|
|
2212
|
+
break;
|
|
2213
|
+
// valueBoolean
|
|
2214
|
+
case "valueBoolean":
|
|
2215
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2216
|
+
targetData["valueType"] = "valueBoolean";
|
|
2217
|
+
break;
|
|
2218
|
+
// valueInteger
|
|
2219
|
+
case "valueInteger":
|
|
2220
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2221
|
+
targetData["valueType"] = "valueInteger";
|
|
2222
|
+
break;
|
|
2223
|
+
// valueDateTime
|
|
2224
|
+
case "valueDateTime":
|
|
2225
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2226
|
+
targetData["valueType"] = "valueDateTime";
|
|
2227
|
+
break;
|
|
2228
|
+
// valuePeriod
|
|
2229
|
+
case "valuePeriod.start":
|
|
2230
|
+
targetData["valuePeriodStart"] = column.text?.div ?? "";
|
|
2231
|
+
targetData["valueType"] = "valuePeriod";
|
|
2232
|
+
break;
|
|
2233
|
+
case "valuePeriod.end":
|
|
2234
|
+
targetData["valuePeriodEnd"] = column.text?.div ?? "";
|
|
2235
|
+
targetData["valueType"] = "valuePeriod";
|
|
2236
|
+
break;
|
|
2237
|
+
// valueTime
|
|
2238
|
+
case "valueTime":
|
|
2239
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2240
|
+
targetData["valueType"] = "valueTime";
|
|
2241
|
+
break;
|
|
2242
|
+
// valueSampledData
|
|
2243
|
+
case "valueSampledData.origin.value":
|
|
2244
|
+
targetData["sampledDataOriginValue"] = column.text?.div ?? "";
|
|
2245
|
+
targetData["valueType"] = "valueSampledData";
|
|
2246
|
+
break;
|
|
2247
|
+
case "valueSampledData.origin.unit":
|
|
2248
|
+
targetData["sampledDataOriginUnit"] = column.text?.div ?? "";
|
|
2249
|
+
break;
|
|
2250
|
+
case "valueSampledData.period":
|
|
2251
|
+
targetData["sampledDataPeriod"] = column.text?.div ?? "";
|
|
2252
|
+
break;
|
|
2253
|
+
case "valueSampledData.factor":
|
|
2254
|
+
targetData["sampledDataFactor"] = column.text?.div ?? "";
|
|
2255
|
+
break;
|
|
2256
|
+
case "valueSampledData.lowerLimit":
|
|
2257
|
+
targetData["sampledDataLowerLimit"] = column.text?.div ?? "";
|
|
2258
|
+
break;
|
|
2259
|
+
case "valueSampledData.upperLimit":
|
|
2260
|
+
targetData["sampledDataUpperLimit"] = column.text?.div ?? "";
|
|
2261
|
+
break;
|
|
2262
|
+
case "valueSampledData.data":
|
|
2263
|
+
targetData["sampledDataData"] = column.text?.div ?? "";
|
|
2264
|
+
break;
|
|
2265
|
+
// valueRange
|
|
2266
|
+
case "valueRange.low.value":
|
|
2267
|
+
targetData["valueRangeLowValue"] = column.text?.div ?? "";
|
|
2268
|
+
targetData["valueType"] = "valueRange";
|
|
2269
|
+
break;
|
|
2270
|
+
case "valueRange.low.unit":
|
|
2271
|
+
targetData["valueRangeLowUnit"] = column.text?.div ?? "";
|
|
2272
|
+
break;
|
|
2273
|
+
case "valueRange.high.value":
|
|
2274
|
+
targetData["valueRangeHighValue"] = column.text?.div ?? "";
|
|
2275
|
+
break;
|
|
2276
|
+
case "valueRange.high.unit":
|
|
2277
|
+
targetData["valueRangeHighUnit"] = column.text?.div ?? "";
|
|
2278
|
+
break;
|
|
2279
|
+
// valueRatio
|
|
2280
|
+
case "valueRatio.numerator.value":
|
|
2281
|
+
targetData["valueRatioNumeratorValue"] = column.text?.div ?? "";
|
|
2282
|
+
targetData["valueType"] = "valueRatio";
|
|
2283
|
+
break;
|
|
2284
|
+
case "valueRatio.numerator.unit":
|
|
2285
|
+
targetData["valueRatioNumeratorUnit"] = column.text?.div ?? "";
|
|
2286
|
+
break;
|
|
2287
|
+
case "valueRatio.denominator.value":
|
|
2288
|
+
targetData["valueRatioDenominatorValue"] = column.text?.div ?? "";
|
|
2289
|
+
break;
|
|
2290
|
+
case "valueRatio.denominator.unit":
|
|
2291
|
+
targetData["valueRatioDenominatorUnit"] = column.text?.div ?? "";
|
|
2292
|
+
break;
|
|
2293
|
+
// referenceRange
|
|
2294
|
+
case "referenceRange.low.value":
|
|
2295
|
+
targetData["referenceRangeLow"] = column.text?.div ?? "";
|
|
2296
|
+
break;
|
|
2297
|
+
case "referenceRange.low.unit":
|
|
2298
|
+
targetData["referenceRangeLowUnit"] = column.text?.div ?? "";
|
|
2299
|
+
break;
|
|
2300
|
+
case "referenceRange.high.value":
|
|
2301
|
+
targetData["referenceRangeHigh"] = column.text?.div ?? "";
|
|
2302
|
+
break;
|
|
2303
|
+
case "referenceRange.high.unit":
|
|
2304
|
+
targetData["referenceRangeHighUnit"] = column.text?.div ?? "";
|
|
2305
|
+
break;
|
|
2306
|
+
case "referenceRange.age.low.value":
|
|
2307
|
+
targetData["referenceRangeAgeLowValue"] = column.text?.div ?? "";
|
|
2308
|
+
break;
|
|
2309
|
+
case "referenceRange.age.low.unit":
|
|
2310
|
+
targetData["referenceRangeAgeLowUnit"] = column.text?.div ?? "";
|
|
2311
|
+
break;
|
|
2312
|
+
case "referenceRange.age.high.value":
|
|
2313
|
+
targetData["referenceRangeAgeHighValue"] = column.text?.div ?? "";
|
|
2314
|
+
break;
|
|
2315
|
+
case "referenceRange.age.high.unit":
|
|
2316
|
+
targetData["referenceRangeAgeHighUnit"] = column.text?.div ?? "";
|
|
2317
|
+
break;
|
|
2318
|
+
default:
|
|
2319
|
+
break;
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
/**
|
|
2323
|
+
* Generate HTML narrative for Diagnostic Results & Observation resources using summary
|
|
2324
|
+
* @param resources - FHIR Composition resources
|
|
2325
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2326
|
+
* @returns HTML string for rendering
|
|
2327
|
+
*/
|
|
2328
|
+
generateSummaryNarrative(resources, timezone) {
|
|
2329
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
2330
|
+
let html = `
|
|
2331
|
+
<div>`;
|
|
2332
|
+
let observationhtml = `
|
|
2333
|
+
<div>
|
|
2334
|
+
<h3>Observations</h3>
|
|
2335
|
+
<table>
|
|
2336
|
+
<thead>
|
|
2337
|
+
<tr>
|
|
2338
|
+
<th>Code</th>
|
|
2339
|
+
<th>Result</th>
|
|
2340
|
+
<th>Reference Range</th>
|
|
2341
|
+
<th>Date</th>
|
|
2342
|
+
</tr>
|
|
2343
|
+
</thead>
|
|
2344
|
+
<tbody>`;
|
|
2345
|
+
let diagnosticReporthtml = `
|
|
2346
|
+
<div>
|
|
2347
|
+
<h3>Diagnostic Reports</h3>
|
|
2348
|
+
<table>
|
|
2349
|
+
<thead>
|
|
2350
|
+
<tr>
|
|
2351
|
+
<th>Report</th>
|
|
2352
|
+
<th>Performer</th>
|
|
2353
|
+
<th>Issued</th>
|
|
2354
|
+
</tr>
|
|
2355
|
+
</thead>
|
|
2356
|
+
<tbody>`;
|
|
2357
|
+
let observationExists = false;
|
|
2358
|
+
let diagnosticReportExists = false;
|
|
2359
|
+
for (const resourceItem of resources) {
|
|
2360
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
2361
|
+
const data = {};
|
|
2362
|
+
const components = [];
|
|
2363
|
+
for (const columnData of rowData.section ?? []) {
|
|
2364
|
+
if (resourceItem.title === "Observation|Labs Summary Grouped by Lab Code") {
|
|
2365
|
+
if (columnData.text?.div === "Observation.component" && columnData.section) {
|
|
2366
|
+
for (const componentSection of columnData.section) {
|
|
2367
|
+
const componentData = {};
|
|
2368
|
+
for (const nestedColumn of componentSection.section ?? []) {
|
|
2369
|
+
this.extractSummaryObservationFields(nestedColumn, componentData);
|
|
2370
|
+
}
|
|
2371
|
+
if (Object.keys(componentData).length > 0) {
|
|
2372
|
+
components.push(componentData);
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
} else {
|
|
2376
|
+
this.extractSummaryObservationFields(columnData, data);
|
|
2377
|
+
}
|
|
2378
|
+
} else if (resourceItem.title === "DiagnosticReportLab Summary Grouped by DiagnosticReport|Lab Code") {
|
|
2379
|
+
switch (columnData.title) {
|
|
2380
|
+
case "Diagnostic Report Name":
|
|
2381
|
+
data["report"] = columnData.text?.div ?? "";
|
|
2382
|
+
break;
|
|
2383
|
+
case "Performer":
|
|
2384
|
+
data["performer"] = columnData.text?.div ?? "";
|
|
2385
|
+
break;
|
|
2386
|
+
case "Issued Date":
|
|
2387
|
+
data["issued"] = columnData.text?.div ?? "";
|
|
2388
|
+
break;
|
|
2389
|
+
case "Status":
|
|
2390
|
+
data["status"] = columnData.text?.div ?? "";
|
|
2391
|
+
break;
|
|
2392
|
+
default:
|
|
2393
|
+
break;
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
if (resourceItem.title === "Observation|Labs Summary Grouped by Lab Code") {
|
|
2398
|
+
observationExists = true;
|
|
2399
|
+
let date = data["effectiveDateTime"] ? templateUtilities.renderTime(data["effectiveDateTime"], timezone) : "";
|
|
2400
|
+
if (!date && data["effectivePeriodStart"]) {
|
|
2401
|
+
date = templateUtilities.renderTime(data["effectivePeriodStart"], timezone);
|
|
2402
|
+
if (data["effectivePeriodEnd"]) {
|
|
2403
|
+
date += " - " + templateUtilities.renderTime(data["effectivePeriodEnd"], timezone);
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
if (components.length > 0) {
|
|
2407
|
+
const groupName = data["code"] ?? "";
|
|
2408
|
+
for (const component of components) {
|
|
2409
|
+
this.formatSummaryObservationData(component);
|
|
2410
|
+
observationhtml += `
|
|
2411
|
+
<tr>
|
|
2412
|
+
<td>${groupName ? groupName + " - " : ""}${component["code"] ?? "-"}</td>
|
|
2413
|
+
<td>${component["formattedValue"] ?? "-"}</td>
|
|
2414
|
+
<td>${component["referenceRange"]?.trim() ?? "-"}</td>
|
|
2415
|
+
<td>${date ?? "-"}</td>
|
|
2416
|
+
</tr>`;
|
|
2417
|
+
}
|
|
2418
|
+
} else {
|
|
2419
|
+
this.formatSummaryObservationData(data);
|
|
2420
|
+
observationhtml += `
|
|
2421
|
+
<tr>
|
|
2422
|
+
<td>${data["code"] ?? "-"}</td>
|
|
2423
|
+
<td>${data["formattedValue"] ?? "-"}</td>
|
|
2424
|
+
<td>${data["referenceRange"]?.trim() ?? "-"}</td>
|
|
2425
|
+
<td>${date ?? "-"}</td>
|
|
2426
|
+
</tr>`;
|
|
2427
|
+
}
|
|
2428
|
+
} else if (resourceItem.title === "DiagnosticReportLab Summary Grouped by DiagnosticReport|Lab Code") {
|
|
2429
|
+
if (data["status"] === "final") {
|
|
2430
|
+
diagnosticReportExists = true;
|
|
2431
|
+
diagnosticReporthtml += `
|
|
2432
|
+
<tr>
|
|
2433
|
+
<td>${data["report"] ?? "-"}</td>
|
|
2434
|
+
<td>${data["performer"] ?? "-"}</td>
|
|
2435
|
+
<td>${templateUtilities.renderTime(data["issued"], timezone) ?? "-"}</td>
|
|
2436
|
+
</tr>`;
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
if (observationExists) {
|
|
2442
|
+
html += observationhtml;
|
|
2443
|
+
html += `
|
|
2444
|
+
</tbody>
|
|
2445
|
+
</table>
|
|
2446
|
+
</div>`;
|
|
2447
|
+
}
|
|
2448
|
+
if (diagnosticReportExists) {
|
|
2449
|
+
html += diagnosticReporthtml;
|
|
2450
|
+
html += `
|
|
2451
|
+
</tbody>
|
|
2452
|
+
</table>
|
|
2453
|
+
</div>`;
|
|
2454
|
+
}
|
|
2455
|
+
html += `
|
|
2456
|
+
</div>`;
|
|
2457
|
+
return html;
|
|
2458
|
+
}
|
|
2063
2459
|
/**
|
|
2064
2460
|
* Internal static implementation that actually generates the narrative
|
|
2065
2461
|
* @param resources - FHIR resources array containing Observation and DiagnosticReport resources
|
|
@@ -2201,6 +2597,57 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
|
|
|
2201
2597
|
});
|
|
2202
2598
|
return _HistoryOfProceduresTemplate.generateStaticNarrative(resources, timezone);
|
|
2203
2599
|
}
|
|
2600
|
+
/**
|
|
2601
|
+
* Generate HTML narrative for Procedure resources using summary
|
|
2602
|
+
* @param resources - FHIR Composition resources
|
|
2603
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2604
|
+
* @returns HTML string for rendering
|
|
2605
|
+
*/
|
|
2606
|
+
generateSummaryNarrative(resources, timezone) {
|
|
2607
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
2608
|
+
let html = `
|
|
2609
|
+
<div>
|
|
2610
|
+
<table>
|
|
2611
|
+
<thead>
|
|
2612
|
+
<tr>
|
|
2613
|
+
<th>Procedure</th>
|
|
2614
|
+
<th>Performer</th>
|
|
2615
|
+
<th>Date</th>
|
|
2616
|
+
</tr>
|
|
2617
|
+
</thead>
|
|
2618
|
+
<tbody>`;
|
|
2619
|
+
for (const resourceItem of resources) {
|
|
2620
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
2621
|
+
const data = {};
|
|
2622
|
+
for (const columnData of rowData.section ?? []) {
|
|
2623
|
+
switch (columnData.title) {
|
|
2624
|
+
case "Procedure Name":
|
|
2625
|
+
data["procedure"] = columnData.text?.div ?? "";
|
|
2626
|
+
break;
|
|
2627
|
+
case "Performer":
|
|
2628
|
+
data["performer"] = columnData.text?.div ?? "";
|
|
2629
|
+
break;
|
|
2630
|
+
case "Performed Date":
|
|
2631
|
+
data["date"] = columnData.text?.div ?? "";
|
|
2632
|
+
break;
|
|
2633
|
+
default:
|
|
2634
|
+
break;
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
html += `
|
|
2638
|
+
<tr>
|
|
2639
|
+
<td>${data["procedure"] ?? "-"}</td>
|
|
2640
|
+
<td>${data["performer"] ?? "-"}</td>
|
|
2641
|
+
<td>${templateUtilities.renderTime(data["date"], timezone) ?? "-"}</td>
|
|
2642
|
+
</tr>`;
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
html += `
|
|
2646
|
+
</tbody>
|
|
2647
|
+
</table>
|
|
2648
|
+
</div>`;
|
|
2649
|
+
return html;
|
|
2650
|
+
}
|
|
2204
2651
|
/**
|
|
2205
2652
|
* Internal static implementation that actually generates the narrative
|
|
2206
2653
|
* @param resources - FHIR Procedure resources
|