326 lines
12 KiB
HTML
326 lines
12 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>TAT监控大屏</title>
|
||
<script src="./js/vue.global.prod.js"></script>
|
||
<link rel="stylesheet" href="./css/element-plus.css">
|
||
<script src="./js/element-plus.js"></script>
|
||
<script src="./js/axios.min.js"></script>
|
||
<script src="./js/dayjs.min.js"></script>
|
||
<link rel="stylesheet" href="./css/index.css">
|
||
<style>
|
||
/* 右上角关闭叉号按钮 透明悬浮 */
|
||
.close-btn-box {
|
||
position: fixed;
|
||
right: 20px;
|
||
top: 30px;
|
||
/* z-index: 9999; */
|
||
}
|
||
|
||
.close-icon-btn {
|
||
width: 44px;
|
||
height: 44px;
|
||
line-height: 44px;
|
||
text-align: center;
|
||
background: transparent;
|
||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||
color: #fff;
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
font-size: 24px;
|
||
font-weight: bold;
|
||
user-select: none;
|
||
}
|
||
|
||
.close-icon-btn:hover {
|
||
background: rgba(255, 0, 0, 0.35);
|
||
border-color: rgba(255, 255, 255, 0.5);
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<div id="app">
|
||
<div class="screen-container">
|
||
<div class="screen-header">
|
||
<div class="screen-title">TAT超时提醒大屏</div>
|
||
<div class="screen-time">{{ nowTime }}</div>
|
||
</div>
|
||
|
||
<div class="grid-wrapper">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<span>已采集待收标本超时</span>
|
||
<span class="red-text">共 {{list1.length}}个标本</span>
|
||
</div>
|
||
<div class="table-box">
|
||
<el-table :data="pageList1" border stripe class="table" height="38vh" :header-cell-style="tableHeaderStyle"
|
||
:cell-style="tableCellStyle" :row-style="tableRowStyle">
|
||
<el-table-column prop="ksdh" label="科室" show-overflow-tooltip></el-table-column>
|
||
<el-table-column label="姓名/条码" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
<span>{{ row.brxm }} / {{ row.sqh }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="标本/项目" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
<span>{{ row.yblx }} / {{ row.jymd }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="cysj" label="采样时间" width="200" show-overflow-tooltip></el-table-column>
|
||
<el-table-column label="等待时间" width="120" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
<span class="red-text">{{ row.holdtime || 0 }} 分钟</span>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<span>已核收未上机超时</span>
|
||
<span class="red-text">共 {{list2.length}}个标本</span>
|
||
</div>
|
||
<div class="table-box">
|
||
<el-table :data="pageList2" border stripe class="table" height="38vh" :header-cell-style="tableHeaderStyle"
|
||
:cell-style="tableCellStyle" :row-style="tableRowStyle">
|
||
<el-table-column prop="ksdh" label="科室" show-overflow-tooltip></el-table-column>
|
||
<el-table-column label="姓名/条码" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
<span>{{ row.brxm }} / {{ row.sqh }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="标本/项目" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
<span>{{ row.yblx }} / {{ row.jymd }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="jssj" label="签收时间" width="200" show-overflow-tooltip></el-table-column>
|
||
<el-table-column label="等待时间" width="120" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
<span class="red-text">{{ row.holdtime || 0 }} 分钟</span>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<span>标本报告未完成超时</span>
|
||
<span class="red-text">共 {{list3.length}}个标本</span>
|
||
</div>
|
||
<div class="table-box">
|
||
<el-table :data="pageList3" border stripe class="table" height="38vh" :header-cell-style="tableHeaderStyle"
|
||
:cell-style="tableCellStyle" :row-style="tableRowStyle">
|
||
<el-table-column prop="yq" label="仪器" show-overflow-tooltip></el-table-column>
|
||
<el-table-column label="样本号/条码号" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
<span>{{ row.ybh }} / {{ row.sqh }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="标本/项目" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
<span>{{ row.yblx }} / {{ row.jymd }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="sjsj" label="上机时间" width="200" show-overflow-tooltip></el-table-column>
|
||
<el-table-column label="等待时间" width="120" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
<span class="red-text">{{ row.holdtime || 0 }} 分钟</span>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header">危急值未处理超时</div>
|
||
<div class="table-box">
|
||
<el-table :data="pageList4" border stripe class="table" height="38vh" :header-cell-style="tableHeaderStyle"
|
||
:cell-style="tableCellStyle" :row-style="tableRowStyle">
|
||
<el-table-column prop="yq" label="仪器" show-overflow-tooltip></el-table-column>
|
||
<el-table-column prop="ybh" label="样本号" show-overflow-tooltip></el-table-column>
|
||
<el-table-column prop="xmmc" label="项目" show-overflow-tooltip></el-table-column>
|
||
<el-table-column prop="csjg" label="结果" show-overflow-tooltip></el-table-column>
|
||
<el-table-column label="等待时间" width="120" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
<span class="red-text">{{ row.holdtime || 0 }} 分钟</span>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右上角 叉号关闭按钮 无文字 -->
|
||
<div class="close-btn-box">
|
||
<div class="close-icon-btn" @click="closeCurrentPage">×</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const { createApp, ref, onMounted, onUnmounted } = Vue;
|
||
|
||
const app = createApp({
|
||
setup() {
|
||
const request = axios.create({ baseURL: '' });
|
||
|
||
// ==================== 从地址栏获取 rows 参数 ====================
|
||
function getPageSizeFromUrl() {
|
||
const params = new URLSearchParams(window.location.search);
|
||
const rows = parseInt(params.get('rows'));
|
||
return !isNaN(rows) && rows > 0 ? rows : 13; // 默认13行
|
||
}
|
||
|
||
// ==================== 配置 ====================
|
||
const PAGE_SIZE = getPageSizeFromUrl(); // 从地址栏获取,默认13
|
||
const PAGE_DELAY = 5000; // 翻页间隔
|
||
const NO_PAGE_DELAY = 5000; // 不足一页刷新间隔
|
||
// ===============================================
|
||
|
||
// 原始数据
|
||
const list1 = ref([]);
|
||
const list2 = ref([]);
|
||
const list3 = ref([]);
|
||
const list4 = ref([]);
|
||
|
||
// 分页展示数据
|
||
const pageList1 = ref([]);
|
||
const pageList2 = ref([]);
|
||
const pageList3 = ref([]);
|
||
const pageList4 = ref([]);
|
||
|
||
// 样式
|
||
const tableHeaderStyle = {
|
||
background: 'rgba(30, 104, 195, 1)',
|
||
color: '#ffffff', fontSize: '16px', fontWeight: 'bold',
|
||
borderColor: '#0099ff', padding: '4px 0px'
|
||
};
|
||
const tableCellStyle = {
|
||
background: 'transparent', color: '#ffffff', fontSize: '15px',
|
||
borderColor: '#0099ff', padding: '2px 0px'
|
||
};
|
||
const tableRowStyle = ({ rowIndex }) => ({
|
||
background: rowIndex % 2 === 0 ? 'transparent' : 'rgba(0, 153, 255, 0.1)'
|
||
});
|
||
|
||
// 时间
|
||
const nowTime = ref('');
|
||
const updateTime = () => {
|
||
nowTime.value = dayjs().format('YYYY年MM月DD日 HH:mm:ss');
|
||
};
|
||
|
||
// 关闭当前网页
|
||
const closeCurrentPage = () => {
|
||
window.close();
|
||
};
|
||
|
||
// 安全清除定时器
|
||
const safeClear = (timer) => timer && clearTimeout(timer);
|
||
|
||
// 核心:分页轮播 + 最后一页刷新
|
||
function startCarousel(list, pageList, onFinish) {
|
||
let currentPage = 0;
|
||
let timer = null;
|
||
|
||
function run() {
|
||
safeClear(timer);
|
||
const total = list.value.length;
|
||
if (total === 0) {
|
||
pageList.value = [];
|
||
timer = setTimeout(run, NO_PAGE_DELAY);
|
||
return;
|
||
}
|
||
|
||
// 不足一页:不翻页,定时刷新
|
||
if (total <= PAGE_SIZE) {
|
||
pageList.value = list.value;
|
||
timer = setTimeout(run, NO_PAGE_DELAY);
|
||
return;
|
||
}
|
||
|
||
// 计算分页
|
||
const start = currentPage * PAGE_SIZE;
|
||
const end = start + PAGE_SIZE;
|
||
pageList.value = list.value.slice(start, end);
|
||
|
||
const isLastPage = end >= total;
|
||
|
||
// 最后一页:停留后刷新数据
|
||
if (isLastPage) {
|
||
timer = setTimeout(() => {
|
||
currentPage = 0;
|
||
onFinish(); // 刷新
|
||
}, PAGE_DELAY);
|
||
} else {
|
||
// 下一页
|
||
timer = setTimeout(() => {
|
||
currentPage++;
|
||
run();
|
||
}, PAGE_DELAY);
|
||
}
|
||
}
|
||
|
||
run();
|
||
return () => safeClear(timer);
|
||
}
|
||
|
||
// 加载数据 + 启动轮播
|
||
function createLoader(url, list, pageList) {
|
||
let stopCarousel = null;
|
||
|
||
async function load() {
|
||
try {
|
||
if (stopCarousel) stopCarousel();
|
||
const { data: res } = await request.get(url);
|
||
list.value = res.data || [];
|
||
stopCarousel = startCarousel(list, pageList, load);
|
||
} catch (e) {
|
||
console.log("加载失败", url);
|
||
setTimeout(load, NO_PAGE_DELAY);
|
||
}
|
||
}
|
||
|
||
load();
|
||
return () => stopCarousel && stopCarousel();
|
||
}
|
||
|
||
// 启动所有表格
|
||
let stop1, stop2, stop3, stop4;
|
||
onMounted(() => {
|
||
updateTime();
|
||
setInterval(updateTime, 1000);
|
||
|
||
stop1 = createLoader('/api/list1', list1, pageList1);
|
||
stop2 = createLoader('/api/list2', list2, pageList2);
|
||
stop3 = createLoader('/api/list3', list3, pageList3);
|
||
stop4 = createLoader('/api/list4', list4, pageList4);
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
stop1?.();
|
||
stop2?.();
|
||
stop3?.();
|
||
stop4?.();
|
||
});
|
||
|
||
return {
|
||
list1, list2, list3, list4,
|
||
pageList1, pageList2, pageList3, pageList4,
|
||
nowTime, tableHeaderStyle, tableCellStyle, tableRowStyle,
|
||
closeCurrentPage
|
||
};
|
||
}
|
||
});
|
||
|
||
app.use(ElementPlus).mount('#app');
|
||
</script>
|
||
</body>
|
||
|
||
</html> |