- 新增 12 个核心页面原型(登录/首页/咨询/预约/商城/健康等) - 新增医生端分包原型(核心 + 临床两个分包) - 新增 AI 客服对话页原型 - 新增 MP UI 优化指南文档 - 更新 wiki 基础设施和小程序文档
646 lines
30 KiB
HTML
646 lines
30 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>HMS 小程序 — 医生端临床</title>
|
||
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
|
||
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
|
||
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
||
<style>
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
body { background: #1a1a1a; font-family: -apple-system, 'PingFang SC', sans-serif; display: flex; flex-direction: column; align-items: center; padding: 40px 20px; gap: 24px; }
|
||
.page-title { color: #999; font-size: 13px; letter-spacing: 0.15em; text-transform: uppercase; }
|
||
.note { color: #666; font-size: 12px; max-width: 1200px; text-align: center; line-height: 1.8; }
|
||
.screens { display: flex; gap: 36px; flex-wrap: wrap; justify-content: center; align-items: flex-start; }
|
||
.screen-wrap { display: flex; flex-direction: column; align-items: center; gap: 12px; }
|
||
.screen-label { color: #888; font-size: 12px; font-style: italic; }
|
||
/* Scrollbar hide */
|
||
.no-scrollbar::-webkit-scrollbar { display: none; }
|
||
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="page-title">HMS 小程序 · 医生端临床</div>
|
||
<div class="note">医生端深靛蓝设计系统 — 临床管理模块。6 个屏幕:告警列表、告警详情、透析列表、透析创建、处方列表、处方详情。</div>
|
||
<div id="root"></div>
|
||
|
||
<script type="text/babel">
|
||
// ─── iOS 设备框 ───
|
||
const iosFrameStyles = {
|
||
wrapper: { display: 'inline-block', padding: 12, background: '#000', borderRadius: 60, boxShadow: '0 0 0 2px #1f2937, 0 20px 60px rgba(0,0,0,0.3)', position: 'relative' },
|
||
screen: { position: 'relative', borderRadius: 48, overflow: 'hidden', background: '#fff' },
|
||
statusBar: { position: 'absolute', top: 0, left: 0, right: 0, height: 54, display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 32px', fontSize: 16, fontWeight: 600, fontFamily: '-apple-system, "SF Pro Text", sans-serif', zIndex: 20, pointerEvents: 'none' },
|
||
dynamicIsland: { position: 'absolute', top: 12, left: '50%', transform: 'translateX(-50%)', width: 124, height: 36, background: '#000', borderRadius: 999, zIndex: 30 },
|
||
content: { position: 'absolute', top: 54, left: 0, right: 0, bottom: 34, overflow: 'auto' },
|
||
homeIndicator: { position: 'absolute', bottom: 10, left: '50%', transform: 'translateX(-50%)', width: 140, height: 5, background: 'rgba(0,0,0,0.3)', borderRadius: 999, zIndex: 10 },
|
||
};
|
||
|
||
function IosFrame({ children, width = 340, height = 740, time = '9:41', battery = 85, darkStatus = false, label }) {
|
||
const statusColor = darkStatus ? '#fff' : '#000';
|
||
return (
|
||
<div class="screen-wrap">
|
||
<div style={iosFrameStyles.wrapper}>
|
||
<div style={{ ...iosFrameStyles.screen, width, height }}>
|
||
<div style={{ ...iosFrameStyles.statusBar, color: statusColor }}>
|
||
<span>{time}</span>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||
<svg width="16" height="12" viewBox="0 0 16 12" fill="none"><path d="M8 11.5a1 1 0 100-2 1 1 0 000 2z" fill={statusColor}/><path d="M3 7.5a7 7 0 0110 0" stroke={statusColor} strokeWidth="1.3" fill="none" strokeLinecap="round"/><path d="M1 4.5a11 11 0 0114 0" stroke={statusColor} strokeWidth="1.3" fill="none" strokeLinecap="round" opacity="0.7"/></svg>
|
||
<div style={{ width: 26, height: 12, border: `1.5px solid ${statusColor}`, borderRadius: 3, padding: 1, position: 'relative' }}>
|
||
<div style={{ width: `${battery}%`, height: '100%', background: statusColor, borderRadius: 1 }} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style={iosFrameStyles.dynamicIsland} />
|
||
<div className="no-scrollbar" style={{ ...iosFrameStyles.content }}>{children}</div>
|
||
<div style={iosFrameStyles.homeIndicator} />
|
||
</div>
|
||
</div>
|
||
{label && <div class="screen-label">{label}</div>}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// ─── 设计 Token — 医生端靛蓝变体 ───
|
||
const T = {
|
||
pri: '#3A6B8C', priL: '#D4E5F0', priD: '#2A4F6A',
|
||
bg: '#F5F0EB', card: '#FFFFFF', surface: '#EDE8E2',
|
||
tx: '#2D2A26', tx2: '#5A554F', tx3: '#78716C',
|
||
bd: '#E8E2DC', bdL: '#F0EBE5',
|
||
acc: '#5B7A5E', accL: '#E8F0E8',
|
||
wrn: '#C4873A', wrnL: '#FFF3E0',
|
||
dan: '#B54A4A', danL: '#FDEAEA',
|
||
serif: "Georgia, 'Times New Roman', serif",
|
||
sans: "-apple-system, 'PingFang SC', sans-serif",
|
||
r: 16, rSm: 12, rXs: 8,
|
||
};
|
||
|
||
// ─── 通用组件 ───
|
||
function NavBar({ title }) {
|
||
return (
|
||
<div style={{ height: 44, display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative', background: T.bg, borderBottom: `1px solid ${T.bdL}`, flexShrink: 0 }}>
|
||
<svg style={{ position: 'absolute', left: 16 }} width="24" height="24" viewBox="0 0 24 24" fill="none" stroke={T.tx} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
||
<path d="M15 18l-6-6 6-6"/>
|
||
</svg>
|
||
<span style={{ fontFamily: T.serif, fontSize: 18, fontWeight: 700, color: T.tx }}>{title}</span>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function Tag({ label, color = T.acc, bg = T.accL }) {
|
||
return (
|
||
<span style={{ display: 'inline-block', fontSize: 11, color, background: bg, padding: '2px 8px', borderRadius: 6, fontWeight: 500 }}>{label}</span>
|
||
);
|
||
}
|
||
|
||
function FilterTabs({ tabs, active = 0 }) {
|
||
return (
|
||
<div style={{ display: 'flex', gap: 8, marginBottom: 16 }}>
|
||
{tabs.map((t, i) => (
|
||
<div key={i} style={{
|
||
padding: '6px 14px', borderRadius: 20, fontSize: 13, fontWeight: i === active ? 600 : 400,
|
||
color: i === active ? '#fff' : T.tx2, background: i === active ? T.pri : T.card,
|
||
border: `1px solid ${i === active ? T.pri : T.bd}`, cursor: 'pointer', transition: 'all 0.2s',
|
||
}}>{t}</div>
|
||
))}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function InfoRow({ label, value }) {
|
||
return (
|
||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '12px 0', borderBottom: `1px solid ${T.bdL}` }}>
|
||
<span style={{ fontSize: 13, color: T.tx3 }}>{label}</span>
|
||
<span style={{ fontSize: 14, color: T.tx, fontWeight: 500 }}>{value}</span>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function FormField({ label, value, placeholder, multiline }) {
|
||
return (
|
||
<div style={{ marginBottom: 14 }}>
|
||
<div style={{ fontSize: 13, color: T.tx2, marginBottom: 6, fontWeight: 500 }}>{label}</div>
|
||
<div style={{
|
||
height: multiline ? 80 : 52, background: T.card, border: `1.5px solid ${T.bd}`,
|
||
borderRadius: T.r, display: 'flex', alignItems: multiline ? 'flex-start' : 'center',
|
||
padding: multiline ? '14px 16px' : '0 16px', fontSize: 14, color: value ? T.tx : T.tx3,
|
||
fontFamily: T.sans, lineHeight: multiline ? 1.5 : 1,
|
||
}}>{value || placeholder}</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function ActionButton({ label, primary, danger, style: extraStyle }) {
|
||
const isDanger = danger;
|
||
const isPrimary = primary;
|
||
return (
|
||
<div style={{
|
||
height: 48, borderRadius: T.r, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||
fontSize: 15, fontWeight: 600, cursor: 'pointer',
|
||
background: isDanger ? 'transparent' : (isPrimary ? T.pri : 'transparent'),
|
||
color: isDanger ? T.dan : (isPrimary ? '#fff' : T.pri),
|
||
border: isDanger ? `1.5px solid ${T.dan}` : (isPrimary ? 'none' : `1.5px solid ${T.pri}`),
|
||
...extraStyle,
|
||
}}>{label}</div>
|
||
);
|
||
}
|
||
|
||
// ─── 屏幕1:告警列表 ───
|
||
function AlertList() {
|
||
const alerts = [
|
||
{ patient: '张三', type: '血压异常', urgency: '紧急', urgencyColor: T.dan, urgencyBg: T.danL,
|
||
value: '158', unit: 'mmHg', ref: '参考 <140', time: '10分钟前', status: '待处理', statusColor: T.dan, statusBg: T.danL },
|
||
{ patient: '赵六', type: '血糖异常', urgency: '紧急', urgencyColor: T.dan, urgencyBg: T.danL,
|
||
value: '15.2', unit: 'mmol/L', ref: '参考 <7.0', time: '2小时前', status: '待处理', statusColor: T.dan, statusBg: T.danL },
|
||
{ patient: '李四', type: '体重异常', urgency: '普通', urgencyColor: T.wrn, urgencyBg: T.wrnL,
|
||
value: '+2.3', unit: 'kg', ref: '周变化', time: '昨天', status: '已处理', statusColor: T.acc, statusBg: T.accL },
|
||
{ patient: '陈七', type: '血压异常', urgency: '紧急', urgencyColor: T.dan, urgencyBg: T.danL,
|
||
value: '162', unit: 'mmHg', ref: '参考 <140', time: '昨天', status: '待处理', statusColor: T.dan, statusBg: T.danL },
|
||
{ patient: '周八', type: '心率异常', urgency: '普通', urgencyColor: T.wrn, urgencyBg: T.wrnL,
|
||
value: '108', unit: 'bpm', ref: '参考 60-100', time: '2天前', status: '已处理', statusColor: T.acc, statusBg: T.accL },
|
||
];
|
||
|
||
return (
|
||
<div style={{ height: '100%', background: T.bg, display: 'flex', flexDirection: 'column' }}>
|
||
<NavBar title="异常告警" />
|
||
<div style={{ flex: 1, overflow: 'auto', padding: '16px 20px 24px' }}>
|
||
{/* 筛选标签 */}
|
||
<FilterTabs tabs={['全部', '高优', '中优', '低优']} active={0} />
|
||
|
||
{/* 统计栏 */}
|
||
<div style={{ display: 'flex', gap: 10, marginBottom: 18 }}>
|
||
{[
|
||
{ label: '今日', value: '8', color: T.pri },
|
||
{ label: '待处理', value: '5', color: T.dan },
|
||
{ label: '已处理', value: '3', color: T.acc },
|
||
].map((s, i) => (
|
||
<div key={i} style={{ flex: 1, background: T.card, borderRadius: T.rSm, padding: '12px 14px', textAlign: 'center', boxShadow: '0 1px 8px rgba(0,0,0,0.04)' }}>
|
||
<div style={{ fontFamily: T.serif, fontSize: 22, fontWeight: 700, color: s.color }}>{s.value}</div>
|
||
<div style={{ fontSize: 11, color: T.tx3, marginTop: 2 }}>{s.label}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* 告警列表 */}
|
||
{alerts.map((a, i) => (
|
||
<div key={i} style={{
|
||
background: T.card, borderRadius: T.r, padding: '16px 18px', marginBottom: 12,
|
||
boxShadow: '0 2px 12px rgba(0,0,0,0.04)', borderLeft: `4px solid ${a.urgencyColor}`,
|
||
}}>
|
||
{/* 头部:患者 + 类型 + 紧急度 */}
|
||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||
<span style={{ fontFamily: T.serif, fontSize: 16, fontWeight: 700, color: T.tx }}>{a.patient}</span>
|
||
<Tag label={a.type} color={T.pri} bg={T.priL} />
|
||
</div>
|
||
<Tag label={a.urgency} color={a.urgencyColor} bg={a.urgencyBg} />
|
||
</div>
|
||
|
||
{/* 异常值 */}
|
||
<div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginBottom: 10 }}>
|
||
<span style={{ fontFamily: T.serif, fontSize: 28, fontWeight: 700, color: a.urgencyColor }}>{a.value}</span>
|
||
<span style={{ fontSize: 13, color: T.tx2 }}>{a.unit}</span>
|
||
<span style={{ fontSize: 12, color: T.tx3, marginLeft: 4 }}>({a.ref})</span>
|
||
</div>
|
||
|
||
{/* 底部:时间 + 状态 */}
|
||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||
<span style={{ fontSize: 12, color: T.tx3 }}>{a.time}</span>
|
||
<Tag label={a.status} color={a.statusColor} bg={a.statusBg} />
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// ─── 屏幕2:告警详情 ───
|
||
function AlertDetail() {
|
||
const history = [
|
||
{ date: '5/8', value: '158/95', note: '偏高', color: T.dan },
|
||
{ date: '5/7', value: '145/90', note: '偏高', color: T.wrn },
|
||
{ date: '5/6', value: '132/85', note: '正常', color: T.acc },
|
||
{ date: '5/5', value: '138/88', note: '偏高', color: T.wrn },
|
||
];
|
||
|
||
return (
|
||
<div style={{ height: '100%', background: T.bg, display: 'flex', flexDirection: 'column' }}>
|
||
<NavBar title="告警详情" />
|
||
<div style={{ flex: 1, overflow: 'auto', padding: '16px 20px 24px' }}>
|
||
{/* 患者信息 */}
|
||
<div style={{
|
||
background: T.card, borderRadius: T.r, padding: '18px 20px', marginBottom: 14,
|
||
boxShadow: '0 2px 12px rgba(0,0,0,0.04)', display: 'flex', alignItems: 'center', gap: 14,
|
||
}}>
|
||
<div style={{
|
||
width: 44, height: 44, borderRadius: 22, background: T.priL,
|
||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||
fontFamily: T.serif, fontSize: 18, fontWeight: 700, color: T.pri,
|
||
}}>张</div>
|
||
<div style={{ flex: 1 }}>
|
||
<div style={{ fontFamily: T.serif, fontSize: 17, fontWeight: 700, color: T.tx, marginBottom: 3 }}>张三</div>
|
||
<div style={{ fontSize: 13, color: T.tx3 }}>58岁 · 男 · 高血压 · 慢性肾病III期</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 告警信息卡片 */}
|
||
<div style={{
|
||
background: T.card, borderRadius: T.r, padding: '18px 20px', marginBottom: 14,
|
||
boxShadow: '0 2px 12px rgba(0,0,0,0.04)', borderLeft: `4px solid ${T.dan}`,
|
||
}}>
|
||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 14 }}>
|
||
<span style={{ fontSize: 14, fontWeight: 600, color: T.tx }}>告警信息</span>
|
||
<Tag label="紧急" color={T.dan} bg={T.danL} />
|
||
</div>
|
||
<InfoRow label="类型" value="血压异常" />
|
||
<InfoRow label="触发时间" value="今天 08:30" />
|
||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '12px 0' }}>
|
||
<span style={{ fontSize: 13, color: T.tx3 }}>异常值</span>
|
||
<div style={{ display: 'flex', alignItems: 'baseline', gap: 4 }}>
|
||
<span style={{ fontFamily: T.serif, fontSize: 22, fontWeight: 700, color: T.dan }}>158</span>
|
||
<span style={{ fontSize: 13, color: T.tx2 }}>mmHg</span>
|
||
<span style={{ fontSize: 12, color: T.tx3, marginLeft: 4 }}>(参考 <140)</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 近期数据 */}
|
||
<div style={{
|
||
background: T.card, borderRadius: T.r, padding: '18px 20px', marginBottom: 14,
|
||
boxShadow: '0 2px 12px rgba(0,0,0,0.04)',
|
||
}}>
|
||
<div style={{ fontSize: 14, fontWeight: 600, color: T.tx, marginBottom: 12 }}>近期数据</div>
|
||
{history.map((h, i) => (
|
||
<div key={i} style={{
|
||
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
||
padding: '10px 0', borderBottom: i < history.length - 1 ? `1px solid ${T.bdL}` : 'none',
|
||
}}>
|
||
<span style={{ fontSize: 13, color: T.tx2, width: 40 }}>{h.date}</span>
|
||
<span style={{ fontFamily: T.serif, fontSize: 15, fontWeight: 600, color: T.tx, flex: 1 }}>{h.value}</span>
|
||
<Tag label={h.note} color={h.color} bg={h.color === T.dan ? T.danL : (h.color === T.wrn ? T.wrnL : T.accL)} />
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* 处理意见 */}
|
||
<div style={{
|
||
background: T.card, borderRadius: T.r, padding: '18px 20px', marginBottom: 14,
|
||
boxShadow: '0 2px 12px rgba(0,0,0,0.04)',
|
||
}}>
|
||
<div style={{ fontSize: 14, fontWeight: 600, color: T.tx, marginBottom: 10 }}>处理意见</div>
|
||
<div style={{
|
||
height: 72, background: T.bg, borderRadius: T.rSm, border: `1px solid ${T.bd}`,
|
||
padding: '12px 14px', fontSize: 13, color: T.tx3, lineHeight: 1.5,
|
||
}}>请输入处理意见...</div>
|
||
</div>
|
||
|
||
{/* 操作按钮 */}
|
||
<div style={{ display: 'flex', gap: 12 }}>
|
||
<ActionButton label="标记已处理" primary style={{ flex: 1 }} />
|
||
<ActionButton label="联系患者" style={{ flex: 1 }} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// ─── 屏幕3:透析列表 ───
|
||
function DialysisList() {
|
||
const records = [
|
||
{ patient: '张三', bed: '3床', mode: 'HD', time: '08:00-12:00', status: '进行中', statusColor: T.wrn, statusBg: T.wrnL,
|
||
detail: '超滤 1.8L/2.3L' },
|
||
{ patient: '李四', bed: '5床', mode: 'HDF', time: '08:30-12:30', status: '进行中', statusColor: T.wrn, statusBg: T.wrnL,
|
||
detail: '超滤 1.2L/2.0L' },
|
||
{ patient: '王五', bed: '1床', mode: 'HD', time: '13:00-17:00', status: '待开始', statusColor: T.tx3, statusBg: T.surface,
|
||
detail: null },
|
||
{ patient: '赵六', bed: '2床', mode: 'HD', time: '08:00-12:00', status: '已完成', statusColor: T.acc, statusBg: T.accL,
|
||
detail: '超滤 2.1L' },
|
||
];
|
||
|
||
return (
|
||
<div style={{ height: '100%', background: T.bg, display: 'flex', flexDirection: 'column' }}>
|
||
<NavBar title="透析管理" />
|
||
<div style={{ flex: 1, overflow: 'auto', padding: '16px 20px 24px' }}>
|
||
{/* 今日统计 */}
|
||
<div style={{ display: 'flex', gap: 10, marginBottom: 18 }}>
|
||
{[
|
||
{ label: '已透析', value: '5', color: T.acc },
|
||
{ label: '进行中', value: '2', color: T.wrn },
|
||
{ label: '待开始', value: '3', color: T.tx3 },
|
||
].map((s, i) => (
|
||
<div key={i} style={{
|
||
flex: 1, background: T.card, borderRadius: T.rSm, padding: '14px 14px', textAlign: 'center',
|
||
boxShadow: '0 1px 8px rgba(0,0,0,0.04)',
|
||
}}>
|
||
<div style={{ fontFamily: T.serif, fontSize: 24, fontWeight: 700, color: s.color }}>{s.value}</div>
|
||
<div style={{ fontSize: 11, color: T.tx3, marginTop: 2 }}>{s.label}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* 透析记录 */}
|
||
{records.map((r, i) => (
|
||
<div key={i} style={{
|
||
background: T.card, borderRadius: T.r, padding: '16px 18px', marginBottom: 12,
|
||
boxShadow: '0 2px 12px rgba(0,0,0,0.04)',
|
||
}}>
|
||
{/* 头部 */}
|
||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
|
||
<span style={{ fontFamily: T.serif, fontSize: 16, fontWeight: 700, color: T.tx }}>{r.patient}</span>
|
||
<Tag label={r.bed} color={T.priD} bg={T.priL} />
|
||
</div>
|
||
<Tag label={r.status} color={r.statusColor} bg={r.statusBg} />
|
||
</div>
|
||
|
||
{/* 信息行 */}
|
||
<div style={{ display: 'flex', gap: 16, marginBottom: r.detail ? 10 : 0 }}>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
|
||
<span style={{ fontSize: 12, color: T.tx3 }}>模式</span>
|
||
<span style={{ fontSize: 13, fontWeight: 600, color: T.pri }}>{r.mode}</span>
|
||
</div>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
|
||
<span style={{ fontSize: 12, color: T.tx3 }}>时段</span>
|
||
<span style={{ fontSize: 13, color: T.tx }}>{r.time}</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 关键指标 */}
|
||
{r.detail && (
|
||
<div style={{
|
||
background: T.bg, borderRadius: T.rXs, padding: '8px 12px',
|
||
fontSize: 13, color: T.tx2,
|
||
}}>
|
||
{r.detail}
|
||
</div>
|
||
)}
|
||
</div>
|
||
))}
|
||
|
||
{/* FAB */}
|
||
<div style={{
|
||
position: 'sticky', bottom: 10, display: 'flex', justifyContent: 'flex-end', pointerEvents: 'none',
|
||
}}>
|
||
<div style={{
|
||
width: 52, height: 52, borderRadius: 26, background: T.pri,
|
||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||
boxShadow: '0 4px 20px rgba(58,107,140,0.4)', pointerEvents: 'auto', cursor: 'pointer',
|
||
}}>
|
||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="2.5" strokeLinecap="round">
|
||
<path d="M12 5v14M5 12h14"/>
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// ─── 屏幕4:透析创建 ───
|
||
function DialysisCreate() {
|
||
const modes = ['HD', 'HDF', 'HF'];
|
||
const activeMode = 0;
|
||
const dialysate = ['碳酸氢盐', '醋酸盐'];
|
||
const anticoagulant = ['低分子肝素', '普通肝素', '无'];
|
||
|
||
return (
|
||
<div style={{ height: '100%', background: T.bg, display: 'flex', flexDirection: 'column' }}>
|
||
<NavBar title="新增透析记录" />
|
||
<div style={{ flex: 1, overflow: 'auto', padding: '16px 20px 24px' }}>
|
||
<FormField label="患者选择" value="张三" placeholder="请选择患者" />
|
||
|
||
{/* 透析模式 — 按钮横排 */}
|
||
<div style={{ marginBottom: 14 }}>
|
||
<div style={{ fontSize: 13, color: T.tx2, marginBottom: 6, fontWeight: 500 }}>透析模式</div>
|
||
<div style={{ display: 'flex', gap: 10 }}>
|
||
{modes.map((m, i) => (
|
||
<div key={i} style={{
|
||
flex: 1, height: 44, borderRadius: T.rSm, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||
fontSize: 14, fontWeight: i === activeMode ? 600 : 400,
|
||
color: i === activeMode ? '#fff' : T.tx2,
|
||
background: i === activeMode ? T.pri : T.card,
|
||
border: `1.5px solid ${i === activeMode ? T.pri : T.bd}`,
|
||
cursor: 'pointer',
|
||
}}>{m}</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<FormField label="床位号" value="3床" placeholder="请输入床位号" />
|
||
<FormField label="开始时间" value="08:00" placeholder="请选择时间" />
|
||
<FormField label="计划时长" value="4小时" placeholder="请输入时长" />
|
||
<FormField label="血流量" value="250 ml/min" placeholder="请输入血流量" />
|
||
|
||
{/* 透析液选择 */}
|
||
<div style={{ marginBottom: 14 }}>
|
||
<div style={{ fontSize: 13, color: T.tx2, marginBottom: 6, fontWeight: 500 }}>透析液</div>
|
||
<div style={{ display: 'flex', gap: 10 }}>
|
||
{dialysate.map((d, i) => (
|
||
<div key={i} style={{
|
||
flex: 1, height: 44, borderRadius: T.rSm, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||
fontSize: 13, fontWeight: i === 0 ? 600 : 400,
|
||
color: i === 0 ? '#fff' : T.tx2,
|
||
background: i === 0 ? T.pri : T.card,
|
||
border: `1.5px solid ${i === 0 ? T.pri : T.bd}`,
|
||
cursor: 'pointer',
|
||
}}>{d}</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* 抗凝剂选择 */}
|
||
<div style={{ marginBottom: 14 }}>
|
||
<div style={{ fontSize: 13, color: T.tx2, marginBottom: 6, fontWeight: 500 }}>抗凝剂</div>
|
||
<div style={{ display: 'flex', gap: 8 }}>
|
||
{anticoagulant.map((a, i) => (
|
||
<div key={i} style={{
|
||
flex: 1, height: 44, borderRadius: T.rSm, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||
fontSize: 12, fontWeight: i === 0 ? 600 : 400,
|
||
color: i === 0 ? '#fff' : T.tx2,
|
||
background: i === 0 ? T.pri : T.card,
|
||
border: `1.5px solid ${i === 0 ? T.pri : T.bd}`,
|
||
cursor: 'pointer',
|
||
}}>{a}</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<FormField label="目标超滤量" value="2.3 L" placeholder="请输入目标超滤量" />
|
||
|
||
{/* 底部按钮 */}
|
||
<div style={{ marginTop: 8 }}>
|
||
<ActionButton label="开始透析" primary />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// ─── 屏幕5:处方列表 ───
|
||
function PrescriptionList() {
|
||
const prescriptions = [
|
||
{ patient: '张三', id: 'PX-20250401', mode: 'HD', freq: '每周3次', date: '4月1日', status: '生效中', statusColor: T.acc, statusBg: T.accL },
|
||
{ patient: '李四', id: 'PX-20250315', mode: 'HDF', freq: '每周2次', date: '3月15日', status: '生效中', statusColor: T.acc, statusBg: T.accL },
|
||
{ patient: '王五', id: 'PX-20250201', mode: 'HD', freq: '每周3次', date: '2月1日', status: '已停用', statusColor: T.tx3, statusBg: T.surface },
|
||
{ patient: '赵六', id: 'PX-20250110', mode: 'HDF', freq: '每周2次', date: '1月10日', status: '生效中', statusColor: T.acc, statusBg: T.accL },
|
||
];
|
||
|
||
return (
|
||
<div style={{ height: '100%', background: T.bg, display: 'flex', flexDirection: 'column' }}>
|
||
<NavBar title="透析处方" />
|
||
<div style={{ flex: 1, overflow: 'auto', padding: '16px 20px 24px' }}>
|
||
{/* 筛选 */}
|
||
<FilterTabs tabs={['生效中', '全部']} active={0} />
|
||
|
||
{/* 处方卡片 */}
|
||
{prescriptions.map((p, i) => (
|
||
<div key={i} style={{
|
||
background: T.card, borderRadius: T.r, padding: '16px 18px', marginBottom: 12,
|
||
boxShadow: '0 2px 12px rgba(0,0,0,0.04)',
|
||
}}>
|
||
{/* 头部 */}
|
||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||
<span style={{ fontFamily: T.serif, fontSize: 16, fontWeight: 700, color: T.tx }}>{p.patient}</span>
|
||
<span style={{ fontSize: 12, color: T.tx3 }}>{p.id}</span>
|
||
</div>
|
||
<Tag label={p.status} color={p.statusColor} bg={p.statusBg} />
|
||
</div>
|
||
|
||
{/* 信息行 */}
|
||
<div style={{ display: 'flex', gap: 20, marginBottom: 4 }}>
|
||
<div>
|
||
<div style={{ fontSize: 11, color: T.tx3, marginBottom: 2 }}>透析模式</div>
|
||
<div style={{ fontSize: 14, fontWeight: 600, color: T.pri }}>{p.mode}</div>
|
||
</div>
|
||
<div>
|
||
<div style={{ fontSize: 11, color: T.tx3, marginBottom: 2 }}>频率</div>
|
||
<div style={{ fontSize: 14, color: T.tx }}>{p.freq}</div>
|
||
</div>
|
||
<div>
|
||
<div style={{ fontSize: 11, color: T.tx3, marginBottom: 2 }}>生效日期</div>
|
||
<div style={{ fontSize: 14, color: T.tx }}>{p.date}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// ─── 屏幕6:处方详情 ───
|
||
function PrescriptionDetail() {
|
||
const params = [
|
||
{ label: '处方编号', value: 'PX-20250401' },
|
||
{ label: '透析模式', value: '血液透析(HD)' },
|
||
{ label: '频率', value: '每周 3 次(周一/三/五)' },
|
||
{ label: '单次时长', value: '4 小时' },
|
||
{ label: '血流量', value: '250 ml/min' },
|
||
{ label: '透析液流速', value: '500 ml/min' },
|
||
{ label: '透析液', value: '碳酸氢盐' },
|
||
{ label: '抗凝剂', value: '低分子肝素 4000IU' },
|
||
{ label: '干体重', value: '65.0 kg' },
|
||
{ label: '目标超滤', value: '2.0-2.5 L' },
|
||
{ label: 'Kt/V 目标', value: '≥1.2' },
|
||
];
|
||
|
||
return (
|
||
<div style={{ height: '100%', background: T.bg, display: 'flex', flexDirection: 'column' }}>
|
||
<NavBar title="处方详情" />
|
||
<div style={{ flex: 1, overflow: 'auto', padding: '16px 20px 24px' }}>
|
||
{/* 患者信息 */}
|
||
<div style={{
|
||
background: T.card, borderRadius: T.r, padding: '18px 20px', marginBottom: 14,
|
||
boxShadow: '0 2px 12px rgba(0,0,0,0.04)', display: 'flex', alignItems: 'center', gap: 14,
|
||
}}>
|
||
<div style={{
|
||
width: 44, height: 44, borderRadius: 22, background: T.priL,
|
||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||
fontFamily: T.serif, fontSize: 18, fontWeight: 700, color: T.pri,
|
||
}}>张</div>
|
||
<div style={{ flex: 1 }}>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 3 }}>
|
||
<span style={{ fontFamily: T.serif, fontSize: 17, fontWeight: 700, color: T.tx }}>张三</span>
|
||
<Tag label="生效中" color={T.acc} bg={T.accL} />
|
||
</div>
|
||
<div style={{ fontSize: 13, color: T.tx3 }}>58岁 · 男</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 详细参数 */}
|
||
<div style={{
|
||
background: T.card, borderRadius: T.r, padding: '4px 20px', marginBottom: 14,
|
||
boxShadow: '0 2px 12px rgba(0,0,0,0.04)',
|
||
}}>
|
||
<div style={{ fontSize: 14, fontWeight: 600, color: T.tx, padding: '14px 0 4px' }}>处方参数</div>
|
||
{params.map((p, i) => (
|
||
<div key={i} style={{
|
||
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
||
padding: '11px 0', borderBottom: i < params.length - 1 ? `1px solid ${T.bdL}` : 'none',
|
||
}}>
|
||
<span style={{ fontSize: 13, color: T.tx3 }}>{p.label}</span>
|
||
<span style={{ fontSize: 14, color: T.tx, fontWeight: 500, textAlign: 'right', maxWidth: '55%' }}>{p.value}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* 医生信息 */}
|
||
<div style={{
|
||
background: T.card, borderRadius: T.r, padding: '16px 20px', marginBottom: 14,
|
||
boxShadow: '0 2px 12px rgba(0,0,0,0.04)',
|
||
}}>
|
||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||
<div>
|
||
<div style={{ fontSize: 12, color: T.tx3, marginBottom: 3 }}>开方医生</div>
|
||
<div style={{ fontSize: 14, color: T.tx, fontWeight: 500 }}>李医生 · 肾内科</div>
|
||
</div>
|
||
<div style={{ textAlign: 'right' }}>
|
||
<div style={{ fontSize: 12, color: T.tx3, marginBottom: 3 }}>生效日期</div>
|
||
<div style={{ fontSize: 14, color: T.tx, fontWeight: 500 }}>2025年4月1日</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 底部操作 */}
|
||
<div style={{ display: 'flex', gap: 12 }}>
|
||
<ActionButton label="调整处方" primary style={{ flex: 1 }} />
|
||
<ActionButton label="停用处方" danger style={{ flex: 1 }} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// ─── 渲染 ───
|
||
function App() {
|
||
return (
|
||
<div class="screens">
|
||
<IosFrame label="告警列表" time="9:41" battery={85}>
|
||
<AlertList />
|
||
</IosFrame>
|
||
<IosFrame label="告警详情" time="9:41" battery={85}>
|
||
<AlertDetail />
|
||
</IosFrame>
|
||
<IosFrame label="透析列表" time="9:42" battery={84}>
|
||
<DialysisList />
|
||
</IosFrame>
|
||
<IosFrame label="透析创建" time="9:43" battery={84}>
|
||
<DialysisCreate />
|
||
</IosFrame>
|
||
<IosFrame label="处方列表" time="9:43" battery={83}>
|
||
<PrescriptionList />
|
||
</IosFrame>
|
||
<IosFrame label="处方详情" time="9:44" battery={83}>
|
||
<PrescriptionDetail />
|
||
</IosFrame>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
|
||
</script>
|
||
</body>
|
||
</html> |