Initial commit of akmon project

This commit is contained in:
2026-01-20 08:04:15 +08:00
commit 77a2bab985
1309 changed files with 343305 additions and 0 deletions

View File

@@ -0,0 +1,166 @@
<template>
<view class="emergency-page">
<view class="header">
<text class="title">急诊管理</text>
<button class="add-btn" @click="showAddEmergency"> 新建急诊</button>
</view>
<view class="stats">
<text>今日急诊: {{ stats.today }}</text>
<text>处理中: {{ stats.processing }}</text>
<text>已解决: {{ stats.resolved }}</text>
</view>
<scroll-view class="emergency-list" scroll-y="true">
<view v-for="item in emergencies" :key="item.id" class="emergency-item" :class="item.severity">
<view class="item-header">
<text class="type">{{ getTypeText(item.emergency_type) }}</text>
<text class="severity">{{ getSeverityText(item.severity) }}</text>
<text class="status">{{ getStatusText(item.status) }}</text>
</view>
<view class="item-content">
<text class="elder">患者: {{ item.elder_name }}</text>
<text class="desc">{{ item.description }}</text>
</view>
<view class="item-footer">
<text class="time">{{ formatDateTime(item.occurred_at) }}</text>
<button v-if="item.status==='active'" class="handle-btn" @click="handleEmergency(item)">处理</button>
</view>
</view>
<view v-if="emergencies.length===0" class="empty-state">
<text>暂无急诊事件</text>
</view>
</scroll-view>
</view>
</template>
<script setup lang="uts">
import { ref, onMounted } from 'vue'
import supa from '@/components/supadb/aksupainstance.uts'
import { formatDateTime } from '../types_new.uts'
type Emergency = {
id: string
appointment_id: string
elder_id: string
elder_name: string
doctor_id: string
emergency_type: string
severity: string
status: string
description: string
occurred_at: string
handled_at: string
handler_notes: string
created_at: string
updated_at: string
}
type EmergencyStats = {
today: number
processing: number
resolved: number
}
const emergencies = ref<Emergency[]>([])
const stats = ref<EmergencyStats>({ today: 0, processing: 0, resolved: 0 })
onMounted(() => {
loadEmergencies()
loadStats()
})
const loadEmergencies = async () => {
const result = await supa
.from('ec_emergencies')
.select('*')
.order('occurred_at', { ascending: false })
.limit(30)
.executeAs<Emergency[]>()
if (result.error == null && result.data != null) {
emergencies.value = result.data
}
}
const loadStats = async () => {
const todayStart = new Date()
todayStart.setHours(0,0,0,0)
const todayEnd = new Date()
todayEnd.setHours(23,59,59,999)
const todayResult = await supa
.from('ec_emergencies')
.select('*', { count: 'exact' })
.gte('occurred_at', todayStart.toISOString())
.lte('occurred_at', todayEnd.toISOString())
.executeAs<Emergency[]>()
const processingResult = await supa
.from('ec_emergencies')
.select('*', { count: 'exact' })
.eq('status', 'processing')
.executeAs<Emergency[]>()
const resolvedResult = await supa
.from('ec_emergencies')
.select('*', { count: 'exact' })
.eq('status', 'resolved')
.executeAs<Emergency[]>()
stats.value = {
today: todayResult.count ?? 0,
processing: processingResult.count ?? 0,
resolved: resolvedResult.count ?? 0
}
}
const getTypeText = (type: string): string => {
const map = new Map([
['fall', '跌倒'],
['stroke', '中风'],
['cardiac', '心脏'],
['other', '其他']
])
return map.get(type) ?? type
}
const getSeverityText = (sev: string): string => {
const map = new Map([
['low', '低'],
['medium', '中'],
['high', '高'],
['critical', '危急']
])
return map.get(sev) ?? sev
}
const getStatusText = (status: string): string => {
const map = new Map([
['active', '待处理'],
['processing', '处理中'],
['resolved', '已解决'],
['cancelled', '已取消']
])
return map.get(status) ?? status
}
const showAddEmergency = () => {
uni.navigateTo({ url: '/pages/ec/doctor/emergency-form' })
}
const handleEmergency = (item: Emergency) => {
uni.navigateTo({ url: `/pages/ec/doctor/emergency-handle?id=${item.id}` })
}
</script>
<style scoped>
.emergency-page { padding: 20px; background: #f5f5f5; min-height: 100vh; }
.header { display: flex; flex-direction: row; justify-content: space-between; align-items: center; margin-bottom: 16px; }
.title { font-size: 20px; font-weight: bold; }
.add-btn { background: #ff4757; color: #fff; border: none; border-radius: 16px; padding: 8px 18px; font-size: 15px; }
.stats { display: flex; flex-direction: row; gap: 18px; margin-bottom: 12px; }
.emergency-list { background: #fff; border-radius: 10px; }
.emergency-item { padding: 14px 10px; border-bottom: 1px solid #f0f0f0; }
.emergency-item:last-child { border-bottom: none; }
.item-header { display: flex; flex-direction: row; gap: 10px; margin-bottom: 6px; }
.type { font-size: 14px; font-weight: 600; }
.severity { font-size: 13px; color: #e67e22; }
.status { font-size: 13px; color: #3498db; }
.item-content { font-size: 13px; color: #555; margin-bottom: 6px; }
.elder { color: #888; margin-right: 10px; }
.desc { color: #555; }
.item-footer { display: flex; flex-direction: row; justify-content: space-between; align-items: center; }
.time { font-size: 12px; color: #999; }
.handle-btn { background: #27ae60; color: #fff; border: none; border-radius: 12px; padding: 6px 14px; font-size: 13px; }
.empty-state { padding: 30px 0; text-align: center; color: #999; }
</style>