- 首页: 健康资讯推荐 + 空状态引导 + 快捷服务字符图标优化 - 健康 Hub: sparkline bar + 参考范围 + 打卡合并到快捷操作 - 日常监测: 3 分组折叠(晨间/晚间/其他) + 异常值高亮 + 提交前确认 - 预约: 已满时段 pointer-events:none + opacity 优化 - 咨询聊天: 消息日期分组(今天/昨天) + 图片预览 - 积分商城: 确认已有余额大字+签到+库存提示 - 医护工作台: 异常体征横幅 + 患者搜索入口 + 快捷操作扩展 - 趋势图表: 骨架屏加载状态 + ECharts 异常标记已有
159 lines
5.8 KiB
TypeScript
159 lines
5.8 KiB
TypeScript
import { useState, useEffect } from 'react';
|
||
import { View, Text, Input, ScrollView } from '@tarojs/components';
|
||
import Taro from '@tarojs/taro';
|
||
import { useAuthStore } from '@/stores/auth';
|
||
import * as doctorApi from '@/services/doctor';
|
||
import Loading from '@/components/Loading';
|
||
import './index.scss';
|
||
|
||
interface CardConfig {
|
||
key: keyof doctorApi.DoctorDashboard;
|
||
label: string;
|
||
initial: string;
|
||
route: string;
|
||
}
|
||
|
||
const CARDS: CardConfig[] = [
|
||
{ key: 'total_patients', label: '我的患者', initial: '患', route: '/pages/doctor/patients/index' },
|
||
{ key: 'unread_messages', label: '未读消息', initial: '消', route: '/pages/doctor/consultation/index' },
|
||
{ key: 'pending_follow_ups', label: '待处理随访', initial: '随', route: '/pages/doctor/followup/index' },
|
||
{ key: 'today_consultations', label: '今日咨询', initial: '诊', route: '/pages/doctor/consultation/index' },
|
||
];
|
||
|
||
const HEALTH_CARDS: CardConfig[] = [
|
||
{ key: 'pending_dialysis_review', label: '待审透析', initial: '透', route: '/pages/doctor/patients/index' },
|
||
{ key: 'pending_lab_review', label: '待审化验', initial: '化', route: '/pages/doctor/report/index' },
|
||
{ key: 'today_appointments', label: '今日预约', initial: '约', route: '/pages/doctor/patients/index' },
|
||
];
|
||
|
||
const QUICK_ACTIONS = [
|
||
{ label: '化验审核', initial: '审', route: '/pages/doctor/report/index' },
|
||
{ label: '患者查询', initial: '查', route: '/pages/doctor/patients/index' },
|
||
{ label: '随访记录', initial: '随', route: '/pages/doctor/followup/index' },
|
||
{ label: '排班查看', initial: '排', route: '/pages/doctor/patients/index' },
|
||
];
|
||
|
||
export default function DoctorHome() {
|
||
const { user, logout } = useAuthStore();
|
||
const [dashboard, setDashboard] = useState<doctorApi.DoctorDashboard | null>(null);
|
||
const [alertCount, setAlertCount] = useState(0);
|
||
const [loading, setLoading] = useState(true);
|
||
|
||
useEffect(() => {
|
||
loadDashboard();
|
||
}, []);
|
||
|
||
const loadDashboard = async () => {
|
||
try {
|
||
const data = await doctorApi.getDashboard();
|
||
setDashboard(data);
|
||
// 从仪表盘数据提取异常体征患者数
|
||
const count = (data as Record<string, unknown>)?.abnormal_vital_count;
|
||
setAlertCount(typeof count === 'number' ? count : 0);
|
||
} catch {
|
||
// 静默失败,显示占位
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const handleCardClick = (card: CardConfig) => {
|
||
Taro.navigateTo({ url: card.route });
|
||
};
|
||
|
||
const handleLogout = () => {
|
||
logout();
|
||
};
|
||
|
||
const getValue = (key: keyof doctorApi.DoctorDashboard): number | string => {
|
||
if (!dashboard) return '-';
|
||
return dashboard[key] ?? 0;
|
||
};
|
||
|
||
if (loading) return <Loading />;
|
||
|
||
return (
|
||
<ScrollView scrollY className='doctor-home'>
|
||
<View className='doctor-home__header'>
|
||
<Text className='doctor-home__title'>医护工作台</Text>
|
||
<Text className='doctor-home__greeting'>
|
||
{user?.display_name || user?.username || '医生'},您好
|
||
</Text>
|
||
<Text className='doctor-home__date'>
|
||
{new Date().toLocaleDateString('zh-CN', { month: 'long', day: 'numeric', weekday: 'long' })}
|
||
</Text>
|
||
</View>
|
||
|
||
{alertCount > 0 && (
|
||
<View className='doctor-home__alert'>
|
||
<Text className='doctor-home__alert-icon'>!</Text>
|
||
<Text className='doctor-home__alert-text'>{alertCount} 位患者体征异常</Text>
|
||
<Text className='doctor-home__alert-link' onClick={() => Taro.navigateTo({ url: '/pages/doctor/patients/index' })}>查看 →</Text>
|
||
</View>
|
||
)}
|
||
|
||
<View className='doctor-home__search'>
|
||
<Input
|
||
className='doctor-home__search-input'
|
||
placeholder='搜索患者姓名...'
|
||
onFocus={() => Taro.navigateTo({ url: '/pages/doctor/patients/index' })}
|
||
/>
|
||
</View>
|
||
|
||
<View className='doctor-home__section'>
|
||
<Text className='doctor-home__section-title'>工作概览</Text>
|
||
<View className='doctor-home__grid'>
|
||
{CARDS.map((card) => (
|
||
<View
|
||
key={card.key}
|
||
className='doctor-home__card'
|
||
onClick={() => handleCardClick(card)}
|
||
>
|
||
<Text className='doctor-home__card-initial'>{card.initial}</Text>
|
||
<Text className='doctor-home__card-num'>{getValue(card.key)}</Text>
|
||
<Text className='doctor-home__card-label'>{card.label}</Text>
|
||
</View>
|
||
))}
|
||
</View>
|
||
</View>
|
||
|
||
<View className='doctor-home__section'>
|
||
<Text className='doctor-home__section-title'>健康审核</Text>
|
||
<View className='doctor-home__grid'>
|
||
{HEALTH_CARDS.map((card) => (
|
||
<View
|
||
key={card.key}
|
||
className='doctor-home__card'
|
||
onClick={() => handleCardClick(card)}
|
||
>
|
||
<Text className='doctor-home__card-initial'>{card.initial}</Text>
|
||
<Text className='doctor-home__card-num'>{getValue(card.key)}</Text>
|
||
<Text className='doctor-home__card-label'>{card.label}</Text>
|
||
</View>
|
||
))}
|
||
</View>
|
||
</View>
|
||
|
||
<View className='doctor-home__section'>
|
||
<Text className='doctor-home__section-title'>快捷操作</Text>
|
||
<View className='doctor-home__quick-actions'>
|
||
{QUICK_ACTIONS.map((action) => (
|
||
<View
|
||
key={action.route}
|
||
className='quick-action'
|
||
onClick={() => Taro.navigateTo({ url: action.route })}
|
||
>
|
||
<Text className='quick-action__initial'>{action.initial}</Text>
|
||
<Text className='quick-action__label'>{action.label}</Text>
|
||
</View>
|
||
))}
|
||
</View>
|
||
</View>
|
||
|
||
<View className='doctor-home__footer'>
|
||
<Text className='doctor-home__logout' onClick={handleLogout}>退出登录</Text>
|
||
</View>
|
||
</ScrollView>
|
||
);
|
||
}
|