From 8d1a535a6353d3cc6aae040127936dddaba80123 Mon Sep 17 00:00:00 2001 From: selfrelease Date: Thu, 18 Jun 2026 10:13:57 +0800 Subject: [PATCH] =?UTF-8?q?feat(workbench):=20=E5=85=A8=E9=9D=A2=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E4=B8=AA=E6=A1=88=E5=B7=A5=E4=BD=9C=E5=8F=B0=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 性能与加载: - 分阶段加载:档案头、个案数据、档案数据各自独立加载,骨架屏替代 spinner - PatientHeadSkeleton / WorkbenchSkeleton / ArchiveSkeleton 三套骨架 - 档案库懒加载(切换 Tab 时才请求) 交互增强: - Alert 卡片增加「标记已读」和「关闭」按钮,调用 acknowledgeAlert / resolveAlert API - 态势感知 Detail 区支持同时展开多个类型(状态独立) - StatCard 点击可折叠/展开,带 chevron 指示 - 待办列表增加分页(每页 8 条) AI 建议: - 从单一方案扩展为 3 套方案(保守 A / 常规 B / 积极 C) - 支持切换标签,卡片内动画过渡 - 每套方案可一键生成对应处置单 - 预置空腹血糖、血压、体重等多套模板 指标卡片: - Sparkline 增加阈值参考虚线(min/max) - 超限高亮点 + 「超限」角标 - 档案库扩展为 8 个指标卡(新增舒张压、OGTT 1h/2h、餐后血糖) - 阈值常量统一管理(THRESHOLDS Map) 分页: - 档案库观测历史分页(每页 8 条) - 待办列表分页 样式完善: - badge-emerald / badge-rose / badge-indigo / badge-calm - btn-xs / btn-success / btn-rose - grid-4 / align-center / border-l-* - 脉冲危急点动画、Tab 未读计数角标 - Alert 支持 updatedAt,severity 别名兼容后端字段 Co-Authored-By: Claude --- pcm-platform/admin-web/src/api/client.ts | 4 + pcm-platform/admin-web/src/api/types.ts | 3 + .../admin-web/src/components/Skeleton.css | 22 + .../admin-web/src/components/Skeleton.tsx | 180 ++ .../admin-web/src/pages/CaseWorkbenchPage.css | 118 +- .../admin-web/src/pages/CaseWorkbenchPage.tsx | 2149 ++++++++++------- pcm-platform/admin-web/src/styles/global.css | 83 + 7 files changed, 1653 insertions(+), 906 deletions(-) create mode 100644 pcm-platform/admin-web/src/components/Skeleton.css create mode 100644 pcm-platform/admin-web/src/components/Skeleton.tsx diff --git a/pcm-platform/admin-web/src/api/client.ts b/pcm-platform/admin-web/src/api/client.ts index 7759943..5662497 100644 --- a/pcm-platform/admin-web/src/api/client.ts +++ b/pcm-platform/admin-web/src/api/client.ts @@ -93,6 +93,10 @@ export const api = { listObservations: (patientId: string): Promise => request(`/patients/${patientId}/observations`), listAlerts: (patientId: string): Promise => request(`/patients/${patientId}/alerts`), + acknowledgeAlert: (patientId: string, alertId: string): Promise => + request(`/patients/${patientId}/alerts/${alertId}/acknowledge`, { method: 'POST' }), + resolveAlert: (patientId: string, alertId: string): Promise => + request(`/patients/${patientId}/alerts/${alertId}/resolve`, { method: 'POST' }), listReminders: (patientId: string): Promise => request(`/patients/${patientId}/reminders`), diff --git a/pcm-platform/admin-web/src/api/types.ts b/pcm-platform/admin-web/src/api/types.ts index 9dd4afc..edb06e4 100644 --- a/pcm-platform/admin-web/src/api/types.ts +++ b/pcm-platform/admin-web/src/api/types.ts @@ -64,10 +64,13 @@ export interface Alert { indicator: string; value: number; level: RiskLevel; + /** severity 为 level 的别名,后端字段对齐 */ + severity: RiskLevel; ruleIds: string[]; messages: string[]; status: AlertStatus; createdAt: string; + updatedAt: string; } // 个案 diff --git a/pcm-platform/admin-web/src/components/Skeleton.css b/pcm-platform/admin-web/src/components/Skeleton.css new file mode 100644 index 0000000..b83ce33 --- /dev/null +++ b/pcm-platform/admin-web/src/components/Skeleton.css @@ -0,0 +1,22 @@ +/* 骨架屏动画 */ +@keyframes shimmer { + 0% { background-position: -400px 0; } + 100% { background-position: 400px 0; } +} + +.skeleton-line { + display: inline-block; + background: linear-gradient( + 90deg, + var(--color-border) 25%, + var(--color-bg) 50%, + var(--color-border) 75% + ); + background-size: 800px 100%; + animation: shimmer 1.5s infinite linear; + vertical-align: middle; +} + +.skeleton-root { + pointer-events: none; +} diff --git a/pcm-platform/admin-web/src/components/Skeleton.tsx b/pcm-platform/admin-web/src/components/Skeleton.tsx new file mode 100644 index 0000000..3f870fe --- /dev/null +++ b/pcm-platform/admin-web/src/components/Skeleton.tsx @@ -0,0 +1,180 @@ +/** + * 骨架屏组件 — 真实布局骨架,提升感知加载速度 + * 替代整页 loading spinner,让用户"看到"即将呈现的内容结构 + */ + +import './Skeleton.css'; + +interface SkeletonLineProps { + width?: string; + height?: string; + radius?: string; +} + +function SkeletonLine({ width = '100%', height = '14px', radius = '4px' }: SkeletonLineProps): JSX.Element { + return ( +