1011 lines
21 KiB
Plaintext
1011 lines
21 KiB
Plaintext
<template>
|
|
<view class="elder-status">
|
|
<!-- 老人基本信息卡片 -->
|
|
<view class="elder-info-card">
|
|
<view class="elder-header">
|
|
<view class="elder-avatar">
|
|
<image class="avatar-image" :src="elderInfo.profile_picture" mode="aspectFill"
|
|
@error="handleAvatarError" v-if="elderInfo.profile_picture" />
|
|
<text class="avatar-fallback" v-else>{{ elderInfo.name ? elderInfo.name.charAt(0) : '?' }}</text>
|
|
</view>
|
|
<view class="elder-basic">
|
|
<text class="elder-name">{{ elderInfo.name }}</text>
|
|
<text class="elder-info">{{ elderInfo.age }}岁 · {{ elderInfo.gender === 'male' ? '男' : '女' }}</text>
|
|
<text class="elder-room">{{ elderInfo.room_number }}房 {{ elderInfo.bed_number }}床</text>
|
|
</view>
|
|
<view class="elder-status">
|
|
<view class="health-indicator" :class="healthStatusClass">
|
|
<view class="indicator-dot"></view>
|
|
<text class="status-text">{{ healthStatusText }}</text>
|
|
</view>
|
|
<view class="care-level">
|
|
<text class="level-text">{{ careLevelText }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="elder-details">
|
|
<view class="detail-row">
|
|
<view class="detail-item">
|
|
<text class="detail-label">入住日期:</text>
|
|
<text class="detail-value">{{ formatDate(elderInfo.admission_date) }}</text>
|
|
</view>
|
|
<view class="detail-item">
|
|
<text class="detail-label">护理员:</text>
|
|
<text class="detail-value">{{ assignedCaregiver }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="detail-row">
|
|
<view class="detail-item">
|
|
<text class="detail-label">主治医生:</text>
|
|
<text class="detail-value">{{ assignedDoctor }}</text>
|
|
</view>
|
|
<view class="detail-item">
|
|
<text class="detail-label">紧急联系人:</text>
|
|
<text class="detail-value">{{ elderInfo.emergency_contact }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 健康状态统计 -->
|
|
<view class="health-stats-section">
|
|
<view class="section-title">
|
|
<text class="title-text">健康状态</text>
|
|
<button class="view-history-btn" @tap="viewHealthHistory">
|
|
<text class="btn-text">查看历史</text>
|
|
</button>
|
|
</view>
|
|
<view class="health-stats-grid">
|
|
<view class="health-stat-card" v-for="vital in recentVitals" :key="vital.type">
|
|
<text class="stat-icon">{{ getVitalIcon(vital.type) }}</text>
|
|
<text class="stat-label">{{ getVitalLabel(vital.type) }}</text>
|
|
<text class="stat-value">{{ vital.value }}{{ getVitalUnit(vital.type) }}</text>
|
|
<text class="stat-time">{{ formatTime(vital.recorded_time) }}</text>
|
|
<view class="stat-trend" :class="vital.trend">
|
|
<text class="trend-icon">{{ getTrendIcon(vital.trend) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 今日活动状态 -->
|
|
<view class="activity-status-section">
|
|
<view class="section-title">
|
|
<text class="title-text">今日活动</text>
|
|
<text class="activity-count">{{ todaysActivities.length }}项</text>
|
|
</view>
|
|
<view class="activity-timeline" v-if="todaysActivities.length > 0">
|
|
<view class="activity-item" v-for="activity in todaysActivities" :key="activity.id">
|
|
<view class="activity-time">
|
|
<text class="time-text">{{ formatTime(activity.scheduled_time) }}</text>
|
|
</view>
|
|
<view class="activity-content">
|
|
<text class="activity-title">{{ activity.title }}</text>
|
|
<text class="activity-location">{{ activity.location }}</text>
|
|
</view>
|
|
<view class="activity-status" :class="activity.status">
|
|
<text class="status-text">{{ getActivityStatusText(activity.status) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="empty-state" v-else>
|
|
<text class="empty-text">今天没有安排活动</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 用药状态 -->
|
|
<view class="medication-status-section">
|
|
<view class="section-title">
|
|
<text class="title-text">用药状态</text>
|
|
<view class="medication-summary">
|
|
<text class="summary-text">已服用 {{ takenMedications }}/{{ totalMedications }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="medication-list" v-if="todaysMedications.length > 0">
|
|
<view class="medication-item" v-for="medication in todaysMedications" :key="medication.id">
|
|
<view class="medication-time">
|
|
<text class="time-text">{{ formatTime(medication.scheduled_time) }}</text>
|
|
</view>
|
|
<view class="medication-info">
|
|
<text class="medication-name">{{ medication.medication_name }}</text>
|
|
<text class="medication-dosage">{{ medication.dosage }}</text>
|
|
</view>
|
|
<view class="medication-status" :class="medication.status">
|
|
<text class="status-icon">{{ getMedicationStatusIcon(medication.status) }}</text>
|
|
<text class="status-text">{{ getMedicationStatusText(medication.status) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="empty-state" v-else>
|
|
<text class="empty-text">今天没有用药安排</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 护理记录摘要 -->
|
|
<view class="care-summary-section">
|
|
<view class="section-title">
|
|
<text class="title-text">护理记录</text>
|
|
<button class="view-all-btn" @tap="viewAllCareRecords">
|
|
<text class="btn-text">查看全部</text>
|
|
</button>
|
|
</view>
|
|
<view class="care-records-preview" v-if="recentCareRecords.length > 0">
|
|
<view class="care-record-item" v-for="record in recentCareRecords" :key="record.id">
|
|
<view class="record-time">
|
|
<text class="time-text">{{ formatDateTime(record.created_at) }}</text>
|
|
</view>
|
|
<view class="record-content">
|
|
<text class="record-type">{{ getCareRecordTypeText(record.type) }}</text>
|
|
<text class="record-notes">{{ record.notes }}</text>
|
|
<text class="record-caregiver">护理员:{{ record.caregiver_name }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="empty-state" v-else>
|
|
<text class="empty-text">暂无护理记录</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 联系方式 -->
|
|
<view class="contact-section">
|
|
<view class="section-title">
|
|
<text class="title-text">联系方式</text>
|
|
</view>
|
|
<view class="contact-list">
|
|
<view class="contact-item" @tap="callCaregiver" v-if="caregiverInfo.phone">
|
|
<text class="contact-icon">👩⚕️</text>
|
|
<view class="contact-info">
|
|
<text class="contact-name">护理员 {{ caregiverInfo.name }}</text>
|
|
<text class="contact-phone">{{ caregiverInfo.phone }}</text>
|
|
</view>
|
|
<text class="contact-action">📞</text>
|
|
</view>
|
|
<view class="contact-item" @tap="callDoctor" v-if="doctorInfo.phone">
|
|
<text class="contact-icon">👨⚕️</text>
|
|
<view class="contact-info">
|
|
<text class="contact-name">医生 {{ doctorInfo.name }}</text>
|
|
<text class="contact-phone">{{ doctorInfo.phone }}</text>
|
|
</view>
|
|
<text class="contact-action">📞</text>
|
|
</view>
|
|
<view class="contact-item" @tap="callFacility">
|
|
<text class="contact-icon">🏥</text>
|
|
<view class="contact-info">
|
|
<text class="contact-name">机构总机</text>
|
|
<text class="contact-phone">400-123-4567</text>
|
|
</view>
|
|
<text class="contact-action">📞</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 快捷操作 -->
|
|
<view class="quick-actions-section">
|
|
<view class="section-title">
|
|
<text class="title-text">快捷操作</text>
|
|
</view>
|
|
<view class="action-buttons">
|
|
<button class="action-btn primary" @tap="sendMessage">
|
|
<text class="btn-text">发送消息</text>
|
|
</button>
|
|
<button class="action-btn secondary" @tap="scheduleVisit">
|
|
<text class="btn-text">预约探访</text>
|
|
</button>
|
|
<button class="action-btn secondary" @tap="viewFinancialRecords">
|
|
<text class="btn-text">费用记录</text>
|
|
</button>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.elder-status {
|
|
padding: 40rpx;
|
|
background-color: #f8f9fa;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.elder-info-card {
|
|
background: white;
|
|
border-radius: 24rpx;
|
|
padding: 40rpx;
|
|
margin-bottom: 40rpx;
|
|
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.05);
|
|
}
|
|
|
|
.elder-header {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
margin-bottom: 30rpx;
|
|
}
|
|
|
|
.elder-avatar {
|
|
width: 120rpx;
|
|
height: 120rpx;
|
|
border-radius: 60rpx;
|
|
margin-right: 30rpx;
|
|
overflow: hidden;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: #f0f0f0;
|
|
}
|
|
|
|
.avatar-image {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.avatar-fallback {
|
|
font-size: 48rpx;
|
|
color: #666;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.elder-basic {
|
|
flex: 1;
|
|
}
|
|
|
|
.elder-name {
|
|
font-size: 48rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
display: block;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.elder-info {
|
|
font-size: 30rpx;
|
|
color: #666;
|
|
display: block;
|
|
margin-bottom: 6rpx;
|
|
}
|
|
|
|
.elder-room {
|
|
font-size: 28rpx;
|
|
color: #007AFF;
|
|
display: block;
|
|
}
|
|
|
|
.elder-status {
|
|
text-align: right;
|
|
}
|
|
|
|
.health-indicator {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
margin-bottom: 12rpx;
|
|
}
|
|
|
|
.indicator-dot {
|
|
width: 20rpx;
|
|
height: 20rpx;
|
|
border-radius: 10rpx;
|
|
margin-right: 12rpx;
|
|
}
|
|
|
|
.status-text {
|
|
font-size: 28rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.health-indicator.stable .indicator-dot {
|
|
background: #4caf50;
|
|
}
|
|
|
|
.health-indicator.stable .status-text {
|
|
color: #4caf50;
|
|
}
|
|
|
|
.health-indicator.attention .indicator-dot {
|
|
background: #ff9800;
|
|
}
|
|
|
|
.health-indicator.attention .status-text {
|
|
color: #ff9800;
|
|
}
|
|
|
|
.health-indicator.critical .indicator-dot {
|
|
background: #f44336;
|
|
}
|
|
|
|
.health-indicator.critical .status-text {
|
|
color: #f44336;
|
|
}
|
|
|
|
.care-level {
|
|
background: #e3f2fd;
|
|
padding: 8rpx 16rpx;
|
|
border-radius: 16rpx;
|
|
}
|
|
|
|
.level-text {
|
|
font-size: 24rpx;
|
|
color: #1976d2;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.elder-details {
|
|
border-top: 1rpx solid #f0f0f0;
|
|
padding-top: 30rpx;
|
|
}
|
|
|
|
.detail-row {
|
|
display: flex;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.detail-row:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.detail-item {
|
|
flex: 1;
|
|
}
|
|
|
|
.detail-label {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
}
|
|
|
|
.detail-value {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.section-title {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-bottom: 24rpx;
|
|
}
|
|
|
|
.title-text {
|
|
font-size: 36rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.view-history-btn,
|
|
.view-all-btn {
|
|
background: #007AFF;
|
|
color: white;
|
|
padding: 16rpx 24rpx;
|
|
border-radius: 20rpx;
|
|
border: none;
|
|
font-size: 24rpx;
|
|
}
|
|
|
|
.activity-count {
|
|
background: #ff6b6b;
|
|
color: white;
|
|
padding: 8rpx 16rpx;
|
|
border-radius: 16rpx;
|
|
font-size: 24rpx;
|
|
}
|
|
|
|
.medication-summary {
|
|
background: #4caf50;
|
|
color: white;
|
|
padding: 8rpx 16rpx;
|
|
border-radius: 16rpx;
|
|
font-size: 24rpx;
|
|
}
|
|
|
|
.health-stats-section,
|
|
.activity-status-section,
|
|
.medication-status-section,
|
|
.care-summary-section,
|
|
.contact-section,
|
|
.quick-actions-section {
|
|
margin-bottom: 40rpx;
|
|
}
|
|
|
|
.health-stats-grid {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 20rpx;
|
|
}
|
|
|
|
.health-stat-card {
|
|
flex: 1;
|
|
min-width: 280rpx;
|
|
background: white;
|
|
padding: 30rpx;
|
|
border-radius: 16rpx;
|
|
position: relative;
|
|
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.05);
|
|
}
|
|
|
|
.stat-icon {
|
|
font-size: 48rpx;
|
|
display: block;
|
|
margin-bottom: 12rpx;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 28rpx;
|
|
color: #666;
|
|
display: block;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: 36rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
display: block;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.stat-time {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
display: block;
|
|
}
|
|
|
|
.stat-trend {
|
|
position: absolute;
|
|
top: 20rpx;
|
|
right: 20rpx;
|
|
width: 40rpx;
|
|
height: 40rpx;
|
|
border-radius: 20rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.stat-trend.up {
|
|
background: #e8f5e8;
|
|
}
|
|
|
|
.stat-trend.down {
|
|
background: #ffebee;
|
|
}
|
|
|
|
.stat-trend.stable {
|
|
background: #f5f5f5;
|
|
}
|
|
|
|
.trend-icon {
|
|
font-size: 24rpx;
|
|
}
|
|
|
|
.activity-timeline,
|
|
.medication-list,
|
|
.care-records-preview {
|
|
background: white;
|
|
border-radius: 16rpx;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.activity-item,
|
|
.medication-item,
|
|
.care-record-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 24rpx;
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
}
|
|
|
|
.activity-item:last-child,
|
|
.medication-item:last-child,
|
|
.care-record-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.activity-time,
|
|
.medication-time,
|
|
.record-time {
|
|
width: 140rpx;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.time-text {
|
|
font-size: 28rpx;
|
|
color: #007AFF;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.activity-content,
|
|
.medication-info,
|
|
.record-content {
|
|
flex: 1;
|
|
margin-left: 20rpx;
|
|
}
|
|
|
|
.activity-title,
|
|
.medication-name,
|
|
.record-type {
|
|
font-size: 32rpx;
|
|
color: #333;
|
|
display: block;
|
|
margin-bottom: 4rpx;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.activity-location,
|
|
.medication-dosage,
|
|
.record-notes {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
display: block;
|
|
margin-bottom: 4rpx;
|
|
}
|
|
|
|
.record-caregiver {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
display: block;
|
|
}
|
|
|
|
.activity-status,
|
|
.medication-status {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8rpx;
|
|
padding: 8rpx 16rpx;
|
|
border-radius: 12rpx;
|
|
font-size: 24rpx;
|
|
}
|
|
|
|
.activity-status.pending,
|
|
.medication-status.scheduled {
|
|
background: #fff3e0;
|
|
color: #ff9800;
|
|
}
|
|
|
|
.activity-status.completed,
|
|
.medication-status.taken {
|
|
background: #e8f5e8;
|
|
color: #4caf50;
|
|
}
|
|
|
|
.medication-status.missed {
|
|
background: #ffebee;
|
|
color: #f44336;
|
|
}
|
|
|
|
.contact-list {
|
|
background: white;
|
|
border-radius: 16rpx;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.contact-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 30rpx;
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
}
|
|
|
|
.contact-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.contact-icon {
|
|
font-size: 48rpx;
|
|
margin-right: 20rpx;
|
|
}
|
|
|
|
.contact-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.contact-name {
|
|
font-size: 32rpx;
|
|
color: #333;
|
|
display: block;
|
|
margin-bottom: 4rpx;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.contact-phone {
|
|
font-size: 28rpx;
|
|
color: #666;
|
|
display: block;
|
|
}
|
|
|
|
.contact-action {
|
|
font-size: 36rpx;
|
|
color: #007AFF;
|
|
}
|
|
|
|
.action-buttons {
|
|
display: flex;
|
|
gap: 20rpx;
|
|
}
|
|
|
|
.action-btn {
|
|
flex: 1;
|
|
padding: 30rpx;
|
|
border-radius: 16rpx;
|
|
border: none;
|
|
font-size: 30rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.action-btn.primary {
|
|
background: #007AFF;
|
|
color: white;
|
|
}
|
|
|
|
.action-btn.secondary {
|
|
background: white;
|
|
color: #007AFF;
|
|
border: 1rpx solid #007AFF;
|
|
}
|
|
|
|
.empty-state {
|
|
background: white;
|
|
padding: 60rpx;
|
|
border-radius: 16rpx;
|
|
text-align: center;
|
|
}
|
|
|
|
.empty-text {
|
|
font-size: 30rpx;
|
|
color: #999;
|
|
}
|
|
</style>
|
|
|
|
<script setup lang="uts">
|
|
import { ref, computed, onMounted } from 'vue'
|
|
import { formatDate, formatTime, formatDateTime, getActivityStatusText, getStatusText } from '../types.uts'
|
|
import type { ElderInfo, HealthVitals, Activity, MedicationSchedule, CareRecord, CaregiverInfo, DoctorInfo } from '../types.uts'
|
|
|
|
// 数据状态
|
|
const elderInfo = ref<ElderInfo>({
|
|
id: '',
|
|
name: '',
|
|
age: 0,
|
|
gender: 'male',
|
|
room_number: '',
|
|
bed_number: '',
|
|
admission_date: '',
|
|
health_status: 'stable',
|
|
care_level: 1,
|
|
emergency_contact: '',
|
|
profile_picture: '',
|
|
family_contact: ''
|
|
})
|
|
|
|
const recentVitals = ref<HealthVitals[]>([])
|
|
const todaysActivities = ref<Activity[]>([])
|
|
const todaysMedications = ref<MedicationSchedule[]>([])
|
|
const recentCareRecords = ref<CareRecord[]>([])
|
|
const caregiverInfo = ref<CaregiverInfo>({
|
|
id: '',
|
|
name: '',
|
|
phone: '',
|
|
department: '',
|
|
specialization: '',
|
|
shift: 'day'
|
|
})
|
|
|
|
const doctorInfo = ref<DoctorInfo>({
|
|
id: '',
|
|
name: '',
|
|
phone: '',
|
|
department: '',
|
|
specialization: '',
|
|
title: ''
|
|
})
|
|
|
|
// 计算属性
|
|
const healthStatusClass = computed(() => {
|
|
return elderInfo.value.health_status || 'stable'
|
|
})
|
|
|
|
const healthStatusText = computed(() => {
|
|
const statusMap = {
|
|
'stable': '稳定',
|
|
'attention': '需关注',
|
|
'critical': '危险'
|
|
}
|
|
return statusMap[elderInfo.value.health_status] || '未知'
|
|
})
|
|
|
|
const careLevelText = computed(() => {
|
|
const levelMap = {
|
|
1: '一级护理',
|
|
2: '二级护理',
|
|
3: '三级护理',
|
|
4: '特级护理'
|
|
}
|
|
return levelMap[elderInfo.value.care_level] || '未设置'
|
|
})
|
|
|
|
const assignedCaregiver = computed(() => {
|
|
return caregiverInfo.value.name || '未分配'
|
|
})
|
|
|
|
const assignedDoctor = computed(() => {
|
|
return doctorInfo.value.name || '未分配'
|
|
})
|
|
|
|
const takenMedications = computed(() => {
|
|
return todaysMedications.value.filter(med => med.status === 'taken').length
|
|
})
|
|
|
|
const totalMedications = computed(() => {
|
|
return todaysMedications.value.length
|
|
})
|
|
|
|
// 辅助函数
|
|
function getVitalIcon(type: string): string {
|
|
const icons = {
|
|
'heart_rate': '❤️',
|
|
'blood_pressure': '🩸',
|
|
'temperature': '🌡️',
|
|
'blood_sugar': '🍯',
|
|
'oxygen_saturation': '🫁'
|
|
}
|
|
return icons[type] || '📊'
|
|
}
|
|
|
|
function getVitalLabel(type: string): string {
|
|
const labels = {
|
|
'heart_rate': '心率',
|
|
'blood_pressure': '血压',
|
|
'temperature': '体温',
|
|
'blood_sugar': '血糖',
|
|
'oxygen_saturation': '血氧'
|
|
}
|
|
return labels[type] || type
|
|
}
|
|
|
|
function getVitalUnit(type: string): string {
|
|
const units = {
|
|
'heart_rate': 'bpm',
|
|
'blood_pressure': 'mmHg',
|
|
'temperature': '°C',
|
|
'blood_sugar': 'mmol/L',
|
|
'oxygen_saturation': '%'
|
|
}
|
|
return units[type] || ''
|
|
}
|
|
|
|
function getTrendIcon(trend: string): string {
|
|
const icons = {
|
|
'up': '↗️',
|
|
'down': '↘️',
|
|
'stable': '→'
|
|
}
|
|
return icons[trend] || '→'
|
|
}
|
|
|
|
function getMedicationStatusIcon(status: string): string {
|
|
const icons = {
|
|
'scheduled': '⏰',
|
|
'taken': '✅',
|
|
'missed': '❌',
|
|
'skipped': '⏭️'
|
|
}
|
|
return icons[status] || '⏰'
|
|
}
|
|
|
|
function getMedicationStatusText(status: string): string {
|
|
const statusMap = {
|
|
'scheduled': '待服用',
|
|
'taken': '已服用',
|
|
'missed': '已错过',
|
|
'skipped': '已跳过'
|
|
}
|
|
return statusMap[status] || '未知'
|
|
}
|
|
|
|
function getCareRecordTypeText(type: string): string {
|
|
const typeMap = {
|
|
'vital_signs': '生命体征',
|
|
'medication': '用药记录',
|
|
'nursing': '护理服务',
|
|
'meal': '用餐记录',
|
|
'activity': '活动记录',
|
|
'incident': '事件记录'
|
|
}
|
|
return typeMap[type] || type
|
|
}
|
|
|
|
function handleAvatarError() {
|
|
elderInfo.value.profile_picture = ''
|
|
}
|
|
|
|
// 导航函数
|
|
function viewHealthHistory() {
|
|
uni.navigateTo({
|
|
url: `/pages/ec/family/health-history?elder_id=${elderInfo.value.id}`
|
|
})
|
|
}
|
|
|
|
function viewAllCareRecords() {
|
|
uni.navigateTo({
|
|
url: `/pages/ec/family/care-records?elder_id=${elderInfo.value.id}`
|
|
})
|
|
}
|
|
|
|
function sendMessage() {
|
|
uni.navigateTo({
|
|
url: `/pages/ec/family/send-message?elder_id=${elderInfo.value.id}`
|
|
})
|
|
}
|
|
|
|
function scheduleVisit() {
|
|
uni.navigateTo({
|
|
url: `/pages/ec/family/schedule-visit?elder_id=${elderInfo.value.id}`
|
|
})
|
|
}
|
|
|
|
function viewFinancialRecords() {
|
|
uni.navigateTo({
|
|
url: `/pages/ec/family/financial-records?elder_id=${elderInfo.value.id}`
|
|
})
|
|
}
|
|
|
|
// 通话功能
|
|
function callCaregiver() {
|
|
if (caregiverInfo.value.phone) {
|
|
uni.makePhoneCall({
|
|
phoneNumber: caregiverInfo.value.phone
|
|
})
|
|
}
|
|
}
|
|
|
|
function callDoctor() {
|
|
if (doctorInfo.value.phone) {
|
|
uni.makePhoneCall({
|
|
phoneNumber: doctorInfo.value.phone
|
|
})
|
|
}
|
|
}
|
|
|
|
function callFacility() {
|
|
uni.makePhoneCall({
|
|
phoneNumber: '400-123-4567'
|
|
})
|
|
}
|
|
|
|
// 数据加载
|
|
async function loadElderInfo() {
|
|
try {
|
|
const pages = getCurrentPages()
|
|
const currentPage = pages[pages.length - 1]
|
|
const elderId = currentPage.$route.query?.elder_id as string
|
|
|
|
if (!elderId) {
|
|
uni.showToast({
|
|
title: '缺少老人ID',
|
|
icon: 'error'
|
|
})
|
|
return
|
|
}
|
|
|
|
const supa = (globalThis as any).supa
|
|
const result = await supa.executeAs('get_elder_info', {
|
|
elder_id: elderId
|
|
})
|
|
|
|
if (result && result.length > 0) {
|
|
elderInfo.value = result[0]
|
|
}
|
|
} catch (error) {
|
|
console.error('加载老人信息失败:', error)
|
|
uni.showToast({
|
|
title: '加载失败',
|
|
icon: 'error'
|
|
})
|
|
}
|
|
}
|
|
|
|
async function loadRecentVitals() {
|
|
try {
|
|
const supa = (globalThis as any).supa
|
|
const result = await supa.executeAs('get_recent_vitals', {
|
|
elder_id: elderInfo.value.id,
|
|
limit: 4
|
|
})
|
|
if (result && result.length > 0) {
|
|
recentVitals.value = result
|
|
}
|
|
} catch (error) {
|
|
console.error('加载健康数据失败:', error)
|
|
}
|
|
}
|
|
|
|
async function loadTodaysActivities() {
|
|
try {
|
|
const supa = (globalThis as any).supa
|
|
const today = new Date().toISOString().split('T')[0]
|
|
const result = await supa.executeAs('get_elder_activities', {
|
|
elder_id: elderInfo.value.id,
|
|
date: today
|
|
})
|
|
if (result && result.length > 0) {
|
|
todaysActivities.value = result
|
|
}
|
|
} catch (error) {
|
|
console.error('加载今日活动失败:', error)
|
|
}
|
|
}
|
|
|
|
async function loadTodaysMedications() {
|
|
try {
|
|
const supa = (globalThis as any).supa
|
|
const today = new Date().toISOString().split('T')[0]
|
|
const result = await supa.executeAs('get_elder_medications', {
|
|
elder_id: elderInfo.value.id,
|
|
date: today
|
|
})
|
|
if (result && result.length > 0) {
|
|
todaysMedications.value = result
|
|
}
|
|
} catch (error) {
|
|
console.error('加载用药信息失败:', error)
|
|
}
|
|
}
|
|
|
|
async function loadRecentCareRecords() {
|
|
try {
|
|
const supa = (globalThis as any).supa
|
|
const result = await supa.executeAs('get_recent_care_records', {
|
|
elder_id: elderInfo.value.id,
|
|
limit: 3
|
|
})
|
|
if (result && result.length > 0) {
|
|
recentCareRecords.value = result
|
|
}
|
|
} catch (error) {
|
|
console.error('加载护理记录失败:', error)
|
|
}
|
|
}
|
|
|
|
async function loadCaregiverInfo() {
|
|
try {
|
|
const supa = (globalThis as any).supa
|
|
const result = await supa.executeAs('get_assigned_caregiver', {
|
|
elder_id: elderInfo.value.id
|
|
})
|
|
if (result && result.length > 0) {
|
|
caregiverInfo.value = result[0]
|
|
}
|
|
} catch (error) {
|
|
console.error('加载护理员信息失败:', error)
|
|
}
|
|
}
|
|
|
|
async function loadDoctorInfo() {
|
|
try {
|
|
const supa = (globalThis as any).supa
|
|
const result = await supa.executeAs('get_assigned_doctor', {
|
|
elder_id: elderInfo.value.id
|
|
})
|
|
if (result && result.length > 0) {
|
|
doctorInfo.value = result[0]
|
|
}
|
|
} catch (error) {
|
|
console.error('加载医生信息失败:', error)
|
|
}
|
|
}
|
|
|
|
// 初始化
|
|
onMounted(async () => {
|
|
await loadElderInfo()
|
|
if (elderInfo.value.id) {
|
|
await Promise.all([
|
|
loadRecentVitals(),
|
|
loadTodaysActivities(),
|
|
loadTodaysMedications(),
|
|
loadRecentCareRecords(),
|
|
loadCaregiverInfo(),
|
|
loadDoctorInfo()
|
|
])
|
|
}
|
|
})
|
|
</script>
|