Files
hms/apps/miniprogram/src/pages/doctor/index.tsx
iven 202c6dd0d2
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
feat(miniprogram): 小程序设备数据集成打通 — Phase 3
- 首页设备入口简化为直接跳转按钮(去除硬编码 never 状态)
- 体征录入页增加「从设备同步」入口,设备数据自动回填表单
- 设备同步页支持 returnTo 参数,完成后返回录入页
- 医护工作台增加告警中心固定导航入口(带数字角标)
2026-04-29 06:36:12 +08:00

164 lines
6.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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/alerts/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/alerts/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 })}
>
<View className='quick-action__icon-wrap'>
<Text className='quick-action__initial'>{action.initial}</Text>
{action.label === '告警中心' && alertCount > 0 && (
<Text className='quick-action__badge'>{alertCount > 99 ? '99+' : alertCount}</Text>
)}
</View>
<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>
);
}