ebc

index.vue 24KB

    <template> <div class="index" style="overflow:hidden"> <div :style="`background-image: url(${imgBg})`" class="top" > <img src="@/assets/images/brand.png" class="top-logo"> </div> <div> <div class="time"><span style="color: #00d8f3;font-size: 21px;">{{ nowDate | dateFormat }}</span></div> <div class="goto" @click="gotoSystem"><t-icon icon="arrow-right-outline"></t-icon>进入系统</div> </div> <div class="body"> <div class="body-left"> <div :style="`height:34%`" class="body-left-item"> <div :style="`background-image: url(${titleImgBg})`" class="title"> <span class="title-span">出勤统计</span> </div> <div id="doughnut" style="height: 100%;width: 100%"></div> </div> <div :style="`height:34%;margin-top: 3%;`" class="body-left-item"> <div :style="`background-image: url(${titleImgBg})`" class="title"> <span class="title-span">告警分析</span> </div> <div id="bar" style="height: 100%;width: 100%"></div> </div> <div :style="`height:29%;margin-top: 3%;`" class="body-left-item"> <div :style="`background-image: url(${titleImgBg})`" class="title"> <span class="title-span">近24h告警</span> </div> <div class="top4"> <t-row v-for="(item,index) in topData" :gutter="2" align="center" class="top4-row"> <t-col span="6"> <div :style="`background-image: url(${polygon})`" class="polygon">{{ index + 1 }}</div> &nbsp;&nbsp;{{ item.name }}</t-col> <t-col span="2" offset="4">{{ item.value }}个</t-col> </t-row> </div> </div> </div> <div class="body-center"> <div :style="`background-image: url(${titleImgBg})`" class="title" style="width: 370px;"> <span class="title-span">重点区域监控</span> </div> <!-- <video-player ref="videoPlayer" :options="videoOptions" :playsinline="true" class="vjs-custom-skin videoPlayer"></video-player>--> <video-player v-if="videoOptions !== {}" ref="videoPlayer" :options="videoOptions" :playsinline="true" class="vjs-custom-skin videoPlayer" ></video-player> <div class="videoPlayers"> <div v-for="(item,index) in videoOptionsList" class="videoPlayer-sm" @click="videoSwitchover(item,index)"> <!-- <video-player ref="videoPlayer"--> <!-- :options="item.options"--> <!-- :playsinline="true"--> <!-- :style="`padding: 0 2.5% 2.5% 2%;border-radius: 5px;border: ${1-index}px solid #009bf3;`"--> <!-- class="vjs-custom-skin videoPlayer">--> <!-- </video-player>--> <video-player ref="videoPlayer" :playsinline="false" :events="events" :options="item.options" :style="`padding: 0 2.5% 2.5% 2%;border-radius: 5px;`" :class="{ 'checkedIndex': index == checkedIndex }" class="vjs-custom-skin videoPlayer" @dblclick="handlefullscreenchange" ></video-player> <div style="color: white;text-align: center;">{{ item.name }}</div> </div> </div> </div> <div class="body-right"> <div :style="`background-image: url(${titleImgBg})`" class="title" style="width: 330px;"> <span class="title-span">人员进出识别</span> </div> <div v-for="(item,index) in distinguishData" :style="`background-image: url(${border})`" class="distinguish"> <div class="distinguish-title"> {{ item.monitorSceneName }} </div> <div class="distinguish-row"> <div class="similarity"> <p class="p">{{ item.simi }}</p> </div> <img :src="item.newImg" alt="" class="distinguish-col"> <img :src="item.headerImage" class="distinguish-col"> <div style="width: 40%;margin-top: 4%;height: 79%;"> <div class="distinguish-col-row">{{ item.employeeName }}({{ item.employeeCode }})</div> <div class="distinguish-col-row">{{ item.taskExecuteTime }}</div> </div> </div> </div> <!-- <img src="@/assets/images/indexT2.png" style="width: 95%;height: 95%;padding-left: 15px;padding-top: 10px;">--> </div> </div> </div> </template> <script> import imgBg from '@/assets/images/indexTop.png' import avatar from '@/assets/images/avatar.png' import titleImgBg from '@/assets/images/indexTitle.png' import polygon from '@/assets/images/polygon.png' import border from '@/assets/images/border.png' import echarts from 'echarts' import dasapi from '@/api/dashboard' import sysapi from '@/api/system' import 'video.js/dist/video-js.css' import 'vue-video-player/src/custom-theme.css' import 'videojs-flash' import RtmpVideo from '../videoSurveillance/components/rtmpVideoPlay' import videojs from 'video.js' window.videojs = videojs require('video.js/dist/lang/zh-CN.js') require('video.js/dist/video-js.min.css') export default { filters: { dateFormat(value) { var year = value.getFullYear() var month = value.getMonth() + 1 month >= 10 ? month : '0' + month var day = value.getDate() >= 10 ? value.getDate() : '0' + value.getDate() var hours = value.getHours() >= 10 ? value.getHours() : '0' + value.getHours() var minutes = value.getMinutes() >= 10 ? value.getMinutes() : '0' + value.getMinutes() var seconds = value.getSeconds() >= 10 ? value.getSeconds() : '0' + value.getSeconds() return ( year + '年' + month + '月' + day + '日 ' + hours + ':' + minutes + ':' + seconds ) } }, components: { RtmpVideo }, data() { return { checkedIndex: 0, events: ['fullscreenchange'], nowDate: new Date(), videoOptions: {}, videoOptionsList: [], imgBg: imgBg, titleImgBg: titleImgBg, avatar: avatar, polygon: polygon, border: border, attendanceData: [], population: 0, alarmDataX: [], alarmDataY: [], topData: [], topData1: [], distinguishData: [] } }, computed: { player() { return this.$refs.videoPlayer1.player } }, mounted () { this.initVideo() setInterval(() => { // 当前时间 this.nowDate = new Date() }, 1000) this.initRecognition() this.initAttendance() this.initAlarm() this.init24Top() setInterval(() => { // 识别记录 this.initRecognition() }, 10000) }, methods: { async createMyButton () { this.$nextTick(() => { const bars = document.querySelectorAll('.vjs-control-bar') let time = document.getElementsByClassName('vjs-current-time vjs-time-control vjs-control') let start = document.getElementsByClassName('vjs-play-control vjs-control vjs-button') let volume = document.getElementsByClassName('vjs-volume-panel vjs-control vjs-volume-panel-horizontal') let text = document.getElementsByClassName('vjs-live-control vjs-control') bars.forEach((item, index) => { time.forEach(item => { item.remove() }) start.forEach(item => { item.remove() }) volume.forEach(item => { item.remove() }) text.forEach(item => { item.remove() }) }) }) }, handlefullscreenchange(val) { // 因为我是又封装了一个组件,打印val会有相应所需的属性,全屏状态为:isFullscreen_ val.isFullscreen_ = !val.isFullscreen_ // this.$emit('fullscreenchange', val) }, initVideo() { sysapi.getTerminalRel(2).then(res => { this.videoOptions = { autoplay: true, // 如果true,浏览器准备好时开始回放。 muted: true, // 默认情况下将会消除任何音频。 loop: false, // 导致视频一结束就重新开始。 preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持) language: 'zh-CN', aspectRatio: '16:10', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3") // fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。 // 是否流体自适应容器宽高 fluid: true, // // 设置视频播放器的显示宽度(以像素为单位) // width: '100px', // // 设置视频播放器的显示高度(以像素为单位) // height: '300px', sources: [{ withCredentials: false, type: 'application/x-mpegURL', // 这里的种类支持很多种:基本视频格式、直播、流媒体等,具体可以参看git网址项目 src: res.data.data[0].videoUrl // url地址 }], flash: { hls: { withCredentials: false } }, html5: { hls: { withCredentials: false } }, notSupportedMessage: '此视频暂无法播放,请稍后再试', // 允许覆盖Video.js无法播放媒体源时显示的默认信息。 controlBar: { timeDivider: false, durationDisplay: false, remainingTimeDisplay: false, fullscreenToggle: true, // 全屏按钮, pictureInPictureToggle: false } } this.videoOptionsList = [] res.data.data.forEach(e => { this.videoOptionsList.push({ options: { autoplay: true, // 如果true,浏览器准备好时开始回放。 muted: true, // 默认情况下将会消除任何音频。 loop: false, // 导致视频一结束就重新开始。 preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持) language: 'zh-CN', aspectRatio: '16:10', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3") // fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。 // 是否流体自适应容器宽高 fluid: true, // // 设置视频播放器的显示宽度(以像素为单位) // width: '100px', // // 设置视频播放器的显示高度(以像素为单位) // height: '400px', sources: [{ withCredentials: false, type: 'application/x-mpegURL', // 这里的种类支持很多种:基本视频格式、直播、流媒体等,具体可以参看git网址项目 src: e.videoUrl // url地址 }], flash: { hls: { withCredentials: false } }, html5: { hls: { withCredentials: false } }, notSupportedMessage: '此视频暂无法播放,请稍后再试', // 允许覆盖Video.js无法播放媒体源时显示的默认信息。 controlBar: { timeDivider: false, durationDisplay: false, remainingTimeDisplay: false, fullscreenToggle: false // 全屏按钮 } }, name: e.resourceToolName }) this.createMyButton() }) }) }, videoSwitchover(itme,index) { this.videoOptions.sources = itme.options.sources this.checkedIndex = index }, gotoSystem() { this.$router.push({name: 'videoSurveillance'}) }, initAttendance() { this.attendanceData = dasapi.queryAttendanceChart().then(res => { this.population = res.data.totalSize res.data.dataList.forEach(e => { if (e.name === '在岗') { e.itemStyle = { color: '#00A7F4' } } if (e.name === '请假') { e.itemStyle = { color: '#FFCE00' } } if (e.name === '缺勤') { e.itemStyle = { color: '#FF3F00' } } }) this.attendanceData = res.data.dataList this.initAttendanceData() }) }, initAlarm() { this.population = dasapi.queryAlarmAnalysisChart().then(res => { res.data.forEach(e => { this.alarmDataX.push(e.name) this.alarmDataY.push(e.value) }) this.initAlarmData() }) }, init24Top() { this.topData = dasapi.queryAlarmAnalysisTopList().then(res => { this.topData = [] for (var i = 0; i < 5; i++) { if (res.data[i]) { this.topData.push(res.data[i]) } } }) }, initRecognition() { dasapi.queryHomeLastInAndOutRecord({monitorSceneId: 3}).then(res => { var data = res.data.data if (data.length > 4) { data = data.slice(0, 4) } data.forEach(e => { e.simi = e.simi.split('.')[0] + '%' e.newImg = e.idenPictureUrl var loadTimer var imgObject = new Image() imgObject.setAttribute('crossOrigin', 'anonymous') imgObject.src = e.idenPictureUrl imgObject.onLoad = onImgLoaded() function onImgLoaded() { if (loadTimer != null) clearTimeout(loadTimer) if (!imgObject.complete) { loadTimer = setTimeout(function() { onImgLoaded() }, 3) } else { e.newImg = getImagePortion(imgObject, e.face_box[2] - e.face_box[0], e.face_box[3] - e.face_box[1], e.face_box[0], e.face_box[1]) } } function getImagePortion(imgObj, newWidth, newHeight, startX, startY) { var tnCanvas = document.createElement('canvas') var tnCanvasContext = tnCanvas.getContext('2d') tnCanvas.width = newWidth; tnCanvas.height = newHeight var bufferCanvas = document.createElement('canvas') var bufferContext = bufferCanvas.getContext('2d') bufferCanvas.width = imgObj.width bufferCanvas.height = imgObj.height bufferContext.drawImage(imgObj, 0, 0) tnCanvasContext.drawImage(bufferCanvas, startX, startY, newWidth, newHeight, 0, 0, newWidth, newHeight) return tnCanvas.toDataURL() } }) this.distinguishData = data }) }, initAttendanceData() { var dom = document.getElementById('doughnut') var myChart = echarts.init(dom) var option = null option = { tooltip: { trigger: 'item', formatter: '{a} <br/>{b} : {c}人 ({d}%)' }, legend: { bottom: '20%', left: 'center', data: this.attendanceData, formatter: this.legendFormatter, textStyle: { color: '#fff' } }, graphic: [ // 为环形图中间添加文字 { type: 'text', left: 'center', top: '38%', style: { text: this.population + '人', textAlign: 'center', fill: '#ffffff', fontSize: 12 } } ], series: [ { type: 'pie', radius: ['25%', '40%'], center: ['50%', '40%'], name: '出勤统计', label: { normal: { formatter: '{d}% ' } }, data: this.attendanceData, emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } } } ] } if (option && typeof option === 'object') { myChart.setOption(option, true) } }, legendFormatter(data) { var legend this.attendanceData.forEach(e => { if (data === e.name) { legend = e.value } }) return data + ': ' + legend + '人' }, initAlarmData() { var dom = document.getElementById('bar') var myChart = echarts.init(dom) var option = null var gridWidth = 320 // 可以根据canvas的宽度和grid的right,left,width进行计算 var fontsize = 12 // 字体大小 var wordNum = parseInt((gridWidth / this.alarmDataX.length) / fontsize) var flag = 0 this.alarmDataX.forEach(value => { if (value) { var strs = value.split('') var str = '' for (var i = 0, s; s = strs[i++];) { str += s if (!(i % wordNum)) { flag = -20 } } } }) option = { color: ['#3398DB'], tooltip: { trigger: 'axis', axisPointer: { // 坐标轴指示器,坐标轴触发有效 type: 'shadow' // 默认为直线,可选为:'line' | 'shadow' } }, grid: { left: '4%', right: '7%', bottom: '15%', top: '10%', containLabel: true }, xAxis: [ { type: 'category', data: this.alarmDataX, axisTick: { alignWithLabel: true }, axisLabel: { show: true, interval: 0, rotate: flag, textStyle: { fontSize: 12, color: '#fff' } } } ], yAxis: [ { type: 'value', minInterval: 1, axisLabel: { show: true, textStyle: { fontSize: 13, color: '#fff' } }, splitLine: { show: false } } ], series: [ { name: '数量', type: 'bar', barWidth: '40%', data: this.alarmDataY, itemStyle: { normal: { color: new echarts.graphic.LinearGradient( 0, 0, 0, 1, [ {offset: 0, color: '#00FEFF'}, {offset: 1, color: '#0C7EFC'} ] ), label: { show: true, // 是否展示 position: 'top', // 在上方显示 formatter: function(name) { return name.value + '个' }, textStyle: { fontSize: 14, color: '#fff' } } } } } ] } if (option && typeof option === 'object') { myChart.setOption(option, true) } } } } </script> <style lang="scss"> .index{ height:100vh; background-color: #011d40; .time{ width: 500px; height: 28px; padding-left: 48px; margin-top: -14px; } .goto{ cursor: pointer; margin-top: -30px; width: 8%; height: 40px; border-radius: 5px; background-color: #011d40; /* 浏览器不支持的时候显示 */ box-shadow: 0 0 30px -10px #009bf3 inset; margin-left: 91%; align-items: center; text-align: center; padding-top: 6px; color:#00d8f3; font-size: 18px; } .top{ -moz-background-size:100% 100%; background-size:100% 100%; display: flex; align-items: center; text-align: center; height: 6%; overflow: hidden; position: relative; .top-logo{ position: absolute; top:50%; left:50%; transform: translate(-50%,-50%); height: 50%; width: 25%; vertical-align: middle } } .body{ display: flex; height: 90%; padding-top: 1%; justify-content: space-around; .body-left{ width: 23%; height: 96%; .body-left-item{ width: 100%; border-radius: 5px; background-color: #011d40; /* 浏览器不支持的时候显示 */ box-shadow: 0 0 30px -10px #009bf3 inset; .top4{ padding-left: 15px; padding-right: 15px; color: #00d8f3; font-size: 15px; height: 100%; .top4-row{ border: 0 none; border-bottom: 2px dotted #00466b; height: 16%; .col-6{ display: flex; .polygon{ -moz-background-size:100% 100%; background-size:100% 100%; align-items: center; text-align: center; height: 100%; width: 15%; } } } } } } .body-center{ width: 50%; height: 96%; border-radius: 5px; background-color: #011d40; /* 浏览器不支持的时候显示 */ box-shadow: 0 0 30px -10px #009bf3 inset; } .body-right{ width: 23%; height: 96%; border-radius: 5px; background-color: #011d40; /* 浏览器不支持的时候显示 */ box-shadow: 0 0 30px -10px #009bf3 inset; .distinguish{ -moz-background-size:100% 100%; background-size:100% 100%; width: 88%; height: 22%; margin-left: 6%; margin-top: 3%; padding-left: 1%; padding-right: 1%; padding-top: 1%; padding-bottom: 1%; .distinguish-title{ align-items: center; text-align: center; height: 28px; width: 100%; margin: 0 auto; font-size: 16px; color: #00d8f3; //background-color: #003C74; 100% background: linear-gradient(to right, #011d40,#003C74,#011D40); } .distinguish-row{ display: flex; color: #00d8f3; width: 100%; height: 100%; position: relative; .similarity{ position: absolute; left:22%; top:27%; border: 2px solid #00d8f3; width: 30px; height: 30px; background: #090404; opacity: 0.5; border-radius: 50%; padding-top: 1%; filter:alpha(opacity=50); /*支持IE */ -moz-opacity:0.5; /*支持FF */ //opacity:0.5; .p{ position:relative; color: #00d8f3; font-size: 10px } } .distinguish-col{ width: 27%; margin-top: 2%; height: 70%; } .distinguish-col-row{ padding-left: 5%; padding-top: 5%; height: 40%; width: 130%; color: white; font-size: 14px; } } } } } .title{ -moz-background-size:100% 100%; background-size:100% 100%; align-items: center; text-align: center; height: 28px; width: 100%; margin: 0 auto; .title-span{ height: 28px; align-items: center; text-align: center; font-size: 14px; color: #00d8f3; margin: auto; } } .titleWide{ -moz-background-size:100% 100%; background-size:100% 100%; align-items: center; text-align: center; height: 28px; width: 47%; margin: 0 auto; .title-span{ height: 28px; align-items: center; text-align: center; font-size: 14px; color: #00d8f3; margin: auto; } } .videoPlayer{ width: 100%; padding: 1.5% 2.5% 0.5% 2.5%; } .videoPlayers{ display: flex; width: 100%; height: 25%; padding: 0 2.5% 0.5% 2.5%; justify-content: space-around; .videoPlayer-sm{ z-index:9999; cursor: pointer; width: 23%; height: 95%; } } .vjs-progress-control{ visibility:hidden } .checkedIndex{ border: 1px solid #009bf3; } } </style>