From 796047fbe84d51816f44be535501415d3c66dd9d Mon Sep 17 00:00:00 2001
From: yxh <172933527@qq.com>
Date: 星期日, 21 六月 2026 23:24:37 +0800
Subject: [PATCH] yxh

---
 /dev/null  |  472 ----------
 big.html   |  563 +++++++++--
 logo0.png  |    0 
 small.html |  189 +++
 big滚动.html |  823 +++++++++++++++++
 big1.html  |  680 ++++++++++++++
 6 files changed, 2,095 insertions(+), 632 deletions(-)

diff --git a/big.html b/big.html
index 54c827d..a2fb0ab 100644
--- a/big.html
+++ b/big.html
@@ -1,9 +1,10 @@
-<!doctype html>
+锘�<!doctype html>
 <html lang="zh-CN">
 
 <head>
     <meta charset="UTF-8" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi" />
+    <meta name="viewport"
+        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi" />
     <meta http-equiv="X-UA-Compatible" content="IE=edge" />
     <title>澶у巺</title>
     <style>
@@ -11,7 +12,8 @@
             margin: 0;
             padding: 0;
             box-sizing: border-box;
-            /* Android 6 鍙敤涓枃瀛椾綋 */;
+            /* Android 6 鍙敤涓枃瀛椾綋 */
+            ;
             font-family: "Droid Sans Fallback", "Noto Sans CJK SC", "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
         }
 
@@ -64,10 +66,43 @@
         }
 
         .top-header .time-info {
-            font-size: 24px;
+            font-size: 20px;
             color: #aaa;
             margin-left: auto;
             z-index: 2;
+            text-align: right;
+            line-height: 1.3;
+        }
+
+        .time-info-inner {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-align: center;
+            -webkit-align-items: center;
+            align-items: center;
+        }
+
+        .time-left {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-orient: vertical;
+            -webkit-flex-direction: column;
+            flex-direction: column;
+            text-align: right;
+            line-height: 1.3;
+        }
+
+        .time-right {
+            margin-left: 8px;
+        }
+
+        .top-header .time-info .time-clock {
+            font-size: 36px;
+            font-weight: bold;
+            color: #ffcc00;
+            line-height: 1.1;
         }
 
         /* 3. 涓讳綋鍐呭锛坓ap 鏇挎崲涓� margin 鍏煎鏃� Chrome锛� */
@@ -78,20 +113,35 @@
             display: -webkit-box;
             display: -webkit-flex;
             display: flex;
+            -webkit-box-orient: vertical;
+            -webkit-box-direction: normal;
+            -webkit-flex-direction: column;
+            flex-direction: column;
             padding: 15px 20px;
             overflow: hidden;
         }
 
-        .main-content > .column-box {
-            margin-left: 5px;
-            margin-right: 5px;
+        /* 鍒楄瀹瑰櫒 */
+        .columns-row {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            overflow: hidden;
         }
 
-        .main-content > .column-box:first-child {
+        .columns-row>.column-box {
+            margin-left: 3px;
+            margin-right: 3px;
+        }
+
+        .columns-row>.column-box:first-child {
             margin-left: 0;
         }
 
-        .main-content > .column-box:last-child {
+        .columns-row>.column-box:last-child {
             margin-right: 0;
         }
 
@@ -106,7 +156,7 @@
             flex-direction: column;
             background: rgba(10, 40, 80, 0.5);
             border-radius: 0;
-            padding: 10px;
+            padding: 6px;
             -webkit-box-flex: 1;
             -webkit-flex: 1;
             flex: 1;
@@ -128,16 +178,13 @@
 
         /* 鏍囬琛� */
         .col-title-line {
-            font-size: 22px;
+            font-size: 28px;
             font-weight: bold;
             color: #4da6ff;
             text-align: center;
         }
 
         .col-title {
-            font-size: 22px;
-            font-weight: bold;
-            color: #4da6ff;
             padding-bottom: 8px;
             border-bottom: 1px solid #003366;
             margin-bottom: 10px;
@@ -145,9 +192,14 @@
         }
 
         .col-subtitle {
-            font-size: 14px;
-            color: #999;
+            font-size: 24px;
+            font-weight: bold;
+            color: #ffcc00;
             text-align: center;
+            min-height: 20px;
+            /* 鍗充娇涓虹┖涔熶繚鐣欓珮搴︼紝闃叉鏍囬鏍忛珮浣庝笉骞� */
+            line-height: 1.4;
+            word-break: keep-all;
         }
 
         /* 鎮h�呭垪琛� */
@@ -156,34 +208,41 @@
             -webkit-flex: 1;
             flex: 1;
             overflow-y: auto;
-            padding-right: 5px;
-        }
-
-        /* 绗�1鏍忥細涓�琛屼袱涓� */
-        #col-0 {
+            padding-right: 2px;
             display: -webkit-box;
             display: -webkit-flex;
             display: flex;
-            -webkit-flex-wrap: wrap;
-            flex-wrap: wrap;
             -webkit-align-content: flex-start;
             align-content: flex-start;
         }
 
-        .col-normal .patient-list {
-            display: -webkit-box;
-            display: -webkit-flex;
-            display: flex;
+        /* 涓�琛屼袱涓紙甯歌蹇冪數鍥俱�佸姩鎬佸績鐢碉級 */
+        .patient-list.two-per-row {
+            -webkit-flex-wrap: wrap;
+            flex-wrap: wrap;
+        }
+
+        .patient-list.two-per-row .patient-item {
+            width: 46%;
+            margin: 0 2%;
+        }
+
+        /* 涓�琛屼竴涓� */
+        .patient-list.one-per-row {
             -webkit-box-orient: vertical;
             -webkit-box-direction: normal;
             -webkit-flex-direction: column;
             flex-direction: column;
         }
 
+        .patient-list.one-per-row .patient-item {
+            width: 100%;
+        }
+
         /* 鎮h�呴」鐩� */
         .patient-item {
-            font-size: 22px;
-            padding: 8px 5px;
+            font-size: 28px;
+            padding: 4px 3px;
             display: -webkit-box;
             display: -webkit-flex;
             display: flex;
@@ -194,19 +253,22 @@
             line-height: 1.4;
         }
 
-        #col-0 .patient-item {
-            width: 45%;
-            font-size: 20px;
-            margin: 0 2.5%;
-        }
-
         .p-number {
             color: #ffcc00;
             font-weight: bold;
-            margin-right: 8px;
+            margin-right: 6px;
+            -webkit-flex-shrink: 0;
+            flex-shrink: 0;
         }
 
         .p-name {
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            font-weight: bold;
+        }
+
+        .p-name-wrap {
             -webkit-box-flex: 1;
             -webkit-flex: 1;
             flex: 1;
@@ -218,8 +280,31 @@
         .p-room {
             color: #4da6ff;
             font-weight: bold;
-            font-size: 18px;
-            margin-left: 5px;
+            font-size: 22px;
+            margin-left: 4px;
+            -webkit-flex-shrink: 0;
+            flex-shrink: 0;
+        }
+
+        /* 杩囧彿鎮h�咃細鎺掑湪鍒楀唴锛岃瑙夊急鍖� */
+        .patient-item.missed {
+            color: #aa8888;
+        }
+
+        .patient-item.missed .p-number {
+            color: #cc9966;
+        }
+
+        .patient-item.missed .p-name {
+            color: #aa8888;
+        }
+
+        .patient-item.missed .p-missed-tag {
+            color: #ff6666;
+            font-size: 22px;
+            margin-left: 4px;
+            -webkit-flex-shrink: 0;
+            flex-shrink: 0;
         }
 
         /* 搴曢儴鏍� */
@@ -245,10 +330,30 @@
             text-align: center;
         }
 
+        /* 娴嬭瘯璇煶鎸夐挳 */
+        #test-voice-btn {
+            margin-left: 20px;
+            background-color: #007bff;
+            color: white;
+            border: none;
+            padding: 10px 20px;
+            border-radius: 6px;
+            font-size: 16px;
+            cursor: pointer;
+            font-weight: bold;
+            -webkit-flex-shrink: 0;
+            flex-shrink: 0;
+        }
+
+        #test-voice-btn:hover {
+            background-color: #0056b3;
+        }
+
         /* 婊氬姩鏉� */
         .patient-list::-webkit-scrollbar {
             width: 4px;
         }
+
         .patient-list::-webkit-scrollbar-thumb {
             background: #444;
             border-radius: 2px;
@@ -256,14 +361,21 @@
 
         /* 璋冭瘯闈㈡澘 */
         .debug-panel {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-orient: vertical;
+            -webkit-box-direction: normal;
+            -webkit-flex-direction: column;
+            flex-direction: column;
             position: fixed;
             right: 15px;
             bottom: 70px;
-            width: 350px;
-            height: 200px;
-            background: rgba(0, 0, 0, 0.9);
+            width: 380px;
+            height: 220px;
+            background: rgba(0, 0, 0, 0.92);
             color: #0f0;
-            border-radius: 4px;
+            border-radius: 6px;
             font-family: monospace;
             font-size: 12px;
             z-index: 9999;
@@ -322,7 +434,7 @@
     <!-- 椤堕儴鏍� -->
     <div class="top-header">
         <img src="logo.png" alt="logo" />
-        <span class="title-text">鏈嶅姟澶у巺鎺掑垪</span>
+        <span class="title-text">蹇冪數璇婂尯澶у巺</span>
         <span class="time-info" id="headerTime"></span>
     </div>
 
@@ -331,11 +443,12 @@
 
     <!-- 搴曢儴鏍� -->
     <div class="bottom-footer">
-        <div class="footer-tip">娓╅Θ鎻愮ず锛氳鍚埌鍛煎彨鍚庡墠寰�瀵瑰簲璇婂</div>
+        <div class="footer-tip">娓╅Θ鎻愮ず锛氬惉鍒板懠鍙悗璇峰墠寰�瀵瑰簲璇婂锛岃繃鍙锋偅鑰呭埌瀵艰瘖鍙板鐞嗭紒</div>
+        <button id="test-voice-btn" onclick="testVoice()">娴嬭瘯璇煶</button>
     </div>
 
     <!-- 璋冭瘯闈㈡澘 -->
-    <div class="debug-panel" id="debugPanel">
+    <div class="debug-panel" id="debugPanel" >
         <div class="debug-header">
             <span>[璋冭瘯] 杩愯鏃ュ織</span>
             <button onclick="document.getElementById('debugBody').innerHTML=''">娓呯┖</button>
@@ -355,61 +468,125 @@
             var body = document.getElementById("debugBody");
             if (body) {
                 body.insertAdjacentHTML("beforeend", logHtml);
-                body.scrollTop = body.scrollHeight;
+                // requestAnimationFrame 纭繚 DOM 鏇存柊鍚庡啀婊氬姩
+                requestAnimationFrame(function () {
+                    body.scrollTop = body.scrollHeight;
+                });
             }
         }
 
         // ================= 搴旂敤鐘舵�� =================
+        // 鍛煎彨鍙彿娆℃暟鍙傛暟锛氬懠鍙偅鑰呭氨璇婃椂閲嶅鎾姤鐨勬鏁帮紝榛樿 2 娆�
+        var CALL_TIMES = 2;   
+        // 涓�琛屼袱涓偅鑰呯殑鍒楃储寮曪紙甯歌蹇冪數鍥俱�佸姩鎬佸績鐢碉級
+        var TWO_PER_ROW_COLS = [0, 1];
+        // 椋熼亾鐢电敓鐞嗘槸鍚︽樉绀猴紙false 闅愯棌锛宼rue 鏄剧ず锛�
+        var SHOW_COL_ESOPHAGEAL = false;
         var appState = {
-            columnTitles: ["甯歌蹇冪數鍥�", "鍔ㄦ�佸績鐢�", "骞虫澘杩愬姩蹇冪數", "椋熼亾鐢电敓鐞�", "鍔ㄨ剦纭寲鐩戞祴"],
-            columnSubTitles: ["搴婅竟蹇冪數鍥�(甯歌+棰戣氨)M / 蹇冪數鍚戦噺鍥綨", "鍔ㄦ�佽鍘婥", "", "", ""],
+            columnTitles: ["甯歌蹇冪數鍥�/蹇冪數鍚戦噺鍥�", "鍔ㄦ�佸績鐢�/琛�鍘�", "骞虫澘杩愬姩蹇冪數", "椋熼亾鐢电敓鐞�", "鍔ㄨ剦纭寲鐩戞祴"],
+            columnSubTitles: ["1鍙�-2鍙疯瘖瀹�", "2鍙疯瘖瀹�", "4鍙疯瘖瀹�", "6鍙疯瘖瀹�", "5鍙疯瘖瀹�"],
             patients: [],
-            apiBaseUrl: "http://192.168.100.110/admin-api",
+            // apiBaseUrl: "http://192.168.3.12/admin-api",
+            apiBaseUrl: "http://10.0.2.193/admin-api",
             pollTimer: null,
-            callRepeatTimes: 2,
             spokenPatients: {},
             ttsQueue: [],
-            isSpeaking: false
+            isSpeaking: false,
+        };
+
+        var patStatus = {
+            3: "宸茶繃鍙�-鎺掗槦", 5: "宸茶繃鍙�", 7: "宸茶繃鍙�-瀹夎", 10: "鎺掗槦涓�", 12: "浜插拰",
+            13: "浜插拰-瀹夎", 15: "宸插彫鍥�", 20: "鍊欒瘖涓�", 30: "灏辫瘖涓�", 33: "宸查鐢�",
+            34: "宸插彫鍥�-瀹夎", 36: "瀹夎涓�", 40: "宸插氨璇�"
         };
 
         // ================= 璇煶鎾姤 =================
+        // Android WebView GC 淇濇姢锛氬叏灞�鎸佹湁 utterance 寮曠敤锛岄槻姝㈣鍥炴敹瀵艰嚧鏃犲0
+        var _gCurrentUtterance = null;
+
         function processTtsQueue() {
             if (appState.isSpeaking || appState.ttsQueue.length === 0) return;
             appState.isSpeaking = true;
             var text = appState.ttsQueue.shift();
             logDebug("[鎾姤] " + text);
 
-            var utterance = new SpeechSynthesisUtterance(text);
-            // Android 6 榛樿璇�熷彲鑳藉緢蹇紝閫傚綋璋冩參
-            utterance.rate = 0.85;
-            utterance.onend = function () {
-                appState.isSpeaking = false;
-                processTtsQueue();
-            };
-            utterance.onerror = function (e) {
-                logDebug("[TTS閿欒] " + (e.error || "unknown"));
-                appState.isSpeaking = false;
-                processTtsQueue();
-            };
-
-            // 浼樺厛灏濊瘯璁惧鍘熺敓 TTS 鎺ュ彛
+            // 浼樺厛灏濊瘯璁惧鍘熺敓 TTS 鎺ュ彛 (wowjoy)
             if (typeof wowjoy !== 'undefined' && typeof wowjoy.speek === 'function') {
                 try {
                     wowjoy.speek(text);
+                    logDebug("[鎾姤] wowjoy.speek 宸茶皟鐢�");
                     setTimeout(function () { appState.isSpeaking = false; processTtsQueue(); }, 4000);
                     return;
                 } catch (e) { logDebug("[wowjoy澶辫触] " + e.message); }
             }
 
-            if (window.speechSynthesis) {
-                // Android 6 WebView 鏈夋椂闇�瑕佸厛 cancel 鍐� speak
-                window.speechSynthesis.cancel();
-                window.speechSynthesis.speak(utterance);
-            } else {
+            if (!window.speechSynthesis) {
                 logDebug("[TTS] 娴忚鍣ㄤ笉鏀寔璇煶鍚堟垚");
                 appState.isSpeaking = false;
                 processTtsQueue();
+                return;
             }
+
+            // 浠呭湪鏈夎闊虫鍦ㄦ挱鏀炬椂鎵� cancel锛岄伩鍏嶄笉蹇呰鐨勪腑鏂�
+            if (window.speechSynthesis.speaking) {
+                logDebug("[鎾姤] cancel 褰撳墠鎾斁");
+                window.speechSynthesis.cancel();
+            }
+
+            var utterance = new SpeechSynthesisUtterance(text);
+            utterance.rate = 0.85;
+            utterance.volume = 1.0;
+            // Android WebView GC 淇濇姢锛氬瓨鍏ㄥ眬寮曠敤
+            _gCurrentUtterance = utterance;
+
+            utterance.onstart = function () {
+                logDebug("[鎾姤] onstart 瑙﹀彂");
+            };
+            utterance.onend = function () {
+                logDebug("[鎾姤] onend 瑙﹀彂");
+                _gCurrentUtterance = null;
+                appState.isSpeaking = false;
+                // 寤惰繜涓�涓嬭寮曟搸瀹屽叏閲婃斁
+                setTimeout(function () { processTtsQueue(); }, 200);
+            };
+            utterance.onerror = function (e) {
+                logDebug("[TTS閿欒] " + (e.error || "unknown"));
+                _gCurrentUtterance = null;
+                appState.isSpeaking = false;
+                setTimeout(function () { processTtsQueue(); }, 200);
+            };
+
+            // 纭繚璇煶鍖呭凡鍔犺浇 (Android 涓� getVoices 鍙兘鍒濆涓虹┖)
+            var voices = window.speechSynthesis.getVoices();
+            if (voices.length > 0) {
+                utterance.voice = voices[0];
+                logDebug("[鎾姤] 浣跨敤璇煶: " + voices[0].name + " lang=" + voices[0].lang);
+            } else {
+                logDebug("[鎾姤] getVoices 涓虹┖, 绛夊緟 voiceschanged 浜嬩欢");
+                var voicesLoaded = false;
+                var onVoicesChange = function () {
+                    if (voicesLoaded) return;
+                    voicesLoaded = true;
+                    var v2 = window.speechSynthesis.getVoices();
+                    if (v2.length > 0) {
+                        utterance.voice = v2[0];
+                        logDebug("[鎾姤] 璇煶鍔犺浇瀹屾垚: " + v2[0].name);
+                    }
+                    window.speechSynthesis.speak(utterance);
+                };
+                window.speechSynthesis.addEventListener('voiceschanged', onVoicesChange);
+                // 濡傛灉 1s 鍐呮病瑙﹀彂锛岀洿鎺� speak
+                setTimeout(function () {
+                    if (!voicesLoaded) {
+                        logDebug("[鎾姤] voiceschanged 瓒呮椂, 鐩存帴 speak");
+                        window.speechSynthesis.speak(utterance);
+                    }
+                }, 1000);
+                return;
+            }
+
+            window.speechSynthesis.speak(utterance);
+            logDebug("[鎾姤] speak 宸茶皟鐢�");
         }
 
         function speak(text) {
@@ -418,47 +595,179 @@
             processTtsQueue();
         }
 
-        // ================= 娓叉煋 =================
-        function renderMainContent() {
-            var main = document.getElementById("mainContent");
-            main.innerHTML = "";
+        // ================= 璇煶娴嬭瘯 =================
+        function testVoice() {
+            logDebug("[璇煶娴嬭瘯] ========== 寮�濮� ==========");
+            var testText = "娴嬭瘯璇煶鎾姤";
 
-            for (var i = 0; i < appState.columnTitles.length; i++) {
-                var titleHtml = '<div class="col-title-line">' + appState.columnTitles[i] + '</div>';
-                if (appState.columnSubTitles[i]) {
-                    titleHtml += '<div class="col-subtitle">' + appState.columnSubTitles[i] + '</div>';
+            // 1. 妫�娴� wowjoy 鍘熺敓鎺ュ彛
+            var hasWowjoy = (typeof wowjoy !== 'undefined');
+            logDebug("[璇煶娴嬭瘯] wowjoy 瀵硅薄瀛樺湪=" + hasWowjoy);
+            if (hasWowjoy) {
+                logDebug("[璇煶娴嬭瘯] wowjoy.speek 绫诲瀷=" + (typeof wowjoy.speek));
+                if (typeof wowjoy.speek === 'function') {
+                    try {
+                        wowjoy.speek(testText);
+                        logDebug("[璇煶娴嬭瘯] wowjoy.speek 宸茶皟鐢紝娉ㄦ剰鍚澶囧0闊�");
+                    } catch (e) {
+                        logDebug("[璇煶娴嬭瘯] wowjoy.speek 寮傚父: " + e.message);
+                    }
+                }
+            }
+
+            // 2. 妫�娴� SpeechSynthesis
+            var hasSpeech = (typeof window.speechSynthesis !== 'undefined');
+            logDebug("[璇煶娴嬭瘯] speechSynthesis 瀵硅薄瀛樺湪=" + hasSpeech);
+            
+            if (hasSpeech) {
+                var syn = window.speechSynthesis;
+                logDebug("[璇煶娴嬭瘯] speaking=" + syn.speaking + " pending=" + syn.pending + " paused=" + syn.paused);
+
+                var voices = syn.getVoices();
+                logDebug("[璇煶娴嬭瘯] getVoices 杩斿洖 " + voices.length + " 涓闊冲寘");
+                for (var v = 0; v < Math.min(voices.length, 5); v++) {
+                    logDebug("[璇煶娴嬭瘯]   璇煶[" + v + "] " + voices[v].name + " lang=" + voices[v].lang + " local=" + voices[v].localService);
                 }
 
-                var colClass = (i === 0) ? 'col-wide' : 'col-normal';
-                var colHtml = '<div class="column-box ' + colClass + '">' +
-                    '<div class="col-title">' + titleHtml + '</div>' +
-                    '<div class="patient-list" id="col-' + i + '"></div>' +
-                    '</div>';
-                main.insertAdjacentHTML("beforeend", colHtml);
+                // 濡傛灉 voices 涓虹┖锛岀瓑寰呭姞杞藉悗鍐嶆挱
+                function doSpeakTest() {
+                    var v2 = syn.getVoices();
+                    var u = new SpeechSynthesisUtterance(testText);
+                    u.rate = 0.85;
+                    u.volume = 1.0;
+                    if (v2.length > 0) {
+                        u.voice = v2[0];
+                        logDebug("[璇煶娴嬭瘯] 閫夋嫨璇煶: " + v2[0].name);
+                    }
+                    // GC 淇濇姢
+                    window._testUtterance = u;
+                    u.onstart = function() { logDebug("[璇煶娴嬭瘯] onstart 瑙﹀彂 鉁�"); };
+                    u.onend = function() { logDebug("[璇煶娴嬭瘯] onend 瑙﹀彂 鉁�"); window._testUtterance = null; };
+                    u.onerror = function(e) { logDebug("[璇煶娴嬭瘯] onerror: " + (e.error || "unknown")); window._testUtterance = null; };
+                    
+                    if (syn.speaking) {
+                        logDebug("[璇煶娴嬭瘯] 鏈夎闊虫鍦ㄦ挱鏀撅紝鍏� cancel");
+                        syn.cancel();
+                        setTimeout(function () { syn.speak(u); logDebug("[璇煶娴嬭瘯] speak 宸茶皟鐢�(寤惰繜)"); }, 300);
+                    } else {
+                        syn.speak(u);
+                        logDebug("[璇煶娴嬭瘯] speak 宸茶皟鐢�");
+                    }
+                }
+
+                if (voices.length === 0) {
+                    logDebug("[璇煶娴嬭瘯] 璇煶鍒楄〃涓虹┖锛岀瓑寰� voiceschanged...");
+                    var loaded = false;
+                    var handler = function () {
+                        if (loaded) return;
+                        loaded = true;
+                        logDebug("[璇煶娴嬭瘯] voiceschanged 瑙﹀彂, 璇煶鏁�=" + syn.getVoices().length);
+                        doSpeakTest();
+                    };
+                    syn.addEventListener('voiceschanged', handler);
+                    setTimeout(function () {
+                        if (!loaded) {
+                            logDebug("[璇煶娴嬭瘯] voiceschanged 瓒呮椂(2s), 寮哄埗娴嬭瘯");
+                            doSpeakTest();
+                        }
+                    }, 2000);
+                } else {
+                    doSpeakTest();
+                }
             }
+
+            if (!hasWowjoy && !hasSpeech) {
+                logDebug("[璇煶娴嬭瘯] 鏃犱换浣� TTS 寮曟搸鍙敤锛�");
+            }
+            logDebug("[璇煶娴嬭瘯] ========== 缁撴潫 ==========");
         }
 
-        function renderPatients() {
-            for (var i = 0; i < appState.columnTitles.length; i++) {
-                var col = document.getElementById("col-" + i);
-                if (col) col.innerHTML = "";
-            }
+        // ================= 娓叉煋锛氭爣棰樻鏋讹紙浠呭垵濮嬪寲涓�娆★級=================
+        function initLayout() {
+            logDebug("[甯冨眬] initLayout 寮�濮�, 鍒楁暟=" + appState.columnTitles.length);
+            var main = document.getElementById("mainContent");
+            if (!main) { logDebug("[甯冨眬] mainContent 鍏冪礌鏈壘鍒�!"); return; }
+            var html = '<div class="columns-row">';
+            var visibleCount = 0;
 
-            for (var c = 0; c < appState.patients.length; c++) {
-                var colData = appState.patients[c];
-                if (Array.isArray(colData)) {
-                    var col = document.getElementById("col-" + c);
-                    if (!col) continue;
-                    for (var p = 0; p < colData.length; p++) {
-                        var pat = colData[p];
-                        var roomHtml = pat.roomName ? '<span class="p-room">(' + pat.roomName + ')</span>' : '';
-                        var itemHtml = '<div class="patient-item">' +
-                            '<span class="p-number">' + (pat.bookSeqNum || '') + '</span>' +
-                            '<span class="p-name">' + (pat.patName || '') + '</span>' +
-                            roomHtml +
-                            '</div>';
-                        col.insertAdjacentHTML("beforeend", itemHtml);
-                    }
+            for (var i = 0; i < appState.columnTitles.length; i++) {
+                // 椋熼亾鐢电敓鐞嗭細閫氳繃 SHOW_COL_ESOPHAGEAL 鎺у埗鏄鹃殣
+                if (i === 3 && !SHOW_COL_ESOPHAGEAL) {
+                    logDebug("[甯冨眬] 鍒�" + i + " 椋熼亾鐢电敓鐞� 宸查殣钘�");
+                    continue;
+                }
+
+                var subtitle = appState.columnSubTitles[i] || "&nbsp;";
+                // 涓�琛屼袱涓殑鍒楃敤 col-wide锛屽惁鍒� col-normal
+                var isTwoPerRow = TWO_PER_ROW_COLS.indexOf(i) !== -1;
+                var colClass = isTwoPerRow ? 'col-wide' : 'col-normal';
+                var rowClass = isTwoPerRow ? 'two-per-row' : 'one-per-row';
+                logDebug("[甯冨眬] 鍒�" + i + " " + appState.columnTitles[i] + " class=" + colClass + " row=" + rowClass);
+                html += '<div class="column-box ' + colClass + '">' +
+                    '<div class="col-title">' +
+                    '<div class="col-title-line">' + appState.columnTitles[i] + '</div>' +
+                    '<div class="col-subtitle">' + subtitle + '</div>' +
+                    '</div>' +
+                    '<div class="patient-list ' + rowClass + '" id="col-' + i + '"></div>' +
+                    '</div>';
+                visibleCount++;
+            }
+            html += '</div>';
+            main.innerHTML = html;
+            logDebug("[甯冨眬] initLayout 瀹屾垚, 鍙鍒�=" + visibleCount);
+        }
+
+        // ================= 娓叉煋锛氭偅鑰呭垪琛紙diff 鏇存柊锛屽彧鏀瑰彉鍖栫殑鍒楋級=================
+        function desensitizeName(name) {
+            if (!name || name.length < 2) return name || '';
+            return name.charAt(0) + '*' + name.substring(2);
+        }
+
+        function isMissedStatus(status) {
+            var s = parseInt(status, 10);
+            return s === 3 || s === 5 || s === 7;
+        }
+
+        function buildColumnHtml(colData) {
+            if (!Array.isArray(colData) || colData.length === 0) return "";
+            var h = "";
+            for (var p = 0; p < colData.length; p++) {
+                var pat = colData[p];
+                var missedClass = isMissedStatus(pat.status) ? ' missed' : '';
+                var roomHtml = (!isMissedStatus(pat.status) && pat.roomName) ? '<span class="p-room">' + pat.roomName + '</span>' : '';
+                h += '<div class="patient-item' + missedClass + '">' +
+                    '<span class="p-number">' + (pat.seqNum || '') + '</span>' +
+                    '<span class="p-name-wrap"><span class="p-name">' + desensitizeName(pat.patName) + '</span>' + roomHtml +
+                    (missedClass ? '<span class="p-missed-tag">杩囧彿</span>' : '') + '</span>' +
+                    '</div>';
+            }
+            return h;
+        }
+        function isSameColumn(a, b) {
+            if (!Array.isArray(a) || !Array.isArray(b)) return a === b;
+            if (a.length !== b.length) return false;
+            for (var i = 0; i < a.length; i++) {
+                if (a[i].patId !== b[i].patId) return false;
+                if (a[i].roomName !== b[i].roomName) return false;
+                if (parseInt(a[i].status, 10) !== parseInt(b[i].status, 10)) return false;
+            }
+            return true;
+        }
+
+        function updatePatients(dataList) {
+            for (var i = 0; i < appState.columnTitles.length; i++) {
+                var newData = (dataList && dataList[i]) ? dataList[i] : [];
+                var oldData = appState.patients[i];
+
+                // diff锛氭暟鎹湭鍙樺寲鍒欒烦杩囪鍒� DOM 鎿嶄綔
+                if (isSameColumn(oldData, newData)) continue;
+
+                var col = document.getElementById("col-" + i);
+                if (col) {
+                    col.innerHTML = buildColumnHtml(newData);
+                    logDebug("[鏇存柊] 鍒�" + i + " " + appState.columnTitles[i] + " 鍒锋柊 " + newData.length + " 浜�");
+                } else {
+                    logDebug("[鏇存柊] 鍒�" + i + " DOM涓嶅瓨鍦�(鍙兘宸查殣钘�)");
                 }
             }
         }
@@ -485,10 +794,10 @@
                             }
                             if (!oldPat || !oldPat.roomName) {
                                 var repeatText = "";
-                                for (var r = 0; r < appState.callRepeatTimes; r++) {
-                                    repeatText += "璇� " + newPat.bookSeqNum + " 鍙� " + newPat.patName + " 鍒� " + newPat.roomName + " 灏辫瘖銆�";
-                                }
-                                speak(repeatText);
+                                repeatText += "璇� " + newPat.seqNum + " 鍙� " + newPat.patName + " 鍒� " + newPat.roomName + " 灏辫瘖銆�";
+                                for (var r = 0; r < CALL_TIMES; r++) {
+                                    speak(repeatText);
+                                }                                
                                 appState.spokenPatients[newPat.patId] = true;
                                 logDebug("[鎺掗槦] " + newPat.patName + " -> " + newPat.roomName);
                             }
@@ -501,22 +810,28 @@
         // ================= 鏁版嵁鑾峰彇 =================
         function fetchQueueData() {
             var url = appState.apiBaseUrl + "/ecg/screen/big-screen-data";
+            logDebug("[璇锋眰] GET " + url);
             $.ajax({
                 url: url,
                 type: "GET",
                 dataType: "json",
                 timeout: 5000,
                 success: function (res) {
+                    logDebug("[鍝嶅簲] code=" + (res ? res.code : "null"));
                     var dataList = [];
                     if (res && res.code === 0 && res.data) {
                         for (var i = 0; i < appState.columnTitles.length; i++) {
                             var key = i.toString();
                             dataList[i] = (res.data[key] && Array.isArray(res.data[key])) ? res.data[key] : [];
+                            logDebug("[鏁版嵁] 鍒�" + i + " " + appState.columnTitles[i] + " 鎮h�呮暟=" + dataList[i].length);
                         }
+                    } else {
+                        logDebug("[鍝嶅簲] 寮傚父 code=" + (res ? res.code : "null") + " msg=" + (res ? res.msg : ""));
                     }
+                    // 鍏� diff 鏇存柊 DOM锛屽啀鎾姤锛屾渶鍚庝繚瀛樻暟鎹敤浜庝笅娆″姣�
+                    updatePatients(dataList);
                     checkAndSpeakNewRooms(appState.patients, dataList);
                     appState.patients = dataList;
-                    renderPatients();
 
                     // Android 6 WebView 閫氬父涓嶆敮鎸� performance.memory锛屽畨鍏ㄥ畧鍗�
                     try {
@@ -524,43 +839,57 @@
                             var usedMB = (window.performance.memory.usedJSHeapSize / 1048576).toFixed(2);
                             logDebug("[鍐呭瓨] " + usedMB + " MB");
                         }
-                    } catch (e) {}
+                    } catch (e) { }
                 },
                 error: function (err) {
-                    logDebug("[璇锋眰澶辫触] " + (err.statusText || "缃戠粶閿欒"));
+                    logDebug("[璇锋眰澶辫触] status=" + err.status + " " + (err.statusText || "缃戠粶閿欒") + " url=" + url);
                 }
             });
         }
 
         // ================= 鍒濆鍖� =================
         function onReady() {
-            renderMainContent();
+            logDebug("[鍒濆鍖朷 onReady 寮�濮�");
+            logDebug("[鐜] speechSynthesis=" + (typeof window.speechSynthesis !== 'undefined') + " wowjoy=" + (typeof wowjoy !== 'undefined'));
+            try {
+                initLayout();
+                logDebug("[鍒濆鍖朷 initLayout 瀹屾垚");
+            } catch (e) { logDebug("[鍒濆鍖朷 initLayout 寮傚父: " + e.message); }
             updateHeaderTime();
             setInterval(updateHeaderTime, 1000);
-            fetchQueueData();
+            try {
+                fetchQueueData();
+                logDebug("[鍒濆鍖朷 棣栨 fetchQueueData 宸插彂璧�");
+            } catch (e) { logDebug("[鍒濆鍖朷 fetchQueueData 寮傚父: " + e.message); }
             appState.pollTimer = setInterval(fetchQueueData, 5000);
-            logDebug("[绯荤粺] 鍚姩瀹屾垚 - Android 6.0.1");
+            logDebug("[绯荤粺] 鍚姩瀹屾垚 - Android 6.0.1 杞闂撮殧5s");
         }
 
         function updateHeaderTime() {
             var now = new Date();
             var weekDays = ["鏄熸湡鏃�", "鏄熸湡涓�", "鏄熸湡浜�", "鏄熸湡涓�", "鏄熸湡鍥�", "鏄熸湡浜�", "鏄熸湡鍏�"];
             function padZero(num) { return num < 10 ? '0' + num : '' + num; }
-            var dateStr = now.getFullYear() + "骞�" + padZero(now.getMonth() + 1) + "鏈�" + padZero(now.getDate()) + "鏃� " + weekDays[now.getDay()];
+            var dateStr = now.getFullYear() + "骞�" + padZero(now.getMonth() + 1) + "鏈�" + padZero(now.getDate()) + "鏃�";
+            var weekStr = weekDays[now.getDay()];
             var timeStr = padZero(now.getHours()) + ":" + padZero(now.getMinutes());
             var el = document.getElementById("headerTime");
-            if (el) el.textContent = dateStr + " " + timeStr;
+            // 鏄熸湡鍜屾棩鏈熷悇鍗犱竴琛屽湪宸︼紝鏃堕棿澶у瓧鍦ㄥ彸璺ㄤ袱琛�
+            if (el) el.innerHTML = '<div class="time-info-inner"><div class="time-left"><div>' + weekStr + '</div><div>' + dateStr + '</div></div><div class="time-right"><span class="time-clock">' + timeStr + '</span></div></div>';
         }
 
         // 鍏煎 DOM ready锛圓ndroid 6 鏌愪簺 WebView 鍙兘娌℃湁 $锛�
+        logDebug("[鍏ュ彛] readyState=" + document.readyState + " jQuery=" + (typeof $ !== 'undefined'));
         if (typeof $ !== 'undefined') {
+            logDebug("[鍏ュ彛] 浣跨敤 jQuery.ready");
             $(document).ready(onReady);
         } else if (document.readyState === 'complete' || document.readyState === 'interactive') {
+            logDebug("[鍏ュ彛] DOM宸插氨缁�, setTimeout瑙﹀彂");
             setTimeout(onReady, 1);
         } else {
+            logDebug("[鍏ュ彛] 鐩戝惉 DOMContentLoaded");
             document.addEventListener('DOMContentLoaded', onReady);
         }
     </script>
 </body>
 
-</html>
+</html>
\ No newline at end of file
diff --git a/big.html.bak b/big.html.bak
deleted file mode 100644
index 871e128..0000000
--- a/big.html.bak
+++ /dev/null
@@ -1,472 +0,0 @@
-<!doctype html>
-<html lang="zh-CN">
-
-<head>
-    <meta charset="UTF-8" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
-    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
-    <title>澶у巺</title>
-    <style>
-        * {
-            margin: 0;
-            padding: 0;
-            box-sizing: border-box;
-            font-family: "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
-        }
-
-        /* 1. 鍏ㄥ眬娣辫壊鑳屾櫙 */
-        body {
-            background: #001f3f;
-            /* 娣辫摑鑹茶儗鏅紝閫傚悎澶у睆 */
-            color: #fff;
-            height: 100vh;
-            overflow: hidden;
-            display: flex;
-            flex-direction: column;
-            font-size: 14px;
-        }
-
-        /* 2. 椤堕儴鏍� - 绠�鍖栬竟妗嗭紝娣辫壊涓婚 */
-        .top-header {
-            display: flex;
-            align-items: center;
-            padding: 15px 30px;
-            background: rgba(0, 30, 60, 0.9);
-            /* 娣辫壊鍗婇�忔槑 */
-            white-space: nowrap;
-            position: relative;
-            border-bottom: 1px solid #003366;
-        }
-
-        .top-header img {
-            height: 50px;
-            margin-right: 20px;
-            z-index: 2;
-        }
-
-        .top-header .title-text {
-            position: absolute;
-            left: 50%;
-            transform: translateX(-50%);
-            font-size: 32px;
-            font-weight: bold;
-            color: #fff;
-            z-index: 1;
-        }
-
-        .top-header .time-info {
-            font-size: 24px;
-            color: #aaa;
-            margin-left: auto;
-            z-index: 2;
-        }
-
-        /* 3. 涓讳綋鍐呭 */
-        .main-content {
-            flex: 1;
-            display: flex;
-            padding: 15px 20px;
-            overflow: hidden;
-            gap: 10px;
-        }
-
-        /* 鍒楀鍣� - 绉婚櫎闃村奖鍜屽渾瑙掞紝鏇寸畝娲� */
-        .column-box {
-            display: flex;
-            flex-direction: column;
-            background: rgba(10, 40, 80, 0.5);
-            /* 娣辫壊鍗婇�忔槑鑳屾櫙 */
-            border-radius: 0;
-            padding: 10px;
-            flex: 1;
-            min-width: 0;
-            border: 1px solid #003366;
-        }
-
-        .column-box.col-wide {
-            flex: 2.5;
-        }
-
-        .column-box.col-normal {
-            flex: 1;
-        }
-
-        /* 鏍囬鏍峰紡 - 绠�鍖栦笅鍒掔嚎 */
-        .col-title {
-            font-size: 22px;
-            font-weight: bold;
-            color: #4da6ff;
-            padding-bottom: 8px;
-            border-bottom: 1px solid #003366;
-            margin-bottom: 10px;
-            text-align: center;
-        }
-
-        .col-subtitle {
-            font-size: 14px;
-            color: #999;
-            text-align: center;
-        }
-
-        /* 鎮h�呭垪琛� */
-        .patient-list {
-            flex: 1;
-            overflow-y: auto;
-            padding-right: 5px;
-        }
-
-        /* 銆愬叧閿慨鏀广�戠1鏍忓己鍒朵竴琛�2涓� */
-        #col-0 {
-            display: flex;
-            flex-wrap: wrap;
-            align-content: flex-start;
-        }
-
-        /* 绗�2-5鏍忎繚鎸佸崟鍒� */
-        .col-normal .patient-list {
-            display: flex;
-            flex-direction: column;
-        }
-
-        /* 4. 鎮h�呴」鐩� - 鏋佺畝妯″紡 */
-        .patient-item {
-            font-size: 22px;
-            padding: 8px 5px;
-            display: flex;
-            align-items: center;
-            color: #fff;
-            line-height: 1.4;
-        }
-
-        /* 銆愪紭鍖栦慨鏀广�戠1鏍忥細澧炲姞鍒楅棿璺濓紝鏀瑰杽鎷ユ尋鎰� */
-        #col-0 .patient-item {
-            width: 45%;
-            /* 1. 缂╁噺瀹藉害锛屼负闂撮殧鐣欏嚭绌洪棿 */
-            font-size: 20px;
-            margin: 0 2.5%;
-            /* 2. 娣诲姞宸﹀彸澶栬竟璺濓紝涓ゅ垪涔嬮棿鎬婚棿闅斾负5% */
-        }
-
-        .p-number {
-            color: #ffcc00;
-            font-weight: bold;
-            margin-right: 8px;
-        }
-
-        .p-name {
-            flex: 1;
-            overflow: hidden;
-            text-overflow: ellipsis;
-            white-space: nowrap;
-        }
-
-        .p-room {
-            color: #4da6ff;
-            font-weight: bold;
-            font-size: 18px;
-            margin-left: 5px;
-        }
-
-        /* 5. 搴曢儴鏍� - 灞呬腑鏄剧ず */
-        .bottom-footer {
-            display: flex;
-            justify-content: center;
-            /* 灞呬腑 */
-            align-items: center;
-            padding: 10px 30px;
-            background: rgba(0, 30, 60, 0.9);
-            border-top: 1px solid #003366;
-        }
-
-        .footer-tip {
-            font-size: 22px;
-            color: #ffcc00;
-            font-weight: bold;
-            text-align: center;
-        }
-
-        /* 婊氬姩鏉$編鍖� - 缁嗕竴鐐� */
-        .patient-list::-webkit-scrollbar {
-            width: 4px;
-        }
-
-        .patient-list::-webkit-scrollbar-thumb {
-            background: #444;
-            border-radius: 2px;
-        }
-
-        /* 6. 璋冭瘯妗嗘牱寮� */
-        .debug-panel {
-            position: fixed;
-            right: 15px;
-            bottom: 70px;
-            width: 350px;
-            height: 200px;
-            background: rgba(0, 0, 0, 0.9);
-            color: #0f0;
-            border-radius: 4px;
-            font-family: monospace;
-            font-size: 12px;
-            z-index: 9999;
-            overflow: hidden;
-        }
-
-        .debug-header {
-            display: flex;
-            justify-content: space-between;
-            align-items: center;
-            padding: 5px;
-            background: #333;
-            border-bottom: 1px solid #000;
-        }
-
-        .debug-header span {
-            font-weight: bold;
-            font-size: 13px;
-        }
-
-        .debug-header button {
-            background: #c00;
-            color: #fff;
-            border: none;
-            padding: 2px 6px;
-            font-size: 10px;
-            cursor: pointer;
-        }
-
-        .debug-body {
-            flex: 1;
-            padding: 5px;
-            overflow-y: auto;
-            font-size: 11px;
-        }
-
-        .debug-line {
-            margin-bottom: 2px;
-        }
-
-        .debug-time {
-            color: #888;
-        }
-    </style>
-</head>
-
-<body>
-    <!-- 椤堕儴鏍� -->
-    <div class="top-header">
-        <img src="logo.png" alt="logo" />
-        <span class="title-text">鏈嶅姟澶у巺鎺掑垪</span>
-        <span class="time-info" id="headerTime"></span>
-    </div>
-
-    <!-- 涓讳綋鍐呭 -->
-    <div class="main-content" id="mainContent"></div>
-
-    <!-- 搴曢儴鏍� -->
-    <div class="bottom-footer">
-        <!-- 娓╅Θ鎻愮ず璇眳涓� -->
-        <div class="footer-tip">娓╅Θ鎻愮ず锛氳鍚埌鍛煎彨鍚庡墠寰�瀵瑰簲璇婂</div>
-    </div>
-
-    <!-- 璋冭瘯闈㈡澘 -->
-    <div class="debug-panel" id="debugPanel">
-        <div class="debug-header">
-            <span>馃洜锔� 杩愯鏃ュ織</span>
-            <button onclick="document.getElementById('debugBody').innerHTML=''">娓呯┖</button>
-        </div>
-        <div class="debug-body" id="debugBody"></div>
-    </div>
-
-    <script src="./static/jquery.min.js"></script>
-    <script>
-        // ================= 璋冭瘯鏃ュ織鍑芥暟 =================
-        function logDebug(msg) {
-            var now = new Date();
-            var timeStr = now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
-            var logHtml = '<div class="debug-line"><span class="debug-time">[' + timeStr + ']</span>' + msg + '</div>';
-            console.log("[" + timeStr + "] " + msg);
-            var $body = $("#debugBody");
-            $body.append(logHtml);
-            $body.scrollTop($body[0].scrollHeight);
-        }
-
-        // ================= 搴旂敤鐘舵�� =================
-        var appState = {
-            columnTitles: ["甯歌蹇冪數鍥�", "鍔ㄦ�佸績鐢�", "骞虫澘杩愬姩蹇冪數", "椋熼亾鐢电敓鐞�", "鍔ㄨ剦纭寲鐩戞祴"],
-            columnSubTitles: ["搴婅竟蹇冪數鍥�(甯歌+棰戣氨)M / 蹇冪數鍚戦噺鍥綨", "鍔ㄦ�佽鍘婥", "", "", ""],
-            patients: [],
-            apiBaseUrl: "http://192.168.100.110/admin-api",
-            pollTimer: null,
-            callRepeatTimes: 2,
-            spokenPatients: {},
-            ttsQueue: [],
-            isSpeaking: false
-        };
-
-        // ================= 璇煶鎾姤 =================
-        function processTtsQueue() {
-            if (appState.isSpeaking || appState.ttsQueue.length === 0) return;
-            appState.isSpeaking = true;
-            var text = appState.ttsQueue.shift();
-            logDebug("馃攰 寮�濮嬫挱鎶�: " + text);
-
-            var utterance = new SpeechSynthesisUtterance(text);
-            utterance.onend = function () {
-                appState.isSpeaking = false;
-                processTtsQueue();
-            };
-            utterance.onerror = function () {
-                appState.isSpeaking = false;
-                processTtsQueue();
-            };
-
-            if (typeof wowjoy !== 'undefined' && typeof wowjoy.speek === 'function') {
-                try {
-                    wowjoy.speek(text);
-                    setTimeout(function () { appState.isSpeaking = false; processTtsQueue(); }, 4000);
-                    return;
-                } catch (e) { logDebug("鉂� wowjoy 璋冪敤澶辫触: " + e.message); }
-            }
-
-            if (window.speechSynthesis) { window.speechSynthesis.speak(utterance); }
-            else { appState.isSpeaking = false; processTtsQueue(); }
-        }
-
-        function speak(text) {
-            if (!text) return;
-            appState.ttsQueue.push(text);
-            processTtsQueue();
-        }
-
-        // ================= 娓叉煋鍑芥暟 =================
-        function renderMainContent() {
-            var $main = $("#mainContent");
-            $main.empty();
-
-            for (var i = 0; i < appState.columnTitles.length; i++) {
-                var titleHtml = '<div class="col-title-line">' + appState.columnTitles[i] + '</div>';
-                if (appState.columnSubTitles[i]) {
-                    titleHtml += '<div class="col-subtitle">' + appState.columnSubTitles[i] + '</div>';
-                }
-
-                var colClass = (i === 0) ? 'col-wide' : 'col-normal';
-                // 娉ㄦ剰锛氳繖閲屼笉鍐嶇粰绗�1鏍忓姞 col-flex锛岀敱 CSS #col-0 寮哄埗鎺у埗
-                var colHtml = '<div class="column-box ' + colClass + '">' +
-                    '<div class="col-title">' + titleHtml + '</div>' +
-                    '<div class="patient-list" id="col-' + i + '"></div>' +
-                    '</div>';
-                $main.append(colHtml);
-            }
-        }
-
-        function renderPatients() {
-            for (var i = 0; i < appState.columnTitles.length; i++) {
-                $("#col-" + i).empty();
-            }
-
-            for (var c = 0; c < appState.patients.length; c++) {
-                var colData = appState.patients[c];
-                if (Array.isArray(colData)) {
-                    var $col = $("#col-" + c);
-                    for (var p = 0; p < colData.length; p++) {
-                        var pat = colData[p];
-                        var roomHtml = pat.roomName ? '<span class="p-room">(' + pat.roomName + ')</span>' : '';
-                        var itemHtml = '<div class="patient-item">' +
-                            '<span class="p-number">' + (pat.bookSeqNum || '') + '</span>' +
-                            '<span class="p-name">' + (pat.patName || '') + '</span>' +
-                            roomHtml +
-                            '</div>';
-                        $col.append(itemHtml);
-                    }
-                }
-            }
-        }
-
-        // ================= 鏁版嵁瀵规瘮涓庢挱鎶� =================
-        function checkAndSpeakNewRooms(oldData, newData) {
-            if (!oldData || oldData.length === 0) return;
-            for (var c = 0; c < newData.length; c++) {
-                var newCol = newData[c];
-                var oldCol = oldData[c];
-                if (Array.isArray(newCol)) {
-                    for (var p = 0; p < newCol.length; p++) {
-                        var newPat = newCol[p];
-                        if (newPat.roomName) {
-                            if (appState.spokenPatients[newPat.patId]) continue;
-                            var oldPat = null;
-                            if (Array.isArray(oldCol)) {
-                                for (var k = 0; k < oldCol.length; k++) {
-                                    if (oldCol[k].patId === newPat.patId) {
-                                        oldPat = oldCol[k];
-                                        break;
-                                    }
-                                }
-                            }
-                            if (!oldPat || !oldPat.roomName) {
-                                var repeatText = "";
-                                for (var r = 0; r < appState.callRepeatTimes; r++) {
-                                    repeatText += "璇� " + newPat.bookSeqNum + " 鍙� " + newPat.patName + " 鍒� " + newPat.roomName + " 灏辫瘖銆�";
-                                }
-                                speak(repeatText);
-                                appState.spokenPatients[newPat.patId] = true;
-                                logDebug("馃敂 鍔犲叆鎾姤闃熷垪: " + newPat.patName);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        // ================= 鏁版嵁鑾峰彇 =================
-        function fetchQueueData() {
-            var url = appState.apiBaseUrl + "/ecg/screen/big-screen-data";
-            $.ajax({
-                url: url,
-                type: "GET",
-                dataType: "json",
-                timeout: 5000,
-                success: function (res) {
-                    var dataList = [];
-                    if (res && res.code === 0 && res.data) {
-                        for (var i = 0; i < appState.columnTitles.length; i++) {
-                            var key = i.toString();
-                            dataList[i] = (res.data[key] && Array.isArray(res.data[key])) ? res.data[key] : [];
-                        }
-                    }
-                    checkAndSpeakNewRooms(appState.patients, dataList);
-                    appState.patients = dataList;
-                    renderPatients();
-
-                    if (window.performance && window.performance.memory) {
-                        var usedMB = (window.performance.memory.usedJSHeapSize / 1048576).toFixed(2);
-                        logDebug("馃捑 鍐呭瓨: " + usedMB + " MB");
-                    }
-                },
-                error: function (err) {
-                    logDebug("鉂� 璇锋眰澶辫触: " + err.statusText);
-                }
-            });
-        }
-
-        // ================= 鍒濆鍖� =================
-        $(document).ready(function () {
-            renderMainContent();
-            updateHeaderTime();
-            setInterval(updateHeaderTime, 1000);
-            fetchQueueData();
-            appState.pollTimer = setInterval(fetchQueueData, 5000);
-            logDebug("鉁� 绯荤粺鍚姩");
-        });
-
-        function updateHeaderTime() {
-            var now = new Date();
-            var weekDays = ["鏄熸湡鏃�", "鏄熸湡涓�", "鏄熸湡浜�", "鏄熸湡涓�", "鏄熸湡鍥�", "鏄熸湡浜�", "鏄熸湡鍏�"];
-            function padZero(num) { return num < 10 ? '0' + num : '' + num; }
-            var dateStr = now.getFullYear() + "骞�" + padZero(now.getMonth() + 1) + "鏈�" + padZero(now.getDate()) + "鏃� " + weekDays[now.getDay()];
-            var timeStr = padZero(now.getHours()) + ":" + padZero(now.getMinutes());
-            $("#headerTime").text(dateStr + " " + timeStr);
-        }
-    </script>
-</body>
-
-</html>
\ No newline at end of file
diff --git a/big1.html b/big1.html
new file mode 100644
index 0000000..848b08d
--- /dev/null
+++ b/big1.html
@@ -0,0 +1,680 @@
+锘�<!doctype html>
+<html lang="zh-CN">
+
+<head>
+    <meta charset="UTF-8" />
+    <meta name="viewport"
+        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+    <title>澶у巺</title>
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+            /* Android 6 鍙敤涓枃瀛椾綋 */
+            ;
+            font-family: "Droid Sans Fallback", "Noto Sans CJK SC", "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
+        }
+
+        /* 1. 鍏ㄥ眬娣辫壊鑳屾櫙 */
+        body {
+            background: #001f3f;
+            color: #fff;
+            height: 100vh;
+            overflow: hidden;
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-orient: vertical;
+            -webkit-box-direction: normal;
+            -webkit-flex-direction: column;
+            flex-direction: column;
+            font-size: 14px;
+        }
+
+        /* 2. 椤堕儴鏍� */
+        .top-header {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-align: center;
+            -webkit-align-items: center;
+            align-items: center;
+            padding: 15px 30px;
+            background: rgba(0, 30, 60, 0.9);
+            white-space: nowrap;
+            position: relative;
+            border-bottom: 1px solid #003366;
+        }
+
+        .top-header img {
+            height: 50px;
+            margin-right: 20px;
+            z-index: 2;
+        }
+
+        .top-header .title-text {
+            position: absolute;
+            left: 50%;
+            -webkit-transform: translateX(-50%);
+            transform: translateX(-50%);
+            font-size: 32px;
+            font-weight: bold;
+            color: #fff;
+            z-index: 1;
+        }
+
+        .top-header .time-info {
+            font-size: 20px;
+            color: #aaa;
+            margin-left: auto;
+            z-index: 2;
+            text-align: right;
+            line-height: 1.3;
+        }
+
+        .time-info-inner {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-align: center;
+            -webkit-align-items: center;
+            align-items: center;
+        }
+
+        .time-left {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-orient: vertical;
+            -webkit-flex-direction: column;
+            flex-direction: column;
+            text-align: right;
+            line-height: 1.3;
+        }
+
+        .time-right {
+            margin-left: 8px;
+        }
+
+        .top-header .time-info .time-clock {
+            font-size: 36px;
+            font-weight: bold;
+            color: #ffcc00;
+            line-height: 1.1;
+        }
+
+        /* 3. 涓讳綋鍐呭锛坓ap 鏇挎崲涓� margin 鍏煎鏃� Chrome锛� */
+        .main-content {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-orient: vertical;
+            -webkit-box-direction: normal;
+            -webkit-flex-direction: column;
+            flex-direction: column;
+            padding: 15px 20px;
+            overflow: hidden;
+        }
+
+        /* 鍒楄瀹瑰櫒 */
+        .columns-row {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            overflow: hidden;
+        }
+
+        .columns-row>.column-box {
+            margin-left: 5px;
+            margin-right: 5px;
+        }
+
+        .columns-row>.column-box:first-child {
+            margin-left: 0;
+        }
+
+        .columns-row>.column-box:last-child {
+            margin-right: 0;
+        }
+
+        /* 鍒楀鍣� */
+        .column-box {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-orient: vertical;
+            -webkit-box-direction: normal;
+            -webkit-flex-direction: column;
+            flex-direction: column;
+            background: rgba(10, 40, 80, 0.5);
+            border-radius: 0;
+            padding: 10px;
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            min-width: 0;
+            border: 1px solid #003366;
+        }
+
+        .column-box.col-wide {
+            -webkit-box-flex: 2.5;
+            -webkit-flex: 2.5;
+            flex: 2.5;
+        }
+
+        .column-box.col-normal {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+        }
+
+        /* 鏍囬琛� */
+        .col-title-line {
+            font-size: 22px;
+            font-weight: bold;
+            color: #4da6ff;
+            text-align: center;
+        }
+
+        .col-title {
+            padding-bottom: 8px;
+            border-bottom: 1px solid #003366;
+            margin-bottom: 10px;
+            text-align: center;
+        }
+
+        .col-subtitle {
+            font-size: 14px;
+            color: #999;
+            text-align: center;
+            min-height: 20px;
+            /* 鍗充娇涓虹┖涔熶繚鐣欓珮搴︼紝闃叉鏍囬鏍忛珮浣庝笉骞� */
+            ;
+            line-height: 1.4;
+            word-break: keep-all;
+        }
+
+        /* 鎮h�呭垪琛� */
+        .patient-list {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            overflow-y: auto;
+            padding-right: 5px;
+        }
+
+        /* 绗�1鏍忥細涓�琛屼袱涓� */
+        #col-0 {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-flex-wrap: wrap;
+            flex-wrap: wrap;
+            -webkit-align-content: flex-start;
+            align-content: flex-start;
+        }
+
+        .col-normal .patient-list {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-orient: vertical;
+            -webkit-box-direction: normal;
+            -webkit-flex-direction: column;
+            flex-direction: column;
+        }
+
+        /* 鎮h�呴」鐩� */
+        .patient-item {
+            font-size: 22px;
+            padding: 8px 5px;
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-align: center;
+            -webkit-align-items: center;
+            align-items: center;
+            color: #fff;
+            line-height: 1.4;
+        }
+
+        #col-0 .patient-item {
+            width: 45%;
+            font-size: 20px;
+            margin: 0 2.5%;
+        }
+
+        .p-number {
+            color: #ffcc00;
+            font-weight: bold;
+            margin-right: 8px;
+        }
+
+        .p-name {
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+        }
+
+        .p-name-wrap {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+        }
+
+        .p-room {
+            color: #4da6ff;
+            font-weight: bold;
+            font-size: 18px;
+            margin-left: 4px;
+        }
+
+        /* 杩囧彿鎮h�咃細鎺掑湪鍒楀唴锛岃瑙夊急鍖� */
+        .patient-item.missed {
+            color: #aa8888;
+        }
+
+        .patient-item.missed .p-number {
+            color: #cc9966;
+        }
+
+        .patient-item.missed .p-missed-tag {
+            color: #ff6666;
+            font-size: 16px;
+            margin-left: 4px;
+            -webkit-flex-shrink: 0;
+            flex-shrink: 0;
+        }
+
+        /* 搴曢儴鏍� */
+        .bottom-footer {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-pack: center;
+            -webkit-justify-content: center;
+            justify-content: center;
+            -webkit-box-align: center;
+            -webkit-align-items: center;
+            align-items: center;
+            padding: 10px 30px;
+            background: rgba(0, 30, 60, 0.9);
+            border-top: 1px solid #003366;
+        }
+
+        .footer-tip {
+            font-size: 22px;
+            color: #ffcc00;
+            font-weight: bold;
+            text-align: center;
+        }
+
+        /* 婊氬姩鏉� */
+        .patient-list::-webkit-scrollbar {
+            width: 4px;
+        }
+
+        .patient-list::-webkit-scrollbar-thumb {
+            background: #444;
+            border-radius: 2px;
+        }
+
+        /* 璋冭瘯闈㈡澘 */
+        .debug-panel {
+            display: none; /* 闇�瑕佽皟璇曟椂鍒犳帀姝よ鍗冲彲鏄剧ず */
+            position: fixed;
+            right: 15px;
+            bottom: 70px;
+            width: 350px;
+            height: 200px;
+            background: rgba(0, 0, 0, 0.9);
+            color: #0f0;
+            border-radius: 4px;
+            font-family: monospace;
+            font-size: 12px;
+            z-index: 9999;
+            overflow: visible;
+        }
+
+        .debug-header {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-pack: justify;
+            -webkit-justify-content: space-between;
+            justify-content: space-between;
+            -webkit-box-align: center;
+            -webkit-align-items: center;
+            align-items: center;
+            padding: 5px;
+            background: #333;
+            border-bottom: 1px solid #000;
+        }
+
+        .debug-header span {
+            font-weight: bold;
+            font-size: 13px;
+        }
+
+        .debug-header button {
+            background: #c00;
+            color: #fff;
+            border: none;
+            padding: 2px 6px;
+            font-size: 10px;
+            cursor: pointer;
+        }
+
+        .debug-body {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            padding: 5px;
+            overflow-y: auto;
+            font-size: 11px;
+        }
+
+        .debug-line {
+            margin-bottom: 2px;
+        }
+
+        .debug-time {
+            color: #888;
+        }
+    </style>
+</head>
+
+<body>
+    <!-- 椤堕儴鏍� -->
+    <div class="top-header">
+        <img src="logo.png" alt="logo" />
+        <span class="title-text">蹇冪數妫�鏌ユ湇鍔¤瘖鍖哄ぇ鍘�</span>
+        <span class="time-info" id="headerTime"></span>
+    </div>
+
+    <!-- 涓讳綋鍐呭 -->
+    <div class="main-content" id="mainContent"></div>
+
+    <!-- 搴曢儴鏍� -->
+    <div class="bottom-footer">
+        <div class="footer-tip">娓╅Θ鎻愮ず锛氬惉鍒板懠鍙悗璇峰墠寰�瀵瑰簲璇婂锛岃繃鍙锋偅鑰呭埌瀵艰瘖鍙板鐞嗭紒</div>
+    </div>
+
+    <!-- 璋冭瘯闈㈡澘 -->
+    <div class="debug-panel" id="debugPanel" >
+        <div class="debug-header">
+            <span>[璋冭瘯] 杩愯鏃ュ織</span>
+            <button onclick="document.getElementById('debugBody').innerHTML=''">娓呯┖</button>
+        </div>
+        <div class="debug-body" id="debugBody"></div>
+    </div>
+
+    <script src="./static/jquery.min.js"></script>
+    <script>
+        // ================= 璋冭瘯鏃ュ織 =================
+        function logDebug(msg) {
+            var now = new Date();
+            function pad(num) { return num < 10 ? '0' + num : '' + num; }
+            var timeStr = pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds());
+            var logHtml = '<div class="debug-line"><span class="debug-time">[' + timeStr + ']</span> ' + msg + '</div>';
+            console.log("[" + timeStr + "] " + msg);
+            var body = document.getElementById("debugBody");
+            if (body) {
+                body.insertAdjacentHTML("beforeend", logHtml);
+                body.scrollTop = body.scrollHeight;
+            }
+        }
+
+        // ================= 搴旂敤鐘舵�� =================
+        // 鍛煎彨鍙彿娆℃暟鍙傛暟锛氬懠鍙偅鑰呭氨璇婃椂閲嶅鎾姤鐨勬鏁帮紝榛樿 2 娆�
+        var CALL_REPEAT_TIMES = 2;
+        var appState = {
+            columnTitles: ["甯歌蹇冪數鍥�", "鍔ㄦ�佸績鐢靛浘/琛�鍘�", "蹇冪數鍥捐繍鍔ㄨ瘯楠�", "椋熼亾鐢电敓鐞�", "鍔ㄨ剦纭寲鐩戞祴"],
+            columnSubTitles: ["搴婅竟蹇冪數鍥�(甯歌+棰戣氨) / 蹇冪數鍚戦噺鍥�", "", "", "", ""],
+            patients: [],
+            apiBaseUrl: "http://localhost/admin-api",
+            // apiBaseUrl: "http://10.0.2.193/admin-api",
+            pollTimer: null,
+            spokenPatients: {},
+            ttsQueue: [],
+            isSpeaking: false,
+        };
+
+        var patStatus = {
+            3: "宸茶繃鍙�-鎺掗槦", 5: "宸茶繃鍙�", 7: "宸茶繃鍙�-瀹夎", 10: "鎺掗槦涓�", 12: "浜插拰",
+            13: "浜插拰-瀹夎", 15: "宸插彫鍥�", 20: "鍊欒瘖涓�", 30: "灏辫瘖涓�", 33: "宸查鐢�",
+            34: "宸插彫鍥�-瀹夎", 36: "瀹夎涓�", 40: "宸插氨璇�"
+        };
+
+        // ================= 璇煶鎾姤 =================
+        function processTtsQueue() {
+            if (appState.isSpeaking || appState.ttsQueue.length === 0) return;
+            appState.isSpeaking = true;
+            var text = appState.ttsQueue.shift();
+            logDebug("[鎾姤] " + text);
+
+            var utterance = new SpeechSynthesisUtterance(text);
+            // Android 6 榛樿璇�熷彲鑳藉緢蹇紝閫傚綋璋冩參
+            utterance.rate = 0.85;
+            utterance.onend = function () {
+                appState.isSpeaking = false;
+                processTtsQueue();
+            };
+            utterance.onerror = function (e) {
+                logDebug("[TTS閿欒] " + (e.error || "unknown"));
+                appState.isSpeaking = false;
+                processTtsQueue();
+            };
+
+            // 浼樺厛灏濊瘯璁惧鍘熺敓 TTS 鎺ュ彛
+            if (typeof wowjoy !== 'undefined' && typeof wowjoy.speek === 'function') {
+                try {
+                    wowjoy.speek(text);
+                    setTimeout(function () { appState.isSpeaking = false; processTtsQueue(); }, 4000);
+                    return;
+                } catch (e) { logDebug("[wowjoy澶辫触] " + e.message); }
+            }
+
+            if (window.speechSynthesis) {
+                // Android 6 WebView 鏈夋椂闇�瑕佸厛 cancel 鍐� speak
+                window.speechSynthesis.cancel();
+                window.speechSynthesis.speak(utterance);
+            } else {
+                logDebug("[TTS] 娴忚鍣ㄤ笉鏀寔璇煶鍚堟垚");
+                appState.isSpeaking = false;
+                processTtsQueue();
+            }
+        }
+
+        function speak(text) {
+            if (!text) return;
+            appState.ttsQueue.push(text);
+            processTtsQueue();
+        }
+
+        // ================= 娓叉煋锛氭爣棰樻鏋讹紙浠呭垵濮嬪寲涓�娆★級=================
+        function initLayout() {
+            var main = document.getElementById("mainContent");
+            var html = '<div class="columns-row">';
+
+            for (var i = 0; i < appState.columnTitles.length; i++) {
+                // 鏍囬鍜屽壇鏍囬閮芥湁鍥哄畾鍗犱綅锛岄伩鍏嶆湁/鏃犲壇鏍囬鏃堕珮搴﹁烦鍔�
+                var subtitle = appState.columnSubTitles[i] || "&nbsp;";
+                var colClass = (i === 0) ? 'col-wide' : 'col-normal';
+                html += '<div class="column-box ' + colClass + '">' +
+                    '<div class="col-title">' +
+                    '<div class="col-title-line">' + appState.columnTitles[i] + '</div>' +
+                    '<div class="col-subtitle">' + subtitle + '</div>' +
+                    '</div>' +
+                    '<div class="patient-list" id="col-' + i + '"></div>' +
+                    '</div>';
+            }
+            html += '</div>';
+            main.innerHTML = html;
+        }
+
+        // ================= 娓叉煋锛氭偅鑰呭垪琛紙diff 鏇存柊锛屽彧鏀瑰彉鍖栫殑鍒楋級=================
+        function desensitizeName(name) {
+            if (!name || name.length < 2) return name || '';
+            return name.charAt(0) + '*' + name.substring(2);
+        }
+
+        function isMissedStatus(status) {
+            var s = parseInt(status, 10);
+            return s === 3 || s === 5 || s === 7;
+        }
+
+        function buildColumnHtml(colData) {
+            if (!Array.isArray(colData) || colData.length === 0) return "";
+            var h = "";
+            for (var p = 0; p < colData.length; p++) {
+                var pat = colData[p];
+                var missedClass = isMissedStatus(pat.status) ? ' missed' : '';
+                var roomHtml = (!isMissedStatus(pat.status) && pat.roomName) ? '<span class="p-room">(' + pat.roomName + ')</span>' : '';
+                h += '<div class="patient-item' + missedClass + '">' +
+                    '<span class="p-number">' + (pat.seqNum || '') + '</span>' +
+                    '<span class="p-name-wrap"><span class="p-name">' + desensitizeName(pat.patName) + '</span>' + roomHtml +
+                    (missedClass ? '<span class="p-missed-tag">锛堣繃鍙凤級</span>' : '') + '</span>' +
+                    '</div>';
+            }
+            return h;
+        }
+        function isSameColumn(a, b) {
+            if (!Array.isArray(a) || !Array.isArray(b)) return a === b;
+            if (a.length !== b.length) return false;
+            for (var i = 0; i < a.length; i++) {
+                if (a[i].patId !== b[i].patId) return false;
+                if (a[i].roomName !== b[i].roomName) return false;
+                if (parseInt(a[i].status, 10) !== parseInt(b[i].status, 10)) return false;
+            }
+            return true;
+        }
+
+        function updatePatients(dataList) {
+            for (var i = 0; i < appState.columnTitles.length; i++) {
+                var newData = (dataList && dataList[i]) ? dataList[i] : [];
+                var oldData = appState.patients[i];
+
+                // diff锛氭暟鎹湭鍙樺寲鍒欒烦杩囪鍒� DOM 鎿嶄綔
+                if (isSameColumn(oldData, newData)) continue;
+
+                var col = document.getElementById("col-" + i);
+                if (col) col.innerHTML = buildColumnHtml(newData);
+            }
+        }
+
+        // ================= 鏁版嵁瀵规瘮涓庢挱鎶� =================
+        function checkAndSpeakNewRooms(oldData, newData) {
+            if (!oldData || oldData.length === 0) return;
+            for (var c = 0; c < newData.length; c++) {
+                var newCol = newData[c];
+                var oldCol = oldData[c];
+                if (Array.isArray(newCol)) {
+                    for (var p = 0; p < newCol.length; p++) {
+                        var newPat = newCol[p];
+                        if (newPat.roomName) {
+                            if (appState.spokenPatients[newPat.patId]) continue;
+                            var oldPat = null;
+                            if (Array.isArray(oldCol)) {
+                                for (var k = 0; k < oldCol.length; k++) {
+                                    if (oldCol[k].patId === newPat.patId) {
+                                        oldPat = oldCol[k];
+                                        break;
+                                    }
+                                }
+                            }
+                            if (!oldPat || !oldPat.roomName) {
+                                var repeatText = "";
+                                repeatText += "璇� " + newPat.seqNum + " 鍙� " + newPat.patName + " 鍒� " + newPat.roomName + " 灏辫瘖銆�";
+                                for (var r = 0; r < CALL_REPEAT_TIMES; r++) {
+                                    speak(repeatText);
+                                }                                
+                                appState.spokenPatients[newPat.patId] = true;
+                                logDebug("[鎺掗槦] " + newPat.patName + " -> " + newPat.roomName);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // ================= 鏁版嵁鑾峰彇 =================
+        function fetchQueueData() {
+            var url = appState.apiBaseUrl + "/ecg/screen/big-screen-data";
+            $.ajax({
+                url: url,
+                type: "GET",
+                dataType: "json",
+                timeout: 5000,
+                success: function (res) {
+                    var dataList = [];
+                    if (res && res.code === 0 && res.data) {
+                        for (var i = 0; i < appState.columnTitles.length; i++) {
+                            var key = i.toString();
+                            dataList[i] = (res.data[key] && Array.isArray(res.data[key])) ? res.data[key] : [];
+                        }
+                    }
+                    // 鍏� diff 鏇存柊 DOM锛屽啀鎾姤锛屾渶鍚庝繚瀛樻暟鎹敤浜庝笅娆″姣�
+                    updatePatients(dataList);
+                    checkAndSpeakNewRooms(appState.patients, dataList);
+                    appState.patients = dataList;
+
+                    // Android 6 WebView 閫氬父涓嶆敮鎸� performance.memory锛屽畨鍏ㄥ畧鍗�
+                    try {
+                        if (window.performance && window.performance.memory) {
+                            var usedMB = (window.performance.memory.usedJSHeapSize / 1048576).toFixed(2);
+                            logDebug("[鍐呭瓨] " + usedMB + " MB");
+                        }
+                    } catch (e) { }
+                },
+                error: function (err) {
+                    logDebug("[璇锋眰澶辫触] " + (err.statusText || "缃戠粶閿欒"));
+                }
+            });
+        }
+
+        // ================= 鍒濆鍖� =================
+        function onReady() {
+            initLayout();
+            updateHeaderTime();
+            setInterval(updateHeaderTime, 1000);
+            fetchQueueData();
+            appState.pollTimer = setInterval(fetchQueueData, 5000);
+            logDebug("[绯荤粺] 鍚姩瀹屾垚 - Android 6.0.1");
+        }
+
+        function updateHeaderTime() {
+            var now = new Date();
+            var weekDays = ["鏄熸湡鏃�", "鏄熸湡涓�", "鏄熸湡浜�", "鏄熸湡涓�", "鏄熸湡鍥�", "鏄熸湡浜�", "鏄熸湡鍏�"];
+            function padZero(num) { return num < 10 ? '0' + num : '' + num; }
+            var dateStr = now.getFullYear() + "骞�" + padZero(now.getMonth() + 1) + "鏈�" + padZero(now.getDate()) + "鏃�";
+            var weekStr = weekDays[now.getDay()];
+            var timeStr = padZero(now.getHours()) + ":" + padZero(now.getMinutes());
+            var el = document.getElementById("headerTime");
+            // 鏄熸湡鍜屾棩鏈熷悇鍗犱竴琛屽湪宸︼紝鏃堕棿澶у瓧鍦ㄥ彸璺ㄤ袱琛�
+            if (el) el.innerHTML = '<div class="time-info-inner"><div class="time-left"><div>' + weekStr + '</div><div>' + dateStr + '</div></div><div class="time-right"><span class="time-clock">' + timeStr + '</span></div></div>';
+        }
+
+        // 鍏煎 DOM ready锛圓ndroid 6 鏌愪簺 WebView 鍙兘娌℃湁 $锛�
+        if (typeof $ !== 'undefined') {
+            $(document).ready(onReady);
+        } else if (document.readyState === 'complete' || document.readyState === 'interactive') {
+            setTimeout(onReady, 1);
+        } else {
+            document.addEventListener('DOMContentLoaded', onReady);
+        }
+    </script>
+</body>
+
+</html>
\ No newline at end of file
diff --git "a/big\346\273\232\345\212\250.html" "b/big\346\273\232\345\212\250.html"
new file mode 100644
index 0000000..c4b8d04
--- /dev/null
+++ "b/big\346\273\232\345\212\250.html"
@@ -0,0 +1,823 @@
+<!doctype html>
+<html lang="zh-CN">
+
+<head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+    <title>澶у巺</title>
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+            /* Android 6 鍙敤涓枃瀛椾綋 */;
+            font-family: "Droid Sans Fallback", "Noto Sans CJK SC", "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
+        }
+
+        /* 1. 鍏ㄥ眬娣辫壊鑳屾櫙 */
+        body {
+            background: #001f3f;
+            color: #fff;
+            height: 100vh;
+            overflow: hidden;
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-orient: vertical;
+            -webkit-box-direction: normal;
+            -webkit-flex-direction: column;
+            flex-direction: column;
+            font-size: 14px;
+        }
+
+        /* 2. 椤堕儴鏍� */
+        .top-header {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-align: center;
+            -webkit-align-items: center;
+            align-items: center;
+            padding: 15px 30px;
+            background: rgba(0, 30, 60, 0.9);
+            white-space: nowrap;
+            position: relative;
+            border-bottom: 1px solid #003366;
+        }
+
+        .top-header img {
+            height: 50px;
+            margin-right: 20px;
+            z-index: 2;
+        }
+
+        .top-header .title-text {
+            position: absolute;
+            left: 50%;
+            -webkit-transform: translateX(-50%);
+            transform: translateX(-50%);
+            font-size: 32px;
+            font-weight: bold;
+            color: #fff;
+            z-index: 1;
+        }
+
+        .top-header .time-info {
+            font-size: 20px;
+            color: #aaa;
+            margin-left: auto;
+            z-index: 2;
+            text-align: right;
+            line-height: 1.3;
+        }
+
+        .time-info-inner {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-align: center;
+            -webkit-align-items: center;
+            align-items: center;
+        }
+
+        .time-left {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-orient: vertical;
+            -webkit-flex-direction: column;
+            flex-direction: column;
+            text-align: right;
+            line-height: 1.3;
+        }
+
+        .time-right {
+            margin-left: 8px;
+        }
+
+        .top-header .time-info .time-clock {
+            font-size: 36px;
+            font-weight: bold;
+            color: #ffcc00;
+            line-height: 1.1;
+        }
+
+        /* 3. 涓讳綋鍐呭锛坓ap 鏇挎崲涓� margin 鍏煎鏃� Chrome锛� */
+        .main-content {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-orient: vertical;
+            -webkit-box-direction: normal;
+            -webkit-flex-direction: column;
+            flex-direction: column;
+            padding: 15px 20px;
+            overflow: hidden;
+        }
+
+        /* 鍒楄瀹瑰櫒 */
+        .columns-row {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            overflow: hidden;
+        }
+
+        .columns-row > .column-box {
+            margin-left: 5px;
+            margin-right: 5px;
+        }
+
+        .columns-row > .column-box:first-child {
+            margin-left: 0;
+        }
+
+        .columns-row > .column-box:last-child {
+            margin-right: 0;
+        }
+
+        /* 鍒楀鍣� */
+        .column-box {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-orient: vertical;
+            -webkit-box-direction: normal;
+            -webkit-flex-direction: column;
+            flex-direction: column;
+            background: rgba(10, 40, 80, 0.5);
+            border-radius: 0;
+            padding: 10px;
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            min-width: 0;
+            border: 1px solid #003366;
+        }
+
+        .column-box.col-wide {
+            -webkit-box-flex: 2.5;
+            -webkit-flex: 2.5;
+            flex: 2.5;
+        }
+
+        .column-box.col-normal {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+        }
+
+        /* 鏍囬琛� */
+        .col-title-line {
+            font-size: 22px;
+            font-weight: bold;
+            color: #4da6ff;
+            text-align: center;
+        }
+
+        .col-title {
+            padding-bottom: 8px;
+            border-bottom: 1px solid #003366;
+            margin-bottom: 10px;
+            text-align: center;
+        }
+
+        .col-subtitle {
+            font-size: 14px;
+            color: #999;
+            text-align: center;
+            min-height: 20px;
+            /* 鍗充娇涓虹┖涔熶繚鐣欓珮搴︼紝闃叉鏍囬鏍忛珮浣庝笉骞� */;
+            line-height: 1.4;
+            word-break: keep-all;
+        }
+
+        /* 鎮h�呭垪琛� */
+        .patient-list {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            overflow-y: auto;
+            padding-right: 5px;
+        }
+
+        /* 绗�1鏍忥細涓�琛屼袱涓� */
+        #col-0 {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-flex-wrap: wrap;
+            flex-wrap: wrap;
+            -webkit-align-content: flex-start;
+            align-content: flex-start;
+        }
+
+        .col-normal .patient-list {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-orient: vertical;
+            -webkit-box-direction: normal;
+            -webkit-flex-direction: column;
+            flex-direction: column;
+        }
+
+        /* 鎮h�呴」鐩� */
+        .patient-item {
+            font-size: 22px;
+            padding: 8px 5px;
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-align: center;
+            -webkit-align-items: center;
+            align-items: center;
+            color: #fff;
+            line-height: 1.4;
+        }
+
+        #col-0 .patient-item {
+            width: 45%;
+            font-size: 20px;
+            margin: 0 2.5%;
+        }
+
+        .p-number {
+            color: #ffcc00;
+            font-weight: bold;
+            margin-right: 8px;
+        }
+
+        .p-name {
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+        }
+
+        .p-name-wrap {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+        }
+
+        .p-room {
+            color: #4da6ff;
+            font-weight: bold;
+            font-size: 18px;
+            margin-left: 4px;
+        }
+
+        /* 杩囧彿鏍忥紙鍥哄畾鍦� main-content 搴曢儴锛岃嚜鍔ㄦ粴鍔級 */
+        .missed-bar {
+            -webkit-flex-shrink: 0;
+            flex-shrink: 0;
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-align: center;
+            -webkit-align-items: center;
+            align-items: center;
+            background: rgba(80, 20, 20, 0.7);
+            border: 1px solid #993333;
+            padding: 6px 10px;
+            margin-top: 8px;
+        }
+
+        .missed-bar-empty {
+            display: none;
+        }
+
+        .missed-bar-title {
+            -webkit-flex-shrink: 0;
+            flex-shrink: 0;
+            color: #ff6666;
+            font-size: 18px;
+            font-weight: bold;
+            margin-right: 16px;
+            line-height: 30px;
+        }
+
+        /* 婊氬姩瑁佸壀鍖� */
+        .missed-bar-scroll-area {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            overflow: hidden;
+            white-space: nowrap;
+        }
+
+        /* 婊氬姩杞ㄩ亾 */
+        .missed-bar-track {
+            display: inline-block;
+            white-space: nowrap;
+            will-change: transform;
+        }
+
+        .missed-bar-scroll .missed-bar-track {
+            /* 鍔ㄧ敾鏃堕暱鐢� JS 鍔ㄦ�佽缃紝瑙� updateMissedBarSpeed */
+            -webkit-animation-name: missed-scroll;
+            animation-name: missed-scroll;
+            -webkit-animation-timing-function: linear;
+            animation-timing-function: linear;
+            -webkit-animation-iteration-count: infinite;
+            animation-iteration-count: infinite;
+        }
+
+        @-webkit-keyframes missed-scroll {
+            0% { -webkit-transform: translateX(0); transform: translateX(0); }
+            100% { -webkit-transform: translateX(-50%); transform: translateX(-50%); }
+        }
+        @keyframes missed-scroll {
+            0% { transform: translateX(0); }
+            100% { transform: translateX(-50%); }
+        }
+
+        .missed-bar .patient-item {
+            display: -webkit-inline-box;
+            display: -webkit-inline-flex;
+            display: inline-flex;
+            font-size: 17px;
+            padding: 3px 12px;
+            margin-right: 8px;
+            border-right: 1px solid #664444;
+            color: #cc9999;
+        }
+
+        .missed-bar .patient-item:last-child {
+            border-right: none;
+        }
+
+        .missed-bar .p-number {
+            color: #ff9966;
+            font-weight: bold;
+            margin-right: 6px;
+        }
+
+        .missed-bar .p-name {
+            color: #bbaaaa;
+        }
+
+        .missed-bar .p-room {
+            color: #ff6666;
+            font-size: 15px;
+        }
+
+        /* 搴曢儴鏍� */
+        .bottom-footer {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-pack: center;
+            -webkit-justify-content: center;
+            justify-content: center;
+            -webkit-box-align: center;
+            -webkit-align-items: center;
+            align-items: center;
+            padding: 10px 30px;
+            background: rgba(0, 30, 60, 0.9);
+            border-top: 1px solid #003366;
+        }
+
+        .footer-tip {
+            font-size: 22px;
+            color: #ffcc00;
+            font-weight: bold;
+            text-align: center;
+        }
+
+        /* 婊氬姩鏉� */
+        .patient-list::-webkit-scrollbar {
+            width: 4px;
+        }
+        .patient-list::-webkit-scrollbar-thumb {
+            background: #444;
+            border-radius: 2px;
+        }
+
+        /* 璋冭瘯闈㈡澘 */
+        .debug-panel {
+            position: fixed;
+            right: 15px;
+            bottom: 70px;
+            width: 350px;
+            height: 200px;
+            background: rgba(0, 0, 0, 0.9);
+            color: #0f0;
+            border-radius: 4px;
+            font-family: monospace;
+            font-size: 12px;
+            z-index: 9999;
+            overflow: hidden;
+        }
+
+        .debug-header {
+            display: -webkit-box;
+            display: -webkit-flex;
+            display: flex;
+            -webkit-box-pack: justify;
+            -webkit-justify-content: space-between;
+            justify-content: space-between;
+            -webkit-box-align: center;
+            -webkit-align-items: center;
+            align-items: center;
+            padding: 5px;
+            background: #333;
+            border-bottom: 1px solid #000;
+        }
+
+        .debug-header span {
+            font-weight: bold;
+            font-size: 13px;
+        }
+
+        .debug-header button {
+            background: #c00;
+            color: #fff;
+            border: none;
+            padding: 2px 6px;
+            font-size: 10px;
+            cursor: pointer;
+        }
+
+        .debug-body {
+            -webkit-box-flex: 1;
+            -webkit-flex: 1;
+            flex: 1;
+            padding: 5px;
+            overflow-y: auto;
+            font-size: 11px;
+        }
+
+        .debug-line {
+            margin-bottom: 2px;
+        }
+
+        .debug-time {
+            color: #888;
+        }
+    </style>
+</head>
+
+<body>
+    <!-- 椤堕儴鏍� -->
+    <div class="top-header">
+        <img src="logo.png" alt="logo" />
+        <span class="title-text">蹇冪數妫�鏌ユ湇鍔¤瘖鍖哄ぇ鍘�</span>
+        <span class="time-info" id="headerTime"></span>
+    </div>
+
+    <!-- 涓讳綋鍐呭 -->
+    <div class="main-content" id="mainContent"></div>
+
+    <!-- 搴曢儴鏍� -->
+    <div class="bottom-footer">
+        <div class="footer-tip">娓╅Θ鎻愮ず锛氳鍚埌鍛煎彨鍚庡墠寰�瀵瑰簲璇婂锛岃繃鍙锋偅鑰呰鍒板璇婂彴澶勭悊锛�</div>
+    </div>
+
+    <!-- 璋冭瘯闈㈡澘 -->
+    <div class="debug-panel" id="debugPanel">
+        <div class="debug-header">
+            <span>[璋冭瘯] 杩愯鏃ュ織</span>
+            <button onclick="document.getElementById('debugBody').innerHTML=''">娓呯┖</button>
+        </div>
+        <div class="debug-body" id="debugBody"></div>
+    </div>
+
+    <script src="./static/jquery.min.js"></script>
+    <script>
+        // ================= 璋冭瘯鏃ュ織 =================
+        function logDebug(msg) {
+            var now = new Date();
+            function pad(num) { return num < 10 ? '0' + num : '' + num; }
+            var timeStr = pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds());
+            var logHtml = '<div class="debug-line"><span class="debug-time">[' + timeStr + ']</span> ' + msg + '</div>';
+            console.log("[" + timeStr + "] " + msg);
+            var body = document.getElementById("debugBody");
+            if (body) {
+                body.insertAdjacentHTML("beforeend", logHtml);
+                body.scrollTop = body.scrollHeight;
+            }
+        }
+
+        // ================= 搴旂敤鐘舵�� =================
+        var appState = {
+            columnTitles: ["甯歌蹇冪數鍥�", "鍔ㄦ�佸績鐢靛浘/琛�鍘�", "蹇冪數鍥捐繍鍔ㄨ瘯楠�", "椋熼亾鐢电敓鐞�", "鍔ㄨ剦纭寲鐩戞祴"],
+            columnSubTitles: ["搴婅竟蹇冪數鍥�(甯歌+棰戣氨) / 蹇冪數鍚戦噺鍥�", "", "", "", ""],
+            patients: [],
+            apiBaseUrl: "http://localhost/admin-api",
+            // apiBaseUrl: "http://192.168.100.110/admin-api",
+            pollTimer: null,
+            callRepeatTimes: 2,
+            spokenPatients: {},
+            ttsQueue: [],
+            isSpeaking: false,
+            // 杩囧彿鎮h�呮粴鍔ㄩ�熷害閰嶇疆锛氭暟鍊间负鍔ㄧ敾鍛ㄦ湡绉掓暟锛岃秺澶ц秺鎱�
+            missedScrollSpeedSlowest: 10,  // 鏈�鎱㈤�熷害锛堟偅鑰呭皯鏃朵娇鐢紝绉掓暟澶�=鎱級
+            missedScrollSpeedFastest: 5   // 鏈�蹇�熷害锛堟偅鑰呭鏃朵笂闄愶紝绉掓暟灏�=蹇級
+        };
+
+        // ================= 璇煶鎾姤 =================
+        function processTtsQueue() {
+            if (appState.isSpeaking || appState.ttsQueue.length === 0) return;
+            appState.isSpeaking = true;
+            var text = appState.ttsQueue.shift();
+            logDebug("[鎾姤] " + text);
+
+            var utterance = new SpeechSynthesisUtterance(text);
+            // Android 6 榛樿璇�熷彲鑳藉緢蹇紝閫傚綋璋冩參
+            utterance.rate = 0.85;
+            utterance.onend = function () {
+                appState.isSpeaking = false;
+                processTtsQueue();
+            };
+            utterance.onerror = function (e) {
+                logDebug("[TTS閿欒] " + (e.error || "unknown"));
+                appState.isSpeaking = false;
+                processTtsQueue();
+            };
+
+            // 浼樺厛灏濊瘯璁惧鍘熺敓 TTS 鎺ュ彛
+            if (typeof wowjoy !== 'undefined' && typeof wowjoy.speek === 'function') {
+                try {
+                    wowjoy.speek(text);
+                    setTimeout(function () { appState.isSpeaking = false; processTtsQueue(); }, 4000);
+                    return;
+                } catch (e) { logDebug("[wowjoy澶辫触] " + e.message); }
+            }
+
+            if (window.speechSynthesis) {
+                // Android 6 WebView 鏈夋椂闇�瑕佸厛 cancel 鍐� speak
+                window.speechSynthesis.cancel();
+                window.speechSynthesis.speak(utterance);
+            } else {
+                logDebug("[TTS] 娴忚鍣ㄤ笉鏀寔璇煶鍚堟垚");
+                appState.isSpeaking = false;
+                processTtsQueue();
+            }
+        }
+
+        function speak(text) {
+            if (!text) return;
+            appState.ttsQueue.push(text);
+            processTtsQueue();
+        }
+
+        // ================= 娓叉煋锛氭爣棰樻鏋讹紙浠呭垵濮嬪寲涓�娆★級=================
+        function initLayout() {
+            var main = document.getElementById("mainContent");
+            var html = '<div class="columns-row">';
+
+            for (var i = 0; i < appState.columnTitles.length; i++) {
+                // 鏍囬鍜屽壇鏍囬閮芥湁鍥哄畾鍗犱綅锛岄伩鍏嶆湁/鏃犲壇鏍囬鏃堕珮搴﹁烦鍔�
+                var subtitle = appState.columnSubTitles[i] || "&nbsp;";
+                var colClass = (i === 0) ? 'col-wide' : 'col-normal';
+                html += '<div class="column-box ' + colClass + '">' +
+                    '<div class="col-title">' +
+                    '<div class="col-title-line">' + appState.columnTitles[i] + '</div>' +
+                    '<div class="col-subtitle">' + subtitle + '</div>' +
+                    '</div>' +
+                    '<div class="patient-list" id="col-' + i + '"></div>' +
+                    '</div>';
+            }
+            html += '</div>';
+            html += '<div class="missed-bar missed-bar-empty" id="missedBar">' +
+                '<span class="missed-bar-title">杩囧彿鎮h��</span>' +
+                '<div class="missed-bar-scroll-area"><div class="missed-bar-track" id="missedBarTrack"></div></div>' +
+                '</div>';
+            main.innerHTML = html;
+        }
+
+        // ================= 娓叉煋锛氭偅鑰呭垪琛紙diff 鏇存柊锛屽彧鏀瑰彉鍖栫殑鍒楋級=================
+        function desensitizeName(name) {
+            if (!name || name.length < 2) return name || '';
+            return name.charAt(0) + '*' + name.substring(2);
+        }
+
+        function isMissedStatus(status) {
+            var s = parseInt(status, 10);
+            return s === 3 || s === 5 || s === 7;
+        }
+
+        function buildColumnHtml(colData) {
+            if (!Array.isArray(colData) || colData.length === 0) return "";
+            var h = "";
+            for (var p = 0; p < colData.length; p++) {
+                var pat = colData[p];
+                // 杩囧彿鎮h�呬笉鏄剧ず鍦ㄥ垪鍐咃紝缁熶竴鍦ㄥ簳閮ㄨ繃鍙锋爮灞曠ず
+                if (isMissedStatus(pat.status)) continue;
+                var roomHtml = pat.roomName ? '<span class="p-room">(' + pat.roomName + ')</span>' : '';
+                h += '<div class="patient-item">' +
+                    '<span class="p-number">' + (pat.seqNum || '') + '</span>' +
+                    '<span class="p-name-wrap"><span class="p-name">' + desensitizeName(pat.patName) + '</span>' + roomHtml + '</span>' +
+                    '</div>';
+            }
+            return h;
+        }
+
+        function buildMissedBarHtml(dataList) {
+            var allMissed = [];
+            for (var i = 0; i < appState.columnTitles.length; i++) {
+                var colData = (dataList && dataList[i]) ? dataList[i] : [];
+                for (var p = 0; p < colData.length; p++) {
+                    var pat = colData[p];
+                    if (isMissedStatus(pat.status)) {
+                        allMissed.push({ patient: pat, colIndex: i });
+                    }
+                }
+            }
+            if (allMissed.length === 0) return "";
+            var h = "";
+            for (var m = 0; m < allMissed.length; m++) {
+                var item = allMissed[m];
+                var pat = item.patient;
+                var colName = appState.columnTitles[item.colIndex];
+                var roomHtml = pat.roomName ? ' <span class="p-room">' + pat.roomName + '</span>' : '';
+                h += '<span class="patient-item">' +
+                    '<span class="p-number">[' + colName + '] ' + (pat.seqNum || '') + '</span>' +
+                    '<span class="p-name">' + desensitizeName(pat.patName) + '</span>' + roomHtml +
+                    '</span>';
+            }
+            // 澶嶅埗涓�浠藉唴瀹瑰疄鐜版棤缂濆惊鐜粴鍔�
+            return h + h;
+        }
+
+        function isSameColumn(a, b) {
+            if (!Array.isArray(a) || !Array.isArray(b)) return a === b;
+            if (a.length !== b.length) return false;
+            for (var i = 0; i < a.length; i++) {
+                if (a[i].patId !== b[i].patId) return false;
+                if (a[i].roomName !== b[i].roomName) return false;
+                if (parseInt(a[i].status, 10) !== parseInt(b[i].status, 10)) return false;
+            }
+            return true;
+        }
+
+        function updatePatients(dataList) {
+            for (var i = 0; i < appState.columnTitles.length; i++) {
+                var newData = (dataList && dataList[i]) ? dataList[i] : [];
+                var oldData = appState.patients[i];
+
+                // diff锛氭暟鎹湭鍙樺寲鍒欒烦杩囪鍒� DOM 鎿嶄綔
+                if (isSameColumn(oldData, newData)) continue;
+
+                var col = document.getElementById("col-" + i);
+                if (col) col.innerHTML = buildColumnHtml(newData);
+            }
+
+            // 鏇存柊搴曢儴杩囧彿鏍�
+            var missedBar = document.getElementById("missedBar");
+            var missedTrack = document.getElementById("missedBarTrack");
+            if (missedBar && missedTrack) {
+                var missedHtml = buildMissedBarHtml(dataList);
+                if (missedHtml) {
+                    missedTrack.innerHTML = missedHtml;
+                    missedBar.className = "missed-bar missed-bar-scroll";
+                    // 鏍规嵁杩囧彿鎮h�呬汉鏁板姩鎬佽皟鏁存粴鍔ㄩ�熷害
+                    updateMissedBarSpeed(missedTrack, dataList);
+                } else {
+                    missedBar.className = "missed-bar missed-bar-empty";
+                }
+            }
+        }
+
+        // ================= 杩囧彿鏍忔粴鍔ㄩ�熷害 =================
+        // 缁熻杩囧彿鎮h�呮�绘暟锛屽湪 0 鍒� 20 浜轰箣闂寸嚎鎬ф彃鍊煎姩鐢绘椂闀�
+        // 浜哄皯鏃剁敤鏈�鎱㈤�熷害锛堢鏁板ぇ锛夛紝浜哄鏃堕�艰繎鏈�蹇�熷害锛堢鏁板皬锛夛紝鏈�澶� 20 浜鸿揪鍒颁笂闄�
+        function updateMissedBarSpeed(trackEl, dataList) {
+            var count = 0;
+            for (var i = 0; i < appState.columnTitles.length; i++) {
+                var colData = (dataList && dataList[i]) ? dataList[i] : [];
+                for (var p = 0; p < colData.length; p++) {
+                    if (isMissedStatus(colData[p].status)) count++;
+                }
+            }
+            if (count === 0) return;
+
+            var slowest = appState.missedScrollSpeedSlowest;
+            var fastest = appState.missedScrollSpeedFastest;
+            // 浜烘暟闃堝�硷細瓒呰繃姝や汉鏁板嵆浣跨敤鏈�蹇�熷害
+            var maxCount = 20;
+            // 绾挎�ф彃鍊硷細count=1 -> slowest, count>=maxCount -> fastest
+            var ratio = Math.min(count, maxCount) / maxCount;
+            var duration = slowest - (slowest - fastest) * ratio;
+            // 鍙栨暣鍒颁竴浣嶅皬鏁帮紝鍏煎叿绮惧害鍜岀畝娲�
+            duration = Math.round(duration * 10) / 10;
+
+            var animValue = 'missed-scroll ' + duration + 's linear infinite';
+            trackEl.style.webkitAnimation = animValue;
+            trackEl.style.animation = animValue;
+        }
+
+        // ================= 鏁版嵁瀵规瘮涓庢挱鎶� =================
+        function checkAndSpeakNewRooms(oldData, newData) {
+            if (!oldData || oldData.length === 0) return;
+            for (var c = 0; c < newData.length; c++) {
+                var newCol = newData[c];
+                var oldCol = oldData[c];
+                if (Array.isArray(newCol)) {
+                    for (var p = 0; p < newCol.length; p++) {
+                        var newPat = newCol[p];
+                        if (newPat.roomName) {
+                            if (appState.spokenPatients[newPat.patId]) continue;
+                            var oldPat = null;
+                            if (Array.isArray(oldCol)) {
+                                for (var k = 0; k < oldCol.length; k++) {
+                                    if (oldCol[k].patId === newPat.patId) {
+                                        oldPat = oldCol[k];
+                                        break;
+                                    }
+                                }
+                            }
+                            if (!oldPat || !oldPat.roomName) {
+                                var repeatText = "";
+                                for (var r = 0; r < appState.callRepeatTimes; r++) {
+                                    repeatText += "璇� " + newPat.seqNum + " 鍙� " + newPat.patName + " 鍒� " + newPat.roomName + " 灏辫瘖銆�";
+                                }
+                                speak(repeatText);
+                                appState.spokenPatients[newPat.patId] = true;
+                                logDebug("[鎺掗槦] " + newPat.patName + " -> " + newPat.roomName);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // ================= 鏁版嵁鑾峰彇 =================
+        function fetchQueueData() {
+            var url = appState.apiBaseUrl + "/ecg/screen/big-screen-data";
+            $.ajax({
+                url: url,
+                type: "GET",
+                dataType: "json",
+                timeout: 5000,
+                success: function (res) {
+                    var dataList = [];
+                    if (res && res.code === 0 && res.data) {
+                        for (var i = 0; i < appState.columnTitles.length; i++) {
+                            var key = i.toString();
+                            dataList[i] = (res.data[key] && Array.isArray(res.data[key])) ? res.data[key] : [];
+                        }
+                    }
+                    // 鍏� diff 鏇存柊 DOM锛屽啀鎾姤锛屾渶鍚庝繚瀛樻暟鎹敤浜庝笅娆″姣�
+                    updatePatients(dataList);
+                    checkAndSpeakNewRooms(appState.patients, dataList);
+                    appState.patients = dataList;
+
+                    // Android 6 WebView 閫氬父涓嶆敮鎸� performance.memory锛屽畨鍏ㄥ畧鍗�
+                    try {
+                        if (window.performance && window.performance.memory) {
+                            var usedMB = (window.performance.memory.usedJSHeapSize / 1048576).toFixed(2);
+                            logDebug("[鍐呭瓨] " + usedMB + " MB");
+                        }
+                    } catch (e) {}
+                },
+                error: function (err) {
+                    logDebug("[璇锋眰澶辫触] " + (err.statusText || "缃戠粶閿欒"));
+                }
+            });
+        }
+
+        // ================= 鍒濆鍖� =================
+        function onReady() {
+            initLayout();
+            updateHeaderTime();
+            setInterval(updateHeaderTime, 1000);
+            fetchQueueData();
+            appState.pollTimer = setInterval(fetchQueueData, 5000);
+            logDebug("[绯荤粺] 鍚姩瀹屾垚 - Android 6.0.1");
+        }
+
+        function updateHeaderTime() {
+            var now = new Date();
+            var weekDays = ["鏄熸湡鏃�", "鏄熸湡涓�", "鏄熸湡浜�", "鏄熸湡涓�", "鏄熸湡鍥�", "鏄熸湡浜�", "鏄熸湡鍏�"];
+            function padZero(num) { return num < 10 ? '0' + num : '' + num; }
+            var dateStr = now.getFullYear() + "骞�" + padZero(now.getMonth() + 1) + "鏈�" + padZero(now.getDate()) + "鏃�";
+            var weekStr = weekDays[now.getDay()];
+            var timeStr = padZero(now.getHours()) + ":" + padZero(now.getMinutes());
+            var el = document.getElementById("headerTime");
+            // 鏄熸湡鍜屾棩鏈熷悇鍗犱竴琛屽湪宸︼紝鏃堕棿澶у瓧鍦ㄥ彸璺ㄤ袱琛�
+            if (el) el.innerHTML = '<div class="time-info-inner"><div class="time-left"><div>' + weekStr + '</div><div>' + dateStr + '</div></div><div class="time-right"><span class="time-clock">' + timeStr + '</span></div></div>';
+        }
+
+        // 鍏煎 DOM ready锛圓ndroid 6 鏌愪簺 WebView 鍙兘娌℃湁 $锛�
+        if (typeof $ !== 'undefined') {
+            $(document).ready(onReady);
+        } else if (document.readyState === 'complete' || document.readyState === 'interactive') {
+            setTimeout(onReady, 1);
+        } else {
+            document.addEventListener('DOMContentLoaded', onReady);
+        }
+    </script>
+</body>
+</html>
diff --git a/logo0.png b/logo0.png
new file mode 100644
index 0000000..35e084e
--- /dev/null
+++ b/logo0.png
Binary files differ
diff --git a/small.html b/small.html
index e3515a3..9a166ec 100644
--- a/small.html
+++ b/small.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+锘�<!DOCTYPE html>
 <html lang="zh-CN">
 
 <head>
@@ -36,8 +36,7 @@
         .header-top {
             display: flex;
             align-items: center;
-            justify-content: center;
-            gap: 30px;
+            justify-content: space-between;
         }
 
         .logo {
@@ -48,13 +47,19 @@
             display: flex;
             flex-direction: column;
             line-height: 1.2;
-            text-align: center;
+            text-align: right;
         }
 
         .week-day,
         .full-date {
             font-size: 16px;
             color: #666;
+        }
+
+        .header-right {
+            display: flex;
+            align-items: center;
+            gap: 15px;
         }
 
         .clock {
@@ -87,22 +92,35 @@
             border-radius: 12px;
             display: flex;
             flex-direction: row;
-            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+            box-shadow: 0 3px 12px rgba(0, 0, 0, 0.15);
             overflow: hidden;
             flex: 1;
+            border: 2px solid #e0e0e0;
+        }
+
+        .status-active {
+            border-color: #67c23a;
+        }
+
+        .status-waiting {
+            border-color: #e6a23c;
+        }
+
+        .status-missed {
+            border-color: #f56c6c;
         }
 
         /* 宸︿晶鐘舵�佹爣绛� (绔栨帓) */
         .panel-header {
-            width: 60px;
+            width: 70px;
             display: flex;
             align-items: center;
             justify-content: center;
-            font-size: 22px;
+            font-size: 32px;
             font-weight: bold;
             color: #fff;
             writing-mode: vertical-rl;
-            letter-spacing: 6px;
+            letter-spacing: 12px;
             text-align: center;
             flex-shrink: 0;
         }
@@ -134,27 +152,33 @@
         /* 鎮h�呬俊鎭」 (鍥哄畾楂樺害锛屼竴琛屼袱涓�) */
         .patient-item {
             width: calc(50% - 5px);
-            height: 60px;
+            height: 70px;
             display: flex;
-            justify-content: space-between;
+            justify-content: flex-start;
             align-items: center;
-            padding: 0 15px;
+            padding: 0 8px;
             background: #ffffff;
             border: 1px solid #eee;
             border-radius: 8px;
             box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+            white-space: nowrap;
+            overflow: hidden;
         }
 
         .p-name {
-            font-size: 28px;
+            font-size: 36px;
             font-weight: bold;
             color: #303133;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
         }
 
         .p-num {
-            font-size: 24px;
+            font-size: 30px;
             color: #909399;
             font-weight: bold;
+            flex-shrink: 0;
         }
 
         /* ================= 搴曢儴鎺у埗鍖� ================= */
@@ -177,6 +201,7 @@
         }
 
         #test-voice-btn {
+            display: none;
             position: absolute;
             right: 20px;
             background-color: #007bff;
@@ -195,6 +220,7 @@
 
         /* 璋冭瘯淇℃伅鍖� */
         .debug-info {
+            display: none;
             font-size: 14px;
             color: #999;
             background: #f0f0f0;
@@ -222,11 +248,13 @@
     <div class="header">
         <div class="header-top">
             <img src="logo.png" alt="Logo" class="logo">
-            <div class="time-box">
-                <span class="week-day" id="weekDay">鏄熸湡鏃�</span>
-                <span class="full-date" id="fullDate">2024骞�01鏈�01鏃�</span>
+            <div class="header-right">
+                <div class="time-box">
+                    <span class="week-day" id="weekDay">鏄熸湡鏃�</span>
+                    <span class="full-date" id="fullDate">2024骞�01鏈�01鏃�</span>
+                </div>
+                <div class="clock" id="clock">12:00</div>
             </div>
-            <div class="clock" id="clock">12:00</div>
         </div>
         <div class="room-line"><span id="currentRoomId">--</span></div>
     </div>
@@ -234,19 +262,19 @@
     <!-- 涓讳綋鍐呭 -->
     <div class="main-container">
         <!-- 1. 姝e湪灏辫瘖 -->
-        <div class="panel status-active" style="max-height: calc(60px * 2 + 20px + 20px);">
-            <div class="panel-header">姝e湪灏辫瘖</div>
+        <div class="panel status-active" style="max-height: calc(70px * 2 + 20px + 20px);">
+            <div class="panel-header">璇婁腑</div>
             <div class="list-content" id="inProgressList"></div>
         </div>
 
         <!-- 2. 鍊欒瘖涓� -->
-        <div class="panel status-waiting" style="max-height: calc(60px * 4 + 30px + 20px);">
-            <div class="panel-header">鍊欒瘖涓�</div>
+        <div class="panel status-waiting" style="max-height: calc(70px * 4 + 30px + 20px);">
+            <div class="panel-header">绛夊��</div>
             <div class="list-content" id="waitingList"></div>
         </div>
 
         <!-- 3. 杩囧彿 -->
-        <div class="panel status-missed" style="max-height: calc(60px * 3 + 20px + 20px);">
+        <div class="panel status-missed" style="max-height: calc(70px * 3 + 20px + 20px);">
             <div class="panel-header">杩囧彿</div>
             <div class="list-content" id="missedList"></div>
         </div>
@@ -254,7 +282,7 @@
 
     <!-- 搴曢儴鎺у埗鏍� -->
     <div class="footer">
-        <span class="footer-text">娓╅Θ鎻愮ず锛氳鑰愬績绛夊緟锛屼繚鎸佸畨闈欙紒</span>
+        <span class="footer-text">娓╅Θ鎻愮ず锛氳杩囧彿鎮h�呭埌鍒嗚瘖鍙板鐞嗭紒</span>
         <button id="test-voice-btn">娴嬭瘯璇煶</button>
     </div>
 
@@ -262,63 +290,130 @@
     <div class="debug-info" id="debugInfo">璋冭瘯鐘舵�侊細绛夊緟鏁版嵁...</div>
 
     <script>
+        // ================= URL 鍙傛暟璇诲彇 =================
+        function getUrlParam(name) {
+            var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
+            var r = window.location.search.substr(1).match(reg);
+            if (r != null) return decodeURIComponent(r[2]);
+            return null;
+        }
+
         // ================= 閰嶇疆鍙傛暟 =================
         var CONFIG = {
-            apiBaseUrl: "http://192.168.100.110:48080/admin-api",
-            // apiBaseUrl: "http://192.168.100.110:48080/admin-api",
-            roomId: "116",
+            // apiBaseUrl: "http://192.168.3.12/admin-api",
+            apiBaseUrl: "http://10.0.2.193/admin-api",
+            roomId: getUrlParam("roomID") || "116",
             refreshRate: 5000
         };
-        var CALL_TIMES = 2; // 鍙彿娆℃暟
+        // 璇婂缂栧彿 鈫� 鍚嶇О鏄犲皠锛氬綋鎺ュ彛鏈繑鍥� roomName 鏃跺厹搴�
+        var ROOM_NAME_MAP = {
+            "116": "1鍙疯瘖瀹�",
+            "117": "2鍙疯瘖瀹�",
+            "118": "3鍙疯瘖瀹�",
+            "119": "4鍙疯瘖瀹�",
+            "121": "6鍙疯瘖瀹�",
+            "123": "8鍙疯瘖瀹�",
+            "125": "鍒嗚瘖鍙�"
+        };
+        var CALL_TIMES = 2; // 鍙彿娆℃暟        
 
-        var appState = { roomName: '', lastSpokenPatient: null };
+        var appState = { roomName: '', lastSpokenPatient: null, serverTimeOffset: 0 };
         function $(id) { return document.getElementById(id); }
 
         // ================= 鏃堕棿妯″潡 =================
+        function getNow() {
+            return new Date(Date.now() + (appState.serverTimeOffset || 0));
+        }
         function updateClock() {
-            var now = new Date();
+            var now = getNow();
             $('clock').innerText = ('0' + now.getHours()).slice(-2) + ':' + ('0' + now.getMinutes()).slice(-2);
             $('fullDate').innerText = now.getFullYear() + '骞�' + ('0' + (now.getMonth() + 1)).slice(-2) + '鏈�' + ('0' + now.getDate()).slice(-2) + '鏃�';
             $('weekDay').innerText = ['鏄熸湡鏃�', '鏄熸湡涓�', '鏄熸湡浜�', '鏄熸湡涓�', '鏄熸湡鍥�', '鏄熸湡浜�', '鏄熸湡鍏�'][now.getDay()];
         }
+        function syncServerTime(serverTimeStr) {
+            if (!serverTimeStr) return;
+            try {
+                var serverTime = new Date(serverTimeStr);
+                if (!isNaN(serverTime.getTime())) {
+                    appState.serverTimeOffset = serverTime.getTime() - Date.now();
+                    updateDebugInfo("鏃堕棿宸插悓姝� | 鍋忕Щ=" + (appState.serverTimeOffset / 1000).toFixed(1) + "s");
+                }
+            } catch (e) { updateDebugInfo("鏃堕棿鍚屾澶辫触: " + e.message); }
+        }
         setInterval(updateClock, 1000); updateClock();
 
         // ================= 璇煶鎾姤 =================
+        var _gUtterance = null; // GC 淇濇姢
         function speakText(text, times) {
             times = times || CALL_TIMES;
             var isAndroid = /Android/i.test(navigator.userAgent);
             if (isAndroid && window.wowjoy && typeof window.wowjoy.speek === 'function') {
-                for (var i = 0; i < times; i++) setTimeout(function () { window.wowjoy.speek(text); }, i * 1500);
+                updateDebugInfo("TTS: wowjoy妯″紡");
+                for (var i = 0; i < times; i++) {
+                    setTimeout(function () { window.wowjoy.speek(text); }, i * 1500);
+                }
             } else if (window.speechSynthesis) {
-                window.speechSynthesis.cancel();
-                var utterance = new window.SpeechSynthesisUtterance(text);
-                utterance.lang = 'zh-CN'; utterance.rate = 1.0;
-                window.speechSynthesis.speak(utterance);
-                for (var j = 1; j < times; j++) setTimeout(function () { window.speechSynthesis.speak(utterance); }, j * 1500);
+                updateDebugInfo("TTS: speechSynthesis妯″紡");
+                if (window.speechSynthesis.speaking) {
+                    window.speechSynthesis.cancel();
+                }
+                function doSpeak(idx) {
+                    var u = new window.SpeechSynthesisUtterance(text);
+                    u.lang = 'zh-CN';
+                    u.rate = 1.0;
+                    u.volume = 1.0;
+                    _gUtterance = u;
+                    u.onend = function () { _gUtterance = null; };
+                    u.onerror = function (e) { _gUtterance = null; updateDebugInfo("TTS閿欒: " + (e.error || "unknown")); };
+                    window.speechSynthesis.speak(u);
+                }
+                doSpeak(0);
+                for (var j = 1; j < times; j++) {
+                    setTimeout((function (idx) { return function () { doSpeak(idx); }; })(j), j * 1500);
+                }
+            } else {
+                updateDebugInfo("TTS: 鏃犲紩鎿庡彲鐢�");
             }
         }
 
         // ================= 鏁版嵁璇锋眰 =================
         function fetchData() {
             var url = CONFIG.apiBaseUrl + "/ecg/screen/room-screen-data?roomId=" + CONFIG.roomId;
+            updateDebugInfo("璇锋眰: " + url);
             var xhr = new XMLHttpRequest();
             xhr.open('GET', url, true);
+            xhr.timeout = 8000;
             xhr.onreadystatechange = function () {
                 if (xhr.readyState === 4) {
                     if (xhr.status === 200) {
                         try {
                             var response = JSON.parse(xhr.responseText);
                             processData(response);
-                            updateDebugInfo("鑾峰彇鏁版嵁鎴愬姛 | 鍘熷鏁版嵁闀垮害: " + (response.data ? Object.keys(response.data).length : 0));
-                        } catch (e) { updateDebugInfo("JSON瑙f瀽澶辫触: " + e.message); }
-                    } else { updateDebugInfo("璇锋眰澶辫触锛岀姸鎬佺爜: " + xhr.status); }
+                            updateDebugInfo("鎴愬姛 | 鎮h��: " + (response.data ? JSON.stringify(Object.keys(response.data)) : "鏃�"));
+                        } catch (e) { updateDebugInfo("澶勭悊澶辫触: " + e.message); }
+                    } else if (xhr.status === 0) {
+                        updateDebugInfo("缃戠粶閿欒(status=0) | " + url + " | 璇锋鏌PI鏈嶅姟/URL鍙揪鎬�/璺ㄥ煙");
+                    } else {
+                        updateDebugInfo("璇锋眰澶辫触 | status=" + xhr.status + " | " + url);
+                    }
                 }
             };
-            xhr.send();
+            xhr.onerror = function () {
+                updateDebugInfo("缃戠粶寮傚父(onerror) | " + url + " | 璁惧鍙兘鏃犳硶璁块棶璇ュ湴鍧�");
+            };
+            xhr.ontimeout = function () {
+                updateDebugInfo("璇锋眰瓒呮椂 | " + url);
+            };
+            try {
+                xhr.send();
+            } catch (e) {
+                updateDebugInfo("send寮傚父: " + e.message);
+            }
         }
 
         // ================= 鏍稿績涓氬姟閫昏緫澶勭悊 =================
         function processData(res) {
+            syncServerTime(res.serverTime || (res.data && res.data.serverTime) || null);
             var data = res.data || res;
 
             // 1. 鏇存柊璇婂鍚嶇О (浠庣涓�鏉℃暟鎹腑鑾峰彇)
@@ -330,6 +425,9 @@
             if (waitingArr.length > 0) currentRoomName = waitingArr[0].roomName || currentRoomName;
             else if (inProgressArr.length > 0) currentRoomName = inProgressArr[0].roomName || currentRoomName;
             else if (missedArr.length > 0) currentRoomName = missedArr[0].roomName || currentRoomName;
+
+            // 鍏滃簳锛氭帴鍙f湭杩斿洖 roomName 鏃讹紝浠庢湰鍦版槧灏勮〃鍙栬瘖瀹ゅ悕绉�
+            currentRoomName = ROOM_NAME_MAP[currentRoomName] || currentRoomName;
 
             appState.roomName = currentRoomName;
             $('currentRoomId').innerText = currentRoomName;
@@ -375,7 +473,7 @@
                 var patientId = currentPatient.patId || currentPatient.seqNum;
                 if (appState.lastSpokenPatient !== patientId) {
                     appState.lastSpokenPatient = patientId;
-                    speakText(currentPatient.patName + "锛岃鍒�" + appState.roomName, CALL_TIMES);
+                    speakText(currentPatient.patName + "锛岃鍒�" + appState.roomName + "灏辫瘖", CALL_TIMES);
                 }
             } else {
                 appState.lastSpokenPatient = null;
@@ -383,19 +481,24 @@
         }
 
         // ================= 娓叉煋鍒楄〃 =================
+        function desensitizeName(name) {
+            if (!name || name.length < 2) return name || '';
+            return name.charAt(0) + '*' + name.substring(2);
+        }
+
         function renderList(containerId, listData) {
             var container = $(containerId);
+            if (!container) return;
             container.innerHTML = "";
             if (listData.length === 0) {
-                container.innerHTML = '<div style="text-align:center; color:#ccc; width:100%; height:60px; line-height:60px; font-size:18px;">鏆傛棤鎮h��</div>';
+                container.innerHTML = '<div style="text-align:center; color:#ccc; width:100%; height:70px; line-height:70px; font-size:18px;">鏆傛棤鎮h��</div>';
                 return;
             }
             for (var i = 0; i < listData.length; i++) {
                 var item = listData[i];
                 var div = document.createElement('div');
                 div.className = 'patient-item';
-                div.innerHTML = '<span class="p-name">' + (item.patName || '鏈煡') + '</span>' +
-                    '<span class="p-num">' + (item.seqNum || item.bookSeqNum || '--') + '鍙�</span>';
+                div.innerHTML = '<span class="p-num">' + (item.seqNum || '--') + '鍙�</span>&nbsp;<span class="p-name">' + (item.patName ? desensitizeName(item.patName) : '鏈煡') + '</span>';
                 container.appendChild(div);
             }
         }

--
Gitblit v1.9.3