feature: Improve dashboard functionality

This commit is contained in:
voltsrage
2026-06-23 20:19:32 +08:00
parent dd0fd88731
commit 79b6d9d85e
60 changed files with 2857 additions and 164 deletions
@@ -1,14 +1,32 @@
<script setup>
import { storeToRefs } from 'pinia'
import { useRoute } from 'vue-router'
import { useWardStore } from '@/stores/ward'
import { useSettingsStore } from '@/stores/settings'
import { usePolling } from '@/composables/usePolling'
import { WARD_SORT_FIELDS } from '@/composables/wardSort'
import WardToolbar from '@/components/ward/WardToolbar.vue'
import WardTable from '@/components/ward/WardTable.vue'
import Skeleton from '@/components/ui/Skeleton.vue'
import EmptyState from '@/components/ui/EmptyState.vue'
import Badge from '@/components/ui/Badge.vue'
const route = useRoute()
const wardStore = useWardStore()
const { sortedByRisk, loading, error, criticalCount, department } = storeToRefs(wardStore)
const settingsStore = useSettingsStore()
const {
encounters,
displayEncounters,
loading,
error,
criticalCount,
department,
} = storeToRefs(wardStore)
const { wardSortField, wardSortDirection } = storeToRefs(settingsStore)
if (route.query.department) {
wardStore.setDepartment(String(route.query.department))
}
usePolling(() => wardStore.loadEncounters(), 10_000)
@@ -22,6 +40,10 @@ const departments = [
function onDepartmentChange(event) {
wardStore.setDepartment(event.target.value || null)
}
function onMobileSortChange(event) {
wardStore.setSort(event.target.value)
}
</script>
<template>
@@ -48,8 +70,38 @@ function onDepartmentChange(event) {
</select>
</label>
<Skeleton v-if="loading && sortedByRisk.length === 0" :rows="5" />
<EmptyState v-else-if="sortedByRisk.length === 0" message="No active patients" />
<WardTable v-else :patients="sortedByRisk" />
<WardToolbar />
<label class="mb-4 block md:hidden">
<span class="mb-2 block text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">
Sort by
</span>
<select
:value="wardSortField"
class="w-full rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm text-gray-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200"
@change="onMobileSortChange"
>
<option v-for="option in WARD_SORT_FIELDS" :key="option.key" :value="option.key">
{{ option.label }}
</option>
</select>
</label>
<Skeleton v-if="loading && encounters.length === 0" :rows="5" />
<EmptyState
v-else-if="encounters.length === 0"
message="No active patients"
/>
<EmptyState
v-else-if="displayEncounters.length === 0"
message="No patients match your search or filters"
/>
<WardTable
v-else
:patients="displayEncounters"
:sort-field="wardSortField"
:sort-direction="wardSortDirection"
@sort="wardStore.setSort"
/>
</div>
</template>
</template>