Files
hms/apps/miniprogram/src/pages/doctor/index.tsx
iven 0e45778fc3
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 5 UI/UX 优化 — 8 项改进
- 首页: 健康资讯推荐 + 空状态引导 + 快捷服务字符图标优化
- 健康 Hub: sparkline bar + 参考范围 + 打卡合并到快捷操作
- 日常监测: 3 分组折叠(晨间/晚间/其他) + 异常值高亮 + 提交前确认
- 预约: 已满时段 pointer-events:none + opacity 优化
- 咨询聊天: 消息日期分组(今天/昨天) + 图片预览
- 积分商城: 确认已有余额大字+签到+库存提示
- 医护工作台: 异常体征横幅 + 患者搜索入口 + 快捷操作扩展
- 趋势图表: 骨架屏加载状态 + ECharts 异常标记已有
2026-04-28 08:51:27 +08:00

159 lines
5.8 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/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>
);
}