<template> <div v-show="activeBtn == 'fanLocal-ssjc'" class="bg" style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; overflow: hidden" > <a-spin :spinning="loading" /> <div id="fanLocal3D" style="width: 100%; height: 100%; position: absolute; overflow: hidden"> </div> <div id="fanLocal3DCSS" class="threejs-Object-CSS" style="width: 100%; height: 100%; position: absolute; overflow: hidden; pointer-events: none"> <div style="z-index: -1; position: relative" v-if="hasPermission('show:sensorMonitor')"> <div class="elementTag" id="inputBox1"> <div class="elementContent" v-if="selectData.windSpeed1 || selectData.gas3 || selectData.windSpeed_merge || selectData.windQuantity1"> <p v-if="selectData.windSpeed1 || selectData.windSpeed_merge" >风筒入口风速:<span class="value">{{ selectData.windSpeed1 ? selectData.windSpeed1 : selectData.windSpeed_merge ? selectData.windSpeed_merge : '-' }}</span> <span class="unit"> m/s</span> </p> <p v-if="selectData.windInputSpeed1 || selectData.windInputSpeed_merge" >风筒入口风速:<span class="value">{{ selectData.windInputSpeed1 ? selectData.windInputSpeed1 : selectData.windInputSpeed_merge ? selectData.windInputSpeed_merge : '-' }}</span> <span class="unit"> m/s</span> </p> <p v-if="selectData.windQuantity1 || selectData.inletAirVolume_merge" >风筒入口风量:<span class="value">{{ selectData.windQuantity1 ? selectData.windQuantity1 : selectData.inletAirVolume_merge ? selectData.inletAirVolume_merge : '-' }}</span> <span class="unit"> m³/min</span> </p> <p v-if="selectData.gas3" >风筒入口瓦斯浓度: <span class="value">{{ selectData.gas3 ? selectData.gas3 : '-' }}</span> <span class="unit"> %</span> </p> </div> </div> <div class="elementTag" id="outBox"> <div class="elementContent elementContent-r" v-if=" selectData.windQuantity2 || selectData.gas1 || (selectData.windOutSpeed1 && selectData.windOutSpeed_merge) || selectData.ductOutletAirVolume_merge " > <p v-if="selectData.windQuantity2 || selectData.m3 || selectData.ductOutletAirVolume_merge || selectData.windOutSpeed_merge"> 迎头供风量:<span class="value">{{ selectData.windQuantity2 ? selectData.windQuantity2 : selectData.m3 ? selectData.m3 : selectData.ductOutletAirVolume_merge ? selectData.ductOutletAirVolume_merge : '-' }}</span> <span class="unit"> m³/min</span> </p> <p v-if="selectData.gas1" >迎头瓦斯浓度:<span class="value">{{ selectData.gas1 ? selectData.gas1 : '-' }}</span> <span class="unit"> %</span> </p> <p v-if="selectData.windOutSpeed1 || selectData.windOutSpeed_merge" >风筒出口风速<span class="value">{{ selectData.windOutSpeed1 ? selectData.windOutSpeed1 : selectData.windOutSpeed_merge ? selectData.windOutSpeed_merge : '-' }}</span> <span class="unit"> %</span> </p> </div> </div> <div class="elementTag" id="returnBox"> <div class="elementContent elementContent-r" v-if="selectData.gas2"> <p v-if="selectData.gas2" >回风流瓦斯浓度:<span class="value">{{ selectData.gas2 ? selectData.gas2 : '-' }}</span> <span class="unit"> %</span> </p> </div> </div> <div class="elementTag" id="gateBox"> <div class="elementContent"> <p>风门状态:关</p> <p>风门过风面积:{{ selectData.gas1 ? selectData.gas1 : '-' }}</p> </div> </div> <div class="elementTag" id="windownBox"> <div class="elementContent" v-if="modalType == 'fc'"> <p style="pointer-events: auto" ><a class="action-link" @click="goDetailDevice('window_fWindowM3')">风窗详情</a> <ArrowRightOutlined :style="{ color: '#157DC8' }" /> </p> <p v-if="selectData.windSpeed" >风窗风流风速:<span class="value">{{ selectData.windSpeed ? selectData.windSpeed : '-' }}</span> <span class="unit"> m/s</span></p > <p v-if="selectData.fWindowM3" >风窗过风量:<span class="value">{{ selectData.fWindowM3 ? selectData.fWindowM3 : '-' }}</span> <span class="unit"> m³/min</span></p > <p v-if="selectData.OpenDegree" >风窗开度值:<span class="value">{{ selectData.OpenDegree ? selectData.OpenDegree : '-' }}</span> <span class="unit"> %</span></p > <p v-if="selectData.OpenDegree" >风窗过风面积:<span class="value">{{ selectData.forntArea ? selectData.forntArea : '-' }}</span> <span class="unit"> ㎡</span></p > </div> </div> </div> </div> </div> <div class="scene-box"> <div class="top-box" v-if="!loading && activeBtn == 'fanLocal-ssjc'"> <div class="top-center row"> <!-- <div class="vent-flex-row" id="fanLocalSelectDom" v-if="!globalConfig?.simulatedPassword && getDictItemsByCode('fanlocaltype')"> <span style="color: #00f5fe; margin-left: 5px">风机类型:</span> <JDictSelectTag style="width: 180px" v-model:value="devicekide" dictCode="fanlocaltype" :showChooseOption="false" :getPopupContainer="getPopupContainer" @change="changeDeviceKind" /> </div> --> <!-- fanlocal_systeml_zj 模拟局部风机,不显示操作按钮 --> <template v-for="(item, index) in modalTypeArr.leftBtnArr" :key="index"> <div v-if="!(selectData.fanFrequencyType == 'fandp' && item.permission.startsWith('btn:frequency')) && hasPermission(item.permission)" :class="{ 'button-box': btnClick, 'button-disable': !btnClick }" @click="showModal(item)" >{{ item.value }} </div> </template> </div> <div class="top-right row"> <template v-for="(item, index) in modalTypeArr.rightBtnArr" :key="index"> <div v-if=" !(selectData.fanFrequencyType == 'fandp' && (item.permission === 'fanLocal:gasAlarmSet' || item.permission === 'fanLocal:kkjc')) && hasPermission(item.permission) " :class="{ 'button-box': btnClick, 'button-disable': !btnClick }" @click="showModal(item)" >{{ item.value }}</div > </template> </div> </div> <div class="title-text"> {{ selectData.supplyAirAddr || selectData.strinstallpos || selectData.stationname }} </div> <div class="data-show-box" v-if="!loading && activeBtn == 'fanLocal-ssjc'"> <div class="data-item" v-if="leftColumns.length > 0"> <div class="item-header">设备监测</div> <div class="item-container"> <div class="tab"> <div class="tab-item" :class="{ 'tab-item-active-r': warningMonitorRowIndex === 0 }" @click="selectDevice('warningMonitorRowIndex', 0)" >1#风机</div > <div class="tab-item" :class="{ 'tab-item-active-r': warningMonitorRowIndex === 1 }" @click="selectDevice('warningMonitorRowIndex', 1)" >2#风机</div > </div> <div class="container-group"> <div class="warning-group"> <template v-if="selectData.deviceType"> <div class="container-item" v-for="(data, index) in leftColumns" :key="index"> <div class="item-icon"> <CaretRightOutlined class="icon-style" /> </div> <div class="item-name">{{ data.title }}</div> <div v-if="data.dataIndex.startsWith('Fan')"> <div class="item-value" v-if="warningMonitorRowIndex == 0">{{ selectData[data.dataIndex.replace('Fan', 'Fan1')] ? selectData[data.dataIndex.replace('Fan', 'Fan1')] : '-' }}</div> <div class="item-value" v-if="warningMonitorRowIndex == 1">{{ selectData[data.dataIndex.replace('Fan', 'Fan2')] ? selectData[data.dataIndex.replace('Fan', 'Fan2')] : '-' }}</div> </div> <div v-else> <div class="item-value">{{ selectData[data.dataIndex] ? selectData[data.dataIndex] : '-' }}</div> </div> </div> </template> </div> </div> </div> </div> <div> <div class="data-item" v-if="rightColumns.length > 0"> <div class="item-header">环境监测/设备报警</div> <div class="item-container"> <div class="tab"> <div class="tab-item" :class="{ 'tab-item-active-r': dataMonitorRowIndex == 0 }" @click="selectDevice('dataMonitorRowIndex', 0)" >1#风机</div > <div class="tab-item" :class="{ 'tab-item-active-r': dataMonitorRowIndex == 1 }" @click="selectDevice('dataMonitorRowIndex', 1)" >2#风机</div > </div> <div class="container-group container-group-l"> <div class="warning-group" style="max-height: 50%; overflow-y: auto"> <template v-if="deviceType"> <div v-for="(state, index) in rightColumns" :key="index"> <template v-if="!state.dataIndex.endsWith('_w')"> <div class="container-item"> <div class="item-icon"> <CaretRightOutlined class="icon-style" /> </div> <div class="item-name">{{ state.title }}</div> <div v-if="state.dataIndex.startsWith('Fan')"> <div class="item-value" v-if="dataMonitorRowIndex == 0">{{ selectData[state.dataIndex.replace('Fan', 'Fan1')] ? selectData[state.dataIndex.replace('Fan', 'Fan1')] : '-' }}</div> <div class="item-value" v-if="dataMonitorRowIndex == 1">{{ selectData[state.dataIndex.replace('Fan', 'Fan2')] ? selectData[state.dataIndex.replace('Fan', 'Fan2')] : '-' }}</div> </div> <div v-else> <div class="item-value">{{ selectData[state.dataIndex] ? selectData[state.dataIndex] : '-' }} </div> </div> </div> </template> </div> </template> </div> <div class="warning-group" style="max-height: 50%; overflow-y: auto"> <div class="warning-header"> <div class="header-item"> <div class="header-title">报警数量</div> <div class="header-value">{{ selectData['warnLogNotOkCount'] }} </div> </div> </div> <template v-if="deviceType"> <div v-for="(state, index) in leftColumns" :key="index"> <template v-if="state.dataIndex.endsWith('_w')"> <div class="warning-item"> <div class="item-name"> <div class="icon"></div> {{ state.title }} </div> <div v-if="state.dataIndex.startsWith('Fan')"> <div class="signal-item" v-if="warningMonitorRowIndex == 0"> <div class="signal-round" :class="{ 'signal-round-run': selectData[state.dataIndex.replace('Fan', 'Fan1')] == '0', 'signal-round-warning': selectData[state.dataIndex.replace('Fan', 'Fan1')] !== undefined && selectData[state.dataIndex.replace('Fan', 'Fan1')] == '1', 'signal-round-gry': selectData[state.dataIndex.replace('Fan', 'Fan1')] === undefined, }" ></div> <div class="vent-margin-l-8">{{ selectData[state.dataIndex.replace('Fan', 'Fan1')] === undefined ? '无状态' : selectData[state.dataIndex.replace('Fan', 'Fan1')] == '0' ? '正常' : '异常' }}</div> </div> <div class="signal-item" v-if="warningMonitorRowIndex == 1"> <div class="signal-round" :class="{ 'signal-round-run': selectData[state.dataIndex.replace('Fan', 'Fan2')] == '0', 'signal-round-warning': selectData[state.dataIndex.replace('Fan', 'Fan2')] != undefined && selectData[state.dataIndex.replace('Fan', 'Fan2')] == '1', 'signal-round-gry': selectData[state.dataIndex.replace('Fan', 'Fan2')] == undefined, }" ></div> <div class="vent-margin-l-8">{{ selectData[state.dataIndex.replace('Fan', 'Fan2')] == undefined ? '无状态' : selectData[state.dataIndex.replace('Fan', 'Fan2')] == '0' ? '正常' : '异常' }}</div> </div> </div> <div v-else> <div class="signal-item"> <div class="signal-round vent-margin-l-8" :class="{ 'signal-round-run': selectData[state.dataIndex] == '0', 'signal-round-warning': selectData[state.dataIndex] !== undefined && selectData[state.dataIndex] == '1', 'signal-round-gry': selectData[state.dataIndex] === undefined, }" ></div> <div class="vent-margin-l-8">{{ selectData[state.dataIndex] === undefined ? '无状态' : selectData[state.dataIndex] == '0' ? '正常' : '异常' }}</div> </div> </div> </div> </template> </div> </template> </div> </div> </div> </div> </div> </div> </div> <div v-show="activeBtn == 'fanLocal-ssjc'" ref="playerRef" :class="{ 'to-right': rightColumns.length < 1 || leftColumns.length < 1, 'to-no-right': rightColumns.length > 0 && leftColumns.length > 0 }" style="z-index: 999; position: absolute; top: 100px; right: 15px; width: 100%; height: 100%; margin: auto; pointer-events: none" > </div> <a-modal v-model:visible="modalIsShow" :title="modalTitle" :maskStyle="{ backgroundColor: '#000000aa', backdropFilter: 'blur(3px)' }"> <template #footer> <div v-if="controlType != 'startFan'"> <a-button key="back" @click="cancel">返回</a-button> <a-button key="submit" type="primary" :loading="loading" @click="handleOk">确定</a-button> </div> </template> <div class="modal-container"> <div class="vent-flex-row"> <ExclamationCircleFilled style="color: #ffb700; font-size: 30px" /> <div class="warning-text">您是否要进行{{ modalTitle }}操作?</div> </div> <div class="" v-if="controlType == 'startSmoke'"> <!-- 互斥控制 --> <div class="startSmoke-select"> <div class="label">1#风机</div> <a-radio-group v-model:value="mainWindIsShow1" @change="changeMotor" name="localWind1"> <a-radio value="open">开启</a-radio> <a-radio value="stop">停止</a-radio> </a-radio-group> </div> <div class="startSmoke-select"> <div class="label">2#风机</div> <a-radio-group v-model:value="mainWindIsShow2" @change="changeMotor" name="localWind2"> <a-radio value="open">开启</a-radio> <a-radio value="stop">停止</a-radio> </a-radio-group> </div> </div> <div class="" v-if="controlType == 'startFan'"> <!-- 不互斥控制 --> <div class="startSmoke-select"> <div class="label">1#风机:</div> <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan1Open')">开启</div> <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan1Stop')">停止</div> <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan1Reset')">复位</div> </div> <div class="startSmoke-select"> <div class="label">2#风机:</div> <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan2Open')">开启</div> <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan2Stop')">停止</div> <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan2Reset')">复位</div> </div> </div> <!-- 调频 --> <div class="vent-flex-row input-box" v-if="controlType == 'Fan1Frequency'"> <div class="label">1#机运行频率(Hz):</div> <a-input-number size="small" v-model:value="fan1FrequencyVal" :min="20" :max="50" :step="0.1" /> </div> <div class="vent-flex-row input-box" v-if="controlType == 'Fan2Frequency'"> <div class="label">2#机运行频率(Hz):</div> <a-input-number size="small" v-model:value="fan2FrequencyVal" :min="20" :max="50" :step="0.1" /> </div> <div class="vent-flex-row input-box" v-if="controlType == 'FanFrequency'"> <div class="label">风机运行频率(Hz):</div> <a-input-number size="small" v-model:value="fan1FrequencyVal" :min="20" :max="50" :step="0.1" /> </div> <div class="vent-flex-row input-box" v-if="controlType == 'disAirAlarm'"> <div class="label">漏风率(%):</div> <a-input-number size="small" v-model:value="frequencyVal" :min="0" :max="50" :step="0.1" /> </div> <div class="vent-flex-row input-box" v-if="controlType == 'diameter'"> <div class="label">风筒直径(m):</div> <a-input-number size="small" v-model:value="frequencyVal" :min="0" :max="50" :step="0.1" /> </div> <div class="vent-flex-row input-box" v-if="controlType == 'len'"> <div class="label">风筒长度(m):</div> <a-input-number size="small" v-model:value="frequencyVal" :min="0" :max="50" :step="0.1" /> </div> <div class="vent-flex-row input-box" v-if="controlType == 'windPowerLimit'"> <div class="label">风电闭锁限值(m³/min):</div> <a-input-number size="small" v-model:value="frequencyVal" :min="0" :max="50" :step="0.1" /> </div> <div class="vent-flex-row input-box" v-if="controlType == 'gasPowerLimit'"> <div class="label">瓦斯电闭锁限值(m³/min):</div> <a-input-number size="small" v-model:value="frequencyVal" :min="0" :max="50" :step="0.1" /> </div> <div v-if="controlType == 'gasAlarmSet'"> <div class="vent-flex-row input-box"> <div class="label">设置瓦斯超限浓度:</div> <a-input-number size="small" v-model:value="gasWarningVal" :min="0" :max="1" :step="0.01" /> </div> </div> <div v-if="controlType == 'gasAlarm'"> <div class="vent-flex-row input-box"> <div class="label">传感器名称:</div> <a-select placeholder="传感器" @change="handleChangeSensor" :options="sensorList" v-model:value="modalSensor" /> </div> <div class="vent-flex-row input-box"> <div class="label">传感器值:</div> <a-input-number size="small" v-model:value="frequencyVal" :min="0" :max="50" :step="0.1" /> </div> </div> <div v-if="controlType == 'airVolumeAlarm'"> <div class="vent-flex-row input-box"> <div class="label">风量上限(m³/min):</div> <a-input-number size="small" v-model:value="modalTypeArr.rightBtnArr[3].min" :min="0" :max="50" :step="0.1" /> </div> <div class="vent-flex-row input-box"> <div class="label">风量下限(m³/min):</div> <a-input-number size="small" v-model:value="modalTypeArr.rightBtnArr[3].max" :min="0" :max="50" :step="0.1" /> </div> </div> <div class="vent-flex-row input-box" v-if="controlType == 'zhlk'"> <div class="label">目标风量(m³/min):</div> <a-input-number size="small" v-model:value="targetVolume" /> </div> <div v-if="controlType == 'gasOverSet'"> <div class="vent-flex-row input-box"> <div class="label">设置瓦斯超限浓度:</div> <a-input-number size="small" v-model:value="gasWarningVal" :min="0" :max="1" :step="0.01" /> </div> </div> <!-- 启动或停止 --> <div class="" v-if="controlType == 'startSmoke'"> </div> <div v-if="!globalConfig?.simulatedPassword" class="vent-flex-row input-box"> <div class="label">操作密码:</div> <a-input size="small" type="password" v-model:value="passWord" /> </div> </div> </a-modal> <fanlocalHistory v-if="activeBtn == 'fanLocal-history'" :selectData="selectData" :devicekide="devicekide" :deviceId="deviceId" /> <fanlocalWarnHistory v-if="activeBtn == 'fanLocal-warn'" :devicekide="devicekide" :deviceId="deviceId" /> <fanlocalOperateHistory v-if="activeBtn == 'fanLocal-operate'" :devicekide="devicekide" :deviceId="deviceId" /> <fanlocalEchartLine v-if="activeBtn == 'fanLocal-wind'" :historyList="historyList" :chartsColumns="chartsColumns" :deviceId="deviceId" /> <BottomMenu :nav-list="navList" @change="changeActive" /> </template> <script setup lang="ts"> import { ExclamationCircleFilled, ArrowRightOutlined } from '@ant-design/icons-vue'; import { onBeforeMount, ref, watch, onMounted, nextTick, defineAsyncComponent, reactive, onUnmounted, inject, unref } from 'vue'; import BottomMenu from '/@/views/vent/comment/components/bottomMenu.vue'; import fanlocalHistory from './components/fanlocal-history.vue'; import fanlocalWarnHistory from './components/fanlocal-warn-history.vue'; import fanlocalOperateHistory from './components/fanlocal-operate-history.vue'; import fanlocalEchartLine from './components/fanlocal-echart-line.vue'; import { mountedThree, setModelType, destroy, addCssText, addText, playSmoke } from './fanLocal.three'; import lodash from 'lodash'; import { getTableList, list, autoAdjust } from '/@/views/vent/monitorManager/fanLocalMonitor/fanLocal.api'; import { chartsColumns1, navList } from './fanLocal.data'; import { deviceControlApi } from '/@/api/vent/index'; import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns'; import { useRouter } from 'vue-router'; import type { BasicColumn } from '/@/components/Table/src/types/table'; import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue'; import { getPopupContainer } from '/@/utils'; import { getDictItemsByCode } from '/@/utils/dict'; import { message } from 'ant-design-vue'; import { useCamera } from '/@/hooks/system/useCamera'; import { CaretRightOutlined } from '@ant-design/icons-vue'; import { usePermission } from '/@/hooks/web/usePermission'; import { useGlobSetting } from '/@/hooks/setting'; import { useMessage } from '/@/hooks/web/useMessage'; const globalConfig = inject('globalConfig'); const { hasPermission } = usePermission(); const { currentRoute } = useRouter(); const router = useRouter(); const { createConfirm } = useMessage(); const globSetting = useGlobSetting(); const modalTypeArr = reactive({ leftBtnArr: [ { key: 'startSmoke', value: '启停风机', permission: 'btn:openclose', }, { key: 'startFan', value: '启停风机', permission: 'btn:openclose1', }, { key: 'changeSmoke', // 主备两个点位 value: '一键倒机', permission: 'btn:change', }, { key: 'changeFan', // 主备一个点位 value: '一键倒机', permission: 'btn:CtrlFanChange', }, { key: 'fan1ToFan2', value: '1#倒2#', permission: 'btn:ctrlFan1ToFan2', }, { key: 'fan2ToFan1', value: '2#倒1#', permission: 'btn:ctrlFan2ToFan1', }, { key: 'Fan1Frequency', value: '1#调频', permission: 'btn:frequency', }, { key: 'Fan2Frequency', value: '2#调频', permission: 'btn:frequency', }, { key: 'FanFrequency', value: '风机调频', permission: 'btn:frequencyMerge', }, { key: 'windPower', value: '风电闭锁', permission: 'fanLocal:fdbs', }, { key: 'gasPower', value: '瓦斯电闭锁', permission: 'fanLocal:wsdbs', }, { key: 'needAir', value: '需风量', permission: 'fanLocal:control', }, ], rightBtnArr: [ { key: 'gasAlarmSet', value: '瓦斯限值设定', permission: 'fanLocal:gasAlarmSet', }, { key: 'gasOverSet', // value: '瓦斯限值设定', permission: 'fanLocal:gasOverSet', }, { key: 'kkjc', value: '工况辅助决策', permission: 'fanLocal:kkjc', }, { key: 'zhlk', value: '自主联控', permission: 'fanLocal:zhlk', }, { key: 'diameter', value: '风筒直径', permission: 'fanLocal:control', }, { key: 'diameter', value: '风筒直径', permission: 'fanLocal:control', }, { key: 'len', value: '风筒长度', permission: 'fanLocal:control', }, // { // key: 'frequency', // value: '调频', // permission: 'fanLocal:control', // }, { key: 'windPowerLimit', value: '风电闭锁限值', permission: 'fanLocal:control', }, { key: 'gasPowerLimit', value: '瓦斯电闭锁限值', permission: 'fanLocal:control', }, { key: 'airVolumeAlarm', value: '风量报警', permission: 'fanLocal:control', min: 0, max: 100, }, { key: 'disAirAlarm', value: '漏风率报警', permission: 'fanLocal:control', }, // { // key: 'gasAlarm', // value: '瓦斯报警', // permission: 'fanLocal:control', // }, ], }); const sensorList = ref<any[]>([ { value: '1', label: 'T1', }, { value: '2', label: 'T2', }, { value: '3', label: 'T3', }, ]); const scroll = reactive({ y: 180, }); const deviceTypeDicts = getDictItemsByCode('fanlocaltype'); const gasWarningVal = ref(0.6); // 瓦斯最大报警值 const playerRef = ref(); const modalSensor = ref(null); const loading = ref(false); const player1 = ref(); const modalIsShow = ref<boolean>(false); // 是否显示模态框 const modalTitle = ref(''); // 模态框标题显示内容,根据设备操作类型决定 const fan1FrequencyVal = ref(40); //主机频率 const fan2FrequencyVal = ref(40); //备机频率 const mainWindIsShow1 = ref('open'); // 主机默认启动leftColumns const mainWindIsShow2 = ref('stop'); // 备机默认不启动 const fanControl = ref(''); const targetVolume = ref(600); const historyList = ref([]); const remoteChartsColumns = getTableHeaderColumns('fanlocal_chart'); const chartsColumns = remoteChartsColumns && remoteChartsColumns.length > 0 ? remoteChartsColumns : chartsColumns1; const passWord = ref(''); // 默认初始是第一行 const selectRowIndex = ref(0); const dataMonitorRowIndex = ref(0); // 默认数据右边监测的是主机 const warningMonitorRowIndex = ref(0); const xAxisDataGas = ref([]); // 设备数据 const controlType = ref(''); const modalType = ref(''); // 监测数据 const initData = { deviceID: '', deviceType: '', strname: '', dataDh: '-', //压差 dataDtestq: '-', //测试风量 sourcePressure: '-', //气源压力 dataDequivalarea: '-', netStatus: '0', //通信状态 warnLevel_str: '', stationname: '', fanFrequencyType: '', }; const frequencyVal = ref(0); const dataSource = ref([]); // const historySource = ref([]); // 关联设备信息 const linkDeviceInfo = ref({}); // 监测数据 let selectData = reactive(lodash.cloneDeep(initData)); const rightColumns = ref<BasicColumn[]>([]); const leftColumns = ref<BasicColumn[]>([]); const devicekide = ref(''); const deviceType = ref(selectData.deviceType); const deviceId = ref(''); const headElHeight = ref(0); let btnClick = ref(true); // 判断按钮是否可点 //报表导出 // let editID = ref<any>(''); // let fileType = ref(''); // https获取监测数据 let timer: null | NodeJS.Timeout | undefined = null; const { getCamera, removeCamera } = useCamera(); watch(deviceType, (type) => { rightColumns.value = getTableHeaderColumns(type + '_monitor_right') as []; if (rightColumns.value && rightColumns.value.length < 1) { rightColumns.value = getTableHeaderColumns(type.split('_')[0] + '_monitor_right') as []; } leftColumns.value = getTableHeaderColumns(type + '_monitor_left') as []; if (leftColumns.value && leftColumns.value.length < 1) { leftColumns.value = getTableHeaderColumns(type.split('_')[0] + '_monitor_left') as []; } }); const flvURL1 = () => { // return `https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv`; return ''; }; const activeBtn = ref('fanLocal-ssjc'); async function changeActive(activeValue) { activeBtn.value = activeValue; if (activeBtn.value !== 'fanLocal-ssjc') { timer = undefined; clearTimeout(timer); } else { timer = null; await getMonitor(true); } } const selectDevice = (key, val) => { if (key === 'dataMonitorRowIndex') { dataMonitorRowIndex.value = val; } else { warningMonitorRowIndex.value = val; } }; function goDetailDevice(linkDeviceCode) { let linkDeviceId = ''; if (linkDeviceCode.startsWith('window')) { linkDeviceId = linkDeviceInfo.value[linkDeviceCode] ? linkDeviceInfo.value[linkDeviceCode]['id'] : ''; router.push({ path: '/monitorChannel/monitor-window', query: { id: linkDeviceId } }); } } // async function getDataSource() { if (devicekide.value) { const res = await list({ devicetype: devicekide.value, ids: deviceId.value, pagetype: 'normal' }); // const res = await list({ devicetype: 'fanlocal', pagetype: 'normal' }); if (res.msgTxt && res.msgTxt[0] && res.msgTxt[0].datalist && res.msgTxt[0].datalist.length > 0) { const dataArr = res.msgTxt[0].datalist || []; dataSource.value = []; selectRowIndex.value = dataArr.findIndex((item) => item.deviceID === deviceId.value); debugger; if (selectRowIndex.value > -1) { if (!deviceType.value) deviceType.value = dataArr[selectRowIndex.value]['deviceType']; let data = dataArr[selectRowIndex.value]; const readData = data.readData; data = Object.assign(data, readData); if (data['Fan1StartStatus'] && data['Fan1StartStatus'] === '1.0') data['Fan1StartStatus'] = '1'; if (data['Fan2StartStatus'] && data['Fan2StartStatus'] === '1.0') data['Fan2StartStatus'] = '1'; if (data['Fan1StartStatus'] && data['Fan1StartStatus'] === '0.0') data['Fan1StartStatus'] = '0'; if (data['Fan2StartStatus'] && data['Fan2StartStatus'] === '0.0') data['Fan2StartStatus'] = '0'; data['windQuantity2'] = data['windQuantity2'] || data['m3'] || data['ductOutletAirVolume_merge'] || data['windOutSpeed_merge'] || data['windOutSpeed1'] || data['windOutSpeed2'] || data['windOutSpeed_merge']; // if (globSetting.sysOrgCode === 'sdmtjtbetmk') { // if (data['m3']) data['ductOutletAirVolume_merge'] = data['m3']; // if (data['m3']) data['inletAirVolume_merge'] = (Number(data['m3']) * 1.08).toFixed(2); // } Object.assign(selectData, data); if (selectRowIndex.value > -1) { let echartsData = dataArr[selectRowIndex.value]['history'] || []; echartsData = echartsData.filter((item) => { item['FanfHz'] = data['Fan1StartStatus'] == '1' ? item['Fan1fHz'] : data['Fan2StartStatus'] == '1' ? item['Fan2fHz'] : 0; item['windQuantity2'] = item['windQuantity2'] || item['m3'] || item['ductOutletAirVolume_merge'] || item['windOutSpeed_merge'] || item['windOutSpeed1'] || item['windOutSpeed2'] || item['windOutSpeed_merge']; return true; }); historyList.value = echartsData; } } } else { return (dataSource.value = []); } } else { dataSource.value = []; } } async function getMonitor(flag?) { if (Object.prototype.toString.call(timer) === '[object Null]') { timer = await setTimeout( async () => { // debugger; // for (const key in selectData) { // selectData[key] = ''; // } await getDataSource(); // if (dataSource.value.length > 0 && dataSource.value[selectRowIndex.value]) { // deviceType.value = dataSource.value[selectRowIndex.value]['deviceType']; // if (dataSource.value.length > 0 && dataSource.value[selectRowIndex.value]) { // Object.assign(selectData, dataSource.value[selectRowIndex.value]); // } // } playSmoke(selectData); addText(selectData); // historySource.value = selectData.history; if (timer) { timer = null; } getMonitor(); }, flag ? 0 : 1000 ); } } // 获取设备基本信息列表 const deviceBaseList = ref([]); function getDeviceBaseList() { getTableList({ pageSize: 1000 }).then((res) => { deviceBaseList.value = res.records; }); } // 打开并设置modal的标题 function showModal(obj) { if (!btnClick.value) return; if (obj.key == 'kkjc') { gasWarningVal.value = 0.6; // 工况辅助决策 openAssistance(true, {}); return; } controlType.value = obj.key; modalTitle.value = obj.value; passWord.value = ''; modalIsShow.value = true; } function changeMotor(e) { const target = e.target; if (target.name === 'localWind1') { if (target.value === 'open') { mainWindIsShow2.value = 'stop'; } } else if (target.name === 'localWind2') { if (target.value === 'open') { mainWindIsShow1.value = 'stop'; } } } function handleOk(control?) { if (passWord.value == '') { message.warning('请输入密码!'); return; } createConfirm({ iconType: 'warning', title: '控制', content: '您确定要控制吗?', onOk: () => handerFn(), }); const handerFn = () => { const handType = controlType.value; const data = { deviceid: selectData.deviceID, devicetype: selectData.deviceType, paramcode: '', password: passWord.value || globalConfig?.simulatedPassword, value: null, }; if (handType === 'startSmoke') { // 启动风机 // 以下是互斥 if (mainWindIsShow1.value === 'open' && mainWindIsShow2.value === 'stop') { // playSmoke(handType, 'top', frequency, 'open'); data.paramcode = 'CtrlFan1Start'; deviceControlApi(data) .then((res) => { if (res.success) { if (globalConfig.History_Type == 'remote') { message.success('指令已下发至生产管控平台成功!'); } else { message.success('指令已下发成功!'); } modalTitle.value = ''; modalIsShow.value = false; } else { message.error(res.message); } }) .catch((err) => { // modalIsShow.value = true; }); } else if (mainWindIsShow2.value === 'open' && mainWindIsShow1.value === 'stop') { // playSmoke(handType, 'down', frequency, 'open'); data.paramcode = 'CtrlFan2Start'; deviceControlApi(data) .then(() => { if (res.success) { if (globalConfig.History_Type == 'remote') { message.success('指令已下发至生产管控平台成功!'); } else { message.success('指令已下发成功!'); } modalTitle.value = ''; modalIsShow.value = false; } else { message.error(res.message); } }) .catch((err) => {}); } else if (mainWindIsShow1.value === 'stop' && mainWindIsShow2.value === 'stop') { // playSmoke(handType, '', frequency, 'stop'); } } else if (handType === 'startFan') { if (control === 'Fan1Open') { data.paramcode = 'CtrlFan1Start'; } else if (control === 'Fan2Open') { data.paramcode = 'CtrlFan2Start'; } else if (control === 'Fan1Stop') { data.paramcode = 'CtrlFan1Stop'; } else if (control === 'Fan2Stop') { data.paramcode = 'CtrlFan2Stop'; } else if (control === 'Fan1Reset') { data.paramcode = 'CtrlFan1Reset'; } else if (control === 'Fan2Reset') { data.paramcode = 'CtrlFan2Reset'; } deviceControlApi(data) .then((res) => { if (res.success) { if (globalConfig.History_Type == 'remote') { message.success('指令已下发至生产管控平台成功!'); } else { message.success('指令已下发成功!'); } modalTitle.value = ''; modalIsShow.value = false; } else { message.error(res.message); } }) .catch((err) => { btnClick.value = true; }); } else if (handType === 'Fan1Frequency' || handType === 'Fan2Frequency' || handType === 'FanFrequency') { // 调频 if (handType === 'Fan1Frequency') { data.paramcode = 'Fan1FreqHz'; data.value = fan1FrequencyVal.value; } else if (handType === 'Fan2Frequency') { data.paramcode = 'Fan2FreqHz'; data.value = fan2FrequencyVal.value; } else if (handType === 'FanFrequency') { data.paramcode = 'FreqHz_merge'; data.value = fan1FrequencyVal.value; } deviceControlApi(data) .then((res) => { if (res.success) { if (globalConfig.History_Type == 'remote') { message.success('指令已下发至生产管控平台成功!'); } else { message.success('指令已下发成功!'); } modalTitle.value = ''; modalIsShow.value = false; } else { message.error(res.message); } }) .catch((err) => {}); } else if (handType === 'changeSmoke') { if (selectData['Fan1StartStatus'] == '0' || !selectData['Fan1StartStatus']) { data.paramcode = 'CtrlFan1Start'; deviceControlApi(data) .then((res) => { if (res.success) { if (globalConfig.History_Type == 'remote') { message.success('指令已下发至生产管控平台成功!'); } else { message.success('指令已下发成功!'); } modalTitle.value = ''; modalIsShow.value = false; } else { message.error(res.message); } mainWindIsShow1.value = 'stop'; mainWindIsShow2.value = 'open'; }) .catch((err) => {}); } else if (selectData['Fan2StartStatus'] == '0' || !selectData['Fan2StartStatus']) { data.paramcode = 'CtrlFan2Start'; deviceControlApi(data) .then((res) => { if (res.success) { if (globalConfig.History_Type == 'remote') { message.success('指令已下发至生产管控平台成功!'); } else { message.success('指令已下发成功!'); } modalTitle.value = ''; modalIsShow.value = false; } else { message.error(res.message); } mainWindIsShow1.value = 'open'; mainWindIsShow2.value = 'stop'; }) .catch((err) => {}); } // // 一键倒机 // if (mainWindIsShow1.value === 'open' && mainWindIsShow2.value === 'stop') { // // playSmoke('startSmoke', 'down', frequency, 'open'); // data.paramcode = 'CtrlFan2Start'; // deviceControlApi(data).then((res) => { // console.log('设备操作结果', res); // modalTitle.value = ''; // modalIsShow.value = false; // }).catch((err) => { // }); // mainWindIsShow1.value = 'stop'; // mainWindIsShow2.value = 'open'; // } else if (mainWindIsShow2.value === 'open' && mainWindIsShow1.value === 'stop') { // // playSmoke('startSmoke', 'top', frequency, 'open'); // data.paramcode = 'CtrlFan1Start'; // deviceControlApi(data).then((res) => { // console.log('设备操作结果', res); // modalTitle.value = ''; // modalIsShow.value = false; // }).catch((err) => { // }); // mainWindIsShow1.value = 'open'; // mainWindIsShow2.value = 'stop'; // } else if (mainWindIsShow1.value === 'stop' && mainWindIsShow2.value === 'stop') { // // playSmoke(handType, '', frequency, 'stop'); // } } else if (handType === 'changeFan') { data.paramcode = 'CtrlFanStart'; deviceControlApi(data) .then((res) => { if (res.success) { if (globalConfig.History_Type == 'remote') { message.success('指令已下发至生产管控平台成功!'); } else { message.success('指令已下发成功!'); } } else { message.error(res.message); } modalTitle.value = ''; modalIsShow.value = false; }) .catch((err) => {}); } else if (handType === 'fan1ToFan2') { data.paramcode = 'CtrlFan1ToFan2'; deviceControlApi(data).then((res) => { if (res.success) { if (globalConfig.History_Type == 'remote') { message.success('指令已下发至生产管控平台成功!'); } else { message.success('指令已下发成功!'); } modalTitle.value = ''; modalIsShow.value = false; } else { message.error(res.message); } }); } else if (handType === 'fan2ToFan1') { data.paramcode = 'CtrlFan2ToFan1'; deviceControlApi(data).then((res) => { if (res.success) { if (globalConfig.History_Type == 'remote') { message.success('指令已下发至生产管控平台成功!'); } else { message.success('指令已下发成功!'); } modalTitle.value = ''; modalIsShow.value = false; } else { message.error(res.message); } }); } else if (handType === 'gasAlarmSet') { if (passWord.value != '123456') { message.error('密码错误,请重新输入!'); return; } if (gasWarningVal.value) { modalTitle.value = ''; modalIsShow.value = false; setTimeout(() => { passWord.value = ''; modalIsShow.value = true; controlType.value = 'toGkjc'; modalTitle.value = '工况决策辅助'; }, 500); } else { message.error('请核对瓦斯超限浓度值!'); } } else if (handType === 'toGkjc') { if (passWord.value != '123456') { message.error('密码错误,请重新输入!'); return; } //进行工况决策 if (selectData.Fan1StartStatus == '1') { openAssistance(true, { // m3: selectData.m3 || 675.87, m3: 675.87, frequency: 30, // m3: 525.87, //5.0测试数据 // frequency: 35, // frequency: selectData.Fan1fHz || selectData.Fan1FreqHz || selectData.Fan1Loop_Frequency, gasWarningVal: gasWarningVal.value, isCompute: false, }); } else if (selectData.Fan2StartStatus == '1') { openAssistance(true, { // m3: selectData.m3 || 675.87, m3: 675.87, frequency: 30, // frequency: selectData.Fan2fHz || selectData.Fan2FreqHz || selectData.Fan2Loop_Frequency, gasWarningVal: gasWarningVal.value, isCompute: false, }); } else { // openAssistance(true, { m3: 635.04, dataDh: 5748 }); openAssistance(true); } modalTitle.value = ''; modalIsShow.value = false; } else if (handType === 'zhlk' || handType === 'gasOverSet') { if (targetVolume.value) { const params = handType === 'zhlk' ? { auto: 1, fanlocalId: selectData.deviceID, xufengliang: targetVolume.value } : { auto: 1, fanlocalId: selectData.deviceID, gasMax: gasWarningVal.value }; autoAdjust(params).then(() => { if (res.success) { if (globalConfig.History_Type == 'remote') { message.success('指令已下发至生产管控平台成功!'); } else { message.success('指令已下发成功!'); } modalTitle.value = ''; modalIsShow.value = false; } else { message.error(res.message); } }); } } }; } function cancel() { modalTitle.value = ''; modalIsShow.value = false; gasWarningVal.value = 0; } function handleChangeSensor(value: string) { console.log(value); } function addPlayVideo() { if (player1.value && player1.value.play) { if (!player1.value.paused()) player1.value.play(); document.body.removeEventListener('mousedown', addPlayVideo); } } onBeforeMount(() => { getDeviceBaseList(); }); onMounted(async () => { const { query } = unref(currentRoute); if (query['deviceType']) { devicekide.value = query['deviceType'] as string; deviceId.value = query['id'] as string; } mountedThree(player1.value).then(async () => { await getMonitor(true); nextTick(async () => { setModelType('fc'); addCssText(); }); }); await getCamera(deviceId.value, playerRef.value); document.body.addEventListener('mousedown', addPlayVideo, false); }); onUnmounted(() => { destroy(); removeCamera(); if (timer) { clearTimeout(timer); timer = undefined; } }); </script> <style scoped lang="less"> @import '/@/design/theme.less'; @import '/@/design/vent/modal.less'; :deep(.@{ventSpace}-tabs-tabpane-active) { height: 100%; } :deep(.zxm-tabs-content) { height: 100%; } @{theme-deepblue} { .scene-box { --image-lr-top-bg: url('/@/assets/images/themify/deepblue/vent/lr-top-bg.png'); --image-lr-tab-bg: url('/@/assets/images/themify/deepblue/vent/lr-tab-bg.png'); --image-l-tab-active: url('/@/assets/images/themify/deepblue/vent/l-tab-active.png'); --image-r-tab-active: url('/@/assets/images/themify/deepblue/vent/r-tab-active.png'); --image-plane-bottom: url('/@/assets/images/themify/deepblue/vent/plane-bottom.png'); --image-plane-icon-bg: url('/@/assets/images/themify/deepblue/vent/plane-icon-bg.png'); --container-group-bg: linear-gradient(to right, #ffffff22, #53576305); } } .scene-box { --image-lr-top-bg: url('/@/assets/images/vent/lr-top-bg.png'); --image-lr-tab-bg: url('/@/assets/images/vent/lr-tab-bg.png'); --image-l-tab-active: url('/@/assets/images/vent/l-tab-active.png'); --image-r-tab-active: url('/@/assets/images/vent/r-tab-active.png'); --image-plane-bottom: url('/@/assets/images/vent/plane-bottom.png'); --image-plane-icon-bg: url('/@/assets/images/vent/plane-icon-bg.png'); --container-group-bg: linear-gradient(to right, #00deff22, #2081ff05); .title-text { height: 32px; } } .data-show-box { position: relative; display: flex; flex-direction: row; justify-content: space-between; padding: 10px 5px; color: var(--vent-font-color); z-index: 999; top: 60px; .data-item { pointer-events: auto; .item-header { width: 374px; background: var(--image-lr-top-bg) no-repeat; background-size: auto; height: 32px; text-align: center; line-height: 34px; font-size: 15px; font-weight: 600; color: #fafafa; } .item-container { width: 346px; margin: 0 14px; padding: 10px; background: #00377c33; backdrop-filter: blur(2px); .tab { width: 323px; background: var(--image-lr-tab-bg) no-repeat; display: flex; .tab-item { flex: 1; text-align: center; padding-top: 2px; color: #ffffff99; cursor: pointer; } .tab-item-active-l { color: var(--vent-font-action-link); background-image: var(--image-l-tab-active); background-repeat: no-repeat; background-size: auto; background-position: 6px 3px; } .tab-item-active-r { color: var(--vent-font-action-link); background-image: var(--image-r-tab-active); background-repeat: no-repeat; background-position: 0 3px; } } .container-group { width: 314px; margin: 0px 4px; padding: 10px 0; min-height: 432px; background: var(--container-group-bg); max-height: 440px; overflow-y: auto; } .container-item { width: 100%; height: 60px; display: flex; padding: 10px 0 0 20px; margin-bottom: 5px; position: relative; background: var(--image-plane-bottom) no-repeat; background-size: auto; background-position: bottom; &::before { content: ''; display: block; width: 100%; height: 5px; position: absolute; top: 62px; left: 0; background-color: #73f4ff66; backdrop-filter: blur(5px); } .item-icon { width: 54px; height: 45px; background: var(--image-plane-icon-bg) no-repeat; background-size: cover; .icon-style { font-size: 18px; margin: 10px 0 0 20px; color: #ffc800; } } .item-name { width: 180px; line-height: 60px; } .item-value { position: relative; height: 26px; line-height: 24px; margin: 15px 0; text-align: center; width: 80px; border: 1px solid var(--vent-base-border); border-radius: 13px; background: linear-gradient(to right, #00f5fe44, #0090ff44); &::before { width: 6px; height: 6px; content: ''; position: absolute; left: -3px; top: 8px; background: #ffa500; border-radius: 3px; } } } .warning-header { display: flex; font-size: 14px; .header-item { flex: 1; display: flex; justify-content: center; align-items: center; .header-title { color: var(--vent-font-color); margin-top: 10px; } .header-value { // width: 133px; height: 36px; font-weight: 600; font-family: 'douyuFont'; font-size: 16px; color: #ffa500; display: flex; justify-content: center; align-items: center; margin-top: 15px; margin-left: 8px; } } } .warning-group { padding: 0 10px; position: relative; .warning-item { display: flex; flex-direction: row; justify-content: space-between; align-items: center; height: 38px; .item-name { display: flex; align-items: center; // padding-left: 5px; .icon { width: 6px; height: 6px; display: inline-block; background-color: var(--vent-base-light-bg); border-radius: 3px; position: relative; margin-right: 8px; &::before { content: ''; width: 10px; height: 10px; display: block; border: 1px solid #34edff99; border-radius: 5px; position: absolute; top: -2px; left: -2px; } } &::before { content: ''; display: block; width: 1px; height: 38px; position: absolute; left: 12px; background-color: var(--vent-base-light-bg); } } } } .warning-group-r { &::before { content: ''; display: block; width: 1px; height: 100%; position: absolute; left: 12px; background-color: var(--vent-base-light-bg); } } } } } .input-box { display: flex; align-items: center; .input-title { color: #73e8fe; width: auto; } margin-right: 10px; } .label { max-width: 220px; } #fanLocalSelectDom { :deep(.@{ventSpace}-select-dropdown) { left: 0px !important; top: 35px !important; } } .@{ventSpace}-input { width: 150px; } :deep(#LivePlayerBox) { display: flex; flex-direction: row; justify-content: flex-end; padding-right: 380px; pointer-events: none; .video-parent { height: 208px; pointer-events: auto !important; } } .to-right { :deep(#LivePlayerBox) { padding-right: 0px; } } :deep(.button-box) { position: relative; padding: 5px; // border: 1px transparent solid; border-radius: 5px; margin-left: 8px; margin-right: 8px; width: auto; // height: 40px; // border: 1px solid #65dbea; height: 35px !important; display: flex; align-items: center; justify-content: center; color: var(--vent-font-color); padding: 0 15px 5px 15px; cursor: pointer; &:hover { background: var(--vent-device-manager-control-btn-hover); } &::before { width: calc(100% - 6px); height: 27px; content: ''; position: absolute; top: 3px; right: 0; left: 3px; bottom: 0; z-index: -1; border-radius: inherit; /*important*/ background: var(--vent-device-manager-control-btn); } &::after { width: calc(100% + 32px); height: 10px; content: ''; position: absolute; top: 28px; right: 0; left: -16px; bottom: 0; z-index: -1; border-radius: inherit; /*important*/ background-position: center; background-size: 100%; z-index: 999; } } </style>