117 lines
4.3 KiB
Vue
117 lines
4.3 KiB
Vue
<script setup>
|
|
import { computed } from 'vue'
|
|
import Badge from '@/components/ui/Badge.vue'
|
|
import {
|
|
formatGcsClassification,
|
|
formatLastObservation,
|
|
formatLengthOfStay,
|
|
observationStaleness,
|
|
patientRoom,
|
|
stalenessClass,
|
|
} from '@/composables/wardFormat'
|
|
|
|
const props = defineProps({ patient: { type: Object, required: true } })
|
|
|
|
const riskVariant = computed(() => {
|
|
const score = props.patient.news2Score ?? 0
|
|
if (score >= 7) return 'critical'
|
|
if (score >= 5) return 'warning'
|
|
return 'success'
|
|
})
|
|
|
|
const vitalsStaleness = computed(() =>
|
|
observationStaleness(props.patient.lastObservationAt, props.patient.status),
|
|
)
|
|
|
|
const cardLabel = computed(() =>
|
|
`Patient ${props.patient.firstName} ${props.patient.lastName}, room ${patientRoom(props.patient)}`,
|
|
)
|
|
|
|
const emit = defineEmits(['activate'])
|
|
|
|
function onKeydown(event) {
|
|
if (event.key === 'Enter' || event.key === ' ') {
|
|
event.preventDefault()
|
|
emit('activate')
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<article
|
|
role="button"
|
|
tabindex="0"
|
|
:aria-label="cardLabel"
|
|
class="cursor-pointer rounded-lg border border-gray-200 bg-white p-4 shadow-sm transition duration-200 hover:border-gray-300 hover:shadow-md active:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 dark:border-gray-700 dark:bg-gray-900 dark:hover:border-gray-600 dark:active:bg-gray-800"
|
|
@click="emit('activate')"
|
|
@keydown="onKeydown"
|
|
>
|
|
<div class="flex items-start justify-between gap-4">
|
|
<div class="min-w-0 flex-1">
|
|
<div class="flex items-center gap-2">
|
|
<span class="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">
|
|
Room {{ patientRoom(patient) }}
|
|
</span>
|
|
<Badge v-if="patient.sepsisActive" variant="critical" size="xs">Sepsis</Badge>
|
|
</div>
|
|
<h3 class="mt-2 truncate text-base font-semibold text-gray-900 dark:text-white">
|
|
{{ patient.firstName }} {{ patient.lastName }}
|
|
</h3>
|
|
<p class="text-xs text-gray-500 dark:text-gray-400">{{ patient.mrn }}</p>
|
|
<p v-if="patient.attendingPhysician" class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
|
{{ patient.attendingPhysician }}
|
|
</p>
|
|
</div>
|
|
<Badge :variant="riskVariant">NEWS2 {{ patient.news2Score ?? '—' }}</Badge>
|
|
</div>
|
|
|
|
<dl class="mt-4 grid grid-cols-2 gap-4 border-t border-gray-100 pt-4 dark:border-gray-800">
|
|
<div>
|
|
<dt class="text-xs text-gray-500 dark:text-gray-400">SOFA</dt>
|
|
<dd class="mt-2 text-sm font-medium text-gray-900 dark:text-white">
|
|
{{ patient.sofaScore ?? '—' }}
|
|
<span v-if="patient.sofaDelta != null && patient.sofaDelta > 0" class="text-xs text-amber-600 dark:text-amber-400">
|
|
Δ+{{ patient.sofaDelta }}
|
|
</span>
|
|
</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="text-xs text-gray-500 dark:text-gray-400">GCS</dt>
|
|
<dd class="mt-2 text-sm font-medium text-gray-900 dark:text-white">
|
|
{{ patient.gcsScore ?? '—' }}
|
|
<span v-if="patient.gcsClassification" class="text-xs text-gray-500 dark:text-gray-400">
|
|
{{ formatGcsClassification(patient.gcsClassification) }}
|
|
</span>
|
|
</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="text-xs text-gray-500 dark:text-gray-400">qSOFA</dt>
|
|
<dd class="mt-2 text-sm font-medium text-gray-900 dark:text-white">
|
|
{{ patient.qsofaScore ?? '—' }}
|
|
</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="text-xs text-gray-500 dark:text-gray-400">LOS</dt>
|
|
<dd class="mt-2 text-sm font-medium text-gray-900 dark:text-white">
|
|
{{ formatLengthOfStay(patient.admittedAt) }}
|
|
</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="text-xs text-gray-500 dark:text-gray-400">Last vitals</dt>
|
|
<dd class="mt-2 text-sm font-medium" :class="stalenessClass(vitalsStaleness)">
|
|
{{ formatLastObservation(patient.lastObservationAt) }}
|
|
</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="text-xs text-gray-500 dark:text-gray-400">Open alerts</dt>
|
|
<dd class="mt-2">
|
|
<Badge v-if="patient.openAlertCount > 0" :variant="patient.openAlertCount > 2 ? 'critical' : 'warning'">
|
|
{{ patient.openAlertCount }}
|
|
</Badge>
|
|
<span v-else class="text-sm text-gray-400">0</span>
|
|
</dd>
|
|
</div>
|
|
</dl>
|
|
</article>
|
|
</template>
|