| | |
| | | <script setup> |
| | | import { ref, onMounted } from 'vue' |
| | | import { ref, onMounted, nextTick } from 'vue' |
| | | import dayjs from 'dayjs' |
| | | import UQRCode from 'uqrcodejs' |
| | | import { getLargeScreenData } from '@/utils/request' |
| | | import duration from 'dayjs/plugin/duration' |
| | | dayjs.extend(duration) |
| | | import VScaleScreen from 'v-scale-screen' |
| | | |
| | | const initQrcode = () => { |
| | | var qr = new UQRCode(); |
| | | // 设置二维码内容 |
| | | qr.data = "https://uqrcode.cn/doc"; |
| | | qr.size = 254; |
| | | // 调用制作二维码方法 |
| | | qr.make(); |
| | | var canvas = document.getElementById("qrcode"); |
| | | var canvasContext = canvas.getContext("2d"); |
| | | qr.canvasContext = canvasContext; |
| | | qr.drawCanvas(); |
| | | const qrcode = ref('') |
| | | const contentList = ref([]) |
| | | const contentTempList = ref([]) |
| | | const page = ref(1) |
| | | const timer = ref() |
| | | |
| | | const callList = ref([]) |
| | | const activeCall = ref({}) |
| | | const pageCall = ref(0) |
| | | const timerCall = ref() |
| | | |
| | | const initData = () => { |
| | | getLargeScreenData().then(res => { |
| | | if (res.data && res.data.allList) { |
| | | contentList.value = res.data.allList.map(item => { |
| | | if (item.optTime) { |
| | | item.optTimeTemp = dayjs(item.optTime).format('HH:mm') |
| | | if(item.status == 4){ |
| | | if(item.optTime >= new Date().getTime()){ |
| | | item.optTimeTemp = dayjs.duration(item.optTime - new Date().getTime()).format('HH:mm') |
| | | }else{ |
| | | item.optTimeTemp = '-' |
| | | } |
| | | } |
| | | // item.optTimeTemp = dayjs.duration(Math.abs(new Date().getTime() - item.optTime)).format('HH:mm') |
| | | } |
| | | return item |
| | | }) |
| | | clearInterval(timer.value) |
| | | setInitContent() |
| | | } |
| | | if (res.data && res.data.waitWorkList) { |
| | | callList.value = res.data.waitWorkList |
| | | } |
| | | qrcode.value = res.data.qrCode |
| | | initQrcode() |
| | | clearInterval(timerCall.value) |
| | | setInitCall() |
| | | }) |
| | | } |
| | | |
| | | const frequencyFn = (length) => { |
| | | if (length <= 16) { // 2 |
| | | return 30 * 1000 |
| | | } else if (length <= 24) { // 3 |
| | | return 20 * 1000 |
| | | } else if (length <= 32) {// 4 |
| | | return 15 * 1000 |
| | | } else if (length <= 48) {// 6 |
| | | return 10 * 1000 |
| | | } else if (length <= 60) {// 10 |
| | | return 6 * 1000 |
| | | } else { |
| | | return 4 * 1000 |
| | | } |
| | | } |
| | | const frequencyCallFn = (length) => { |
| | | if (length <= 10) { // 2 |
| | | return 6 * 1000 |
| | | } else if (length <= 20) { // 3 |
| | | return 3 * 1000 |
| | | } else { |
| | | return 2 * 1000 |
| | | } |
| | | } |
| | | const setInitContent = () => { |
| | | if (contentList.value && contentList.value.length > 0) { |
| | | contentTempList.value = contentList.value.slice(0, 8) |
| | | if (page.value * 8 >= contentList.value.length) { |
| | | page.value = 1 |
| | | } else { |
| | | page.value++ |
| | | } |
| | | timer.value = setInterval(() => { |
| | | if (page.value * 8 >= contentList.value.length) { |
| | | page.value = 1 |
| | | } else { |
| | | page.value++ |
| | | } |
| | | contentTempList.value = contentList.value.slice((page.value - 1) * 8, page.value * 8) |
| | | }, frequencyFn(contentList.value.length)) |
| | | } |
| | | } |
| | | const setInitCall = () => { |
| | | if (callList.value && callList.value.length > 0) { |
| | | activeCall.value = callList.value[0] |
| | | timerCall.value = setInterval(() => { |
| | | if (pageCall.value >= callList.value.length - 1) { |
| | | pageCall.value = 0 |
| | | } else { |
| | | pageCall.value++ |
| | | } |
| | | activeCall.value = callList.value[pageCall.value] |
| | | }, frequencyCallFn(callList.value.length)) |
| | | } |
| | | } |
| | | |
| | | onMounted(() => { |
| | | initQrcode() |
| | | initData() |
| | | setInterval(() => { |
| | | initData() |
| | | }, 60 * 1000) |
| | | }) |
| | | |
| | | const initQrcode = () => { |
| | | var qr = new UQRCode() |
| | | // 设置二维码内容 |
| | | qr.data = qrcode.value |
| | | qr.size = 268 |
| | | // 调用制作二维码方法 |
| | | qr.make() |
| | | var canvas = document.getElementById("qrcode") |
| | | var canvasContext = canvas.getContext("2d") |
| | | qr.canvasContext = canvasContext |
| | | qr.drawCanvas() |
| | | } |
| | | |
| | | const statusMap = { |
| | | 0: '待确认', |
| | | 1: '待签到', |
| | | 2: '等待叫号', |
| | | 3: '入园等待', |
| | | 4: '已叫号', // 已叫号 月台等待 |
| | | 5: '作业中', |
| | | 6: '作业完成', |
| | | 7: '转移中', |
| | | 8: '异常挂起', |
| | | 9: '已授权离园', |
| | | 10: '已离园', |
| | | 11: '已过号', |
| | | 12: '已取消', |
| | | } |
| | | const weekMap = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'] |
| | | const newWeek = ref(weekMap[new Date().getDay()]) |
| | | const newDate = ref(dayjs().format('YYYY-MM-DD')) |
| | |
| | | newDate.value = dayjs().format('YYYY-MM-DD') |
| | | newTime.value = dayjs().format('HH:mm') |
| | | }, 1000) |
| | | |
| | | const isFullscreen = ref(false) |
| | | const handleFull = () => { |
| | | if (!isFullscreen.value) { |
| | | handleFullScreen() |
| | | } else { |
| | | cancelFullscreen() |
| | | } |
| | | } |
| | | const handler = () => { |
| | | isFullscreen.value = document.fullscreenElement !== null |
| | | if (!isFullscreen) { |
| | | // 退出全屏时候解除监听,不然每次监听都会添加一次绑定 |
| | | document.removeEventListener("fullscreenchange", handler) |
| | | } |
| | | } |
| | | document.addEventListener("fullscreenchange", handler) |
| | | const handleFullScreen = () => { |
| | | let elem = document.documentElement |
| | | // 尝试启用全屏模式 |
| | | if (elem.requestFullscreen) { |
| | | elem.requestFullscreen() |
| | | } else if (elem.mozRequestFullScreen) { // 兼容 Firefox |
| | | elem.mozRequestFullScreen() |
| | | } else if (elem.webkitRequestFullscreen) { // 兼容 Chrome, Safari 和 Opera |
| | | elem.webkitRequestFullscreen() |
| | | } else if (elem.msRequestFullscreen) { // 兼容 IE/Edge |
| | | elem.msRequestFullscreen() |
| | | } |
| | | } |
| | | function cancelFullscreen() { |
| | | if (document.exitFullscreen) { |
| | | document.exitFullscreen() |
| | | } else if (document.msExitFullscreen) { |
| | | document.msExitFullscreen() |
| | | } else if (document.mozCancelFullScreen) { |
| | | document.mozCancelFullScreen() |
| | | } else if (document.webkitExitFullscreen) { |
| | | document.webkitExitFullscreen() |
| | | } |
| | | } |
| | | |
| | | </script> |
| | | <template> |
| | | <div class="main_app"> |
| | | <div class="main_header"> |
| | | <img class="bg" src="@/assets/images/call/title@2x.png" alt=""> |
| | | <div class="title">安泰智慧物流园区-车辆叫号大屏</div> |
| | | <div class="time_wrap"> |
| | | <div class="left"> |
| | | <div class="week">{{ newWeek }}</div> |
| | | <div class="date">{{ newDate }}</div> |
| | | </div> |
| | | <div class="time">{{ newTime }}</div> |
| | | </div> |
| | | </div> |
| | | <div class="main_content"> |
| | | <div class="list"> |
| | | <div class="line header"> |
| | | <div class="item no">序号</div> |
| | | <div class="item">车牌号</div> |
| | | <div class="item status">状态</div> |
| | | <div class="item">停靠月台</div> |
| | | <div class="item">时间</div> |
| | | </div> |
| | | <div class="line"> |
| | | <div class="item no">序号</div> |
| | | <div class="item">车牌号</div> |
| | | <div class="item"> |
| | | <div class="status underway">作业中</div> |
| | | <v-scale-screen width="1920" height="1080" :fullScreen="true"> |
| | | <div class="main_app"> |
| | | <div class="main_header"> |
| | | <img class="bg" src="@/assets/images/call/title@2x.png" alt=""> |
| | | <div class="title">安泰智慧物流园区-车辆叫号大屏</div> |
| | | <div class="time_wrap" @click="handleFull"> |
| | | <div class="left"> |
| | | <div class="week">{{ newWeek }}</div> |
| | | <div class="date">{{ newDate }}</div> |
| | | </div> |
| | | <div class="item">停靠月台</div> |
| | | <div class="item">时间</div> |
| | | </div> |
| | | <div class="line"> |
| | | <div class="item no">序号</div> |
| | | <div class="item">车牌号</div> |
| | | <div class="item"> |
| | | <div class="status call_ed">作业中</div> |
| | | </div> |
| | | <div class="item">停靠月台</div> |
| | | <div class="item">时间</div> |
| | | </div> |
| | | <div class="line"> |
| | | <div class="item no">序号</div> |
| | | <div class="item">车牌号</div> |
| | | <div class="item"> |
| | | <div class="status padding">作业中</div> |
| | | </div> |
| | | <div class="item">停靠月台</div> |
| | | <div class="item">时间</div> |
| | | <div class="time">{{ newTime }}</div> |
| | | </div> |
| | | </div> |
| | | <div class="current"> |
| | | <div class="tip_wrap"> |
| | | <img src="@/assets/images/call/ic_left@2x.png" class="icon icon_l" alt=""> |
| | | <img src="@/assets/images/call/ic_right@2x.png" class="icon icon_r" alt=""> |
| | | <div class="empty"> |
| | | <div class="title">温馨提示</div> |
| | | <div class="line">1、请司机根据叫号屏提示入园</div> |
| | | <div class="line">2、未叫号车辆请耐心等待</div> |
| | | <div class="line">3、请有序排队入园</div> |
| | | <div class="line">4、装卸货结束禁止在园区逗留</div> |
| | | <div class="line">5、请遵守园区安全规章制度</div> |
| | | <div class="main_content"> |
| | | <div class="list"> |
| | | <div class="line header"> |
| | | <div class="item no">序号</div> |
| | | <div class="item">车牌号</div> |
| | | <div class="item status">状态</div> |
| | | <div class="item">停靠月台</div> |
| | | <div class="item">时间</div> |
| | | </div> |
| | | <div class="line" v-for="item in contentTempList" :key="item.id"> |
| | | <div class="item no">{{ item.signNum }}</div> |
| | | <div class="item">{{ item.carCodeFront }}</div> |
| | | <div class="item"> |
| | | <div :class="{ |
| | | call_ed: item.status == 4, |
| | | underway: item.status == 5, |
| | | padding: item.status == 2 || item.status == 3, |
| | | }" class="status">{{ statusMap[item.status] }}</div> |
| | | </div> |
| | | <div class="item">{{ item.platformName || '-' }}</div> |
| | | <div class="item"> |
| | | <div v-if="item.optTimeTemp" class="time_place"> |
| | | {{ item.status == 4 ? '剩余等待时间' : '预计完成时间' }} |
| | | </div> |
| | | <div>{{ item.optTimeTemp || '-' }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="qrcode_wrap"> |
| | | <div class="qrcode"> |
| | | <canvas id="qrcode" width="254" height="254"></canvas> |
| | | <div class="current"> |
| | | <div class="tip_wrap"> |
| | | <img src="@/assets/images/call/ic_left@2x.png" class="icon icon_l" alt=""> |
| | | <img src="@/assets/images/call/ic_right@2x.png" class="icon icon_r" alt=""> |
| | | <div v-if="callList.length > 0" class="current_plat"> |
| | | <div class="id_card">{{ activeCall.carCodeFront }}</div> |
| | | <div class="no">({{ activeCall.signNum }})</div> |
| | | <div class="place"> |
| | | <span>前往</span> |
| | | <span class="plat"> {{ activeCall.platformName }} </span> |
| | | <span>作业</span> |
| | | </div> |
| | | </div> |
| | | <div v-else class="empty"> |
| | | <div class="title">温馨提示</div> |
| | | <div class="line">1、请司机根据叫号屏提示入园</div> |
| | | <div class="line">2、未叫号车辆请耐心等待</div> |
| | | <div class="line">3、请有序排队入园</div> |
| | | <div class="line">4、装卸货结束禁止在园区逗留</div> |
| | | <div class="line">5、请遵守园区安全规章制度</div> |
| | | </div> |
| | | </div> |
| | | <div class="title">请扫码签到</div> |
| | | <div class="qrcode_wrap"> |
| | | <div class="qrcode"> |
| | | <canvas id="qrcode" width="268" height="268"></canvas> |
| | | </div> |
| | | <div class="title">请扫码签到</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="main_footer"> |
| | | <img src="@/assets/images/call/ic_news@2x.png" class="icon" alt=""> |
| | | <div class="title">请根据队列提示信息,依次等候进场</div> |
| | | <div class="icon"></div> |
| | | </div> |
| | | </div> |
| | | <div class="main_footer"> |
| | | <img src="@/assets/images/call/ic_news@2x.png" class="icon" alt=""> |
| | | <div class="title">请根据队列提示信息,依次等候进场</div> |
| | | <div class="icon"></div> |
| | | </div> |
| | | </div> |
| | | </v-scale-screen> |
| | | |
| | | </template> |
| | | |
| | | <style lang="scss" scoped> |
| | | div { |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .main_app { |
| | | color: #fff; |
| | | width: 100%; |
| | | height: 100vh; |
| | | width: 1920px; |
| | | height: 1080px; |
| | | overflow: hidden; |
| | | background-color: #092030; |
| | | position: relative; |
| | | z-index: -2; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: space-between; |
| | | |
| | | .main_header { |
| | | width: 100%; |
| | | height: 112px; |
| | | flex: 10.3; |
| | | position: relative; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 0 50px; |
| | | z-index: 11; |
| | | |
| | | .title { |
| | | font-weight: 800; |
| | | font-size: 48px; |
| | |
| | | .time_wrap { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | .date { |
| | | font-weight: 500; |
| | | font-size: 20px; |
| | | text-align: right; |
| | | } |
| | | |
| | | .week { |
| | | font-weight: 500; |
| | | font-size: 20px; |
| | | text-align: right; |
| | | } |
| | | |
| | | .time { |
| | | font-weight: 500; |
| | | font-size: 50px; |
| | | margin-left: 15px; |
| | | } |
| | | } |
| | | |
| | | .bg { |
| | | position: absolute; |
| | | top: 0; |
| | |
| | | z-index: -1; |
| | | } |
| | | } |
| | | .main_content{ |
| | | flex: 1; |
| | | |
| | | .main_content { |
| | | flex: 82.2; |
| | | display: flex; |
| | | padding: 30px 20px; |
| | | position: relative; |
| | | .list{ |
| | | |
| | | .list { |
| | | flex: 5; |
| | | margin-right: 20px; |
| | | .line{ |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | .line { |
| | | display: flex; |
| | | align-items: center; |
| | | height: 100px; |
| | | &:nth-of-type(2n){ |
| | | background: rgba(255,255,255,0); |
| | | height: 11.1%; |
| | | |
| | | &:nth-of-type(2n) { |
| | | background: rgba(255, 255, 255, 0); |
| | | } |
| | | &:nth-of-type(2n + 1){ |
| | | background: rgba(0,237,255,0.13); |
| | | |
| | | &:nth-of-type(2n + 1) { |
| | | background: rgba(0, 237, 255, 0.13); |
| | | } |
| | | .item{ |
| | | |
| | | .item { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | flex-direction: column; |
| | | font-weight: 500; |
| | | font-size: 36px; |
| | | font-size: 30px; |
| | | flex: 10; |
| | | .status{ |
| | | width: 174px; |
| | | height: 76px; |
| | | height: 100%; |
| | | |
| | | .time_place { |
| | | font-weight: 500; |
| | | font-size: 22px; |
| | | } |
| | | |
| | | .status { |
| | | /* padding: 0 28px; */ |
| | | width: 170px; |
| | | height: 72%; |
| | | border-radius: 8px; |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | } |
| | | .underway{ |
| | | |
| | | .underway { |
| | | background-color: #51b2ce; |
| | | } |
| | | .call_ed{ |
| | | |
| | | .call_ed { |
| | | background-color: #f2a43a; |
| | | } |
| | | .padding{ |
| | | |
| | | .padding { |
| | | background-color: #1c485a; |
| | | } |
| | | } |
| | | .no{ |
| | | |
| | | .no { |
| | | flex: 5; |
| | | } |
| | | |
| | | } |
| | | .header{ |
| | | font-size: bold; |
| | | font-size: 40px; |
| | | background: linear-gradient( 180deg, #00B5D1 0%, #003C57 100%) !important; |
| | | |
| | | .header { |
| | | .item { |
| | | font-size: bold; |
| | | font-size: 36px; |
| | | } |
| | | |
| | | background: linear-gradient(180deg, #00B5D1 0%, #003C57 100%) !important; |
| | | } |
| | | } |
| | | .current{ |
| | | |
| | | .current { |
| | | /* height: calc( 100vh - 192px ); */ |
| | | flex: 2; |
| | | display: flex; |
| | | flex-direction: column; |
| | | .tip_wrap{ |
| | | |
| | | .tip_wrap { |
| | | margin-bottom: 20px; |
| | | width: 100%; |
| | | position: relative; |
| | | flex-shrink: 0; |
| | | /* flex-shrink: 0; */ |
| | | flex: 1; |
| | | .empty{ |
| | | |
| | | .current_plat { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 30px 40px; |
| | | font-weight: 500; |
| | | font-size: 30px; |
| | | .title{ |
| | | text-align: center; |
| | | font-weight: bold; |
| | | font-size: 36px; |
| | | margin-bottom: 20px; |
| | | color: #FFA000; |
| | | height: 100%; |
| | | |
| | | .id_card { |
| | | font-weight: 500; |
| | | font-size: 68px; |
| | | } |
| | | .line{ |
| | | margin-bottom: 10px; |
| | | |
| | | .no { |
| | | margin: 8px 0; |
| | | font-weight: 500; |
| | | font-size: 52px; |
| | | } |
| | | |
| | | .place { |
| | | font-weight: 500; |
| | | font-size: 36px; |
| | | } |
| | | |
| | | .plat { |
| | | color: #fff; |
| | | margin: 0 6px; |
| | | } |
| | | } |
| | | .icon{ |
| | | |
| | | .empty { |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | font-weight: 500; |
| | | font-size: 26px; |
| | | height: 100%; |
| | | |
| | | .title { |
| | | text-align: center; |
| | | font-weight: bold; |
| | | font-size: 32px; |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .line { |
| | | margin-bottom: 8px; |
| | | padding-left: 32px; |
| | | } |
| | | } |
| | | |
| | | .icon { |
| | | position: absolute; |
| | | width: 52px; |
| | | height: 52px; |
| | | } |
| | | .icon_l{ |
| | | |
| | | .icon_l { |
| | | left: 0; |
| | | top: 0; |
| | | } |
| | | .icon_r{ |
| | | |
| | | .icon_r { |
| | | right: 0; |
| | | bottom: 0; |
| | | } |
| | | } |
| | | .qrcode_wrap{ |
| | | |
| | | .qrcode_wrap { |
| | | width: 100%; |
| | | flex: 1; |
| | | flex-shrink: 0; |
| | | /* flex-shrink: 0; */ |
| | | background-color: #51b2ce; |
| | | padding: 36px 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | .qrcode{ |
| | | padding: 12px; |
| | | |
| | | .qrcode { |
| | | padding: 6px 6px 4px; |
| | | background-color: #fff; |
| | | } |
| | | .title{ |
| | | margin-top: 20px; |
| | | |
| | | .title { |
| | | margin-top: 16px; |
| | | font-weight: bold; |
| | | font-size: 38px; |
| | | font-size: 28px; |
| | | color: #111111; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .main_footer{ |
| | | |
| | | .main_footer { |
| | | background-color: #1D8D9E; |
| | | height: 80px; |
| | | flex: 7.4; |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 0 50px; |
| | | .icon{ |
| | | |
| | | .icon { |
| | | width: 52px; |
| | | height: 52px; |
| | | } |
| | | .title{ |
| | | |
| | | .title { |
| | | flex: 1; |
| | | text-align: center; |
| | | font-weight: 500; |