<!-- 布局页 --> <template> <div class="index"> <img class="left-border" src="../assets/img/border-left.png" /> <img class="right-border" src="../assets/img/border-right.png" /> <div class="title"> <span class="txt">{{title}}</span> </div> <user-info class="user-info" /> <div class="main"> <div class="nav"> <div class="block"> <div class="btn left-bg" :class="$route.path == '/FactoryMonitoring/index' ? 'left-bg2' : ''"> <el-select v-model="factoryValue" :popper-append-to-body="false" @change="changeFactory"> <el-option label="全部电厂" :value="0" /> <el-option v-for="item of $x_factoryList" :key="item.plantId" :label="item.shortName" :value="item.plantId" @click.native="clickFactory(item.plantId)" /> </el-select> </div> <div class="btn left-bg left-pos2" :class="$route.path == '/CrewMonitoring/index' ? 'left-bg2' : ''"> <el-select v-model="crewValue" :popper-append-to-body="false" @change="changeCrew"> <el-option label="全部机组" :value="0" /> <el-option v-for="item of $x_factory.plantDevices" :key="item.deviceId" :label="item.deviceName" :value="item.deviceId" @click.native="clickCrew(item.deviceId)" /> </el-select> </div> <div class="btn left-bg left-pos3" :class="$route.path == '/TrendAnalysis/index' ? 'left-bg2' : ''" @click="goPage('/TrendAnalysis')">趋势分析</div> </div> <div class="block"> <div class="btn right-bg right-pos2" :class="$route.path == '/AlarmRecord/index' ? 'right-bg2' : ''" @click="goPage('/AlarmRecord')">报警记录</div> <div class="btn right-bg" :class="$route.path == '/UserManage/index' ? 'right-bg2' : ''" @click="goPage('/UserManage')">用户管理</div> </div> </div> <div class="router-view"> <transition name="fade-transform" mode="out-in"> <router-view /> </transition> </div> </div> <div v-show="!dialogShow" class="global-circle" v-drag @click="showDialog"> 报警监控 </div> <!-- <el-dialog class="dialog-index global" title="报警监控" top="10vh" width="80%" :visible.sync="dialogShow" destroy-on-close center> --> <div v-show="dialogShow" class="dialog-index global" v-drag> <div class="dialog-title"> <div class="left"></div> <div class="center"> 报警监控 </div> <div class="right"> <i class="el-icon-close" @click="dialogShow = false" /> </div> </div> <div class="dialog-main"> <div class="tabs"> <div class="tab" :class="tabIndex == 0 ? 'tab-active' : ''" @click="changeTab(0)"><i class="el-icon-warning" style="color: #E53B4C;" />报警参数</div> <div class="tab" :class="tabIndex == 1 ? 'tab-active' : ''" @click="changeTab(1)"><i class="el-icon-remove" style="color: #ccc;" />无效参数</div> <!-- <div class="tab" :class="tabIndex == 2 ? 'tab-active' : ''" @click="changeTab(2)"><i class="el-icon-s-help" style="color: #00aaff;" />全部参数</div> --> </div> <div class="table"> <el-table :data="tableData" height="100%" v-loading="tableLoading" :element-loading-background="loadingColor"> <el-table-column type="index" label="序号" min-width="4%" align="center"></el-table-column> <el-table-column prop="deviceName" label="机组" min-width="20%" align="center"></el-table-column> <el-table-column prop="cpName" label="监测参数" min-width="32%" align="center"></el-table-column> <el-table-column prop="kksValueR" label="测值" min-width="18%" align="center"></el-table-column> <el-table-column prop="cpUnit" label="单位" min-width="14%" align="center"></el-table-column> <el-table-column prop="state" label="状态" min-width="12%" align="center"> <template v-slot="scope"> <div class="table-tip"> <i class="table-tip-circle" :style="{'background-image': 'linear-gradient(to bottom, ' + getColors(scope.row.state)}" /> </div> </template> </el-table-column> </el-table> </div> <div class="tips"> <div class="tip-item" v-for="item in WarningConfig"> <i class="tip-circle" :style="{'background-image': 'linear-gradient(to bottom, ' + item.color + ',' + item.color2}" /> <span class="tip-txt">{{item.name}}</span> </div> </div> </div> </div> <!-- </el-dialog> --> </div> </template> <script> import { CONFIG, ChartStyle, WarningConfig } from '@/common/const.js' import { getWarnItem, getDeviceNameById, randomData, chatValueHandler } from '@/common/util.js' import UserInfo from '@/components/UserInfo' import User from '@/api/user.js'; export default { components: { UserInfo }, data() { return { loadingColor: ChartStyle.loadingColor, title: CONFIG.TITLE, factoryValue: 0, crewValue: 0, socket: null, // socket dialogShow: false, tabIndex: 0, tableDataAll: [[], [], []], tableData: [], tableLoading: false, WarningConfig: WarningConfig, }; }, watch: { $x_factory: { immediate: true, handler(val) { if(!val) return; this.factoryValue = val.plantId; this.$store.commit('allData', []); this.closeSocket(); this.initSocket(); } }, $x_crew: { immediate: true, handler(val) { this.crewValue = val?.deviceId || 0 } } }, beforeDestroy() { this.closeSocket(); }, methods: { // 初始化socket initSocket() { this.socket = new WebSocket('ws://' + CONFIG.SOCKET + '/all/measure/point/' + this.$x_factory.plantId, [this.$x_user.token.split(' ')[1]]); this.socket.onopen = () => console.log('socket_all success'); this.socket.onerror = e => { console.log('socket_all error', e); User.getRoleList(); // 捕获错误,然后发送一个请求,因为可能是token导致的socket连接错误,发送请求后如果是token过期,会自动注销用户 } this.socket.onmessage = msg => { try{ const data = JSON.parse(msg.data); // console.log('socket_all data', msg); // console.log('socket_all data', data); if (!data) return; this.$store.commit('allData', data); if(this.dialogShow) this.initTableData(); // this.initTableData(); }catch(e){ console.log(e); } } }, // 关闭socket closeSocket() { if (this.socket) { this.socket.close(); this.socket = null; } }, // 页面跳转 goPage(path) { if (this.$route.path.indexOf(path) != -1) return; this.$router.push(path); }, // 改变电厂 changeFactory(val) { if (!val) this.$router.push('/factory'); else { let item = this.$x_factoryList.find(i => i.plantId === val) let endTime = Date.now() + 3600 * 1000 * 24; // 24h后过期 localStorage.setItem('electric_factory', JSON.stringify({ data: item, endTime })); this.$store.commit('factory', item); this.$store.commit('crew', null); this.crewValue = 0; if (this.$route.path !== '/FactoryMonitoring/index') this.$router.push('/FactoryMonitoring'); } }, // 改变机组 changeCrew(val) { if (!val) { this.$store.commit('crew', null); if (this.$route.path !== '/FactoryMonitoring/index') this.$router.push('/FactoryMonitoring'); } else { let item = this.$x_factory.plantDevices.find(i => i.deviceId === val) this.$store.commit('crew', item); if (this.$route.path !== '/CrewMonitoring/index') this.$router.push('/CrewMonitoring'); } }, // 点击电厂,如果当前页面不是全厂页,并且点击了同样的电厂,则跳转到电厂页(因为不会触发changeFactory clickFactory(id) { if(id == this.factoryValue && this.$route.path !== '/FactoryMonitoring/index') this.$router.push('/FactoryMonitoring'); }, // 点击机组,同上 clickCrew(id) { if(id == this.crewValue && this.$route.path !== '/CrewMonitoring/index') this.$router.push('/CrewMonitoring'); }, // 打开弹窗 showDialog() { this.dialogShow = true; this.initTableData(); }, // 切换标签 changeTab(i) { this.tabIndex = i; this.tableData = this.tableDataAll[i]; }, // 处理表格数据 initTableData() { let tableData1 = [], tableData2 = [], tableData3 = [], warnStateMap = {3:true,4:true,5:true}; for (let i = 0; i < this.$x_allData.length; i++) { for (let j = 0; j < this.$x_allData[i].tSdb.length; j++) { const item = this.$x_allData[i].tSdb[j]; // 当前测点 if(!item.kksValue) continue; // 如果没有查出值,则跳过 if(!item.kksValueR) chatValueHandler(item); // 补数据,只补一次 if(!item.deviceName) item.deviceName = getDeviceNameById(item.deviceId); // 添加机组名 // tableData3.push(item); // 全部 if(warnStateMap[item.state]) tableData1.push(item); // 报警 if(item.state == 2) tableData2.push(item); // 无效 } } // 排序 tableData1.sort((a, b) => a.kksCode.localeCompare(b.kksCode)); tableData2.sort((a, b) => a.kksCode.localeCompare(b.kksCode)); // tableData3.sort((a, b) => a.kksCode.localeCompare(b.kksCode)); this.tableDataAll = [tableData1, tableData2, tableData3]; this.tableData = this.tableDataAll[this.tabIndex]; // if(this.tableData1.length) this.dialogShow = true; // 如果有报警,则弹出 }, // 处理渐变色 getColors(state) { const item = getWarnItem(state); if(!item) return '#fff, #fff'; return item.color + ',' + item.color2; }, }, directives: { // 元素拖拽指令 drag(el, binding) { el.onmousedown = e => { el.style.cursor = 'move'; let domW = el.offsetWidth; let domH = el.offsetHeight; let disX = e.clientX - el.offsetLeft; let disY = e.clientY - el.offsetTop; document.onmousemove = e => { let left = e.clientX - disX; let top = e.clientY - disY; if (top > document.body.clientHeight - domH) top = document.body.clientHeight - domH; if (left > document.body.clientWidth - domW) left = document.body.clientWidth - domW; if (top < 0) top = 0; if (left < 0) left = 0; el.style.left = left + 'px'; el.style.top = top + 'px'; } document.onmouseup = e => { el.style.cursor = 'pointer'; document.onmousemove = document.onmouseup = null; } return false; // 阻止冒泡 } } }, }; </script> <style lang="scss" scoped> .index { width: 100%; height: 100%; overflow: hidden; position: relative; background-image: url(../assets/img/bg.png); @extend %background-center; .left-border { position: absolute; left: 0; height: 100%; } .right-border { position: absolute; right: 0; height: 100%; } .title { @extend %pos-center; width: 58.75rem; height: 4.875rem; background-image: url(../assets/img/title-bg.png); @extend %background-center; .txt { font-size: 2.5rem; font-weight: bold; letter-spacing: 0.25rem; @extend %txt-gradients; } } .user-info { width: calc((100% - 58.75rem) / 2); position: absolute; top: 0.8rem; right: 0; } .main { @extend %bg-position; overflow: hidden; .fade-transform-leave-active, .fade-transform-enter-active { transition: all .1s; } .fade-transform-enter { opacity: 0; transform: translateX(-30px); } .fade-transform-leave-to { opacity: 0; transform: translateX(30px); } .nav { display: flex; justify-content: space-between; height: 3.125rem; margin: 0 4.0625rem; .block { display: flex; .btn { width: 11.0625rem; height: 2.9375rem; background-size: 100% 100%; @extend %flex-center; cursor: pointer; font-size: 1rem; text-shadow: 0 2px 8px rgba(78, 97, 214, 0.50); /deep/ .el-select { width: 7.5rem; } /deep/ .el-input__inner { color: #fff; font-size: 1rem; text-shadow: 0 2px 8px rgba(78, 97, 214, 0.50); border: none; background-color: transparent; } /deep/ .el-select .el-input .el-select__caret { font-size: 1.2rem; color: #fff; } /deep/ .el-icon-arrow-up:before { content: "\e78f"; } /deep/ .el-select-dropdown { // background-color: rgba(147,252,255,0.10); background-color: rgba(20, 43, 83, 1.0); border: 1px solid #1B529C; box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.50); } /deep/ .el-select-dropdown__item { color: #eee; font-size: 0.875rem; text-shadow: none; font-weight: 200; } /deep/ .el-select-dropdown__item.selected { color: $color-cyan; } /deep/ .el-select-dropdown__item.hover, /deep/ .el-select-dropdown__item:hover { background-color: rgba(147, 252, 255, 0.20); } /deep/ .popper__arrow { border-bottom-color: #1B529C; } /deep/ .popper__arrow:after { border-bottom-color: transparent; } } .left-bg { background-image: url(../assets/img/btn-l0.png); } .left-bg2 { background-image: url(../assets/img/btn-l1.png); } .right-bg { background-image: url(../assets/img/btn-r0.png); } .right-bg2 { background-image: url(../assets/img/btn-r1.png); } .left-pos2 { position: relative; left: -1.875rem; } .left-pos3 { position: relative; left: -3.75rem; } .right-pos2 { position: relative; right: -1.875rem; } } } .router-view { height: calc(100% - 3.125rem); } } } .global-circle { width: 5rem; height: 5rem; z-index: 10; position: fixed; right: 2rem; bottom: 2rem; background-image: linear-gradient(to bottom, rgba(0, 209, 255, 0.5), rgba(0, 85, 255, 0.5), rgba(0, 0, 255, 0.5)); cursor: pointer; border-radius: 50%; display: flex; justify-content: center; align-items: center; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); font-size: 1.2rem; font-weight: 700; padding: 0.8rem; box-sizing: border-box; } .dialog-index { /deep/.el-dialog__body{ padding-top: 0; } width: 35rem; height: 40rem; z-index: 10; position: fixed; right: 2rem; bottom: 2rem; background-color: rgba(10, 23, 55, 1); border: 1px solid rgba(9, 77, 148, 0.5); padding: 1.5rem; padding-top: 0; box-sizing: border-box; cursor: pointer; .dialog-title { height: 3rem; position: relative; display: flex; align-items: center; justify-content: space-between; .center { @extend %pos-center; } .right { z-index: 1; } } .dialog-main { height: calc(100% - 3rem); box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); background-color: rgba($color: $color-blue, $alpha: 0.1); color: #eee; .tabs{ height: 3rem; display: flex; align-items: center; border-bottom: 1px solid #000; box-sizing: border-box; .tab { font-size: 0.875rem; cursor: pointer; height: 100%; @extend %flex-center; padding: 0 1rem; } .tab-active { background-color: $color-deep-blue; } i { font-size: 1.2rem; margin-right: 0.5rem; } } .table { height: calc(100% - 6rem); background-color: rgba($color: $color-deep-blue, $alpha: 0.3); ::v-deep .el-table th { font-size: 0.875rem; } .table-tip{ @extend %flex-center; .table-tip-circle { width: 1rem; height: 1rem; border-radius: 50%; } } } .tips{ height: 3rem; display: flex; align-items: center; padding: 0 0.5rem; box-sizing: border-box; .tip-item { height: 100%; margin: 0 0.5rem; display: flex; align-items: center; .tip-circle { width: 1rem; height: 1rem; border-radius: 50%; margin-right: 0.5rem; } .tip-txt { font-size: 0.75rem; } } } } } </style>