95 lines
2.7 KiB
Vue
95 lines
2.7 KiB
Vue
<script setup>
|
|
import { computed } from 'vue'
|
|
import Card from '@/components/ui/Card.vue'
|
|
import Badge from '@/components/ui/Badge.vue'
|
|
import Button from '@/components/ui/Button.vue'
|
|
import FeedbackButtons from '@/components/feedback/FeedbackButtons.vue'
|
|
import { alertTypeLabel } from '@/api/normalize'
|
|
|
|
const props = defineProps({
|
|
alert: { type: Object, required: true },
|
|
})
|
|
|
|
const emit = defineEmits(['acknowledge', 'resolve'])
|
|
|
|
const actionHint = computed(() => {
|
|
const hints = {
|
|
QsofaScreen: 'Recommend SOFA labs',
|
|
SofaSepsis: 'Review organ breakdown · Initiate bundle',
|
|
GcsCritical: 'Urgent neuro assessment',
|
|
GcsWarning: 'Monitor consciousness',
|
|
}
|
|
return hints[props.alert.alertType] ?? null
|
|
})
|
|
|
|
function severityVariant(severity) {
|
|
return severity === 'Critical' ? 'critical' : 'warning'
|
|
}
|
|
|
|
function showActions(status) {
|
|
return status !== 'Resolved'
|
|
}
|
|
|
|
function canAcknowledge(status) {
|
|
return status === 'Open' || status === 'Escalated'
|
|
}
|
|
|
|
function canResolve(status) {
|
|
return status === 'Acknowledged'
|
|
}
|
|
|
|
function formatTime(iso) {
|
|
if (!iso) return ''
|
|
return new Date(iso).toLocaleString()
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Card>
|
|
<div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
|
<div class="min-w-0 flex-1">
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
<Badge :variant="severityVariant(alert.severity)">{{ alert.severity }}</Badge>
|
|
<Badge variant="info" size="xs">{{ alert.status }}</Badge>
|
|
<Badge v-if="actionHint" variant="info" size="xs">{{ actionHint }}</Badge>
|
|
</div>
|
|
<h3 class="mt-2 text-sm font-semibold text-gray-900 dark:text-white">
|
|
{{ alertTypeLabel(alert.alertType) }}
|
|
</h3>
|
|
<p v-if="alert.details" class="mt-2 text-sm text-gray-600 dark:text-gray-400">
|
|
{{ alert.details }}
|
|
</p>
|
|
<p class="mt-2 text-xs text-gray-500 dark:text-gray-500">
|
|
{{ formatTime(alert.triggeredAt) }}
|
|
</p>
|
|
</div>
|
|
|
|
<div v-if="showActions(alert.status)" class="flex w-full shrink-0 gap-2 sm:w-auto">
|
|
<Button
|
|
v-if="canAcknowledge(alert.status)"
|
|
size="sm"
|
|
variant="secondary"
|
|
@click="emit('acknowledge')"
|
|
>
|
|
Acknowledge
|
|
</Button>
|
|
<Button
|
|
v-if="canResolve(alert.status)"
|
|
size="sm"
|
|
variant="primary"
|
|
@click="emit('resolve')"
|
|
>
|
|
Resolve
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 border-t border-gray-100 pt-4 dark:border-gray-700">
|
|
<FeedbackButtons
|
|
:alert-id="alert.id"
|
|
:alert-type="alert.alertType"
|
|
:severity="alert.severity"
|
|
/>
|
|
</div>
|
|
</Card>
|
|
</template> |