<!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>
|