2026-05-13 17:50:49 +08:00

428 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<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">共
<CountTo :value="list1.length" />个标本
</span>
</div>
<div class="table-box">
<el-table :data="list1" border stripe header-cell-class-name="table-header" class="table" height="35vh"
ref="table1Ref" :header-cell-style="tableHeaderStyle" :cell-style="tableCellStyle"
:row-style="tableRowStyle">
<el-table-column prop="dept" label="科室" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="item" label="标本/项目" />
<el-table-column prop="time" label="采样/送检时间" />
</el-table>
</div>
<span class="border_bg_leftTop"></span>
<span class="border_bg_rightTop"></span>
<span class="border_bg_leftBottom"></span>
<span class="border_bg_rightBottom"></span>
</div>
<div class="card">
<div class="card-header">
<span>已核收还未上机标本</span>
<span class="red-text">共
<CountTo :value="list2.length" />个标本
</span>
</div>
<div class="table-box">
<el-table :data="list2" border stripe header-cell-class-name="table-header" class="table" height="35vh"
ref="table2Ref" :header-cell-style="tableHeaderStyle" :cell-style="tableCellStyle"
:row-style="tableRowStyle">
<el-table-column prop="barcode" label="条码" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="item" label="检查项目" />
<el-table-column prop="time" label="签收时间" />
</el-table>
</div>
<span class="border_bg_leftTop"></span>
<span class="border_bg_rightTop"></span>
<span class="border_bg_leftBottom"></span>
<span class="border_bg_rightBottom"></span>
</div>
<div class="card">
<div class="card-header">
<span>标本完成效率TAT</span>
</div>
<div class="table-box">
<el-table :data="list3" border stripe header-cell-class-name="table-header" class="table" height="35vh"
ref="table3Ref" :header-cell-style="tableHeaderStyle" :cell-style="tableCellStyle"
:row-style="tableRowStyle">
<el-table-column prop="machine" label="仪器" />
<el-table-column prop="sampleNo" label="样本号" />
<el-table-column prop="item" label="检查项目" />
<el-table-column prop="time" label="签收时间" />
<el-table-column prop="status" label="状态">
<template #default="{ row }">
<span :class="row.status === '超时' ? 'timeout' : ''">
{{ row.status == '超时' ? `剩${row.Timeout}超时` : '' }}
</span>
</template>
</el-table-column>
</el-table>
</div>
<span class="border_bg_leftTop"></span>
<span class="border_bg_rightTop"></span>
<span class="border_bg_leftBottom"></span>
<span class="border_bg_rightBottom"></span>
</div>
<div class="card">
<div class="card-header red-title">危急值结果:(请工作人员及时处理!)</div>
<div class="table-box">
<el-table :data="list4" border stripe header-cell-class-name="table-header" class="table" height="35vh"
ref="table4Ref" :header-cell-style="tableHeaderStyle" :cell-style="tableCellStyle"
:row-style="tableRowStyle">
<el-table-column prop="machine" label="仪器" />
<el-table-column prop="sampleNo" label="样本号" />
<el-table-column prop="item" label="项目" />
<el-table-column prop="result" label="结果" />
<el-table-column prop="confirm" label="确认超时" />
</el-table>
</div>
<span class="border_bg_leftTop"></span>
<span class="border_bg_rightTop"></span>
<span class="border_bg_leftBottom"></span>
<span class="border_bg_rightBottom"></span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import CountTo from '@/components/countTo/index.vue'
import dayjs from 'dayjs'
// 填充模拟数据(保持原有逻辑)
const list1 = ref([
{ dept: '1111', name: '张三', item: '血常规', time: '2024-05-20 08:15:30' },
{ dept: '呼吸内科', name: '李四', item: '生化全套', time: '2024-05-20 09:20:15' },
{ dept: '心内科', name: '王五', item: '凝血功能', time: '2024-05-20 10:05:40' },
{ dept: '消化内科', name: '赵六', item: '尿常规', time: '2024-05-20 11:10:25' },
{ dept: '神经内科', name: '孙七', item: '脑脊液', time: '2024-05-20 12:00:10' },
{ dept: 'patient', name: '周八', item: '肾功能', time: '2024-05-20 13:00:00' },
{ dept: 'patient', name: '王八', item: '肝功能', time: '2024-05-20 13:15:30' },
{ dept: '急诊科', name: '张三', item: '血常规', time: '2024-05-20 08:15:30' },
{ dept: '呼吸内科', name: '李四', item: '生化全套', time: '2024-05-20 09:20:15' },
{ dept: '心内科', name: '王五', item: '凝血功能', time: '2024-05-20 10:05:40' },
{ dept: '消化内科', name: '赵六', item: '尿常规', time: '2024-05-20 11:10:25' },
{ dept: '神经内科', name: '孙七', item: '脑脊液', time: '2024-05-20 12:00:10' },
{ dept: 'patient', name: '周八', item: '肾功能', time: '2024-05-20 13:00:00' },
{ dept: '完结', name: '王八', item: '肝功能', time: '2024-05-20 13:15:30' },
])
const list2 = ref([
{ barcode: 'start', name: '周八', item: '肝功能', time: '2024-05-20 08:30:00' },
{ barcode: '8800123457', name: '吴九', item: '肾功能', time: '2024-05-20 09:10:00' },
{ barcode: '8800123458', name: '郑十', item: '电解质', time: '2024-05-20 10:20:00' },
{ barcode: '8800123459', name: '钱十一', item: '血糖', time: '2024-05-20 11:05:00' },
{ barcode: '8800123456', name: '周八', item: '肝功能', time: '2024-05-20 08:30:00' },
{ barcode: '8800123457', name: '吴九', item: '肾功能', time: '2024-05-20 09:10:00' },
{ barcode: '8800123458', name: '郑十', item: '电解质', time: '2024-05-20 10:20:00' },
{ barcode: '8800123459', name: '钱十一', item: '血糖', time: '2024-05-20 11:05:00' },
{ barcode: '8800123456', name: '周八', item: '肝功能', time: '2024-05-20 08:30:00' },
{ barcode: '8800123457', name: '吴九', item: '肾功能', time: '2024-05-20 09:10:00' },
{ barcode: '8800123458', name: '郑十', item: '电解质', time: '2024-05-20 10:20:00' },
{ barcode: 'end', name: '钱十一', item: '血糖', time: '2024-05-20 11:05:00' },
])
const list3 = ref([
{ machine: 'start', sampleNo: 'S20240520001', item: '血常规', time: '2024-05-20 07:15:00', status: '正常', Timeout: '15分钟' },
{ machine: '罗氏Cobas 8000', sampleNo: 'S20240520002', item: '生化全套', time: '2024-05-20 08:20:00', status: '超时', Timeout: '20分钟' },
{ machine: '希森美康XN-9000', sampleNo: 'S20240520003', item: '凝血功能', time: '2024-05-20 09:00:00', status: '正常', Timeout: '10分钟' },
{ machine: '雅培i2000', sampleNo: 'S20240520004', item: '肿瘤标志物', time: '2024-05-20 10:10:00', status: '超时', Timeout: '25分钟' },
{ machine: '贝克曼AU5800', sampleNo: 'S20240520001', item: '血常规', time: '2024-05-20 07:15:00', status: '正常', Timeout: '15分钟' },
])
const list4 = ref([
{ machine: '贝克曼AU5800', sampleNo: 'S20240520010', item: '血钾', result: '7.8mmol/L', confirm: '15分钟' },
{ machine: '罗氏Cobas 8000', sampleNo: 'S20240520011', item: '血糖', result: '28.5mmol/L', confirm: '10分钟' },
{ machine: '希森美康XN-9000', sampleNo: 'S20240520012', item: '血小板', result: '25×10^9/L', confirm: '20分钟' },
])
// 表格样式配置(贴合大屏蓝色背景)
const tableHeaderStyle = {
background: 'rgba(30, 104, 195, 0.8)', // 表头半透深蓝(匹配截图表头)
color: '#ffffff', // 表头文字白色
fontSize: '16px', // 表头字体偏大
fontWeight: 'bold', // 表头加粗
borderColor: '#0099ff' // 表头边框浅蓝
}
const tableCellStyle = {
background: 'transparent', // 单元格完全透明(继承大屏背景)
color: '#ffffff', // 单元格文字白色
fontSize: '16px', // 单元格字体清晰
borderColor: '#0099ff' // 单元格边框浅蓝(区分度高)
}
const tableRowStyle = ({ rowIndex }: { rowIndex: number }) => {
// 斑马纹用极浅的半透蓝(贴合背景,无灰白)
return {
background: rowIndex % 2 === 0 ? 'transparent' : 'rgba(0, 153, 255, 0.1)',
hover: 'rgba(0, 153, 255, 0.2)' // 悬浮行浅蓝高亮
}
}
const table1Ref = useTemplateRef('table1Ref')
const table2Ref = useTemplateRef('table2Ref')
const table3Ref = useTemplateRef('table3Ref')
const table4Ref = useTemplateRef('table4Ref')
// 封装滚动函数,接收表格ref和数据列表(用于判断是否需要刷新)
const createTableScroll = (tableRef: Ref, dataList: Ref) => {
let scrollTimer: any = null;
let refreshTimer: any = null;
const clear = () => {
clearInterval(scrollTimer);
clearInterval(refreshTimer);
scrollTimer = null;
refreshTimer = null;
};
const start = () => {
clear();
if (!tableRef.value) return;
const table = tableRef.value.layout.table.refs;
const tableWrapper = table.bodyWrapper.firstElementChild?.firstElementChild;
if (!tableWrapper) return;
// 只有当内容超出可视区域时才启动滚动和定时刷新 异步判断(确保DOM渲染完成)
setTimeout(() => {
if (tableWrapper.clientHeight == tableWrapper.scrollHeight) {
// 内容未超出可视区域,无需滚动和定时刷新
clear()
refreshTimer = setInterval(() => {
refreshSingleTableData(dataList);
}, 5000);
}
}, 50);
scrollTimer = setInterval(() => {
tableWrapper.scrollTop += 1;
// 仅当前表格滚到底时,刷新当前表格数据(而非全部)
if (tableWrapper.clientHeight + tableWrapper.scrollTop == tableWrapper.scrollHeight) {
tableWrapper.scrollTop = 0;
// 按需刷新单个表格数据,而非全局refreshData
refreshSingleTableData(dataList);
}
}, 100);
};
return { start, clear };
};
// 每个表格独立实例化滚动
const table1Scroll = createTableScroll(table1Ref, list1);
const table2Scroll = createTableScroll(table2Ref, list2);
const table3Scroll = createTableScroll(table3Ref, list3);
const table4Scroll = createTableScroll(table4Ref, list4);
// 单个表格数据刷新(避免全局刷新)
const refreshSingleTableData = (dataList: Ref) => {
// console.log(`刷新表格数据: ${dataList === list1 ? 'list1' : dataList === list2 ? 'list2' : dataList === list3 ? 'list3' : 'list4'}`);
if (dataList === list1) {
// list1.value = 新数据(保留原有滚动位置逻辑)
}
};
// 定时刷新
let timeTimer: any
// 动态时间
const nowTime = ref('')
const updateTime = () => {
nowTime.value = dayjs().format('YYYY年MM月DD日 HH:mm:ss')
}
// 挂载/卸载时独立控制
onMounted(async () => {
updateTime();
timeTimer = setInterval(updateTime, 1000);
await nextTick()
table1Scroll.start();
table2Scroll.start();
table3Scroll.start();
table4Scroll.start();
});
onUnmounted(() => {
clearInterval(timeTimer);
table1Scroll.clear();
table2Scroll.clear();
table3Scroll.clear();
table4Scroll.clear();
});
</script>
<style scoped>
.screen-container {
width: 100%;
height: 100vh;
background: url(@/assets/images/bg2.jpg);
background-size: 100% 100%;
padding: 20px 40px 20px 50px;
}
.screen-header {
position: relative;
width: 100%;
margin-bottom: 20px;
}
.screen-title {
font-size: 1.875rem;
color: rgba(14, 253, 255, 1);
text-align: center;
font-weight: bold;
text-align: center;
line-height: 30px;
}
.screen-time {
position: absolute;
right: 30px;
font-size: 20px;
color: #0ef;
font-weight: 700;
top: 0;
}
.grid-wrapper {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-top: 35px;
}
.card {
position: relative;
background: transparent;
border: 1px solid #0efdff80;
padding: 10px 20px 20px;
height: 42vh;
}
.border_bg_leftTop {
position: absolute;
left: -0.125rem;
top: -0.625rem;
width: 5.78125rem;
height: 0.78125rem;
display: block;
background: #01279d url(@/assets/images/title_left_bg.png) no-repeat;
background-size: cover;
}
.border_bg_rightTop {
position: absolute;
right: -0.15625rem;
top: -0.15625rem;
width: 1.5625rem;
height: 1.5625rem;
display: block;
background: url(@/assets/images/border_bg.jpg) no-repeat;
background-size: cover;
}
.border_bg_leftBottom {
position: absolute;
left: -0.125rem;
bottom: -0.125rem;
width: 1.5625rem;
height: 1.5625rem;
display: block;
background: url(@/assets/images/border_bg.jpg) no-repeat;
background-size: cover;
}
.border_bg_rightBottom {
position: absolute;
right: -0.15625rem;
bottom: -0.15625rem;
width: 1.25rem;
height: 1.25rem;
display: block;
background: url(@/assets/images/title_right_bg.png) no-repeat;
background-size: cover;
}
:deep(.div__body) {
padding: 12px;
}
.card-header {
font-size: 20px;
font-weight: bold;
margin-bottom: 10px;
color: #fff;
display: flex;
justify-content: space-between;
}
.red-text {
color: #ff4d4f;
}
.red-title {
color: #ff4d4f !important;
}
/* 表格全局样式重置 */
:deep(.table) {
--el-table-bg-color: transparent;
--el-table-border-color: #0099ff;
--el-table-row-hover-bg-color: rgba(0, 153, 255, 0.2);
--el-table--striped-row-bg-color: rgba(0, 153, 255, 0.1);
}
/* 移除Element默认的表格背景/边框样式 */
:deep(.el-table) {
background: transparent !important;
border: none !important;
}
:deep(.el-table th) {
border-right: 1px solid #0099ff !important;
}
:deep(.el-table td) {
border-right: 1px solid #0099ff !important;
}
:deep(.el-table__header-wrapper) {
background: transparent !important;
}
:deep(.el-table__body-wrapper) {
background: transparent !important;
}
.timeout {
color: #00ff00;
font-weight: bold;
font-size: 16px;
}
.tips {
margin-top: 8px;
font-size: 12px;
color: #ff4d4f;
}
</style>