Show fetched-record sections as plain bold headings (no collapse) and resolve DiagnosticReport result Observations to actual lab values
This commit is contained in:
parent
37dba1948e
commit
448db54d4c
|
|
@ -389,9 +389,10 @@ class M3HiuDocumentRepository
|
||||||
if ($refStr === '' || ! isset($resourcesByRef[$refStr])) {
|
if ($refStr === '' || ! isset($resourcesByRef[$refStr])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$label = $this->describeResourceForSection((array) $resourcesByRef[$refStr]);
|
foreach ($this->describeResourceForSection((array) $resourcesByRef[$refStr], $resourcesByRef) as $label) {
|
||||||
if ($label !== '') {
|
if ($label !== '') {
|
||||||
$items[] = $label;
|
$items[] = $label;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,10 +417,15 @@ class M3HiuDocumentRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produces a short, human-readable one-line label for a FHIR resource, for
|
* Produces one or more short, human-readable one-line labels for a FHIR
|
||||||
* display inside a Composition section's accordion body.
|
* resource, for display inside a Composition section's item list. Most
|
||||||
|
* resource types resolve to a single line; DiagnosticReport expands into
|
||||||
|
* one line per linked Observation result (e.g. individual lab test
|
||||||
|
* values) since that's where the actual pathology/lab values live.
|
||||||
|
*
|
||||||
|
* @return array<int, string>
|
||||||
*/
|
*/
|
||||||
private function describeResourceForSection(array $resource): string
|
private function describeResourceForSection(array $resource, array $resourcesByRef = []): array
|
||||||
{
|
{
|
||||||
$type = trim((string) ($resource['resourceType'] ?? ''));
|
$type = trim((string) ($resource['resourceType'] ?? ''));
|
||||||
|
|
||||||
|
|
@ -428,42 +434,130 @@ class M3HiuDocumentRepository
|
||||||
case 'AllergyIntolerance':
|
case 'AllergyIntolerance':
|
||||||
case 'Procedure':
|
case 'Procedure':
|
||||||
case 'ServiceRequest':
|
case 'ServiceRequest':
|
||||||
return trim((string) (($resource['code']['text'] ?? '') ?: ($resource['code']['coding'][0]['display'] ?? '')));
|
$label = trim((string) (($resource['code']['text'] ?? '') ?: ($resource['code']['coding'][0]['display'] ?? '')));
|
||||||
|
return $label !== '' ? [$label] : [];
|
||||||
|
|
||||||
case 'Observation':
|
case 'Observation':
|
||||||
$name = trim((string) (($resource['code']['text'] ?? '') ?: ($resource['code']['coding'][0]['display'] ?? '')));
|
$label = $this->describeObservation($resource);
|
||||||
$val = '';
|
return $label !== '' ? [$label] : [];
|
||||||
if (isset($resource['valueQuantity']) && is_array($resource['valueQuantity'])) {
|
|
||||||
$val = trim((string) (($resource['valueQuantity']['value'] ?? '') . ' ' . ($resource['valueQuantity']['unit'] ?? '')));
|
|
||||||
} elseif (isset($resource['valueString'])) {
|
|
||||||
$val = trim((string) $resource['valueString']);
|
|
||||||
} elseif (isset($resource['valueCodeableConcept'])) {
|
|
||||||
$val = trim((string) (($resource['valueCodeableConcept']['text'] ?? '') ?: ($resource['valueCodeableConcept']['coding'][0]['display'] ?? '')));
|
|
||||||
}
|
|
||||||
return $val !== '' ? ($name . ': ' . $val) : $name;
|
|
||||||
|
|
||||||
case 'MedicationRequest':
|
case 'MedicationRequest':
|
||||||
case 'MedicationStatement':
|
case 'MedicationStatement':
|
||||||
$med = trim((string) (($resource['medicationCodeableConcept']['text'] ?? '') ?: ($resource['medicationCodeableConcept']['coding'][0]['display'] ?? '')));
|
$med = trim((string) (($resource['medicationCodeableConcept']['text'] ?? '') ?: ($resource['medicationCodeableConcept']['coding'][0]['display'] ?? '')));
|
||||||
$dose = trim((string) ($resource['dosageInstruction'][0]['text'] ?? ($resource['dosage'][0]['text'] ?? '')));
|
$dose = trim((string) ($resource['dosageInstruction'][0]['text'] ?? ($resource['dosage'][0]['text'] ?? '')));
|
||||||
return $dose !== '' ? ($med . ' — ' . $dose) : $med;
|
$label = $dose !== '' ? ($med . ' — ' . $dose) : $med;
|
||||||
|
return $label !== '' ? [$label] : [];
|
||||||
|
|
||||||
case 'DiagnosticReport':
|
case 'DiagnosticReport':
|
||||||
$name = trim((string) (($resource['code']['text'] ?? '') ?: ($resource['code']['coding'][0]['display'] ?? '')));
|
$name = trim((string) (($resource['code']['text'] ?? '') ?: ($resource['code']['coding'][0]['display'] ?? '')));
|
||||||
$conclusion = trim((string) ($resource['conclusion'] ?? ''));
|
$conclusion = trim((string) ($resource['conclusion'] ?? ''));
|
||||||
return $conclusion !== '' ? ($name . ' — ' . $conclusion) : $name;
|
$header = $conclusion !== '' ? ($name . ' — ' . $conclusion) : $name;
|
||||||
|
|
||||||
|
$lines = $header !== '' ? [$header] : [];
|
||||||
|
foreach ((array) ($resource['result'] ?? []) as $resultRef) {
|
||||||
|
if (! is_array($resultRef)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$refStr = trim((string) ($resultRef['reference'] ?? ''));
|
||||||
|
if ($refStr === '' || ! isset($resourcesByRef[$refStr])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$obsResource = (array) $resourcesByRef[$refStr];
|
||||||
|
if (trim((string) ($obsResource['resourceType'] ?? '')) !== 'Observation') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$obsLine = $this->describeObservation($obsResource);
|
||||||
|
if ($obsLine !== '') {
|
||||||
|
$lines[] = '– ' . $obsLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $lines;
|
||||||
|
|
||||||
case 'CarePlan':
|
case 'CarePlan':
|
||||||
return trim((string) (($resource['description'] ?? '') ?: ($resource['title'] ?? '')));
|
$label = trim((string) (($resource['description'] ?? '') ?: ($resource['title'] ?? '')));
|
||||||
|
return $label !== '' ? [$label] : [];
|
||||||
|
|
||||||
case 'DocumentReference':
|
case 'DocumentReference':
|
||||||
return trim((string) (($resource['description'] ?? '') ?: ($resource['type']['text'] ?? '') ?: ($resource['type']['coding'][0]['display'] ?? '')));
|
$label = trim((string) (($resource['description'] ?? '') ?: ($resource['type']['text'] ?? '') ?: ($resource['type']['coding'][0]['display'] ?? '')));
|
||||||
|
return $label !== '' ? [$label] : [];
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return '';
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a single "Test name: value unit (Flag)" style line for an
|
||||||
|
* Observation resource, covering the common FHIR value shapes used by
|
||||||
|
* lab/pathology reports (valueQuantity, valueString, valueCodeableConcept,
|
||||||
|
* valueInteger/valueBoolean, and multi-component observations like Blood
|
||||||
|
* Pressure which report systolic/diastolic as separate `component` entries
|
||||||
|
* instead of a single top-level value).
|
||||||
|
*/
|
||||||
|
private function describeObservation(array $resource): string
|
||||||
|
{
|
||||||
|
$name = trim((string) (($resource['code']['text'] ?? '') ?: ($resource['code']['coding'][0]['display'] ?? '')));
|
||||||
|
|
||||||
|
$formatValue = static function (array $obs): string {
|
||||||
|
if (isset($obs['valueQuantity']) && is_array($obs['valueQuantity'])) {
|
||||||
|
return trim((string) (($obs['valueQuantity']['value'] ?? '') . ' ' . ($obs['valueQuantity']['unit'] ?? ($obs['valueQuantity']['code'] ?? ''))));
|
||||||
|
}
|
||||||
|
if (isset($obs['valueString'])) {
|
||||||
|
return trim((string) $obs['valueString']);
|
||||||
|
}
|
||||||
|
if (isset($obs['valueCodeableConcept'])) {
|
||||||
|
return trim((string) (($obs['valueCodeableConcept']['text'] ?? '') ?: ($obs['valueCodeableConcept']['coding'][0]['display'] ?? '')));
|
||||||
|
}
|
||||||
|
if (isset($obs['valueInteger'])) {
|
||||||
|
return trim((string) $obs['valueInteger']);
|
||||||
|
}
|
||||||
|
if (isset($obs['valueBoolean'])) {
|
||||||
|
return $obs['valueBoolean'] ? 'Yes' : 'No';
|
||||||
|
}
|
||||||
|
if (isset($obs['valueDateTime'])) {
|
||||||
|
return trim((string) $obs['valueDateTime']);
|
||||||
|
}
|
||||||
|
if (isset($obs['valueRange']) && is_array($obs['valueRange'])) {
|
||||||
|
$low = $obs['valueRange']['low']['value'] ?? '';
|
||||||
|
$high = $obs['valueRange']['high']['value'] ?? '';
|
||||||
|
return trim($low . ' - ' . $high);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
$val = $formatValue($resource);
|
||||||
|
|
||||||
|
// Multi-component observations (e.g. Blood Pressure: systolic + diastolic)
|
||||||
|
// carry no top-level value, only a `component[]` array each with its
|
||||||
|
// own code + value.
|
||||||
|
if ($val === '' && isset($resource['component']) && is_array($resource['component'])) {
|
||||||
|
$parts = [];
|
||||||
|
foreach ((array) $resource['component'] as $component) {
|
||||||
|
if (! is_array($component)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$compName = trim((string) (($component['code']['text'] ?? '') ?: ($component['code']['coding'][0]['display'] ?? '')));
|
||||||
|
$compVal = $formatValue($component);
|
||||||
|
if ($compVal === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$parts[] = $compName !== '' ? ($compName . ': ' . $compVal) : $compVal;
|
||||||
|
}
|
||||||
|
$val = implode(', ', $parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
$flag = trim((string) (($resource['interpretation'][0]['text'] ?? '') ?: ($resource['interpretation'][0]['coding'][0]['display'] ?? '')));
|
||||||
|
|
||||||
|
$label = $val !== '' ? ($name . ': ' . $val) : $name;
|
||||||
|
if ($flag !== '') {
|
||||||
|
$label .= ' (' . $flag . ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
return trim($label, ' :');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts attached scanned images/PDFs/generic documents (DocumentReference
|
* Extracts attached scanned images/PDFs/generic documents (DocumentReference
|
||||||
* resources, whose content may carry the base64 attachment data inline or
|
* resources, whose content may carry the base64 attachment data inline or
|
||||||
|
|
|
||||||
|
|
@ -809,7 +809,6 @@ $(function() {
|
||||||
docs.forEach(function(doc, di) {
|
docs.forEach(function(doc, di) {
|
||||||
var summary = doc.summary || {};
|
var summary = doc.summary || {};
|
||||||
var sections = Array.isArray(summary.sections) ? summary.sections : [];
|
var sections = Array.isArray(summary.sections) ? summary.sections : [];
|
||||||
var accId = 'abdmFetchAcc' + di;
|
|
||||||
|
|
||||||
html += '<div class="card mb-3">'
|
html += '<div class="card mb-3">'
|
||||||
+ '<div class="card-body">'
|
+ '<div class="card-body">'
|
||||||
|
|
@ -821,9 +820,8 @@ $(function() {
|
||||||
+ '</div>';
|
+ '</div>';
|
||||||
|
|
||||||
if (sections.length) {
|
if (sections.length) {
|
||||||
html += '<div class="accordion" id="' + accId + '">';
|
html += '<div class="abdm-fetch-sections">';
|
||||||
sections.forEach(function(sec, si) {
|
sections.forEach(function(sec, si) {
|
||||||
var itemId = accId + '_' + si;
|
|
||||||
var body = '';
|
var body = '';
|
||||||
if (sec.items && sec.items.length) {
|
if (sec.items && sec.items.length) {
|
||||||
body = '<ul class="mb-0 small">' + sec.items.map(function(it) { return '<li>' + escHtml(it) + '</li>'; }).join('') + '</ul>';
|
body = '<ul class="mb-0 small">' + sec.items.map(function(it) { return '<li>' + escHtml(it) + '</li>'; }).join('') + '</ul>';
|
||||||
|
|
@ -832,13 +830,9 @@ $(function() {
|
||||||
} else {
|
} else {
|
||||||
body = '<div class="small text-muted">No details recorded.</div>';
|
body = '<div class="small text-muted">No details recorded.</div>';
|
||||||
}
|
}
|
||||||
html += '<div class="accordion-item">'
|
html += '<div class="mb-2">'
|
||||||
+ '<h2 class="accordion-header">'
|
+ '<div class="fw-bold">' + escHtml(sec.title || 'Section') + '</div>'
|
||||||
+ '<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#' + itemId + '">' + escHtml(sec.title || 'Section') + '</button>'
|
+ body
|
||||||
+ '</h2>'
|
|
||||||
+ '<div id="' + itemId + '" class="accordion-collapse collapse" data-bs-parent="#' + accId + '">'
|
|
||||||
+ '<div class="accordion-body">' + body + '</div>'
|
|
||||||
+ '</div>'
|
|
||||||
+ '</div>';
|
+ '</div>';
|
||||||
});
|
});
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user