|
|
@@ -0,0 +1,563 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="zh-CN">
|
|
|
+<head>
|
|
|
+<meta charset="UTF-8">
|
|
|
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
+<title>医梦 AI 未来医院 · 感知动线故事板</title>
|
|
|
+<style>
|
|
|
+:root {
|
|
|
+ --accent: #2b1f99; --accent-light: #3ad4d8;
|
|
|
+ --bg: #f5f3fb; --surface: #ffffff; --fg: #1a1835; --muted: #7a7698; --border: #e6e3f0;
|
|
|
+ --warn: #f0a020; --warn-bg: #fff8e8; --warn-text: #735b14;
|
|
|
+ --radius-sm: 8px; --radius-md: 12px; --radius-lg: 16px; --radius-pill: 9999px;
|
|
|
+}
|
|
|
+*{margin:0;padding:0;box-sizing:border-box}
|
|
|
+html{-webkit-text-size-adjust:100%}
|
|
|
+body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC',system-ui,sans-serif;font-size:14px;background:#0a0a14;color:var(--fg);overflow:hidden;height:100vh;display:flex;flex-direction:column}
|
|
|
+
|
|
|
+.timeline-bar{height:26px;background:var(--accent);display:flex;align-items:center;padding:0 14px;gap:8px;flex-shrink:0}
|
|
|
+.tl-act{font-size:9px;color:rgba(255,255,255,.65);font-weight:500;letter-spacing:.03em;white-space:nowrap}
|
|
|
+.tl-steps{display:flex;gap:3px;flex:1}
|
|
|
+.tl-step{flex:1;height:3px;border-radius:2px;background:rgba(255,255,255,.2);transition:all .4s}
|
|
|
+.tl-step.active{background:#fff;box-shadow:0 0 6px rgba(255,255,255,.4)}
|
|
|
+.tl-step.done{background:rgba(255,255,255,.5)}
|
|
|
+.tl-time{font-size:9px;color:rgba(255,255,255,.65);font-weight:500;font-variant-numeric:tabular-nums}
|
|
|
+
|
|
|
+.app-shell{display:grid;grid-template-columns:21% 58% 21%;flex:1;min-height:0;padding:4px 6px 6px 6px;gap:5px;background:var(--bg)}
|
|
|
+.panel{border-radius:var(--radius-md);overflow:hidden;border:1px solid var(--border);background:var(--surface);display:flex;flex-direction:column;min-height:0}
|
|
|
+.ph{height:32px;display:flex;align-items:center;padding:0 10px;border-bottom:1px solid var(--border);flex-shrink:0;gap:5px}
|
|
|
+.ph .pi{width:16px;height:16px;border-radius:4px;display:grid;place-items:center;font-size:9px;flex-shrink:0}
|
|
|
+.ph .pt{font-size:10px;font-weight:600;color:var(--fg)}
|
|
|
+.ph .ps{font-size:8px;color:var(--muted);margin-left:auto}
|
|
|
+
|
|
|
+.pb{padding:8px;flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:6px;background:var(--bg);font-size:10px}
|
|
|
+
|
|
|
+.ns-stats{display:flex;gap:4px}
|
|
|
+.ns-stat{flex:1;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);padding:6px;text-align:center}
|
|
|
+.ns-num{font-size:14px;font-weight:700;color:var(--accent)}
|
|
|
+.ns-lbl{font-size:7px;color:var(--muted);margin-top:1px}
|
|
|
+.ns-sec{font-size:8px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;margin-top:2px}
|
|
|
+.ns-patient{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);padding:6px 8px;display:flex;flex-direction:column;gap:2px;transition:all .5s}
|
|
|
+.ns-patient.highlight{border-color:var(--accent-light);box-shadow:0 0 0 1px var(--accent-light)}
|
|
|
+.np-row{display:flex;align-items:center;gap:5px}
|
|
|
+.np-name{font-size:11px;font-weight:600}
|
|
|
+.np-tag{font-size:7px;padding:1px 5px;border-radius:var(--radius-pill);font-weight:500}
|
|
|
+.np-tag.w{background:color-mix(in oklch,var(--warn) 12%,transparent);color:var(--warn-text)}
|
|
|
+.np-tag.ok{background:color-mix(in oklch,var(--accent-light) 12%,transparent);color:var(--accent)}
|
|
|
+.np-tag.done{background:color-mix(in oklch,var(--accent) 8%,transparent);color:var(--accent)}
|
|
|
+.np-detail{font-size:8px;color:var(--muted);display:flex;gap:6px;flex-wrap:wrap}
|
|
|
+.ns-notif{font-size:8px;padding:4px 7px;border-radius:var(--radius-sm);background:color-mix(in oklch,var(--accent) 5%,transparent);color:var(--accent);display:flex;align-items:center;gap:4px;border-left:2px solid var(--accent-light);animation:fadeUp .4s}
|
|
|
+
|
|
|
+.center-body{flex:1;display:flex;flex-direction:column;min-height:0;background:var(--surface);position:relative}
|
|
|
+.uc-topbar{height:34px;display:flex;align-items:center;padding:0 12px;border-bottom:1px solid var(--border);gap:6px;flex-shrink:0}
|
|
|
+.uc-logo{font-size:10px;font-weight:600;color:var(--accent);display:flex;align-items:center;gap:4px;white-space:nowrap}
|
|
|
+.uc-div{width:1px;height:14px;background:var(--border)}
|
|
|
+.uc-id{font-size:9px;color:var(--muted);display:flex;align-items:center;gap:3px}
|
|
|
+.uc-scene{padding:1px 6px;border-radius:var(--radius-pill);font-size:7px;font-weight:600;background:color-mix(in oklch,var(--accent) 8%,transparent);color:var(--accent)}
|
|
|
+.uc-perc{display:flex;align-items:center;gap:4px;margin-left:auto;font-size:7px}
|
|
|
+.ptag{border-radius:var(--radius-pill);padding:1px 5px;font-weight:500}
|
|
|
+.ptag.l0{background:color-mix(in oklch,var(--warn) 12%,transparent);color:var(--warn-text)}
|
|
|
+.ptag.l1{background:color-mix(in oklch,var(--accent) 8%,transparent);color:var(--accent)}
|
|
|
+.ptag.off{background:color-mix(in oklch,var(--muted) 8%,transparent);color:var(--muted)}
|
|
|
+
|
|
|
+.uc-main{flex:1;display:flex;min-height:0}
|
|
|
+.uc-left{width:170px;border-right:1px solid var(--border);padding:10px 8px;display:flex;flex-direction:column;gap:8px;overflow-y:auto;flex-shrink:0;background:var(--surface)}
|
|
|
+.uc-avatar{width:40px;height:40px;border-radius:50%;background:var(--accent);display:grid;place-items:center;margin:0 auto}
|
|
|
+.uc-avatar svg{width:22px;height:22px;stroke:#fff;stroke-width:2;fill:none}
|
|
|
+.uc-assist-info{text-align:center;font-size:10px}
|
|
|
+.uc-assist-name{font-weight:600;font-size:11px}
|
|
|
+.uc-assist-tag{font-size:8px;color:var(--muted);margin-top:1px}
|
|
|
+.uc-sep{height:0;border-top:1px solid var(--border);margin:0 -2px}
|
|
|
+.uc-label{font-size:7px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;font-weight:600}
|
|
|
+.uc-ex{font-size:9px;padding:4px 6px;background:var(--bg);border-radius:var(--radius-sm);color:var(--muted)}
|
|
|
+.uc-qbtn{font-size:9px;padding:4px 7px;border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--muted);display:flex;align-items:center;gap:4px;transition:all .2s}
|
|
|
+.uc-qbtn.on{color:var(--fg)}
|
|
|
+.uc-bind{padding:7px;border:1px dashed var(--accent);border-radius:var(--radius-md);background:color-mix(in oklch,var(--accent) 4%,transparent);text-align:center;margin-top:auto}
|
|
|
+.uc-bind .ub-title{font-size:9px;font-weight:500;color:var(--accent)}
|
|
|
+.uc-bind .ub-desc{font-size:7px;color:var(--muted);margin:3px 0 5px 0;line-height:1.3}
|
|
|
+.btn-sm{font-size:8px;padding:4px 10px;border-radius:var(--radius-pill);font-weight:500;cursor:pointer;transition:all .15s}
|
|
|
+.btn-primary{background:var(--accent);color:#fff;border:none}
|
|
|
+.btn-secondary{border:1px solid var(--border);color:var(--muted);background:var(--surface)}
|
|
|
+
|
|
|
+.uc-center{flex:1;display:flex;flex-direction:column;min-height:0;background:var(--bg)}
|
|
|
+.uc-chat-h{height:28px;display:flex;align-items:center;padding:0 10px;border-bottom:1px solid var(--border);flex-shrink:0;background:var(--surface);font-size:9px;color:var(--muted);gap:5px}
|
|
|
+.uc-chat-h .dot{width:5px;height:5px;border-radius:50%;background:var(--accent-light)}
|
|
|
+.uc-msgs{flex:1;padding:10px 14px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;overflow-y:auto}
|
|
|
+.uc-empty{display:flex;flex-direction:column;align-items:center;gap:8px;text-align:center}
|
|
|
+.uc-empty-icon{width:42px;height:42px;border-radius:50%;background:color-mix(in oklch,var(--accent) 10%,transparent);display:grid;place-items:center}
|
|
|
+.uc-empty-text{font-size:14px;font-weight:600;color:var(--fg)}
|
|
|
+.uc-empty-hint{font-size:10px;color:var(--muted);max-width:260px;line-height:1.5}
|
|
|
+.uc-empty-chips{display:flex;gap:4px;flex-wrap:wrap;justify-content:center;margin-top:2px}
|
|
|
+.uc-chip{padding:3px 8px;border-radius:var(--radius-pill);font-size:9px;color:var(--accent);background:color-mix(in oklch,var(--accent) 10%,transparent);border:1px solid color-mix(in oklch,var(--accent) 15%,transparent)}
|
|
|
+
|
|
|
+.uc-chat-content{display:none;flex-direction:column;gap:6px;width:100%;overflow-y:auto;flex:1;padding:4px 0}
|
|
|
+.uc-input-bar{height:38px;display:flex;align-items:center;padding:0 10px;border-top:1px solid var(--border);flex-shrink:0;background:var(--surface);gap:4px}
|
|
|
+.uc-input-bar .ub-inp{flex:1;height:28px;padding:0 10px;border:1px solid var(--border);border-radius:var(--radius-pill);font-size:10px;background:var(--bg);color:var(--fg);outline:none}
|
|
|
+.ub-send{width:28px;height:28px;border-radius:50%;background:var(--accent);color:#fff;display:grid;place-items:center;font-size:11px}
|
|
|
+
|
|
|
+.uc-right{width:170px;border-left:1px solid var(--border);padding:10px 8px;display:flex;flex-direction:column;gap:8px;overflow-y:auto;flex-shrink:0;background:var(--surface)}
|
|
|
+.ur-dev{font-size:9px;padding:5px 7px;border:1px solid var(--border);border-radius:var(--radius-sm);display:flex;align-items:center;gap:5px;background:var(--bg)}
|
|
|
+.ur-dev .ud-icon{width:20px;height:20px;border-radius:4px;display:grid;place-items:center;font-size:8px;flex-shrink:0}
|
|
|
+.ur-dev .ud-info{flex:1;min-width:0}
|
|
|
+.ur-dev .ud-name{font-size:9px;font-weight:500}
|
|
|
+.ur-dev .ud-sub{font-size:7px;color:var(--muted)}
|
|
|
+.ud-tag{font-size:7px;padding:1px 5px;border-radius:var(--radius-pill);font-weight:500}
|
|
|
+.ud-tag.unbound{background:color-mix(in oklch,var(--warn) 12%,transparent);color:var(--warn-text)}
|
|
|
+.ud-tag.bound{background:color-mix(in oklch,var(--accent-light) 12%,transparent);color:var(--accent)}
|
|
|
+
|
|
|
+.ur-journey{padding-left:16px;position:relative}
|
|
|
+.ur-journey::before{content:'';position:absolute;left:5px;top:5px;bottom:5px;border-left:1.5px dotted var(--border)}
|
|
|
+.ur-jn{position:relative;padding:2px 0 2px 7px;font-size:8px;color:var(--muted);line-height:1.3;transition:all .4s}
|
|
|
+.ur-jn::before{content:'';position:absolute;left:-12px;top:4px;width:5px;height:5px;border-radius:50%;background:var(--border);border:1.5px solid var(--surface);z-index:1;transition:all .4s}
|
|
|
+.ur-jn.current{color:var(--accent);font-weight:600}
|
|
|
+.ur-jn.current::before{background:var(--accent);box-shadow:0 0 0 3px color-mix(in oklch,var(--accent) 15%,transparent)}
|
|
|
+.ur-jn.done{color:var(--fg)}
|
|
|
+.ur-jn.done::before{background:var(--accent-light)}
|
|
|
+
|
|
|
+.ur-next{border:1px solid var(--accent);border-radius:var(--radius-md);padding:7px;background:color-mix(in oklch,var(--accent) 4%,transparent)}
|
|
|
+.ur-next .un-badge{font-size:7px;font-weight:600;color:var(--accent);text-transform:uppercase;letter-spacing:.03em}
|
|
|
+.ur-next .un-title{font-size:9px;font-weight:500;margin:2px 0}
|
|
|
+.ur-next .un-desc{font-size:7px;color:var(--muted);line-height:1.4}
|
|
|
+.ur-next .un-acts{display:flex;gap:3px;margin-top:4px}
|
|
|
+.ur-perc-grid{display:grid;grid-template-columns:1fr 1fr;gap:3px}
|
|
|
+.ur-perc{padding:3px 5px;border:1px solid var(--border);border-radius:var(--radius-sm);display:flex;flex-direction:column;gap:1px;background:var(--surface)}
|
|
|
+.ur-perc .up-l{font-size:6px;color:var(--muted);text-transform:uppercase;letter-spacing:.03em}
|
|
|
+.ur-perc .up-v{font-size:8px;font-weight:500}
|
|
|
+.up-v.on{color:var(--accent)} .up-v.off{color:var(--muted)} .up-v.warn{color:var(--warn-text)}
|
|
|
+.ur-hint{padding:5px 7px;background:color-mix(in oklch,var(--accent-light) 6%,transparent);border-radius:var(--radius-sm);font-size:7px;color:var(--muted);line-height:1.3;display:flex;gap:4px}
|
|
|
+
|
|
|
+.dr-info{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);padding:7px}
|
|
|
+.dr-name{font-size:12px;font-weight:700}
|
|
|
+.dr-dept{font-size:8px;color:var(--muted);margin-top:1px}
|
|
|
+.dr-stats{font-size:8px;display:flex;gap:8px;color:var(--muted);margin-top:2px}
|
|
|
+.dr-patient{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);padding:5px 7px;display:flex;flex-direction:column;gap:2px;transition:all .5s}
|
|
|
+.dr-patient.highlight{border-color:var(--accent-light)}
|
|
|
+.dp-row{display:flex;align-items:center;gap:5px}
|
|
|
+.dp-name{font-size:10px;font-weight:500}
|
|
|
+.dp-time{font-size:7px;color:var(--muted);margin-left:auto}
|
|
|
+.dp-tag{font-size:7px;padding:0 5px;border-radius:var(--radius-pill);font-weight:500}
|
|
|
+.dp-tag.pending{background:color-mix(in oklch,var(--warn) 12%,transparent);color:var(--warn-text)}
|
|
|
+.dp-tag.ok{background:color-mix(in oklch,var(--accent-light) 12%,transparent);color:var(--accent)}
|
|
|
+.dp-tag.tmr{background:color-mix(in oklch,var(--accent) 8%,transparent);color:var(--accent)}
|
|
|
+.dr-notif{font-size:8px;padding:3px 6px;border-radius:var(--radius-sm);background:color-mix(in oklch,var(--accent-light) 8%,transparent);color:var(--accent);display:flex;align-items:center;gap:3px;border-left:2px solid var(--accent-light);animation:fadeUp .4s}
|
|
|
+
|
|
|
+.bottombar{height:28px;background:var(--surface);border-top:1px solid var(--border);display:flex;align-items:center;padding:0 14px;gap:8px;flex-shrink:0}
|
|
|
+.bbl{font-size:8px;color:var(--muted);font-weight:500;white-space:nowrap}
|
|
|
+.bbn{display:flex;align-items:center;gap:4px;padding:2px 7px;border-radius:var(--radius-pill);font-size:7px;white-space:nowrap;background:color-mix(in oklch,var(--accent) 10%,transparent);color:var(--accent)}
|
|
|
+.bbn .b-dot{width:3px;height:3px;border-radius:50%;background:currentColor;opacity:.6}
|
|
|
+
|
|
|
+@DataFlow{0%{background-position:200% 0}100%{background-position:-200% 0}}
|
|
|
+.data-flow{position:absolute;height:2px;background:linear-gradient(90deg,transparent,var(--accent-light),transparent);background-size:200% 100%;animation:DataFlow 1s linear infinite;opacity:.4;pointer-events:none;z-index:5;display:none}
|
|
|
+
|
|
|
+@keyframes fadeUp{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:translateY(0)}}
|
|
|
+@keyframes fadeIn{from{opacity:0}to{opacity:1}}
|
|
|
+@keyframes slideUp{from{transform:translateY(15px);opacity:0}to{transform:translateY(0);opacity:1}}
|
|
|
+@keyframes ripple{0%{transform:scale(.4);opacity:.7}100%{transform:scale(2.6);opacity:0}}
|
|
|
+@keyframes breathe{0%,100%{opacity:1}50%{opacity:.5}}
|
|
|
+@keyframes glow{0%,100%{box-shadow:0 0 4px rgba(58,212,216,.2)}50%{box-shadow:0 0 12px rgba(58,212,216,.5)}}
|
|
|
+</style>
|
|
|
+</head>
|
|
|
+<body>
|
|
|
+
|
|
|
+<div class="timeline-bar" id="tlBar">
|
|
|
+ <span class="tl-act" id="tlAct">第一幕 · 开场亮相</span>
|
|
|
+ <div class="tl-steps" id="tlSteps">
|
|
|
+ <div class="tl-step active"></div><div class="tl-step"></div><div class="tl-step"></div><div class="tl-step"></div><div class="tl-step"></div>
|
|
|
+ </div>
|
|
|
+ <span class="tl-time" id="tlTime">0:00</span>
|
|
|
+</div>
|
|
|
+
|
|
|
+<div class="app-shell" id="appShell">
|
|
|
+ <!-- LEFT: Nurse Station -->
|
|
|
+ <div class="panel"><div class="ph"><span class="pi" style="background:color-mix(in oklch,var(--accent-light) 15%,transparent)">🏥</span><span class="pt">护士站 · 患者总览</span><span class="ps" id="nsStatus">等待患者</span></div>
|
|
|
+ <div class="pb" id="nsBody">
|
|
|
+ <div class="ns-stats"><div class="ns-stat"><div class="ns-num" id="nsOnline">0</div><div class="ns-lbl">在线设备</div></div><div class="ns-stat"><div class="ns-num" id="nsToday">0</div><div class="ns-lbl">今日接诊</div></div><div class="ns-stat"><div class="ns-num" id="nsTomorrow">0</div><div class="ns-lbl">明日预约</div></div></div>
|
|
|
+ <div class="ns-sec">患者队列</div>
|
|
|
+ <div id="nsQueue"><div style="padding:16px;text-align:center;color:var(--muted);font-size:10px">等待患者入院</div></div>
|
|
|
+ <div id="nsNotifs"></div>
|
|
|
+ </div></div>
|
|
|
+
|
|
|
+ <!-- CENTER: Unified Entry Client -->
|
|
|
+ <div class="panel" style="position:relative;overflow:hidden">
|
|
|
+ <div class="data-flow" id="dataFlow" style="top:0;left:0;right:0"></div>
|
|
|
+ <div class="center-body">
|
|
|
+ <div class="uc-topbar">
|
|
|
+ <span class="uc-logo"><svg width="12" height="12" viewBox="0 0 24 24"><rect x="2" y="2" width="20" height="20" rx="4" fill="none" stroke="currentColor" stroke-width="1.5"/><line x1="8" y1="2" x2="8" y2="22" stroke="currentColor" stroke-width="1.5"/></svg>空海医院</span>
|
|
|
+ <span class="uc-div"></span>
|
|
|
+ <span class="uc-id"><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 4-7 8-7s8 3 8 7"/></svg><span id="ucPatient">患者:<strong>—</strong></span></span>
|
|
|
+ <span class="uc-scene">门诊</span>
|
|
|
+ <span class="uc-perc" id="ucPerc"><span class="ptag l0">L0</span><span class="ptag off">NFC 待触发</span><span class="ptag off">BLE 未连接</span></span>
|
|
|
+ </div>
|
|
|
+ <div class="uc-main">
|
|
|
+ <div class="uc-left">
|
|
|
+ <div class="uc-avatar"><svg viewBox="0 0 24 24"><rect x="2" y="2" width="20" height="20" rx="4"/><line x1="12" y1="2" x2="12" y2="22"/><line x1="2" y1="12" x2="22" y2="12"/></svg></div>
|
|
|
+ <div class="uc-assist-info"><div class="uc-assist-name">空海医院医疗助手</div><div class="uc-assist-tag" id="ucAssistTag">感知您的状态,主动推送服务</div></div>
|
|
|
+ <div class="uc-sep"></div>
|
|
|
+ <div class="uc-label">你可以这样说</div>
|
|
|
+ <div class="uc-ex">我头疼三天,想挂号</div>
|
|
|
+ <div class="uc-ex">找神经内科李明医生</div>
|
|
|
+ <div class="uc-sep"></div>
|
|
|
+ <div class="uc-label">高频功能</div>
|
|
|
+ <div class="uc-qbtn">📋 挂号预约</div>
|
|
|
+ <div class="uc-qbtn">🧭 科室导诊</div>
|
|
|
+ <div class="uc-qbtn">💳 门诊缴费</div>
|
|
|
+ <div class="uc-qbtn">📊 查报告</div>
|
|
|
+ <div class="uc-sep"></div>
|
|
|
+ <div class="uc-label">设备与服务</div>
|
|
|
+ <div class="uc-qbtn">📱 NFC 碰一碰</div>
|
|
|
+ <div class="uc-qbtn">🤖 呼叫机器人</div>
|
|
|
+ <div class="uc-bind" id="ucBind">
|
|
|
+ <div class="ub-title">绑定设备,开启感知</div>
|
|
|
+ <div class="ub-desc">NFC碰一碰或扫码绑定,系统自动感知身份和位置</div>
|
|
|
+ <button class="btn-sm btn-primary" style="width:100%">NFC 碰一碰绑定</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="uc-center">
|
|
|
+ <div class="uc-chat-h"><span class="dot"></span>空海医院医疗助手 · 在线</div>
|
|
|
+ <div class="uc-msgs" id="ucMsgs">
|
|
|
+ <div class="uc-empty" id="ucEmpty">
|
|
|
+ <div class="uc-empty-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" stroke-width="1.6"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></div>
|
|
|
+ <div class="uc-empty-text">您好,我是门诊助手</div>
|
|
|
+ <div class="uc-empty-hint" id="ucEmptyHint">请说出您的就诊需求。绑定设备后可自动识别身份。</div>
|
|
|
+ <div class="uc-empty-chips"><span class="uc-chip">我头疼想挂号</span><span class="uc-chip">找神经内科</span></div>
|
|
|
+ </div>
|
|
|
+ <div class="uc-chat-content" id="ucChat"></div>
|
|
|
+ </div>
|
|
|
+ <div class="uc-input-bar"><input class="ub-inp" placeholder="请说出您的就诊需求…" readonly><div class="ub-send">➤</div></div>
|
|
|
+ </div>
|
|
|
+ <div class="uc-right">
|
|
|
+ <div class="uc-label">设备绑定</div>
|
|
|
+ <div class="ur-dev"><div class="ud-icon" style="background:color-mix(in oklch,var(--accent-light) 12%,transparent)">⌚</div><div class="ud-info"><div class="ud-name">华为手表</div><div class="ud-sub">未检测到</div></div><span class="ud-tag unbound" id="udTag1">未绑定</span></div>
|
|
|
+ <div class="ur-dev"><div class="ud-icon" style="background:color-mix(in oklch,var(--accent) 10%,transparent)">📱</div><div class="ud-info"><div class="ud-name">Mate 60 Pro</div><div class="ud-sub">未检测到</div></div><span class="ud-tag unbound" id="udTag2">未绑定</span></div>
|
|
|
+ <div class="uc-sep"></div>
|
|
|
+ <div class="uc-label">就诊动线</div>
|
|
|
+ <div class="ur-journey" id="urJourney">
|
|
|
+ <div class="ur-jn current" data-jn="0">入院</div>
|
|
|
+ <div class="ur-jn" data-jn="1">身份绑定</div>
|
|
|
+ <div class="ur-jn" data-jn="2">任务加载</div>
|
|
|
+ <div class="ur-jn" data-jn="3">挂号/分诊</div>
|
|
|
+ <div class="ur-jn" data-jn="4">诊区签到</div>
|
|
|
+ <div class="ur-jn" data-jn="5">候诊→就诊</div>
|
|
|
+ <div class="ur-jn" data-jn="6">缴费→离院</div>
|
|
|
+ </div>
|
|
|
+ <div class="uc-sep"></div>
|
|
|
+ <div class="uc-label">下一步</div>
|
|
|
+ <div class="ur-next" id="urNext">
|
|
|
+ <div class="un-badge" id="unBadge">⟳ 待完成</div>
|
|
|
+ <div class="un-title" id="unTitle">绑定设备与身份</div>
|
|
|
+ <div class="un-desc" id="unDesc">请使用手机 NFC 碰一碰自助终端感应区完成绑定。</div>
|
|
|
+ <div class="un-acts" id="unActs"><button class="btn-sm btn-primary" style="flex:1;text-align:center">NFC 碰一碰</button><button class="btn-sm btn-secondary" style="flex:1;text-align:center">扫码绑定</button></div>
|
|
|
+ </div>
|
|
|
+ <div class="uc-sep"></div>
|
|
|
+ <div class="uc-label">感知状态</div>
|
|
|
+ <div class="ur-perc-grid" id="urPercGrid">
|
|
|
+ <div class="ur-perc"><span class="up-l">身份</span><span class="up-v on">已识别</span></div>
|
|
|
+ <div class="ur-perc"><span class="up-l">设备</span><span class="up-v off" id="percDev">未绑定</span></div>
|
|
|
+ <div class="ur-perc"><span class="up-l">位置</span><span class="up-v warn" id="percLoc">L0 手动</span></div>
|
|
|
+ <div class="ur-perc"><span class="up-l">业务</span><span class="up-v off" id="percBiz">无任务</span></div>
|
|
|
+ </div>
|
|
|
+ <div class="ur-hint"><span>💡</span><span id="urHint">设备绑定后进入 L1 感知模式。</span></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- RIGHT: Doctor Station -->
|
|
|
+ <div class="panel"><div class="ph"><span class="pi" style="background:color-mix(in oklch,var(--accent-light) 15%,transparent)">🩺</span><span class="pt">医生工作站</span><span class="ps" id="drStatus">待诊中</span></div>
|
|
|
+ <div class="pb" id="drBody">
|
|
|
+ <div class="dr-info"><div class="dr-name">李明 <span style="font-size:10px;font-weight:400;color:var(--muted)">主任医师</span></div><div class="dr-dept">神经内科 · 门诊三楼 301 诊室</div><div class="dr-stats"><span id="drQCount">候诊 0 人</span><span id="drTodayCount">今日接诊 0 人</span></div></div>
|
|
|
+ <div class="ns-sec" id="drListLabel">今日待诊</div>
|
|
|
+ <div id="drList"><div style="padding:16px;text-align:center;color:var(--muted);font-size:10px">等待患者到诊</div></div>
|
|
|
+ <div id="drNotifs"></div>
|
|
|
+ </div></div>
|
|
|
+</div>
|
|
|
+
|
|
|
+<footer class="bottombar" id="bottomBar">
|
|
|
+ <span class="bbl">服务通知</span>
|
|
|
+ <div id="bottomNotifs"><span class="bbn"><span class="b-dot"></span>系统就绪 — 等待患者操作</span></div>
|
|
|
+</footer>
|
|
|
+
|
|
|
+<script>
|
|
|
+const $=id=>document.getElementById(id);
|
|
|
+function delay(ms){return new Promise(r=>setTimeout(r,ms))}
|
|
|
+
|
|
|
+// ─── helpers ───
|
|
|
+function addNotif(contId, txt){
|
|
|
+ const el=document.createElement('div');
|
|
|
+ el.className=contId==='nsNotifs'?'ns-notif':'dr-notif';
|
|
|
+ el.textContent=txt;
|
|
|
+ $(contId).appendChild(el);
|
|
|
+ setTimeout(()=>el.remove(),5000);
|
|
|
+}
|
|
|
+function setBottom(txt){$('bottomNotifs').innerHTML=`<span class="bbn"><span class="b-dot"></span>${txt}</span>`}
|
|
|
+
|
|
|
+function addMsg(role, txt){
|
|
|
+ return new Promise(r=>setTimeout(()=>{
|
|
|
+ const cc=$('ucChat'), d=document.createElement('div');
|
|
|
+ d.style.cssText='display:flex;gap:6px;align-items:flex-start;animation:fadeUp .3s ease;margin-bottom:2px';
|
|
|
+ d.innerHTML=`<span style="font-size:10px;font-weight:600;color:${role==='ai'?'var(--accent)':'var(--fg)'};flex-shrink:0;width:24px">${role==='ai'?'🤖':'👤'}</span><span style="font-size:10px;color:var(--fg);line-height:1.5">${txt}</span>`;
|
|
|
+ cc.appendChild(d);cc.scrollTop=cc.scrollHeight; r();
|
|
|
+ },0));
|
|
|
+}
|
|
|
+function typeMsg(role, txt, chDelay=25, stDelay=0){
|
|
|
+ return new Promise(r=>{setTimeout(()=>{
|
|
|
+ const cc=$('ucChat'), d=document.createElement('div');
|
|
|
+ d.style.cssText='display:flex;gap:6px;align-items:flex-start;animation:fadeUp .3s ease;margin-bottom:2px';
|
|
|
+ const sp=document.createElement('span');
|
|
|
+ sp.style.cssText=`font-size:10px;font-weight:600;color:${role==='ai'?'var(--accent)':'var(--fg)'};flex-shrink:0;width:24px`;
|
|
|
+ sp.textContent=role==='ai'?'🤖':'👤';
|
|
|
+ const ts=document.createElement('span');
|
|
|
+ ts.style.cssText='font-size:10px;color:var(--fg);line-height:1.5';
|
|
|
+ d.appendChild(sp);d.appendChild(ts);cc.appendChild(d);
|
|
|
+ let i=0;
|
|
|
+ function type(){if(i<txt.length){ts.innerHTML=txt.slice(0,i+1);cc.scrollTop=cc.scrollHeight;i++;setTimeout(type,chDelay)}else r()}
|
|
|
+ type();
|
|
|
+ },stDelay)});
|
|
|
+}
|
|
|
+
|
|
|
+function setJourney(n){
|
|
|
+ for(let i=0;i<=6;i++){const el=document.querySelector(`[data-jn="${i}"]`);el.classList.remove('current','done');
|
|
|
+ if(i<n)el.classList.add('done');else if(i===n)el.classList.add('current')}
|
|
|
+}
|
|
|
+function setPerc(tagId, txt, cls){const el=$(tagId);el.textContent=txt;el.className='up-v '+cls}
|
|
|
+
|
|
|
+// ─── ACTS ───
|
|
|
+async function act0(){
|
|
|
+ // reset everything
|
|
|
+ $('nsOnline').textContent='0';$('nsToday').textContent='0';$('nsTomorrow').textContent='0';
|
|
|
+ $('nsQueue').innerHTML='<div style="padding:16px;text-align:center;color:var(--muted);font-size:10px">等待患者入院</div>';
|
|
|
+ $('nsNotifs').innerHTML='';$('nsStatus').textContent='等待患者';
|
|
|
+ $('drList').innerHTML='<div style="padding:16px;text-align:center;color:var(--muted);font-size:10px">等待患者到诊</div>';
|
|
|
+ $('drNotifs').innerHTML='';$('drQCount').textContent='候诊 0 人';$('drTodayCount').textContent='今日接诊 0 人';
|
|
|
+ $('drListLabel').textContent='今日待诊';$('drStatus').textContent='待诊中';
|
|
|
+ $('ucPatient').innerHTML='患者:<strong>—</strong>';
|
|
|
+ $('ucPerc').innerHTML='<span class="ptag l0">L0</span><span class="ptag off">NFC 待触发</span><span class="ptag off">BLE 未连接</span>';
|
|
|
+ $('ucEmpty').style.display='flex';$('ucChat').style.display='none';$('ucChat').innerHTML='';
|
|
|
+ $('ucAssistTag').textContent='感知您的状态,主动推送服务';
|
|
|
+ $('udTag1').textContent='未绑定';$('udTag1').className='ud-tag unbound';
|
|
|
+ $('udTag2').textContent='未绑定';$('udTag2').className='ud-tag unbound';
|
|
|
+ setJourney(0);
|
|
|
+ $('unBadge').textContent='⟳ 待完成';$('unTitle').textContent='绑定设备与身份';
|
|
|
+ $('unDesc').textContent='请使用手机 NFC 碰一碰自助终端感应区完成绑定。';
|
|
|
+ $('unActs').innerHTML='<button class="btn-sm btn-primary" style="flex:1;text-align:center">NFC 碰一碰</button><button class="btn-sm btn-secondary" style="flex:1;text-align:center">扫码绑定</button>';
|
|
|
+ setPerc('percDev','未绑定','off');setPerc('percLoc','L0 手动','warn');setPerc('percBiz','无任务','off');
|
|
|
+ $('urHint').textContent='设备绑定后进入 L1 感知模式。';
|
|
|
+ $('ucBind').innerHTML='<div class="ub-title">绑定设备,开启感知</div><div class="ub-desc">NFC碰一碰或扫码绑定,系统自动感知身份和位置</div><button class="btn-sm btn-primary" style="width:100%">NFC 碰一碰绑定</button>';
|
|
|
+ document.querySelectorAll('.uc-qbtn').forEach(b=>b.classList.remove('on'));
|
|
|
+ setBottom('系统就绪 — 等待患者操作');
|
|
|
+ $('dataFlow').style.display='none';
|
|
|
+ $('appShell').style.display='grid';$('appShell').style.opacity='1';
|
|
|
+ $('tlBar').style.display='flex';$('bottomBar').style.display='flex';
|
|
|
+ const ending=document.querySelector('[data-ending]');if(ending)ending.remove();
|
|
|
+}
|
|
|
+
|
|
|
+async function act1(){
|
|
|
+ setJourney(0);
|
|
|
+ $('ucEmpty').style.display='flex';$('ucChat').style.display='none';$('ucChat').innerHTML='';
|
|
|
+
|
|
|
+ // NFC animation
|
|
|
+ const overlay=document.createElement('div');
|
|
|
+ overlay.id='nfcOverlay';overlay.style.cssText='position:absolute;top:47%;left:50%;transform:translate(-50%,-50%);z-index:10;pointer-events:none;text-align:center';
|
|
|
+ overlay.innerHTML=`<div style="position:relative;width:70px;height:70px;margin:0 auto"><div style="position:absolute;inset:0;border-radius:50%;border:2px solid var(--accent-light);animation:ripple 1.2s ease-out infinite"></div><div style="position:absolute;inset:0;border-radius:50%;border:2px solid var(--accent-light);animation:ripple 1.2s ease-out infinite;animation-delay:.4s"></div><div style="position:absolute;inset:0;border-radius:50%;border:2px solid var(--accent-light);animation:ripple 1.2s ease-out infinite;animation-delay:.8s"></div><div style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-size:24px">📱</div></div><div style="font-size:9px;color:var(--accent-light);margin-top:4px;font-weight:500">碰一碰连接中…</div>`;
|
|
|
+ document.querySelector('.center-body').appendChild(overlay);
|
|
|
+ await delay(2500);
|
|
|
+ const nfo=document.getElementById('nfcOverlay');if(nfo)nfo.remove();
|
|
|
+
|
|
|
+ // Identity bound
|
|
|
+ $('ucPatient').innerHTML='患者:<strong>医小梦</strong>';
|
|
|
+ $('ucPerc').innerHTML='<span class="ptag l1">L1</span><span class="ptag l1">NFC 已连接</span><span class="ptag l1">BLE 在线</span>';
|
|
|
+ setPerc('percDev','已绑定','on');setPerc('percLoc','L1 门诊大厅','on');
|
|
|
+ $('udTag1').textContent='已绑定';$('udTag1').className='ud-tag bound';
|
|
|
+ $('udTag2').textContent='已绑定';$('udTag2').className='ud-tag bound';
|
|
|
+ $('ucBind').innerHTML='<div style="font-size:9px;color:var(--accent);font-weight:500">✅ 已绑定 · Mate 60 Pro</div>';
|
|
|
+ $('ucAssistTag').textContent='医小梦您好!欢迎来到空海医院';
|
|
|
+ document.querySelectorAll('.uc-qbtn').forEach(b=>b.classList.add('on'));
|
|
|
+ setJourney(2);
|
|
|
+
|
|
|
+ // Nurse
|
|
|
+ $('nsOnline').textContent='1';$('nsToday').textContent='1';
|
|
|
+ $('nsQueue').innerHTML='<div class="ns-patient highlight" style="animation:fadeUp .4s"><div class="np-row"><span class="np-name">医小梦</span><span class="np-tag ok">已入院</span></div><div class="np-detail"><span>📍 门诊大厅</span><span>📱 设备已绑定</span></div></div>';
|
|
|
+ $('nsStatus').textContent='1 名患者';
|
|
|
+ addNotif('nsNotifs','📋 设备绑定事件 · 医小梦');
|
|
|
+
|
|
|
+ // Doctor
|
|
|
+ $('drList').innerHTML='<div class="dr-patient" style="animation:fadeUp .4s"><div class="dp-row"><span class="dp-name">医小梦</span><span class="dp-time">— 未挂号</span></div><div style="font-size:7px;color:var(--muted);display:flex;gap:4px;margin-top:1px"><span>📍 门诊大厅</span><span>还未挂号</span></div></div>';
|
|
|
+ $('drQCount').textContent='候诊 1 人';$('drStatus').textContent='有患者';
|
|
|
+ addNotif('drNotifs','📋 新患者入院 · 医小梦');
|
|
|
+
|
|
|
+ // Chat greeting
|
|
|
+ $('ucEmpty').style.display='none';$('ucChat').style.display='flex';
|
|
|
+ await typeMsg('ai','医小梦您好!欢迎来到空海医院。已为您自动加载信息。检测到您还没有挂号,需要帮您看看挂哪个科室吗?',22,300);
|
|
|
+ await delay(500);
|
|
|
+ const btnRow=document.createElement('div');
|
|
|
+ btnRow.style.cssText='display:flex;gap:5px;margin-top:2px;animation:fadeUp .4s';
|
|
|
+ btnRow.innerHTML='<button class="btn-sm btn-primary" style="flex:1;text-align:center">我要挂号</button><button class="btn-sm btn-secondary" style="flex:1;text-align:center">科室导诊</button>';
|
|
|
+ $('ucChat').appendChild(btnRow);
|
|
|
+
|
|
|
+ $('unBadge').textContent='⬆ 下一步';
|
|
|
+ $('unTitle').textContent='选择服务';
|
|
|
+ $('unDesc').textContent='是否要挂号或查询科室信息?';
|
|
|
+ $('unActs').innerHTML='<button class="btn-sm btn-primary" style="flex:1;text-align:center">我要挂号</button>';
|
|
|
+ $('urHint').textContent='已进入 L1 感知模式,系统可自动识别身份和位置。';
|
|
|
+ setBottom('📱 设备绑定成功 · 感知 L1 · 门诊大厅');
|
|
|
+
|
|
|
+ $('dataFlow').style.display='block';await delay(1500);$('dataFlow').style.display='none';
|
|
|
+}
|
|
|
+
|
|
|
+async function act2(){
|
|
|
+ $('ucChat').style.display='flex';
|
|
|
+ setJourney(3);setPerc('percBiz','AI 导诊中','warn');
|
|
|
+
|
|
|
+ await addMsg('user','我头疼三天,还有点恶心');
|
|
|
+ await delay(1000);
|
|
|
+ await typeMsg('ai','好的,我来了解一下。请问有没有伴随发热、视物模糊呢?',25,300);
|
|
|
+ await delay(2000);
|
|
|
+ await addMsg('user','没有发热,就是头疼恶心想吐');
|
|
|
+ await delay(1200);
|
|
|
+ await typeMsg('ai','明白了。根据您的症状描述,建议优先选择神经内科。李明主任医师今天上午有号,需要帮您预约吗?',22,500);
|
|
|
+ await delay(800);
|
|
|
+
|
|
|
+ const rec=document.createElement('div');
|
|
|
+ rec.style.cssText='background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:10px 12px;animation:slideUp .4s;max-width:260px';
|
|
|
+ rec.innerHTML='<span style="display:inline-block;font-size:7px;padding:1px 5px;border-radius:var(--radius-pill);background:var(--accent-light);color:#fff;font-weight:600;margin-bottom:4px">🏆 推荐</span><div style="font-size:12px;font-weight:700">神经内科 · 李明 主任医师</div><div style="font-size:9px;color:var(--muted);margin:2px 0">今天 10:30 · ¥25(模拟)</div><div style="display:flex;gap:5px;margin-top:5px"><button class="btn-sm btn-primary" style="flex:1;text-align:center">确认挂号</button><button class="btn-sm btn-secondary" style="flex:1;text-align:center">换医生看看</button></div>';
|
|
|
+ $('ucChat').appendChild(rec);
|
|
|
+
|
|
|
+ // Nurse
|
|
|
+ $('nsQueue').innerHTML='<div class="ns-patient highlight" style="animation:fadeUp .4s"><div class="np-row"><span class="np-name">医小梦</span><span class="np-tag ok">导诊完成</span></div><div class="np-detail"><span>🏥 推荐:神经内科</span><span>👨⚕️ 李明</span></div></div>';
|
|
|
+ addNotif('nsNotifs','📋 导诊完成 · 医小梦 → 神经内科');
|
|
|
+
|
|
|
+ // Doctor
|
|
|
+ $('drList').innerHTML='<div class="dr-patient highlight" style="animation:fadeUp .4s"><div class="dp-row"><span class="dp-name">医小梦</span><span class="dp-tag pending">推荐中</span><span class="dp-time">10:30</span></div><div style="font-size:7px;color:var(--muted);margin-top:1px"><span>🏥 神经内科 · 李明</span></div></div>';
|
|
|
+ addNotif('drNotifs','📋 导诊完成 · 医小梦 → 神经内科');
|
|
|
+
|
|
|
+ setBottom('📋 推荐科室:神经内科 · 李明 主任医师');
|
|
|
+ await delay(2500);
|
|
|
+
|
|
|
+ // Loading
|
|
|
+ const ld=document.createElement('div');
|
|
|
+ ld.id='loading';ld.style.cssText='text-align:center;padding:6px;animation:fadeIn .3s';
|
|
|
+ ld.innerHTML='<span style="font-size:9px;color:var(--muted)">⏳ 正在锁定号源…</span>';
|
|
|
+ $('ucChat').appendChild(ld);
|
|
|
+ await delay(1500);
|
|
|
+ const ldEl=document.getElementById('loading');if(ldEl)ldEl.remove();
|
|
|
+
|
|
|
+ // Success
|
|
|
+ const suc=document.createElement('div');
|
|
|
+ suc.style.cssText='background:linear-gradient(135deg,color-mix(in oklch,var(--accent-light) 10%,var(--surface)),var(--surface));border:1px solid var(--accent-light);border-radius:var(--radius-md);padding:12px;animation:slideUp .4s;max-width:260px';
|
|
|
+ suc.innerHTML='<div style="font-size:28px;text-align:center">🎉</div><div style="font-size:14px;font-weight:700;text-align:center">挂号成功!</div><div style="font-size:10px;color:var(--muted);text-align:center;line-height:1.6;margin:4px 0">神经内科 · 李明 主任医师<br>今天 10:30 · 门诊三楼 301 诊室<br>预约号:<strong>A023</strong><br>请前往诊区,到达后自动引导签到</div><div style="text-align:center;margin-top:4px"><button class="btn-sm btn-primary">查看我的就诊动线</button></div>';
|
|
|
+ $('ucChat').appendChild(suc);
|
|
|
+
|
|
|
+ setJourney(4);
|
|
|
+ setPerc('percBiz','已挂号 · A023','on');
|
|
|
+
|
|
|
+ // Nurse
|
|
|
+ $('nsTomorrow').textContent='1';
|
|
|
+ $('nsQueue').innerHTML='<div class="ns-patient" style="border-color:var(--accent-light);animation:fadeUp .4s"><div class="np-row"><span class="np-name">医小梦</span><span class="np-tag done">✅ 已挂号</span></div><div class="np-detail"><span>🏥 神经内科</span><span>👨⚕️ 李明</span><span>⏰ 10:30</span><span>#A023</span></div></div>';
|
|
|
+ addNotif('nsNotifs','✅ 医小梦 已挂号 · 10:30 神经内科');
|
|
|
+
|
|
|
+ // Doctor
|
|
|
+ $('drList').innerHTML='<div class="dr-patient highlight" style="animation:fadeUp .4s"><div class="dp-row"><span class="dp-name">医小梦</span><span class="dp-tag ok">已挂号</span><span class="dp-time">10:30</span></div><div style="font-size:7px;color:var(--muted);margin-top:1px"><span>预约号 A023</span></div></div>';
|
|
|
+ $('drQCount').textContent='候诊 1 人';$('drTodayCount').textContent='今日接诊 1 人';$('drStatus').textContent='待诊中';
|
|
|
+ addNotif('drNotifs','📋 +1 预约 · 医小梦 10:30');
|
|
|
+
|
|
|
+ $('unBadge').textContent='⬆ 下一步';
|
|
|
+ $('unTitle').textContent='前往诊区签到';
|
|
|
+ $('unDesc').textContent='请前往三楼神经内科301诊室。到达后系统自动感知并推送签到。';
|
|
|
+ $('unActs').innerHTML='';
|
|
|
+ setBottom('📋 预约号 A023 · 10:30 · 神经内科 · 请前往诊区签到');
|
|
|
+
|
|
|
+ $('dataFlow').style.display='block';await delay(1500);$('dataFlow').style.display='none';
|
|
|
+}
|
|
|
+
|
|
|
+async function act3(){
|
|
|
+ // Location update
|
|
|
+ $('ucPerc').innerHTML='<span class="ptag l1">L1</span><span class="ptag l1">神经内科诊区</span><span class="ptag l1">BLE 在线</span>';
|
|
|
+ setPerc('percLoc','L1 神经内科诊区','on');
|
|
|
+ setBottom('📍 位置感知:已进入神经内科诊区');
|
|
|
+ await delay(1500);
|
|
|
+
|
|
|
+ // Active check-in card
|
|
|
+ $('ucChat').innerHTML='';
|
|
|
+ await typeMsg('ai','检测到您已到达神经内科诊区——',22,0);
|
|
|
+ await delay(500);
|
|
|
+
|
|
|
+ const chk=document.createElement('div');
|
|
|
+ chk.style.cssText='background:var(--surface);border:2px solid var(--accent);border-radius:var(--radius-md);padding:12px;animation:slideUp .4s;max-width:260px';
|
|
|
+ chk.innerHTML='<div style="font-size:13px;font-weight:700;margin-bottom:6px">📍 主动签到</div><div style="display:flex;justify-content:space-between;font-size:10px;padding:3px 0"><span style="color:var(--muted)">预约号</span><span><strong>A023</strong></span></div><div style="display:flex;justify-content:space-between;font-size:10px;padding:3px 0"><span style="color:var(--muted)">当前叫号</span><span>第 018 号</span></div><div style="font-size:9px;color:var(--accent);font-weight:500;margin:6px 0">⚡ 无需找签到机,点击即可签到</div><button class="btn-sm btn-primary" style="width:100%;text-align:center;margin-top:4px">一键签到</button>';
|
|
|
+ $('ucChat').appendChild(chk);
|
|
|
+
|
|
|
+ $('unBadge').innerHTML='⚡ 服务找人';
|
|
|
+ $('unBadge').style.color='var(--accent)';
|
|
|
+ $('unTitle').textContent='系统主动推送签到';
|
|
|
+ $('unDesc').textContent='感知到位于神经内科诊区,无需寻找签到机——系统正在主动为您服务。';
|
|
|
+ setBottom('📍 检测到诊区到达 · 推送主动签到');
|
|
|
+
|
|
|
+ // Nurse station location update
|
|
|
+ $('nsQueue').querySelector('.np-detail span:first-child').textContent='📍 神经内科诊区';
|
|
|
+
|
|
|
+ await delay(2500);
|
|
|
+
|
|
|
+ // Check-in success
|
|
|
+ $('ucChat').innerHTML='';
|
|
|
+ await typeMsg('ai','检测到您已到达神经内科诊区——',22,0);
|
|
|
+ await delay(200);
|
|
|
+ const suc=document.createElement('div');
|
|
|
+ suc.style.cssText='background:linear-gradient(135deg,color-mix(in oklch,var(--accent-light) 10%,var(--surface)),var(--surface));border:1px solid var(--accent-light);border-radius:var(--radius-md);padding:12px;animation:slideUp .4s;max-width:260px';
|
|
|
+ suc.innerHTML='<div style="font-size:24px;text-align:center">✅</div><div style="font-size:14px;font-weight:700;text-align:center;color:var(--accent-light)">签到成功!</div><div style="font-size:10px;color:var(--muted);text-align:center;line-height:1.6;margin:4px 0">预约号 A023 · 当前叫号 019<br>前面还有 <strong>4 位</strong>患者<br>预计等候约 15 分钟</div>';
|
|
|
+ $('ucChat').appendChild(suc);
|
|
|
+
|
|
|
+ setJourney(5);
|
|
|
+ setPerc('percBiz','候诊中 · 第23位','on');
|
|
|
+
|
|
|
+ $('unBadge').textContent='⏳ 候诊中';$('unBadge').style.color='var(--accent)';
|
|
|
+ $('unTitle').textContent='当前叫号 019 · 第 23 位';
|
|
|
+ $('unDesc').textContent='预计等候 15 分钟。请留意叫号屏和手机通知。';
|
|
|
+ $('unActs').innerHTML='';
|
|
|
+ setBottom('✅ 签到成功 · 候诊中 · 当前叫号 019 · 第 23 位');
|
|
|
+
|
|
|
+ // Nurse
|
|
|
+ $('nsQueue').innerHTML='<div class="ns-patient" style="border-color:var(--accent-light);animation:fadeUp .4s"><div class="np-row"><span class="np-name">医小梦</span><span class="np-tag ok">候诊中</span></div><div class="np-detail"><span>📍 神经内科诊区</span><span>🔢 第 23 位</span><span>⏳ 约 15 分钟</span></div></div>';
|
|
|
+
|
|
|
+ // Doctor
|
|
|
+ $('drList').innerHTML='<div class="dr-patient" style="animation:fadeUp .4s"><div class="dp-row"><span class="dp-name">019 · 赵丽华</span><span style="font-size:7px;color:var(--muted)">候诊中</span></div></div><div class="dr-patient highlight" style="animation:fadeUp .4s"><div class="dp-row"><span class="dp-name">A023 · 医小梦</span><span class="dp-tag pending">候诊中</span><span class="dp-time">第23位</span></div></div>';
|
|
|
+ $('drQCount').textContent='候诊 5 人';$('drStatus').textContent='候诊中';
|
|
|
+}
|
|
|
+
|
|
|
+async function act4(){
|
|
|
+ await delay(500);
|
|
|
+ $('appShell').style.transition='all .8s ease';$('appShell').style.opacity='0';
|
|
|
+ await delay(800);$('appShell').style.display='none';$('tlBar').style.display='none';$('bottomBar').style.display='none';
|
|
|
+
|
|
|
+ const ending=document.createElement('div');
|
|
|
+ ending.setAttribute('data-ending','');
|
|
|
+ ending.style.cssText='position:fixed;inset:0;background:var(--accent);display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:100;animation:fadeIn .6s';
|
|
|
+ ending.innerHTML='<div style="text-align:center;animation:slideUp .6s"><div style="font-size:26px;font-weight:700;color:var(--accent-light);letter-spacing:.02em;margin-bottom:8px">感知 <span style="color:rgba(255,255,255,.35)">→</span> 动线 <span style="color:rgba(255,255,255,.35)">→</span> AI 调度 <span style="color:rgba(255,255,255,.35)">→</span> 服务外显</div><div style="font-size:15px;color:#fff;margin-bottom:4px;opacity:.8">患者少找路、少找窗口、少找设备</div><div style="width:100px;height:2px;background:var(--accent-light);margin:14px auto;border-radius:1px"></div><div style="font-size:18px;color:#fff;font-weight:600;letter-spacing:.04em">EMOON · 医梦</div><div style="font-size:11px;color:rgba(255,255,255,.45);margin-top:4px;letter-spacing:.05em">AI 未来医院 · 服务主动找人</div></div>';
|
|
|
+ document.body.appendChild(ending);
|
|
|
+}
|
|
|
+
|
|
|
+// ─── AUTO-ADVANCE ───
|
|
|
+const ACTS=[
|
|
|
+ {name:'第一幕 · 开场亮相', start:0, dur:5000, fn:act0},
|
|
|
+ {name:'第二幕 · 感知绑定', start:5, dur:9000, fn:act1},
|
|
|
+ {name:'第三幕 · AI 导诊挂号',start:14, dur:15000, fn:act2},
|
|
|
+ {name:'第四幕 · 诊区签到', start:29, dur:10000, fn:act3},
|
|
|
+ {name:'第五幕 · 结尾定版', start:39, dur:7000, fn:act4},
|
|
|
+];
|
|
|
+let cur=-1, timer=null;
|
|
|
+
|
|
|
+function fmt(s){return Math.floor(s/60)+':'+(s%60).toString().padStart(2,'0')}
|
|
|
+
|
|
|
+async function go(idx){
|
|
|
+ clearTimeout(timer);cur=idx;
|
|
|
+ document.querySelectorAll('.tl-step').forEach((e,i)=>{e.classList.toggle('active',i===idx);e.classList.toggle('done',i<idx)});
|
|
|
+ $('tlAct').textContent=ACTS[idx].name;$('tlTime').textContent=fmt(ACTS[idx].start);
|
|
|
+ query('.scene-label',true).forEach(e=>e.remove());
|
|
|
+ await ACTS[idx].fn();
|
|
|
+ if(idx+1<ACTS.length) timer=setTimeout(()=>go(idx+1),ACTS[idx].dur);
|
|
|
+}
|
|
|
+function query(s,all){return all?document.querySelectorAll(s):document.querySelector(s)}
|
|
|
+
|
|
|
+document.addEventListener('DOMContentLoaded',()=>go(0));
|
|
|
+</script>
|
|
|
+</body>
|
|
|
+</html>
|