yxh
yxh
2026-06-16 0450b2569821cef5d0f9827afea8612bf645cbfe
yxh
已修改3个文件
已添加1个文件
668 ■■■■■ 文件已修改
.vscode/launch.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
big.html 192 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
big.html.bak 472 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
small.html 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
.vscode/launch.json
@@ -8,7 +8,7 @@
            "type": "editor-browser",
            "request": "launch",
            "name": "Open big.html",
            "url": "file:///d%3A/publish/web/call_jh/integration.html"
            "url": "file:///d%3A/publish/web/call_jh/big.html"
        }
    ]
}
big.html
@@ -3,7 +3,7 @@
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <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,28 +11,36 @@
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
            /* 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. é¡¶éƒ¨æ  - ç®€åŒ–边框,深色主题 */
        /* 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;
@@ -47,6 +55,7 @@
        .top-header .title-text {
            position: absolute;
            left: 50%;
            -webkit-transform: translateX(-50%);
            transform: translateX(-50%);
            font-size: 32px;
            font-weight: bold;
@@ -61,37 +70,70 @@
            z-index: 2;
        }
        /* 3. ä¸»ä½“内容 */
        /* 3. ä¸»ä½“内容(gap æ›¿æ¢ä¸º margin å…¼å®¹æ—§ Chrome) */
        .main-content {
            -webkit-box-flex: 1;
            -webkit-flex: 1;
            flex: 1;
            display: -webkit-box;
            display: -webkit-flex;
            display: flex;
            padding: 15px 20px;
            overflow: hidden;
            gap: 10px;
        }
        /* åˆ—容器 - ç§»é™¤é˜´å½±å’Œåœ†è§’,更简洁 */
        .main-content > .column-box {
            margin-left: 5px;
            margin-right: 5px;
        }
        .main-content > .column-box:first-child {
            margin-left: 0;
        }
        .main-content > .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 {
            font-size: 22px;
            font-weight: bold;
@@ -110,41 +152,52 @@
        /* æ‚£è€…列表 */
        .patient-list {
            -webkit-box-flex: 1;
            -webkit-flex: 1;
            flex: 1;
            overflow-y: auto;
            padding-right: 5px;
        }
        /* ã€å…³é”®ä¿®æ”¹ã€‘第1栏强制一行2个 */
        /* ç¬¬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;
        }
        /* ç¬¬2-5栏保持单列 */
        .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;
        }
        /* 4. æ‚£è€…项目 - æžç®€æ¨¡å¼ */
        /* æ‚£è€…项目 */
        .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;
        }
        /* ã€ä¼˜åŒ–修改】第1栏:增加列间距,改善拥挤感 */
        #col-0 .patient-item {
            width: 45%;
            /* 1. ç¼©å‡å®½åº¦ï¼Œä¸ºé—´éš”留出空间 */
            font-size: 20px;
            margin: 0 2.5%;
            /* 2. æ·»åŠ å·¦å³å¤–è¾¹è·ï¼Œä¸¤åˆ—ä¹‹é—´æ€»é—´éš”ä¸º5% */
        }
        .p-number {
@@ -154,6 +207,8 @@
        }
        .p-name {
            -webkit-box-flex: 1;
            -webkit-flex: 1;
            flex: 1;
            overflow: hidden;
            text-overflow: ellipsis;
@@ -167,11 +222,16 @@
            margin-left: 5px;
        }
        /* 5. åº•部栏 - å±…中显示 */
        /* åº•部栏 */
        .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);
@@ -185,17 +245,16 @@
            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;
@@ -212,8 +271,14 @@
        }
        .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;
@@ -235,6 +300,8 @@
        }
        .debug-body {
            -webkit-box-flex: 1;
            -webkit-flex: 1;
            flex: 1;
            padding: 5px;
            overflow-y: auto;
@@ -264,14 +331,13 @@
    <!-- åº•部栏 -->
    <div class="bottom-footer">
        <!-- æ¸©é¦¨æç¤ºè¯­å±…中 -->
        <div class="footer-tip">温馨提示:请听到呼叫后前往对应诊室</div>
    </div>
    <!-- è°ƒè¯•面板 -->
    <div class="debug-panel" id="debugPanel">
        <div class="debug-header">
            <span>🛠️ è¿è¡Œæ—¥å¿—</span>
            <span>[调试] è¿è¡Œæ—¥å¿—</span>
            <button onclick="document.getElementById('debugBody').innerHTML=''">清空</button>
        </div>
        <div class="debug-body" id="debugBody"></div>
@@ -279,15 +345,18 @@
    <script src="./static/jquery.min.js"></script>
    <script>
        // ================= è°ƒè¯•日志函数 =================
        // ================= è°ƒè¯•日志 =================
        function logDebug(msg) {
            var now = new Date();
            var timeStr = now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
            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 = $("#debugBody");
            $body.append(logHtml);
            $body.scrollTop($body[0].scrollHeight);
            var body = document.getElementById("debugBody");
            if (body) {
                body.insertAdjacentHTML("beforeend", logHtml);
                body.scrollTop = body.scrollHeight;
            }
        }
        // ================= åº”用状态 =================
@@ -295,7 +364,7 @@
            columnTitles: ["常规心电图", "动态心电", "平板运动心电", "食道电生理", "动脉硬化监测"],
            columnSubTitles: ["床边心电图(常规+频谱)M / å¿ƒç”µå‘量图N", "动态血压C", "", "", ""],
            patients: [],
            apiBaseUrl: "http://192.168.3.12/admin-api",
            apiBaseUrl: "http://192.168.100.110/admin-api",
            pollTimer: null,
            callRepeatTimes: 2,
            spokenPatients: {},
@@ -308,28 +377,39 @@
            if (appState.isSpeaking || appState.ttsQueue.length === 0) return;
            appState.isSpeaking = true;
            var text = appState.ttsQueue.shift();
            logDebug("🔊 å¼€å§‹æ’­æŠ¥: " + text);
            logDebug("[播报] " + text);
            var utterance = new SpeechSynthesisUtterance(text);
            // Android 6 é»˜è®¤è¯­é€Ÿå¯èƒ½å¾ˆå¿«ï¼Œé€‚当调慢
            utterance.rate = 0.85;
            utterance.onend = function () {
                appState.isSpeaking = false;
                processTtsQueue();
            };
            utterance.onerror = function () {
            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); }
                } catch (e) { logDebug("[wowjoy失败] " + e.message); }
            }
            if (window.speechSynthesis) { window.speechSynthesis.speak(utterance); }
            else { appState.isSpeaking = false; processTtsQueue(); }
            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) {
@@ -338,10 +418,10 @@
            processTtsQueue();
        }
        // ================= æ¸²æŸ“函数 =================
        // ================= æ¸²æŸ“ =================
        function renderMainContent() {
            var $main = $("#mainContent");
            $main.empty();
            var main = document.getElementById("mainContent");
            main.innerHTML = "";
            for (var i = 0; i < appState.columnTitles.length; i++) {
                var titleHtml = '<div class="col-title-line">' + appState.columnTitles[i] + '</div>';
@@ -350,24 +430,25 @@
                }
                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);
                main.insertAdjacentHTML("beforeend", colHtml);
            }
        }
        function renderPatients() {
            for (var i = 0; i < appState.columnTitles.length; i++) {
                $("#col-" + i).empty();
                var col = document.getElementById("col-" + i);
                if (col) col.innerHTML = "";
            }
            for (var c = 0; c < appState.patients.length; c++) {
                var colData = appState.patients[c];
                if (Array.isArray(colData)) {
                    var $col = $("#col-" + c);
                    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>' : '';
@@ -376,7 +457,7 @@
                            '<span class="p-name">' + (pat.patName || '') + '</span>' +
                            roomHtml +
                            '</div>';
                        $col.append(itemHtml);
                        col.insertAdjacentHTML("beforeend", itemHtml);
                    }
                }
            }
@@ -409,7 +490,7 @@
                                }
                                speak(repeatText);
                                appState.spokenPatients[newPat.patId] = true;
                                logDebug("🔔 åŠ å…¥æ’­æŠ¥é˜Ÿåˆ—: " + newPat.patName);
                                logDebug("[排队] " + newPat.patName + " -> " + newPat.roomName);
                            }
                        }
                    }
@@ -437,26 +518,29 @@
                    appState.patients = dataList;
                    renderPatients();
                    // Android 6 WebView é€šå¸¸ä¸æ”¯æŒ performance.memory,安全守卫
                    try {
                    if (window.performance && window.performance.memory) {
                        var usedMB = (window.performance.memory.usedJSHeapSize / 1048576).toFixed(2);
                        logDebug("💾 å†…å­˜: " + usedMB + " MB");
                            logDebug("[内存] " + usedMB + " MB");
                    }
                    } catch (e) {}
                },
                error: function (err) {
                    logDebug("❌ è¯·æ±‚失败: " + err.statusText);
                    logDebug("[请求失败] " + (err.statusText || "网络错误"));
                }
            });
        }
        // ================= åˆå§‹åŒ– =================
        $(document).ready(function () {
        function onReady() {
            renderMainContent();
            updateHeaderTime();
            setInterval(updateHeaderTime, 1000);
            fetchQueueData();
            appState.pollTimer = setInterval(fetchQueueData, 5000);
            logDebug("✅ ç³»ç»Ÿå¯åЍ");
        });
            logDebug("[系统] å¯åŠ¨å®Œæˆ - Android 6.0.1");
        }
        function updateHeaderTime() {
            var now = new Date();
@@ -464,7 +548,17 @@
            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);
            var el = document.getElementById("headerTime");
            if (el) el.textContent = dateStr + " " + timeStr;
        }
        // å…¼å®¹ DOM ready(Android 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>
big.html.bak
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,472 @@
<!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;
        }
        /* æ‚£è€…列表 */
        .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. æ‚£è€…项目 - æžç®€æ¨¡å¼ */
        .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 / å¿ƒç”µå‘量图N", "动态血压C", "", "", ""],
            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>
small.html
@@ -264,7 +264,7 @@
    <script>
        // ================= é…ç½®å‚æ•° =================
        var CONFIG = {
            apiBaseUrl: "http://192.168.3.12:48080/admin-api",
            apiBaseUrl: "http://192.168.100.110:48080/admin-api",
            // apiBaseUrl: "http://192.168.100.110:48080/admin-api",
            roomId: "116",
            refreshRate: 5000