feat(health): 工作台遗留项修复 — UNION ALL 聚合 + 团队概览 + 较昨日对比
1. 待办列表 UNION ALL 聚合:list_action_items 现从 ai_suggestion + alerts + follow_up_task 三表查询, ActionType 扩展为 AiSuggestion/Alert/Followup/DataAnomaly 四种类型, get_action_thread 按类型构建不同线程时间线(AI 建议/告警/随访) 2. 真实团队概览:get_team_overview 从 doctor_profile + follow_up_task + alerts 聚合成员统计和风险分布 3. 统计卡片较昨日描述:PersonalStatsResp 新增 6 个 yesterday_* 字段, Home.tsx 统计卡片底部渲染"较昨日+N"绿色/红色描述 4. 前端 ActionDetailDrawer 改用 item.id(action_type:uuid 格式)调用线程 API
This commit is contained in:
@@ -78,6 +78,7 @@ interface StatCardDef {
|
||||
key: string;
|
||||
title: string;
|
||||
getValue: (p: PersonalStats | null, s: ReturnType<typeof useStatsData>) => number;
|
||||
getDiff?: (p: PersonalStats | null) => number | undefined;
|
||||
icon: React.ReactNode;
|
||||
suffix?: string;
|
||||
path: string;
|
||||
@@ -106,15 +107,15 @@ const STAT_TEXT_COLORS: string[] = ['#2563EB', '#7C3AED', '#DC2626', '#D97706'];
|
||||
|
||||
const ROLE_STATS: Record<DashboardRole, StatCardDef[]> = {
|
||||
doctor: [
|
||||
{ key: 'my-patients', title: '我的患者', getValue: (p) => p?.my_patients ?? 0, icon: <TeamOutlined />, path: '/health/patients' },
|
||||
{ key: 'today-appointments', title: '今日预约', getValue: (p) => p?.today_appointments ?? 0, icon: <CalendarOutlined />, path: '/health/appointments' },
|
||||
{ key: 'consultations', title: '本月咨询', getValue: (p) => p?.consultations_this_month ?? 0, icon: <MessageOutlined />, path: '/health/consultations' },
|
||||
{ key: 'my-patients', title: '我的患者', getValue: (p) => p?.my_patients ?? 0, getDiff: (p) => { const c = p?.my_patients, y = p?.yesterday_my_patients; return c != null && y != null ? c - y : undefined; }, icon: <TeamOutlined />, path: '/health/patients' },
|
||||
{ key: 'today-appointments', title: '今日预约', getValue: (p) => p?.today_appointments ?? 0, getDiff: (p) => { const c = p?.today_appointments, y = p?.yesterday_today_appointments; return c != null && y != null ? c - y : undefined; }, icon: <CalendarOutlined />, path: '/health/appointments' },
|
||||
{ key: 'consultations', title: '本月咨询', getValue: (p) => p?.consultations_this_month ?? 0, getDiff: (p) => { const c = p?.consultations_this_month, y = p?.yesterday_consultations_this_month; return c != null && y != null ? c - y : undefined; }, icon: <MessageOutlined />, path: '/health/consultations' },
|
||||
{ key: 'followup-rate', title: '随访完成率', getValue: (p) => p?.follow_up_rate ?? 0, icon: <HeartOutlined />, suffix: '%', path: '/health/follow-ups' },
|
||||
],
|
||||
nurse: [
|
||||
{ key: 'today-appointments', title: '今日预约', getValue: (p) => p?.today_appointments ?? 0, icon: <CalendarOutlined />, path: '/health/appointments' },
|
||||
{ key: 'today-followups', title: '今日随访', getValue: (p) => p?.today_follow_ups ?? 0, icon: <HeartOutlined />, path: '/health/follow-ups' },
|
||||
{ key: 'overdue', title: '逾期随访', getValue: (p) => p?.overdue_follow_ups ?? 0, icon: <AlertOutlined />, path: '/health/follow-ups' },
|
||||
{ key: 'today-appointments', title: '今日预约', getValue: (p) => p?.today_appointments ?? 0, getDiff: (p) => { const c = p?.today_appointments, y = p?.yesterday_today_appointments; return c != null && y != null ? c - y : undefined; }, icon: <CalendarOutlined />, path: '/health/appointments' },
|
||||
{ key: 'today-followups', title: '今日随访', getValue: (p) => p?.today_follow_ups ?? 0, getDiff: (p) => { const c = p?.today_follow_ups, y = p?.yesterday_today_follow_ups; return c != null && y != null ? c - y : undefined; }, icon: <HeartOutlined />, path: '/health/follow-ups' },
|
||||
{ key: 'overdue', title: '逾期随访', getValue: (p) => p?.overdue_follow_ups ?? 0, getDiff: (p) => { const c = p?.overdue_follow_ups, y = p?.yesterday_overdue_follow_ups; return c != null && y != null ? c - y : undefined; }, icon: <AlertOutlined />, path: '/health/follow-ups' },
|
||||
{ key: 'vital-rate', title: '体征上报率', getValue: (p) => p?.vital_signs_report_rate ?? 0, icon: <MedicineBoxOutlined />, suffix: '%', path: '/health/vital-signs' },
|
||||
],
|
||||
admin: [
|
||||
@@ -249,6 +250,7 @@ export default function Home() {
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 16, marginBottom: 24 }}>
|
||||
{statDefs.map((def, i) => {
|
||||
const value = def.getValue(personalStats, statsData);
|
||||
const diff = def.getDiff?.(personalStats);
|
||||
return (
|
||||
<div
|
||||
key={def.key}
|
||||
@@ -275,6 +277,11 @@ export default function Home() {
|
||||
<StatValue value={value} loading={loading} />
|
||||
{def.suffix && <span style={{ fontSize: 14, marginLeft: 2 }}>{def.suffix}</span>}
|
||||
</div>
|
||||
{diff != null && (
|
||||
<div style={{ fontSize: 11, marginTop: 4, color: diff > 0 ? '#16A34A' : diff < 0 ? '#DC2626' : '#94A3B8' }}>
|
||||
{diff === 0 ? '与昨日持平' : `较昨日 ${diff > 0 ? '+' : ''}${diff}`}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user