|
|
<template>
|
|
|
<section class="waitBox bg-[#F3F2FA]">
|
|
|
<nav
|
|
|
class="h-[11.11vh] pl-[3.7vh] pr-[2.22vh] flex justify-between items-center bg-[#5D49AF] relative overflow-hidden">
|
|
|
<div class="logBox h-[7vh]">
|
|
|
<img class="h-full" :src="logoUrl" v-show="logoUrl" />
|
|
|
<img class="h-full" :src="logoUrlBackup" v-show="!logoUrl && logoUrlBackup" />
|
|
|
</div>
|
|
|
<div class="absolute titleBox w-full flex justify-around">
|
|
|
<div class="flex items-center">
|
|
|
<p class="text-[5.55vh] font-bold mr-[1.48vh]">家属等候大屏</p>
|
|
|
<span class="text-[2.96vh] text-[#ccc] tracking-widest">({{ carouselCountDown }}s)</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="timeBox text-right">
|
|
|
<p class="text-[3.14vh] font-medium leading-tight">{{ formatTime }}</p>
|
|
|
<p class="text-[1.66vh]">{{ formatDate }}</p>
|
|
|
</div>
|
|
|
</nav>
|
|
|
<main class="h-[calc(100vh-18.51vh)] p-[15px] pb-0 relative overflow-hidden" ref="mainRef">
|
|
|
<div class="absolute top-[24px] left-1/2 -translate-x-1/2 w-[calc(100%-30px)]">
|
|
|
<div class="bg-[#9A82FF] flex text-center" :style="carouselNav">
|
|
|
<template v-for="item in colList">
|
|
|
<div class="font-semibold border-r truncate"
|
|
|
:style="item['width'] ? `flex-basis:${item['width']}px` : `flex-grow: 1;`" :key="item['columnCode']"
|
|
|
v-if="item['isShow']">
|
|
|
{{ item['columnName'] }}
|
|
|
</div>
|
|
|
</template>
|
|
|
</div>
|
|
|
<div :style="carouselWrap" class="border border-[#9A82FF] border-t-0" v-loading="isLoading">
|
|
|
<template v-if="patientList['length']">
|
|
|
<el-carousel direction="vertical" :autoplay="false" indicatorPosition="none" ref="carousel"
|
|
|
@change="onCarouselChange">
|
|
|
<el-carousel-item v-for="(item, index) in patientList" :key="index">
|
|
|
<section class="carouselItemBox">
|
|
|
<template v-for="(subItem, index) in item">
|
|
|
<div :key="index" :style="carouselItemStyle">
|
|
|
<div class="flex text-center">
|
|
|
<template v-for="item in colList">
|
|
|
<template v-if="item['columnCode'] == 'ProcStatusName'">
|
|
|
<div class="border-r text-[#333] font-semibold truncate"
|
|
|
:style="{ color: `${textWaitToColor(subItem['ProcStatusName'])}`, 'flex-basis': `${item['width']}px` }"
|
|
|
:key="item['columnCode']" v-if="item['isShow']">
|
|
|
{{ subItem['ProcStatusName'] }}
|
|
|
</div>
|
|
|
</template>
|
|
|
<template v-else-if="item['columnCode'] == 'PatientName'">
|
|
|
<div class="border-r text-[#333] font-semibold truncate"
|
|
|
:style="item['width'] ? `flex-basis:${item['width']}px` : `flex-grow: 1;`"
|
|
|
:key="item['columnCode']" v-if="item['isShow']">
|
|
|
{{ desensitizationText(subItem[item['columnCode']]) }}
|
|
|
</div>
|
|
|
</template>
|
|
|
<template v-else>
|
|
|
<div class="border-r text-[#333] font-semibold truncate"
|
|
|
:style="item['width'] ? `flex-basis:${item['width']}px` : `flex-grow: 1;`"
|
|
|
:key="item['columnCode']" v-if="item['isShow']">
|
|
|
{{ subItem[item['columnCode']] }}
|
|
|
</div>
|
|
|
</template>
|
|
|
</template>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
</section>
|
|
|
</el-carousel-item>
|
|
|
</el-carousel>
|
|
|
</template>
|
|
|
</div>
|
|
|
<div class="popupBox" v-if="showPopup">
|
|
|
<div>
|
|
|
<p v-for="(item, index) in popupMag" :key="index">
|
|
|
{{ item }}
|
|
|
</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="absolute bottom-2 left-1/2 -translate-x-1/2 flex">
|
|
|
<template v-for="(item, index) in patientList">
|
|
|
<div class="w-3 h-3 rounded-full bg-[#D8D8D8] mx-1" :class="{ '!bg-[#8C8D92]': index == activeIndex }"
|
|
|
:key="index" />
|
|
|
</template>
|
|
|
</div>
|
|
|
</main>
|
|
|
<footer class="h-[7.4vh] flex items-center justify-around bg-[#5D49AF] overflow-hidden">
|
|
|
<div class="flex items-center">
|
|
|
<div class="logBox w-[15vh] h-[3.7vh] mr-[1.48vh]">
|
|
|
<img class="h-full" src="@/assets/svg/Wait/footText.png" />
|
|
|
</div>
|
|
|
<p class="text-[2.59vh]">请勿吸烟,请照顾好自己随身携带的物品,请耐心等待,我们将竭诚为您服务</p>
|
|
|
</div>
|
|
|
</footer>
|
|
|
<audio ref="audioRef" class="invisible"></audio>
|
|
|
</section>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import { getDynamicTableHeader, getDynamicTableList, getGlobeConfig, getAudio } from '@/api/publishApi';
|
|
|
import { Carousel, CarouselItem } from 'element-ui';
|
|
|
import dayjs from 'dayjs';
|
|
|
import { statusToTxt, textWaitToColor } from '@/utils/common';
|
|
|
import Stomp from 'stompjs';
|
|
|
const { MQTT_SERVICE, MQTT_USERNAME, MQTT_PASSWORD } = window.globalMQ;
|
|
|
|
|
|
export default {
|
|
|
data() {
|
|
|
return {
|
|
|
isLoading: true,
|
|
|
mainRefHeight: 0,
|
|
|
showItemNum: 8,
|
|
|
carouselNav: {},
|
|
|
carouselWrap: {},
|
|
|
carouselItemStyle: {},
|
|
|
patientList: [],
|
|
|
currentDateTime: dayjs().format('YYYY-MM-DD HH:mm dddd'),
|
|
|
dateTimer: null,
|
|
|
carouselCountDown: 10,
|
|
|
carouselTimer: null,
|
|
|
activeIndex: 0,
|
|
|
getDataTimer: null,
|
|
|
popupMsgList: [],
|
|
|
showPopup: false,
|
|
|
hasPlay: false,
|
|
|
playNum: 0,
|
|
|
popupMag: [],
|
|
|
popupTimer: null,
|
|
|
synth: window.speechSynthesis,
|
|
|
colList: [],
|
|
|
queryCondition: [],
|
|
|
logoUrl: "",
|
|
|
logoUrlBackup: "",
|
|
|
groupIndex: -1,
|
|
|
roomNameList: [],
|
|
|
};
|
|
|
},
|
|
|
methods: {
|
|
|
statusToTxt,
|
|
|
textWaitToColor,
|
|
|
onGetPageData() {
|
|
|
let today = dayjs().format('YYYY-MM-DD');
|
|
|
// let today = '2024-06-06';
|
|
|
// let today = '2025-02-26';
|
|
|
const QueryFiledDic = {};
|
|
|
this.queryCondition.forEach(queryItem => {
|
|
|
if (queryItem['queryType'] == 'dateTime') {
|
|
|
QueryFiledDic[queryItem['queryFiled']] = today;
|
|
|
}
|
|
|
});
|
|
|
getDynamicTableList({
|
|
|
PageSize: 999,
|
|
|
GroupCode: 'JSDHQDP',
|
|
|
QueryFiledDic,
|
|
|
})
|
|
|
.then(res => {
|
|
|
this.patientList = [];
|
|
|
|
|
|
if (res['Data']['Data']['length']) {
|
|
|
if (this.groupIndex >= 0) {
|
|
|
if (this.roomNameList[this.groupIndex]) {
|
|
|
res['Data']['Data'] = res['Data']['Data'].filter(item => {
|
|
|
return this.roomNameList[this.groupIndex].includes(item['RoomName'])
|
|
|
})
|
|
|
} else {
|
|
|
res['Data']['Data'] = [];
|
|
|
}
|
|
|
}
|
|
|
for (let index = 0; index < res['Data']['Data']['length']; index++) {
|
|
|
const element = res['Data']['Data'][index];
|
|
|
const groupIndex = parseInt(index / this.showItemNum);
|
|
|
if (this.patientList[groupIndex]) {
|
|
|
this.patientList[groupIndex].push(element);
|
|
|
} else {
|
|
|
this.patientList[groupIndex] = [element];
|
|
|
}
|
|
|
}
|
|
|
if (!this.carouselTimer && res['Data']['Data']['length'] > this.showItemNum) {
|
|
|
this.onCarouselTimer();
|
|
|
}
|
|
|
} else {
|
|
|
clearInterval(this.carouselTimer);
|
|
|
}
|
|
|
})
|
|
|
.finally(() => {
|
|
|
this.isLoading = false;
|
|
|
});
|
|
|
},
|
|
|
onCarouselTimer() {
|
|
|
this.$nextTick(() => {
|
|
|
this.carouselTimer = setInterval(() => {
|
|
|
this.carouselCountDown -= 1;
|
|
|
if (this.carouselCountDown == 0) {
|
|
|
this.$refs.carousel.next();
|
|
|
this.carouselCountDown = 10;
|
|
|
}
|
|
|
}, 1000);
|
|
|
});
|
|
|
},
|
|
|
onCalculate() {
|
|
|
// 根据展示数量计算高度
|
|
|
this.mainRefHeight = parseInt(this.$refs.mainRef.clientHeight - 15 - 40);
|
|
|
const rowHeight = this.mainRefHeight / (this.showItemNum + 1);
|
|
|
this.carouselNav = {
|
|
|
'font-size': `${(rowHeight * 0.53).toFixed(2)}px`,
|
|
|
'line-height': `${rowHeight.toFixed(2)}px`,
|
|
|
};
|
|
|
this.carouselWrap = {
|
|
|
height: `${(rowHeight * this.showItemNum).toFixed(2)}px`,
|
|
|
};
|
|
|
this.carouselItemStyle = {
|
|
|
'line-height': `${rowHeight.toFixed(2)}px`,
|
|
|
'font-size': `${(rowHeight * 0.5).toFixed(2)}px`,
|
|
|
};
|
|
|
},
|
|
|
onCarouselChange(index) {
|
|
|
this.activeIndex = index;
|
|
|
},
|
|
|
setRabitMQ() {
|
|
|
this.client = Stomp.client(MQTT_SERVICE);
|
|
|
this.connect();
|
|
|
},
|
|
|
connect: function () {
|
|
|
const headers = {
|
|
|
login: MQTT_USERNAME,
|
|
|
passcode: MQTT_PASSWORD,
|
|
|
};
|
|
|
this.client.connect(headers, this.onConnected, this.onFailed);
|
|
|
},
|
|
|
onConnected: function () {
|
|
|
this.client.subscribe('/exchange/DeviceExchange/SignsNonStandard', this.responseCallback);
|
|
|
},
|
|
|
responseCallback: function (frame) {
|
|
|
try {
|
|
|
if (frame.body) {
|
|
|
let data = JSON.parse(frame.body);
|
|
|
data['msg'] = JSON.parse(data['msg']);
|
|
|
if (this.groupIndex >= 0) {
|
|
|
if (this.roomNameList[this.groupIndex]) {
|
|
|
if (!this.roomNameList[this.groupIndex].includes(data['msg']['patientRoomName'])) {
|
|
|
return
|
|
|
}
|
|
|
} else {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
this.popupMsgList.push(data['msg']['notice'].replaceAll(',', ','));
|
|
|
}
|
|
|
} catch (e) {
|
|
|
console.warn(e);
|
|
|
}
|
|
|
},
|
|
|
onFailed: function (frame) {
|
|
|
console.group("MQ Failed:")
|
|
|
console.log(frame);
|
|
|
console.groupEnd();
|
|
|
setTimeout(() => {
|
|
|
this.client = Stomp.client(MQTT_SERVICE);
|
|
|
Stomp.over(this.client);
|
|
|
this.connect();
|
|
|
}, 5000);
|
|
|
},
|
|
|
onPopupPlay() {
|
|
|
if (!this.hasPlay && this.popupMsgList.length) {
|
|
|
this.hasPlay = true;
|
|
|
this.popupMag = this.popupMsgList[0].replace(/[,,]/g, '').split('#');
|
|
|
this.showPopup = true;
|
|
|
this.playNum++;
|
|
|
getAudio({ text: this.popupMsgList[0].replaceAll("#", '') }).then(res => {
|
|
|
const blob = new Blob([res['data']], { type: "audio/wav" });
|
|
|
const audioUrl = URL.createObjectURL(blob);
|
|
|
|
|
|
if (this.$refs.audioRef) {
|
|
|
this.$refs.audioRef.src = audioUrl
|
|
|
this.$refs.audioRef.play()
|
|
|
}
|
|
|
|
|
|
this.$refs.audioRef.onended = () => {
|
|
|
if (this.playNum < 3) {
|
|
|
this.playNum++;
|
|
|
setTimeout(() => {
|
|
|
this.$refs.audioRef.play()
|
|
|
}, 500);
|
|
|
} else {
|
|
|
this.popupMag = "";
|
|
|
this.showPopup = false;
|
|
|
this.playNum = 0;
|
|
|
this.hasPlay = false;
|
|
|
this.popupMsgList.shift();
|
|
|
URL.revokeObjectURL(audioUrl)
|
|
|
this.$refs.audioRef.onended = null
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
},
|
|
|
desensitizationText(text) {
|
|
|
if (text.length <= 1) {
|
|
|
return text;
|
|
|
}
|
|
|
if (text.length === 2) {
|
|
|
return text.charAt(0) + '*';
|
|
|
}
|
|
|
return text.charAt(0) + '*'.repeat(text.length - 2) + text.charAt(text.length - 1);
|
|
|
},
|
|
|
onGetblobe() {
|
|
|
getGlobeConfig({ isTree: false }).then(res => {
|
|
|
res['Data']['Item'].forEach(item => {
|
|
|
if (item['Key'] == 'HospitalLogo') {
|
|
|
this.logoUrl = item['Value']
|
|
|
|
|
|
}
|
|
|
if (item['Key'] == "CorporateLogo") {
|
|
|
this.logoUrlBackup = item['Value']
|
|
|
}
|
|
|
if (item['Key'] == "RoomName") {
|
|
|
this.roomNameList = JSON.parse(item['Value'])
|
|
|
}
|
|
|
})
|
|
|
})
|
|
|
},
|
|
|
},
|
|
|
mounted() {
|
|
|
this.$nextTick(() => {
|
|
|
this.onCalculate();
|
|
|
this.onGetblobe();
|
|
|
// 每秒更新一次当前时间
|
|
|
this.dateTimer = setInterval(() => {
|
|
|
this.currentDateTime = dayjs().format('YYYY-MM-DD HH:mm dddd');
|
|
|
}, 10000);
|
|
|
getDynamicTableHeader({
|
|
|
query: 'JSDHQDP',
|
|
|
}).then(res => {
|
|
|
if (res['Data']['Data']['length']) {
|
|
|
res = res['Data']['Data'][0];
|
|
|
this.colList = JSON.parse(res['ReportHeadColumn']);
|
|
|
this.queryCondition = JSON.parse(res['QueryCondition']);
|
|
|
}
|
|
|
this.onGetPageData();
|
|
|
this.getDataTimer = setInterval(() => {
|
|
|
this.onGetPageData();
|
|
|
}, 35000);
|
|
|
this.popupTimer = setInterval(() => {
|
|
|
this.onPopupPlay();
|
|
|
}, 2000);
|
|
|
window.addEventListener('resize', this.onCalculate);
|
|
|
this.setRabitMQ();
|
|
|
});
|
|
|
// setTimeout(() => {
|
|
|
// this.popupMsgList.push('请,金尧仙,的家属#到,手术室门口接病人');
|
|
|
// }, 1000);
|
|
|
});
|
|
|
},
|
|
|
components: {
|
|
|
'el-carousel': Carousel,
|
|
|
'el-carousel-item': CarouselItem,
|
|
|
},
|
|
|
computed: {
|
|
|
formatDate() {
|
|
|
const timeArr = this.currentDateTime.split(' ');
|
|
|
let weekName = '星期一';
|
|
|
if (timeArr[2] == 'Tuesday') {
|
|
|
weekName = '星期二';
|
|
|
}
|
|
|
if (timeArr[2] == 'Wednesday') {
|
|
|
weekName = '星期三';
|
|
|
}
|
|
|
if (timeArr[2] == 'Thursday') {
|
|
|
weekName = '星期四';
|
|
|
}
|
|
|
if (timeArr[2] == 'Friday') {
|
|
|
weekName = '星期五';
|
|
|
}
|
|
|
if (timeArr[2] == 'Saturday') {
|
|
|
weekName = '星期六';
|
|
|
}
|
|
|
if (timeArr[2] == 'Sunday') {
|
|
|
weekName = '星期日';
|
|
|
}
|
|
|
return `${timeArr[0]} ${weekName}`;
|
|
|
},
|
|
|
formatTime() {
|
|
|
return this.currentDateTime.split(' ')[1];
|
|
|
},
|
|
|
},
|
|
|
watch: {
|
|
|
'$route.params.groupIndex'(newVal) {
|
|
|
if (newVal) {
|
|
|
this.groupIndex = newVal;
|
|
|
} else {
|
|
|
this.groupIndex = -1;
|
|
|
}
|
|
|
this.onGetPageData();
|
|
|
}
|
|
|
},
|
|
|
beforeDestroy() {
|
|
|
// 清除定时器
|
|
|
clearInterval(this.dateTimer);
|
|
|
clearInterval(this.carouselTimer);
|
|
|
clearInterval(this.getDataTimer);
|
|
|
clearInterval(this.popupTimer);
|
|
|
// 组件销毁前移除 resize 事件监听器
|
|
|
window.removeEventListener('resize', this.onCalculate);
|
|
|
},
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
:deep(.el-carousel) {
|
|
|
height: 100%;
|
|
|
|
|
|
.el-carousel__container,
|
|
|
.el-carousel__item {
|
|
|
height: 100%;
|
|
|
|
|
|
.carouselItemBox {
|
|
|
>div:nth-child(odd) {
|
|
|
background: #fff;
|
|
|
}
|
|
|
|
|
|
>div:nth-child(even) {
|
|
|
background: #f5f8ff;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.popupBox {
|
|
|
position: absolute;
|
|
|
top: 0%;
|
|
|
left: 0%;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
z-index: 9999;
|
|
|
|
|
|
div {
|
|
|
position: absolute;
|
|
|
top: 50%;
|
|
|
left: 50%;
|
|
|
transform: translate(-50%, -50%);
|
|
|
box-shadow: 0px 3px 14px 0px rgba(0, 0, 0, 0.2);
|
|
|
font-size: 9vh;
|
|
|
white-space: nowrap;
|
|
|
padding: 3vh;
|
|
|
backdrop-filter: blur(2px);
|
|
|
background: #ece5ffe6;
|
|
|
|
|
|
p {
|
|
|
color: #333;
|
|
|
text-align: center;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</style>
|