Files
hms/docs/design/mp-redesign-consultation.html
iven df1d85bfde docs: T40 UI 审计报告 + wiki 更新 + Docker 配置
- T40 UI 审计计划和结果文档(docs/qa/)
- wiki 更新:miniprogram 设计系统合规审计记录 + index 关键数字更新
- 审计 V2 完整报告(docs/audits/v2/)
- 讨论记录文档(docs/discussions/)
- 设计规格和实施计划(docs/superpowers/)
- 角色测试计划和结果(docs/qa/role-test-*)
- Docker 生产部署配置
2026-05-13 23:29:42 +08:00

228 lines
12 KiB
HTML
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.
<!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; }
.flow { display: flex; gap: 32px; flex-wrap: wrap; justify-content: center; align-items: flex-start; }
.flow-step { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.flow-label { color: #888; font-size: 12px; font-style: italic; }
.flow-arrow { color: #555; font-size: 24px; align-self: center; margin-top: 40px; }
</style>
</head>
<body>
<div class="page-title">在线咨询 · 列表 + 聊天详情</div>
<div id="root"></div>
<script type="text/babel">
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)' },
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', color: '#000' },
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: 0, 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 = 393, height = 852, time = '9:41', battery = 85 }) {
return (
<div style={iosFrameStyles.wrapper}>
<div style={{ ...iosFrameStyles.screen, width, height }}>
<div style={iosFrameStyles.statusBar}><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="#000"/><path d="M3 7.5a7 7 0 0110 0" stroke="#000" strokeWidth="1.3" fill="none" strokeLinecap="round"/></svg><div style={{ width:26,height:12,border:'1.5px solid #000',borderRadius:3,padding:1 }}><div style={{ width:`${battery}%`,height:'100%',background:'#000',borderRadius:1 }} /></div></div></div>
<div style={iosFrameStyles.dynamicIsland} />
<div style={iosFrameStyles.content}>{children}</div>
<div style={iosFrameStyles.homeIndicator} />
</div>
</div>
);
}
const T = {
pri: '#C4623A', priL: '#F0DDD4', priD: '#8B3E1F',
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',
serif: "Georgia, 'Times New Roman', serif",
r: 16, rSm: 12, rXs: 8,
};
// ─── 咨询列表 ───
function ConsultList() {
const sessions = [
{ id: 1, subject: '血压波动咨询', doctor: '王明 · 心内科', lastMsg: '您的检查报告已出,建议下周复查一次', time: '10 分钟前', status: 'active', statusLabel: '进行中', unread: 2 },
{ id: 2, subject: '肾功能复查', doctor: '李华 · 肾内科', lastMsg: '复查结果整体平稳,继续观察', time: '昨天', status: 'active', statusLabel: '进行中', unread: 0 },
{ id: 3, subject: '用药调整', doctor: '赵丽 · 内科', lastMsg: '好的,按新方案服药两周后反馈', time: '3 天前', status: 'pending', statusLabel: '等待接诊', unread: 0 },
{ id: 4, subject: '体检报告解读', doctor: '张伟 · 全科', lastMsg: '各项指标正常,继续保持', time: '上周', status: 'closed', statusLabel: '已结束', unread: 0 },
];
const statusStyle = {
active: { bg: T.accL, color: T.acc },
pending: { bg: T.wrnL, color: T.wrn },
closed: { bg: T.surface, color: T.tx3 },
};
return (
<div style={{ height: '100%', background: T.bg }}>
<div style={{ padding: '20px 20px 0' }}>
{/* 导航栏 */}
<div style={{ height: 44, display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative' }}>
<span style={{ position: 'absolute', left: 0, color: T.pri, fontSize: 16 }}> 返回</span>
<span style={{ fontSize: 17, fontWeight: 600, color: T.tx }}>在线咨询</span>
</div>
</div>
<div style={{ padding: '12px 20px 20px' }}>
{/* 副标题 */}
<div style={{ fontSize: 14, color: T.tx3, marginBottom: 20 }}>随时随地连接专业医生</div>
{/* 新建咨询入口 */}
<div style={{ background: T.pri, borderRadius: T.r, height: 48, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8, marginBottom: 20, boxShadow: '0 2px 8px rgba(196,98,58,0.25)' }}>
<span style={{ color: '#fff', fontSize: 17, fontWeight: 600 }}>发起咨询</span>
</div>
{/* 会话列表 */}
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
{sessions.map((s) => {
const ss = statusStyle[s.status];
return (
<div key={s.id} style={{
background: T.card, borderRadius: T.r, padding: 16,
boxShadow: '0 1px 4px rgba(45,42,38,0.04)',
opacity: s.status === 'closed' ? 0.6 : 1,
}}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 6 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<div style={{ width: 36, height: 36, borderRadius: 18, background: T.priL, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
<span style={{ fontFamily: T.serif, fontSize: 16, fontWeight: 700, color: T.pri }}>{s.doctor.charAt(0)}</span>
</div>
<div>
<div style={{ fontSize: 15, fontWeight: 600, color: T.tx }}>{s.subject}</div>
<div style={{ fontSize: 12, color: T.tx3, marginTop: 1 }}>{s.doctor}</div>
</div>
</div>
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 4 }}>
<span style={{ fontSize: 12, color: T.tx3 }}>{s.time}</span>
<span style={{ fontSize: 10, padding: '2px 6px', borderRadius: 4, background: ss.bg, color: ss.color, fontWeight: 500 }}>{s.statusLabel}</span>
</div>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ fontSize: 13, color: T.tx2, flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', marginRight: 8 }}>{s.lastMsg}</span>
{s.unread > 0 && (
<span style={{ minWidth: 18, height: 18, borderRadius: 9, background: T.dan, color: '#fff', fontSize: 11, fontWeight: 600, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '0 5px', flexShrink: 0 }}>{s.unread}</span>
)}
</div>
</div>
);
})}
</div>
</div>
</div>
);
}
// ─── 聊天详情 ───
function ChatDetail() {
const messages = [
{ id: 1, role: 'system', text: '今天', type: 'date' },
{ id: 2, role: 'patient', text: '王医生您好,我最近血压波动比较大,早上起来经常 140+,想咨询一下。', time: '09:12' },
{ id: 3, role: 'doctor', text: '您好,请问最近有按时服药吗?有没有头晕、胸闷的情况?', time: '09:15' },
{ id: 4, role: 'patient', text: '药一直在吃,偶尔会有一点头晕。', time: '09:18' },
{ id: 5, role: 'doctor', text: '看了一下您最近的体征数据,收缩压确实有上升趋势。建议加做一个肾功能检查,排除继发性因素。', time: '09:22' },
{ id: 6, role: 'patient', text: '好的,需要空腹吗?', time: '09:25' },
{ id: 7, role: 'doctor', text: '需要空腹。我帮您开一个检查单,您明天早上来就可以。', time: '09:28' },
];
return (
<div style={{ height: '100%', background: T.bg, display: 'flex', flexDirection: 'column' }}>
{/* 导航栏 */}
<div style={{ height: 44, display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative', background: T.card, borderBottom: `1px solid ${T.bdL}`, flexShrink: 0 }}>
<span style={{ position: 'absolute', left: 16, color: T.pri, fontSize: 16 }}> 返回</span>
<div style={{ textAlign: 'center' }}>
<div style={{ fontSize: 17, fontWeight: 600, color: T.tx }}>血压波动咨询</div>
<div style={{ fontSize: 11, color: T.acc }}>王明 · 进行中</div>
</div>
</div>
{/* 消息区 */}
<div style={{ flex: 1, padding: '16px 16px 0', overflowY: 'auto' }}>
{messages.map((msg) => {
if (msg.type === 'date') {
return (
<div key={msg.id} style={{ textAlign: 'center', margin: '12px 0' }}>
<span style={{ fontSize: 12, color: T.tx3, background: T.surface, padding: '2px 12px', borderRadius: 999 }}>{msg.text}</span>
</div>
);
}
const isSelf = msg.role === 'patient';
return (
<div key={msg.id} style={{ display: 'flex', justifyContent: isSelf ? 'flex-end' : 'flex-start', marginBottom: 16, gap: 8 }}>
{!isSelf && (
<div style={{ width: 32, height: 32, borderRadius: 16, background: T.priL, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
<span style={{ fontFamily: T.serif, fontSize: 13, fontWeight: 700, color: T.pri }}></span>
</div>
)}
<div style={{ maxWidth: '70%' }}>
<div style={{
background: isSelf ? T.pri : T.card,
borderRadius: isSelf ? '16px 16px 4px 16px' : '16px 16px 16px 4px',
padding: '12px 16px',
boxShadow: '0 1px 4px rgba(45,42,38,0.06)',
}}>
<span style={{ fontSize: 15, color: isSelf ? '#fff' : T.tx, lineHeight: 1.6 }}>{msg.text}</span>
</div>
<div style={{ fontSize: 11, color: T.tx3, marginTop: 4, textAlign: isSelf ? 'right' : 'left' }}>{msg.time}</div>
</div>
</div>
);
})}
</div>
{/* 输入栏 */}
<div style={{ background: T.card, borderTop: `1px solid ${T.bdL}`, padding: '10px 16px 38px', display: 'flex', gap: 10, alignItems: 'center', flexShrink: 0 }}>
<div style={{ flex: 1, height: 40, background: T.bg, borderRadius: 20, border: `1.5px solid ${T.bd}`, display: 'flex', alignItems: 'center', padding: '0 14px' }}>
<span style={{ fontSize: 15, color: T.tx3 }}>输入消息...</span>
</div>
<div style={{ width: 40, height: 40, borderRadius: 20, background: T.pri, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, boxShadow: '0 2px 6px rgba(196,98,58,0.3)' }}>
<span style={{ color: '#fff', fontSize: 14, fontWeight: 600 }}></span>
</div>
</div>
</div>
);
}
// ─── 渲染 ───
function App() {
return (
<div className="flow">
<div className="flow-step">
<span className="flow-label">咨询列表</span>
<IosFrame time="9:41" battery={85}>
<ConsultList />
</IosFrame>
</div>
<div className="flow-arrow"></div>
<div className="flow-step">
<span className="flow-label">聊天详情</span>
<IosFrame time="9:41" battery={85}>
<ChatDetail />
</IosFrame>
</div>
</div>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>
</body>
</html>