| | |
| | | <div class="left-top withFilter"> |
| | | <div class="chart-head"> |
| | | <div class="chart-tit">预警汇总</div> |
| | | <el-radio-group v-model="chart1Search"> |
| | | <el-radio-group v-model="countTime" @change="changeTotal"> |
| | | <el-radio :label="1" size="small" border>当日</el-radio> |
| | | <el-radio :label="2" size="small" border>近7天</el-radio> |
| | | <el-radio :label="3" size="small" border>近30天</el-radio> |
| | |
| | | </div> |
| | | <div class="chart-cont"> |
| | | <div class="orange"> |
| | | <div><span>30</span><span>橙色预警</span></div> |
| | | <div><span>{{yellowNum}}</span><span>橙色预警</span></div> |
| | | </div> |
| | | <div class="red"> |
| | | <div><span>10</span><span>红色预警</span></div> |
| | | <div><span>{{redNum}}</span><span>红色预警</span></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | @change="timeChange" |
| | | format="YYYY-MM-DD" value-format="YYYY-MM-DD HH:mm:ss" |
| | | /> |
| | | </div> |
| | |
| | | <div class="chart-head"> |
| | | <div class="chart-tit">设备状态</div> |
| | | <div class="sys-status"> |
| | | <Cpu style="width: 1.2em; height: 1.2em; color: #fff" /> |
| | | <div>系统状态:<span>正常</span></div> |
| | | <Cpu :class="online == 3 ? 'onlineIcon':'offlineIcon'"/> |
| | | <div>系统状态:<span :class="online == 3 ? 'online':'offline'">{{online == 3?'正常':'异常'}}</span></div> |
| | | </div> |
| | | </div> |
| | | <div class="chart-cont"> |
| | | <div class="online"> |
| | | <dv-decoration-9 :color="['#22aaff','rgba(34,170,255,.6)']"> |
| | | <div color-green font-600 class="isOnline" bg="~ dark/0"> |
| | | 0 |
| | | {{online}} |
| | | </div> |
| | | </dv-decoration-9> |
| | | <div>在线</div> |
| | |
| | | <div class="online"> |
| | | <dv-decoration-9 :color="['#ee594a','rgba(238,89,74,.6)']"> |
| | | <div color-red font-600 class="isOnline red-font" bg="~ dark/0"> |
| | | 1 |
| | | {{3 - online}} |
| | | </div> |
| | | </dv-decoration-9> |
| | | <div style="color:#ee594a;">离线</div> |
| | |
| | | <div></div> |
| | | <div></div> |
| | | </div> |
| | | <dv-scroll-board :config="bigConfig" class="scroll-table" @mouseover="mouseoverHandler" @click="clickHandler" /> |
| | | <!-- <dv-scroll-board :config="bigConfig" class="scroll-table" @mouseover="mouseoverHandler" @click="clickHandler" />--> |
| | | <table class="weather"> |
| | | <tr class="weatherTit"><td>时间</td><td>温度</td><td>湿度</td><td>风速</td><td>风向</td><td>气压</td></tr> |
| | | <tr v-for="(item,index) in weatherData" :key="index" class="weatherRow"> |
| | | <td>{{item.time}}</td> |
| | | <td>{{item.temp}}</td> |
| | | <td>{{item.humidity}}</td> |
| | | <td>{{item.windSpeed}}</td> |
| | | <td>{{item.windDirection}}</td> |
| | | <td>{{item.pressure}}</td> |
| | | </tr> |
| | | </table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <div class="right-top withFilterLong"> |
| | | <div class="chart-head"> |
| | | <div class="chart-tit long-tit">气体浓度监测</div> |
| | | <el-select v-model="gasSearch" :teleported="false" class="m-2" placeholder="Select" size="small"> |
| | | <div class="searchGroup"> |
| | | <el-select v-model="gasSearch" :teleported="false" class="m-2" placeholder="Select" size="small" @change="changeGas1"> |
| | | <el-option |
| | | v-for="item in gasOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | :key="item.id" |
| | | :label="item.name" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | <div class="checkMore" @click="toNdPage()"><el-icon><DArrowRight /></el-icon></div> |
| | | </div> |
| | | </div> |
| | | <div class="chart-cont"> |
| | | <div class="echart" :id="gasN"></div> |
| | |
| | | <div class="chart-head"> |
| | | <div class="chart-tit long-tit">气体通量监测</div> |
| | | <div class="searchGroup"> |
| | | <el-select v-model="searchParams.gasSearch" :teleported="false" class="m-2" placeholder="Select" size="small"> |
| | | <el-select v-model="tlGasSearch" :teleported="false" class="m-2" placeholder="Select" size="small" @change="changeGas2"> |
| | | <el-option |
| | | v-for="item in gasOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | :key="item.id" |
| | | :label="item.name" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | <el-select v-model="searchParams.areaSearch" :teleported="false" class="m-2" placeholder="Select" size="small"> |
| | | <el-option |
| | | v-for="item in areaOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | <div class="checkMore" @click="toTlPage()"><el-icon><DArrowRight /></el-icon></div> |
| | | <!-- <el-select v-model="searchParams.areaSearch" :teleported="false" class="m-2" placeholder="Select" size="small">--> |
| | | <!-- <el-option--> |
| | | <!-- v-for="item in areaOptions"--> |
| | | <!-- :key="item.id"--> |
| | | <!-- :label="item.name"--> |
| | | <!-- :value="item.id"--> |
| | | <!-- />--> |
| | | <!-- </el-select>--> |
| | | </div> |
| | | </div> |
| | | <div class="chart-cont"> |
| | |
| | | </div> |
| | | <div class="chart-cont"> |
| | | <div class="online"> |
| | | <div class="totalNum"><span>1048</span>条</div> |
| | | <div class="totalNum"><span>{{ gasTotal }}</span>条</div> |
| | | <div class="dataPic"></div> |
| | | <div class="totalNum">浓度条数</div> |
| | | </div> |
| | | <div class="online"> |
| | | <div class="totalNum"><span>566</span>条</div> |
| | | <div class="totalNum"><span>{{ tlTotal }}</span>条</div> |
| | | <div class="dataPic"></div> |
| | | <div class="totalNum">通量条数</div> |
| | | </div> |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <el-dialog |
| | | v-model="dialogWarning" |
| | | title="预警信息" |
| | | width="35%" |
| | | :append-to-body="true" |
| | | :draggable="true" |
| | | custom-class="warningMsg" |
| | | top="2vh" |
| | | > |
| | | <div class="warning-cont"> |
| | | <div><span>预警信息:</span><span>{{warningGas.content}}</span></div> |
| | | <div><span>预警时间:</span><span>{{warningGas.warnTime}}</span></div> |
| | | <div><span>预警气体:</span><span>{{warningGas.gasName}}</span></div> |
| | | <div><span>预警级别:</span><span :class="warningGas.gasThresholdName == '红色预警'?'red':''">{{warningGas.gasThresholdName}}</span></div> |
| | | <div><span>气体单位:</span><span>{{warningGas.gasUnit}}</span></div> |
| | | <div><span>预警浓度:</span><span>{{warningGas.gasConcentration}}</span></div> |
| | | <div><span>处理状态:</span><span>{{warningGas.status == 0?'未处理':warningGas.status == 1?'已处理':'--'}}</span></div> |
| | | <div v-if="warningGas.handlerRealName"><span>处理人:</span><span>{{warningGas.handlerRealName}}</span></div> |
| | | <div v-if="warningGas.handlerTime"><span>处理时间:</span><span>{{warningGas.handlerTime}}</span></div> |
| | | </div> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="primary" @click="dialogWarning = false"> |
| | | 确认 |
| | | </el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import "amfe-flexible"; |
| | | import AMapLoader from '@amap/amap-jsapi-loader' |
| | | import { shallowRef } from '@vue/reactivity' |
| | | import { storeToRefs } from 'pinia'; |
| | | import { useUserInfo } from '/@/stores/userInfo'; |
| | | import {bigScreenApi} from "/@/api/bigScreen"; |
| | | // 定义接口来定义对象的类型 |
| | | interface TableDataState { |
| | | socket: any |
| | | timer: any |
| | | heartbeat: any |
| | | heartbeatTimeOut: any |
| | | lockReconnect: boolean |
| | | maxReconnect: number |
| | | reconnectTime: number |
| | | time: string |
| | | date: string |
| | | weekDay: string |
| | | dayTime:string |
| | | isFull: boolean |
| | | chart1Search: number | null |
| | | chart2Search: Array<string> |
| | | infoParams: {} |
| | | gasSearch: number | null |
| | | tlGasSearch: number | null |
| | | gasOptions: Array<gasType> |
| | | searchParams: Object |
| | | gasData: Array<any> |
| | | gasTlData: Array<any> |
| | | areaOptions: Array<gasType> |
| | | gasTotal: null | number |
| | | tlTotal: null | number |
| | | online: number |
| | | warningGas: {}, |
| | | dialogWarning: boolean |
| | | countTime: null | number |
| | | yellowNum: null | number |
| | | redNum: null | number |
| | | weatherData: Array<any> |
| | | } |
| | | |
| | | interface gasType { |
| | | label: string |
| | | value: number | null |
| | | name: string |
| | | id: number | null |
| | | } |
| | | |
| | | export default defineComponent({ |
| | |
| | | isFull: Boolean |
| | | }, |
| | | setup(props,context) { |
| | | const userInfo = useUserInfo(); |
| | | const { userInfos } = storeToRefs(userInfo); |
| | | const state = reactive<TableDataState>({ |
| | | yellowNum: null, |
| | | redNum: null, |
| | | socket: null, |
| | | timer: null, |
| | | heartbeat: null, |
| | | heartbeatTimeOut: null, |
| | | lockReconnect: false, |
| | | maxReconnect: 3, // 最大重连次数,-1代表无限重连 |
| | | reconnectTime: 0, // 重连尝试次数 |
| | | time: '', |
| | | date: '', |
| | | weekDay: '', |
| | | dayTime: '', |
| | | isFull: props.isFull, |
| | | chart1Search: 1, |
| | | chart2Search: [], |
| | | gasSearch: 1, |
| | | gasOptions: [ |
| | | { |
| | | label: '气体一', |
| | | value: 1 |
| | | infoParams:{ |
| | | startTime: '', |
| | | endTime: '' |
| | | }, |
| | | { |
| | | label: '气体二', |
| | | value: 2 |
| | | }, |
| | | { |
| | | label: '气体三', |
| | | value: 3 |
| | | } |
| | | ], |
| | | searchParams:{ |
| | | gasSearch: 1, |
| | | areaSearch: 1 |
| | | }, |
| | | areaOptions: [ |
| | | { |
| | | label: '区域一', |
| | | value: 1 |
| | | }, |
| | | { |
| | | label: '区域二', |
| | | value: 2 |
| | | }, |
| | | { |
| | | label: '区域三', |
| | | value: 3 |
| | | } |
| | | ] |
| | | gasSearch: null, |
| | | tlGasSearch: null, |
| | | gasOptions: [], |
| | | gasData: [], |
| | | gasTlData: [], |
| | | areaOptions: [], |
| | | gasTotal: 0, |
| | | tlTotal: 0, |
| | | online: 3, |
| | | warningGas: {}, |
| | | dialogWarning: false, |
| | | countTime: 1, |
| | | weatherData: [] |
| | | }); |
| | | const router = useRouter(); |
| | | const gasN = ref("eChartgasN" + Date.now() + Math.random()) |
| | |
| | | |
| | | // 页面加载时 |
| | | onMounted(() => { |
| | | getGasData() |
| | | getWarningNum() |
| | | getWarningInfo() |
| | | getWarning() |
| | | getUnusual() |
| | | getAreaData() |
| | | const baseSize = 38; |
| | | function setRem() { |
| | | const scale = document.documentElement.clientWidth / 1920;/* 当前页面宽度缩放比例,可根据自己需要修改 */ |
| | |
| | | setInterval(() => { |
| | | getDateTime(); |
| | | }, 1000); |
| | | initgasN() |
| | | initgasT() |
| | | initMap() |
| | | }) |
| | | |
| | | onUnmounted(()=>{ |
| | | destroyedWs() |
| | | }) |
| | | const toNdPage = () =>{ |
| | | router.push('/gasData') |
| | | } |
| | | const toTlPage = () =>{ |
| | | router.push('/fluxData') |
| | | } |
| | | const getGasData = async ()=>{ |
| | | const res = await bigScreenApi().getGas() |
| | | if(res.data.code == 100){ |
| | | state.gasOptions = res.data.data |
| | | state.gasSearch = state.gasOptions[0].id |
| | | state.tlGasSearch = state.gasOptions[0].id |
| | | }else { |
| | | ElMessage({ |
| | | type: 'warning', |
| | | message: res.data.msg |
| | | }); |
| | | } |
| | | getGasSocket() |
| | | getGasTLSocket() |
| | | getGasNdData() |
| | | getGasTlData() |
| | | } |
| | | |
| | | const getAreaData = async ()=>{ |
| | | const res = await bigScreenApi().getAreas({pageSize: 99, pageIndex: 1, searchParams:{name: ''}}) |
| | | if(res.data.code == 100){ |
| | | state.areaOptions = res.data.data |
| | | // state.searchParams.areaSearch = state.areaOptions[0].id |
| | | }else { |
| | | ElMessage({ |
| | | type: 'warning', |
| | | message: res.data.msg |
| | | }); |
| | | } |
| | | } |
| | | |
| | | const getWarningNum = async ()=>{ |
| | | const res = await bigScreenApi().getWarningNum({countTime: state.countTime}) |
| | | if(res.data.code == 100){ |
| | | state.yellowNum = res.data.data?res.data.data.yellowWarnNum:0 |
| | | state.redNum = res.data.data?res.data.data.redWarnNum:0 |
| | | }else { |
| | | ElMessage({ |
| | | type: 'warning', |
| | | message: res.data.msg |
| | | }); |
| | | } |
| | | } |
| | | |
| | | const getGasNdData = async ()=>{ |
| | | const res = await bigScreenApi().getGasNdData({startTime: '',endTime: '',gasName: state.gasSearch}) |
| | | if(res.data.code == 100){ |
| | | if(res.data.data && res.data.data.length>0){ |
| | | state.gasTotal = res.data.data.length |
| | | const timeList = res.data.data.map(i=>i.time.slice(11)) |
| | | const dotList = res.data.data.map(i=>i.gasValue) |
| | | const weather = res.data.data.map((item)=>{ |
| | | return { |
| | | time: item.time?item.time.slice(11):'--', |
| | | temp: item.temp?item.temp:'--', |
| | | humidity: item.humidity?item.humidity:'--', |
| | | windSpeed: item.windSpeed?item.windSpeed:'--', |
| | | windDirection: item.windDirection?item.windDirection:'--', |
| | | pressure: item.pressure?item.pressure:'--' |
| | | } |
| | | }) |
| | | state.weatherData = [...weather].reverse().slice(0, 4); |
| | | initgasN(dotList.slice(dotList.length - 50),timeList.slice(timeList.length - 50)) |
| | | } |
| | | }else { |
| | | ElMessage({ |
| | | type: 'warning', |
| | | message: res.data.msg |
| | | }); |
| | | } |
| | | } |
| | | |
| | | const getGasTlData = async ()=>{ |
| | | const res = await bigScreenApi().getGasTlData({startTime: '',endTime: '',gasName: state.tlGasSearch,areaId: null}) |
| | | if(res.data.code == 100){ |
| | | if(res.data.data && res.data.data.length>0){ |
| | | state.tlTotal = res.data.data.length |
| | | const gasTime = res.data.data.map(i=>i.time?.slice(11)) |
| | | const gasTlTime = [...new Set(gasTime)] |
| | | let areaData = state.areaOptions.map((item)=>{ |
| | | return { |
| | | areaId: item.id, |
| | | name: item.name, |
| | | dotList: [] |
| | | } |
| | | }) |
| | | for(let i of gasTlTime){ |
| | | const sameTimeData = res.data.data.filter(it=>it.time?.slice(11) == i) |
| | | for(let j of areaData){ |
| | | const foundData = sameTimeData.find(k=>k.areaId == j.areaId) |
| | | if(foundData){ |
| | | j.dotList.push(foundData.gasValue) |
| | | }else{ |
| | | j.dotList.push(0) |
| | | } |
| | | } |
| | | } |
| | | const chartData = areaData.map((i)=>{ |
| | | return { |
| | | name: i.name, |
| | | type: 'bar', |
| | | stack: 'total', |
| | | data: i.dotList.slice(i.dotList.length - 20) |
| | | } |
| | | }) |
| | | initgasT(gasTlTime.slice(gasTlTime.length - 20),chartData) |
| | | } |
| | | }else { |
| | | ElMessage({ |
| | | type: 'warning', |
| | | message: res.data.msg |
| | | }); |
| | | } |
| | | } |
| | | |
| | | const getWarningInfo = async ()=>{ |
| | | const res = await bigScreenApi().getWarningInfo(state.infoParams) |
| | | if(res.data.code == 100){ |
| | | if(res.data.data && res.data.data.length>0){ |
| | | const newData = res.data.data.map((item)=>{ |
| | | let i = [] |
| | | if(item.gasThresholdName == '红色预警'){ |
| | | i[0] = `<span style="color:red;">${item.gasThresholdName}</span>` |
| | | }else{ |
| | | i[0] = item.gasThresholdName |
| | | } |
| | | i[1] = item.gasName |
| | | i[2] = item.gasConcentration |
| | | i[3] = item.warnTime |
| | | return i |
| | | }) |
| | | config.data = newData |
| | | } |
| | | }else { |
| | | ElMessage({ |
| | | type: 'warning', |
| | | message: res.data.msg |
| | | }); |
| | | } |
| | | } |
| | | const timeChange = (value:Array<string>)=>{ |
| | | state.infoParams.startTime = value[0] |
| | | state.infoParams.endTime = value[1] |
| | | getWarningInfo() |
| | | } |
| | | |
| | | const changeGas1 = (value) =>{ |
| | | getGasNdData() |
| | | getGasSocket() |
| | | } |
| | | |
| | | const changeGas2 = (value)=>{ |
| | | getGasTlData() |
| | | getGasTLSocket() |
| | | } |
| | | |
| | | const changeTotal = () =>{ |
| | | getWarningNum() |
| | | } |
| | | |
| | | const getWarning = ()=>{ |
| | | initWebSocket('/ws/gas/exc/','预警',60) |
| | | } |
| | | |
| | | const getUnusual = ()=>{ |
| | | initWebSocket('/ws/gas/device/exc/','异常',60) |
| | | } |
| | | |
| | | const getGasSocket = ()=>{ |
| | | initWebSocket('/ws/gas/','气体浓度',30) |
| | | } |
| | | |
| | | const getGasTLSocket = ()=>{ |
| | | initWebSocket('/ws/gas/flux/','气体通量',120) |
| | | } |
| | | |
| | | const initWebSocket =async (requireUrl: string,type: string,beat: number)=>{ |
| | | if (typeof WebSocket === 'undefined') { |
| | | alert('您的浏览器不支持socket'); |
| | | } else { |
| | | // 实例化socket |
| | | let uid = userInfos.value.uid |
| | | let url = import.meta.env.VITE_API_URL + requireUrl + `${uid}` |
| | | url = url.replace('https', 'ws').replace('http', 'ws') |
| | | state.socket = new WebSocket(url) |
| | | // 监听socket连接 |
| | | state.socket.onopen = () => { |
| | | console.log('socket连接成功') |
| | | startHeartbeat(beat) |
| | | |
| | | } |
| | | // 监听socket错误信息 |
| | | state.socket.onerror = () => { |
| | | console.log('socket连接错误') |
| | | console.log(state.socket,'soc') |
| | | // reconnect() |
| | | } |
| | | // 监听socket消息 |
| | | state.socket.onmessage = (msg) => { |
| | | // if (msg.data === '连接成功') return |
| | | const text = msg.data |
| | | //收到服务器信息,心跳重置并发送 |
| | | startHeartbeat(beat); |
| | | if (text.indexOf("连接成功") > 0) { |
| | | return; |
| | | } |
| | | if(type == '预警'){ |
| | | console.log('预警') |
| | | const socketData = JSON.parse(text) |
| | | state.warningGas = JSON.parse(JSON.stringify(socketData)) |
| | | state.dialogWarning = true |
| | | } |
| | | if(type == '异常'){ |
| | | const socketData = JSON.parse(text) |
| | | const deviceStatus = JSON.parse(JSON.stringify(socketData)) |
| | | if(deviceStatus.conState == 1){ |
| | | if(deviceStatus.fluxState == 0){ |
| | | if(deviceStatus.hardwareState.find(i=>i !== 0)){ |
| | | state.online = 1 |
| | | }else{ |
| | | state.online = 2 |
| | | } |
| | | }else{ |
| | | if(deviceStatus.hardwareState.find(i=>i !== 0)){ |
| | | state.online = 0 |
| | | }else{ |
| | | state.online = 1 |
| | | } |
| | | } |
| | | }else{ |
| | | if(deviceStatus.fluxState == 0){ |
| | | if(deviceStatus.hardwareState.find(i=>i !== 0)){ |
| | | state.online = 2 |
| | | }else{ |
| | | state.online = 3 |
| | | } |
| | | }else{ |
| | | if(deviceStatus.hardwareState.find(i=>i !== 0)){ |
| | | state.online = 1 |
| | | }else{ |
| | | state.online = 2 |
| | | } |
| | | } |
| | | } |
| | | } |
| | | if(type == '气体浓度'){ |
| | | state.gasData = JSON.parse(text) |
| | | let gasNum = '' |
| | | let newArr = JSON.parse(JSON.stringify(state.gasData)) |
| | | state.gasTotal = newArr.length |
| | | const weather = newArr.map((item)=>{ |
| | | return { |
| | | time: item.dataReceivingTime?item.dataReceivingTime.slice(11,19):'--', |
| | | temp: item.temp?item.temp:'--', |
| | | humidity: item.humidity?item.humidity:'--', |
| | | windSpeed: item.windSpeed?item.windSpeed:'--', |
| | | windDirection: item.windDirection?item.windDirection:'--', |
| | | pressure: item.pressure?item.pressure:'--' |
| | | } |
| | | }) |
| | | state.weatherData = [...weather].reverse().slice(0, 4); |
| | | for(let key in newArr[0]){ |
| | | if(newArr[0][key] == state.gasSearch && key.indexOf("gasName") !== -1){ |
| | | gasNum = key.substring(7) |
| | | } |
| | | } |
| | | const dotList = newArr.map((item)=>{ |
| | | for(let key in item){ |
| | | if(key.indexOf("gasValue") !== -1 && key.substring(8) == gasNum){ |
| | | return item[key] |
| | | } |
| | | } |
| | | }) |
| | | const gasTime = state.gasData.map(i=>i.dataReceivingTime?.slice(11,19)) |
| | | initgasN(dotList.slice(dotList.length - 50),gasTime.slice(gasTime.length - 50)) |
| | | } |
| | | |
| | | if(type == '气体通量'){ |
| | | state.gasTlData = JSON.parse(text) |
| | | let newArr = JSON.parse(JSON.stringify(state.gasTlData)) |
| | | state.tlTotal = newArr.length |
| | | const gasTime = newArr.map(i=>i.dataReceivingTime?.slice(11,19)) |
| | | const gasTlTime = [...new Set(gasTime)] |
| | | let areaData = state.areaOptions.map((item)=>{ |
| | | return { |
| | | areaId: item.id, |
| | | name: item.name, |
| | | dotList: [] |
| | | } |
| | | }) |
| | | for(let i of gasTlTime){ |
| | | const sameTimeData = newArr.filter(it=>it.dataReceivingTime?.slice(11,19) == i) |
| | | for(let j of areaData){ |
| | | const foundData = sameTimeData.find(k=>k.areaId == j.areaId) |
| | | if(foundData){ |
| | | let gasNum = '' |
| | | for(let key in sameTimeData[0]){ |
| | | if(sameTimeData[0][key] == state.tlGasSearch && key.indexOf("gasName") !== -1){ |
| | | gasNum = key.substring(7) |
| | | } |
| | | } |
| | | for(let key in foundData){ |
| | | if(key.indexOf("gasValue") !== -1 && key.substring(8) == gasNum){ |
| | | j.dotList.push(foundData[key]) |
| | | } |
| | | } |
| | | }else{ |
| | | j.dotList.push(0) |
| | | } |
| | | } |
| | | } |
| | | const chartData = areaData.map((i)=>{ |
| | | return { |
| | | name: i.name, |
| | | type: 'bar', |
| | | stack: 'total', |
| | | data: i.dotList.slice(i.dotList.length - 20) |
| | | } |
| | | }) |
| | | initgasT(gasTlTime.slice(gasTlTime.length - 20),chartData) |
| | | } |
| | | |
| | | } |
| | | state.socket.onclose=()=>{ |
| | | console.log("socket已经关闭") |
| | | } |
| | | } |
| | | } |
| | | const reconnect = (beat)=> { |
| | | if (state.socket.readyState === 1) { |
| | | // 如果状态等于1代表 websocket连接正常 |
| | | return; |
| | | } |
| | | if (state.lockReconnect || (state.maxReconnect !== -1 && state.reconnectTime >= state.maxReconnect)) { |
| | | return; |
| | | } |
| | | |
| | | // 让重连锁变为true,阻止进入下一个循环 |
| | | state.lockReconnect = true; |
| | | setTimeout(() => { |
| | | state.reconnectTime++; |
| | | console.log("尝试重连"); |
| | | // 建立新连接 |
| | | // initWebSocket(); |
| | | getGasSocket() |
| | | state.lockReconnect = false; |
| | | }, beat * 1000); |
| | | } |
| | | |
| | | const startHeartbeat = (beat)=> { |
| | | const webSocket = state.socket; |
| | | // 清空定时器 |
| | | clearTimeout(state.heartbeat); |
| | | state.heartbeat = null; |
| | | clearTimeout(state.heartbeatTimeOut); |
| | | state.heartbeatTimeOut = null; |
| | | // 延时发送下一次心跳 |
| | | // console.log("心跳开启"); |
| | | state.heartbeat = setTimeout(() => { |
| | | // 如果连接正常 |
| | | // console.log("连接状态", webSocket.readyState); |
| | | if (webSocket.readyState === 1) { |
| | | //这里发送一个心跳,后端收到后,返回一个心跳消息, |
| | | let params = JSON.stringify({ |
| | | type: "ping", |
| | | toUserId: userInfos.value.uid, |
| | | }); |
| | | webSocket.send(params); |
| | | // 心跳发送后,如果服务器超时未响应则断开,如果响应了会被重置心跳定时器 |
| | | state.heartbeatTimeOut = setTimeout(() => { |
| | | webSocket.close(); |
| | | // 响应超时时间 |
| | | }, beat * 1000); |
| | | } else { |
| | | // 否则重连 |
| | | reconnect(beat); |
| | | } |
| | | // 心跳间隔时间是30s |
| | | }, beat * 1000); |
| | | } |
| | | |
| | | const destroyedWs=()=> { |
| | | console.log("ws销毁"); |
| | | // 关闭使用close方法关闭socket |
| | | if (state.socket) { |
| | | state.socket.close(); |
| | | } |
| | | state.socket = null; |
| | | // 清除定时器 |
| | | state.timer = null; |
| | | clearInterval(state.timer); |
| | | clearTimeout(state.heartbeat); |
| | | state.heartbeat = null; |
| | | clearTimeout(state.heartbeatTimeOut); |
| | | state.heartbeatTimeOut = null; |
| | | } |
| | | |
| | | const config = reactive({ |
| | | header: ['预警级别','气体名称', '气体浓度', '时间'], |
| | | data: [ |
| | | ['红色预警', '甲烷', '19', '2023-08-10'], |
| | | ['<span style="color:red;">红色预警</span>', '甲烷', '19', '2023-08-10'], |
| | | ['红色预警', '甲烷', '19', '2023-08-10'], |
| | | ['红色预警', '甲烷', '19', '2023-08-10'], |
| | | ['红色预警', '甲烷', '19', '2023-08-10'], |
| | | ['红色预警', '甲烷', '19', '2023-08-10'] |
| | | ], |
| | | data: [], |
| | | index: true, |
| | | columnWidth: [38], |
| | | align: ['center','center','center','center','center'], |
| | |
| | | evenRowBGC: '' |
| | | }) |
| | | |
| | | const bigConfig = reactive({ |
| | | header: ['时间','温度', '湿度', '风速', '风向', '气压'], |
| | | data: [ |
| | | ['2023-08-10 13:29:25','56', '105', '40', '32', '20'],['2023-08-10 13:29:25','56', '105', '40', '32', '20'],['2023-08-10 13:29:25','56', '105', '40', '32', '20'],['2023-08-10 13:29:25','56', '105', '40', '32', '20'],['2023-08-10 13:29:25','56', '105', '40', '32', '20'],['2023-08-10 13:29:25','56', '105', '40', '32', '20'],['2023-08-10 13:29:25','56', '105', '40', '32', '20'],['2023-08-10 13:29:25','56', '105', '40', '32', '20'],['2023-08-10 13:29:25','56', '105', '40', '32', '20'] |
| | | ], |
| | | align: ['center','center','center','center','center','center'], |
| | | headerBGC: '', |
| | | oddRowBGC: '', |
| | | evenRowBGC: '', |
| | | rowNum: 3 |
| | | }) |
| | | // const bigConfig = reactive({ |
| | | // header: ['时间','温度', '湿度', '风速', '风向', '气压'], |
| | | // data: [], |
| | | // align: ['center','center','center','center','center','center'], |
| | | // headerBGC: '', |
| | | // oddRowBGC: '', |
| | | // evenRowBGC: '', |
| | | // rowNum: 3 |
| | | // }) |
| | | |
| | | const mouseoverHandler = (e: any) => { |
| | | console.log(e) |
| | |
| | | } |
| | | |
| | | type EChartsOption = echarts.EChartsOption |
| | | const initgasN =()=>{ |
| | | const initgasN =(data:Array<string>,time: Array<string>)=>{ |
| | | let dom = document.getElementById(gasN.value); |
| | | let myChart = echarts.init(dom); |
| | | let option: EChartsOption; |
| | | option = { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: ['10:36:30', '10:36:30', '10:36:30', '10:36:30', '10:36:30', '10:36:30', '10:36:30', '10:36:30', '10:36:30', '10:36:30', '10:36:30', '10:36:30'], |
| | | data: time, |
| | | axisLabel: { |
| | | color: '#fff' |
| | | }, |
| | | splitLine: { |
| | | show: false |
| | | } |
| | | }, |
| | | yAxis: { |
| | |
| | | grid: { |
| | | top: '5%', |
| | | bottom: '10%', |
| | | right: '0%' |
| | | right: '2%' |
| | | }, |
| | | series: [ |
| | | { |
| | | data: [150, 230, 224, 218, 135, 147, 230, 224, 218, 135, 147, 260], |
| | | data: data, |
| | | type: 'line', |
| | | // label:{ |
| | | // show: true, |
| | | // color: '#fff', |
| | | // textBorderColor: 'transparent' |
| | | // }, |
| | | label:{ |
| | | show: true, |
| | | color: '#fff', |
| | | textBorderColor: 'transparent', |
| | | fontSize: 8 |
| | | }, |
| | | // showSymbol: false, |
| | | lineStyle:{ |
| | | color: '#54d5ff' |
| | | }, |
| | | itemStyle:{ |
| | | color: '#54d5ff', |
| | | }, |
| | | areaStyle:{ |
| | | color: { |
| | | type: 'linear', |
| | | x: 0, |
| | | y: 0, |
| | | x2: 0, |
| | | y2: 1, |
| | | colorStops: [{ |
| | | offset: 0, color: '#2af' // 0% 处的颜色 |
| | | }, { |
| | | offset: 1, color: 'rgba(255,255,255,.1)' // 100% 处的颜色 |
| | | }], |
| | | global: false // 缺省为 false |
| | | } |
| | | } |
| | | } |
| | | ] |
| | |
| | | myChart.resize(); |
| | | }); |
| | | } |
| | | const initgasT =()=>{ |
| | | const initgasT =(time: Array<string>,data: Array<any>)=>{ |
| | | let dom = document.getElementById(gasT.value); |
| | | let myChart = echarts.init(dom); |
| | | let option: EChartsOption; |
| | |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: ['10:36:30', '10:36:30', '10:36:30', '10:36:30', '10:36:30', '10:36:30'], |
| | | data: time, |
| | | axisLabel: { |
| | | color: '#fff' |
| | | } |
| | |
| | | color: '#ccc' |
| | | } |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '2011', |
| | | type: 'bar', |
| | | data: [18, 23, 29, 10, 13, 6], |
| | | label:{ |
| | | show: true, |
| | | color: '#fff', |
| | | textBorderColor: 'transparent' |
| | | } |
| | | }, |
| | | { |
| | | name: '2012', |
| | | type: 'bar', |
| | | data: [19, 23, 31, 12, 13, 6], |
| | | label:{ |
| | | show: true, |
| | | color: '#fff', |
| | | textBorderColor: 'transparent' |
| | | } |
| | | } |
| | | ] |
| | | series: data |
| | | } |
| | | |
| | | option && myChart.setOption(option); |
| | |
| | | mapStyle: 'amap://styles/normal', |
| | | zoom: 18, |
| | | center: [85.057805, 45.62550], |
| | | // layers:[ |
| | | layers:[ |
| | | // new AMap.TileLayer.RoadNet({}), |
| | | // new AMap.TileLayer.Satellite() |
| | | // ], |
| | | ], |
| | | zooms:[2,20], |
| | | }) |
| | | |
| | |
| | | return { |
| | | timeForm, |
| | | config, |
| | | bigConfig, |
| | | gasN, |
| | | gasT, |
| | | map, |
| | | toNdPage, |
| | | toTlPage, |
| | | timeChange, |
| | | mouseoverHandler, |
| | | changeTotal, |
| | | clickHandler, |
| | | changeGas1, |
| | | changeGas2, |
| | | toFull, |
| | | back, |
| | | ...toRefs(state) |
| | |
| | | } |
| | | }); |
| | | </script> |
| | | <style lang="scss"> |
| | | .warningMsg{ |
| | | background: rgba(4,18,67,.8); |
| | | border: 1px solid #00FFFF; |
| | | border-radius: 8px; |
| | | |
| | | .el-dialog__title{ |
| | | color: #fff; |
| | | } |
| | | |
| | | .warning-cont{ |
| | | width: 100%; |
| | | &>div{ |
| | | width: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | color: #fff; |
| | | margin-bottom: 10px; |
| | | span{ |
| | | &:first-of-type{ |
| | | text-align: right; |
| | | } |
| | | &:last-of-type{ |
| | | margin-left: 10px; |
| | | color: #11feee; |
| | | } |
| | | } |
| | | .red{ |
| | | color: red; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | <style lang="scss" scoped> |
| | | .charts-container{ |
| | | width: 100%; |
| | |
| | | } |
| | | .el-select{ |
| | | width: 60%; |
| | | height: 20px; |
| | | height: 24px; |
| | | } |
| | | ::v-deep(.el-popper){ |
| | | background-color: rgba(10,31,92,1); |
| | |
| | | |
| | | .sys-status{ |
| | | width: 66%; |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 16px; |
| | | line-height: 40px; |
| | | .onlineIcon{ |
| | | width: 18px; |
| | | height: 18px; |
| | | color: #11feee; |
| | | } |
| | | .offlineIcon{ |
| | | width: 18px; |
| | | height: 18px; |
| | | color: red; |
| | | } |
| | | div{ |
| | | color: #fff; |
| | | margin-left: 2px; |
| | | .online{ |
| | | color: #11feee; |
| | | margin-left: 10px; |
| | | } |
| | | .offline{ |
| | | color: red; |
| | | margin-left: 10px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .sys-offstatus{ |
| | | width: 66%; |
| | | height: 70%; |
| | | display: flex; |
| | | align-items: center; |
| | |
| | | color: #fff; |
| | | margin-left: 2px; |
| | | span{ |
| | | color: #11feee; |
| | | color: red; |
| | | margin-left: 10px; |
| | | font-size: 14px; |
| | | } |
| | |
| | | } |
| | | |
| | | .el-radio-group{ |
| | | height: 90%; |
| | | height: 24px; |
| | | width: 66%; |
| | | flex-flow: row nowrap; |
| | | display: flex; |
| | |
| | | } |
| | | :deep(.el-date-editor){ |
| | | width: 66%; |
| | | height: 20px; |
| | | height: 24px; |
| | | .el-range-separator{ |
| | | color: #fff; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-input__wrapper){ |
| | | height: 24px; |
| | | box-shadow: none; |
| | | border: 1px solid #11FEEE; |
| | | background: #005dd6; |
| | | background: rgba(0,0,0,0); |
| | | color: #fff; |
| | | |
| | | input{ |
| | |
| | | |
| | | .searchGroup{ |
| | | width: 60%; |
| | | height: 20px; |
| | | height: 24px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: right; |
| | | padding-right: 4px; |
| | | .checkMore{ |
| | | width: 22px; |
| | | height: 22px; |
| | | cursor: pointer; |
| | | margin-left: 10px; |
| | | line-height: 24px; |
| | | font-size: 14px; |
| | | border-radius: 50%; |
| | | border: 1px solid #11FEEE; |
| | | color: #11FEEE; |
| | | text-align: center; |
| | | &:hover{ |
| | | background-color: rgba(10,31,92,1); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .chart-cont{ |
| | |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 5px 10px; |
| | | padding: 0 10px 5px 15px; |
| | | .bigPic{ |
| | | width: 100%; |
| | | height: 50px; |
| | |
| | | background-size: 90% 90%; |
| | | } |
| | | } |
| | | .weather{ |
| | | width: 100%; |
| | | height: calc(100% - 60px); |
| | | background: url("../../../assets/warningScreen/scroll-bg.png") no-repeat bottom; |
| | | background-size: 100% 82%; |
| | | |
| | | tr{ |
| | | width: 100%; |
| | | height: 20%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-around; |
| | | td{ |
| | | width: calc(100% / 6); |
| | | text-align: center; |
| | | box-sizing: border-box; |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | .weatherTit{ |
| | | color: #11feee; |
| | | } |
| | | .weatherRow{ |
| | | color: #fff; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | :deep(.dv-scroll-board){ |
| | | width: 100%; |
| | | height: calc(100% - 60px); |
| | | .header{ |
| | | color: #11feee; |
| | | text-align: center; |
| | | } |
| | | .rows{ |
| | | background: url("../../../assets/warningScreen/scroll-bg.png") no-repeat center; |