126 lines
4.1 KiB
Vue
126 lines
4.1 KiB
Vue
<template>
|
|
<div
|
|
class="flex flex-col xl:flex-row xl:items-start gap-3 p-3 rounded-input border border-line bg-canvas"
|
|
data-testid="observation-row"
|
|
>
|
|
<div class="flex-1 grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-5 gap-3 min-w-0">
|
|
<div>
|
|
<label class="workstation-field-label">Code</label>
|
|
<select
|
|
:value="observation.observationCode"
|
|
@change="update('observationCode', ($event.target as HTMLSelectElement).value)"
|
|
class="form-input text-sm py-1.5"
|
|
:disabled="readonly"
|
|
>
|
|
<option value="">Select...</option>
|
|
<option value="HEART_RATE">Heart Rate</option>
|
|
<option value="TEMP_C">Temperature (C)</option>
|
|
<option value="BP_SYSTOLIC">BP Systolic</option>
|
|
<option value="BP_DIASTOLIC">BP Diastolic</option>
|
|
<option value="RESP_RATE">Respiratory Rate</option>
|
|
<option value="SPO2">SpO2</option>
|
|
<option value="POTASSIUM_MEQ_L">Potassium</option>
|
|
<option value="GLUCOSE_MG_DL">Glucose</option>
|
|
<option value="WBC_K_UL">WBC</option>
|
|
<option value="LACTATE_MMOL_L">Lactate</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="workstation-field-label">
|
|
Value
|
|
<OcrConfidenceBadge :label="ocrLabel" :level="ocrLevel" />
|
|
</label>
|
|
<input
|
|
:value="observation.value"
|
|
@change="update('value', parseFloat(($event.target as HTMLInputElement).value))"
|
|
type="number"
|
|
step="0.01"
|
|
:class="['form-input', 'text-sm', 'py-1.5', valueInputClass]"
|
|
:disabled="readonly"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label class="workstation-field-label">Unit</label>
|
|
<input
|
|
:value="observation.unit"
|
|
@change="update('unit', ($event.target as HTMLInputElement).value)"
|
|
type="text"
|
|
class="form-input text-sm py-1.5"
|
|
:disabled="readonly"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label class="workstation-field-label">Recorded At</label>
|
|
<input
|
|
:value="observation.recordedAt?.substring(0, 16)"
|
|
@change="update('recordedAt', ($event.target as HTMLInputElement).value)"
|
|
type="datetime-local"
|
|
class="form-input text-sm py-1.5"
|
|
:disabled="readonly"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label class="workstation-field-label">Note</label>
|
|
<input
|
|
:value="observation.note"
|
|
@change="update('note', ($event.target as HTMLInputElement).value)"
|
|
type="text"
|
|
class="form-input text-sm py-1.5"
|
|
placeholder="Optional"
|
|
:disabled="readonly"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
v-if="showVerified"
|
|
class="flex items-center shrink-0 xl:mt-7"
|
|
>
|
|
<label class="inline-flex items-center gap-2 cursor-pointer">
|
|
<input
|
|
type="checkbox"
|
|
:checked="verified"
|
|
@change="$emit('verify', observation.id, ($event.target as HTMLInputElement).checked)"
|
|
class="w-4 h-4 text-clinical-safe rounded"
|
|
/>
|
|
<span class="text-xs text-ink-secondary">OK</span>
|
|
</label>
|
|
</div>
|
|
|
|
<button
|
|
v-if="!readonly && !showVerified"
|
|
type="button"
|
|
@click="$emit('delete', observation.id)"
|
|
class="self-start xl:mt-7 text-clinical-danger hover:text-clinical-critical text-sm font-medium"
|
|
>
|
|
Remove
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type { DraftObservation } from '../types'
|
|
import type { OcrConfidenceLevel } from '../composables/useOcrFieldConfidence'
|
|
import OcrConfidenceBadge from './OcrConfidenceBadge.vue'
|
|
|
|
defineProps<{
|
|
observation: DraftObservation
|
|
readonly?: boolean
|
|
showVerified?: boolean
|
|
verified?: boolean
|
|
valueInputClass?: string
|
|
ocrLabel?: string | null
|
|
ocrLevel?: OcrConfidenceLevel | null
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'update', field: string, value: unknown): void
|
|
(e: 'delete', obsId: string): void
|
|
(e: 'verify', obsId: string, passed: boolean): void
|
|
}>()
|
|
|
|
function update(field: string, value: unknown) {
|
|
emit('update', field, value)
|
|
}
|
|
</script>
|