2004 lines
69 KiB
Vue
2004 lines
69 KiB
Vue
<template>
|
||
<div class="windBlower" ref="windBlower">
|
||
<el-row>
|
||
<el-col :md="24" :lg="6">
|
||
<div class="cardContentLeft">
|
||
<!--实时预览-->
|
||
<div class="overview">
|
||
<div class="cardLabel">
|
||
{{ '名称:' + route.query.name + ' ' + '型号:' + route.query.model }}
|
||
</div>
|
||
<div class="overviewDataSection" ref="listContainer">
|
||
<div class="overviewDataSectionItem">
|
||
<span class="realLeft">机组运行状态:</span>
|
||
<span class="reafRight">{{ realTimeDataState }}</span>
|
||
</div>
|
||
<div class="overviewDataSectionItem">
|
||
<span class="realLeft">风速:</span>
|
||
<span class="reafRight">{{ overviewData.iwindspeed }}</span>
|
||
</div>
|
||
<div class="overviewDataSectionItem">
|
||
<span class="realLeft">风向:</span>
|
||
<span class="reafRight">{{ overviewData.iwinddirection }}</span>
|
||
</div>
|
||
<div class="overviewDataSectionItem">
|
||
<span class="realLeft">发电机转速:</span>
|
||
<span class="reafRight">{{ overviewData.igenspeed }}</span>
|
||
</div>
|
||
<div class="overviewDataSectionItem">
|
||
<span class="realLeft">有功功率:</span>
|
||
<span class="reafRight">{{ overviewData.igenpower }}</span>
|
||
</div>
|
||
<div class="overviewDataSectionItem">
|
||
<span class="realLeft">给定有功功率:</span>
|
||
<span class="reafRight">{{ overviewData.iactivepowersetpointvalue }}</span>
|
||
</div>
|
||
<div class="overviewDataSectionItem">
|
||
<span class="realLeft">无功功率:</span>
|
||
<span class="reafRight">{{ overviewData.ireactivepower }}</span>
|
||
</div>
|
||
<div class="overviewDataSectionItem">
|
||
<span class="realLeft">给定无功功率:</span>
|
||
<span class="reafRight">{{ overviewData.ireactivepowersetpointvalue }}</span>
|
||
</div>
|
||
<div class="overviewDataSectionItem">
|
||
<span class="realLeft">限电原因:</span>
|
||
<span class="reafRight">{{ overviewData.powerlimitsource }}</span>
|
||
</div>
|
||
<div class="overviewDataSectionItem">
|
||
<span class="realLeft">机舱位置:</span>
|
||
<span class="reafRight">{{ overviewData.ivanedirection }}</span>
|
||
</div>
|
||
<div class="overviewDataSectionItem">
|
||
<span class="realLeft">日发电量:</span>
|
||
<span class="reafRight">{{ overviewData.ikwhthisday }}</span>
|
||
</div>
|
||
</div>
|
||
<div class="overviewDataBtn">
|
||
<el-icon color="#0064AA" @click="() => (overviewSlotData.visible = true)"><DArrowRight /></el-icon>
|
||
</div>
|
||
</div>
|
||
|
||
<!--温度-->
|
||
<div class="temperatureList">
|
||
<div class="chartPart-item" @click="openTemperature">
|
||
<div class="chartParm" ref="temperatureChartRef1"></div>
|
||
</div>
|
||
<div class="chartPart-item" @click="openTemperature">
|
||
<div class="chartParm" ref="temperatureChartRef2"></div>
|
||
</div>
|
||
<div class="chartPart-item" @click="openTemperature">
|
||
<div class="chartParm" ref="temperatureChartRef3"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-col>
|
||
|
||
<el-col :md="24" :lg="12">
|
||
<div class="cardContentCenter">
|
||
<!--风机控制-->
|
||
<div class="controlBackgroundImg" ref="backgroundImgRef">
|
||
<div class="switchWindBlower">
|
||
<el-tooltip :content="beforeAirBlower.name">
|
||
<el-icon color="#fff" size="30" @click="switchAirblower(0)"><ArrowLeftBold /></el-icon>
|
||
</el-tooltip>
|
||
<el-tooltip :content="afterAirBlower.name">
|
||
<el-icon color="#fff" size="30" @click="switchAirblower(1)"><ArrowRightBold /></el-icon>
|
||
</el-tooltip>
|
||
</div>
|
||
<div class="control-type">
|
||
<el-tag v-if="realTimeData.locked === 1" class="control-tag control-tag-left" type="primary">已锁定</el-tag>
|
||
<el-tag class="control-tag" type="primary">{{ realTimeDataState }}</el-tag>
|
||
</div>
|
||
<div class="btnLeft">
|
||
<el-button
|
||
@click="sendCommand('setTurbineFastStart')"
|
||
v-if="realTimeData.processedoperationmode !== 16"
|
||
class="control-btn"
|
||
type="primary"
|
||
>启动</el-button
|
||
>
|
||
<el-button @click="sendCommand('setTurbineStop')" v-else class="control-btn" type="primary">停机</el-button>
|
||
<el-button @click="sendCommand('setTurbineResetStatusCode')" class="control-btn" type="primary">复位</el-button>
|
||
<el-button @click="sendManualCommand(1)" v-if="realTimeData.locked !== 1" class="control-btn" type="primary"
|
||
>锁定</el-button
|
||
>
|
||
<el-button @click="sendManualCommand(0)" v-else class="control-btn" type="primary">解锁</el-button>
|
||
</div>
|
||
<el-tooltip :content="subSystem[0]">
|
||
<div @click="openSubSystem(0)" class="dot index-1"></div>
|
||
</el-tooltip>
|
||
<el-tooltip :content="subSystem[1]">
|
||
<div @click="openSubSystem(1)" class="dot index-2"></div>
|
||
</el-tooltip>
|
||
<el-tooltip :content="subSystem[2]">
|
||
<div @click="openSubSystem(2)" class="dot index-3"></div>
|
||
</el-tooltip>
|
||
<el-tooltip :content="subSystem[3]">
|
||
<div @click="openSubSystem(3)" class="dot index-4"></div>
|
||
</el-tooltip>
|
||
<el-tooltip :content="subSystem[4]">
|
||
<div @click="openSubSystem(4)" class="dot index-5"></div>
|
||
</el-tooltip>
|
||
<el-tooltip :content="subSystem[5]">
|
||
<div @click="openSubSystem(5)" class="dot index-6"></div>
|
||
</el-tooltip>
|
||
<el-tooltip :content="subSystem[6]">
|
||
<div @click="openSubSystem(6)" class="dot index-7"></div>
|
||
</el-tooltip>
|
||
<el-tooltip :content="subSystem[7]">
|
||
<div @click="openSubSystem(7)" class="dot index-8"></div>
|
||
</el-tooltip>
|
||
<el-tooltip :content="subSystem[8]">
|
||
<div @click="openSubSystem(8)" class="dot index-9"></div>
|
||
</el-tooltip>
|
||
<el-tooltip :content="subSystem[9]">
|
||
<div @click="openSubSystem(9)" class="dot index-10"></div>
|
||
</el-tooltip>
|
||
<el-tooltip :content="subSystem[10]">
|
||
<div @click="openSubSystem(10)" class="dot index-11"></div>
|
||
</el-tooltip>
|
||
<el-tooltip :content="subSystem[11]">
|
||
<div @click="openSubSystem(11)" class="dot index-12"></div>
|
||
</el-tooltip>
|
||
</div>
|
||
<!-- 功率趋势 -->
|
||
<div class="chartPart">
|
||
<div class="power">
|
||
<div class="chartBox">
|
||
<div class="power-chart" ref="powerChartRef"></div>
|
||
</div>
|
||
</div>
|
||
<div class="chartPart-item item_bar">
|
||
<div class="frequencyChart" ref="frequencyChartRef"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-col>
|
||
<el-col :md="24" :lg="6" style="background: #f5f5f5">
|
||
<div class="cardContentRight">
|
||
<!--发电量概况-->
|
||
<div class="summarize">
|
||
<div class="cardLabel">发电量概况</div>
|
||
<div class="summarize-panel-list">
|
||
<div class="summarize-panel-row">
|
||
<div class="summarize-panel">
|
||
<div class="summarize-panel-pic">
|
||
<img src="~assets/dashboard/fdl1.png" alt="" />
|
||
</div>
|
||
<div class="summarize-panel-base">
|
||
<div>
|
||
<span class="content-number">{{ realTimeDataForSingle.ikwhthisday }}</span>
|
||
</div>
|
||
<div>{{ realTimeDataForSingleUnit.ikwhthisday }}</div>
|
||
<div>日发电量</div>
|
||
</div>
|
||
</div>
|
||
<div class="summarize-panel">
|
||
<div class="summarize-panel-pic">
|
||
<img src="~assets/dashboard/fdl2.png" alt="" />
|
||
</div>
|
||
<div class="summarize-panel-base">
|
||
<div>
|
||
<span class="content-number">{{ realTimeDataForSingle.monthprodenergy }}</span>
|
||
</div>
|
||
<div>{{ realTimeDataForSingleUnit.monthprodenergy }}</div>
|
||
<div>月发电量</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="summarize-panel-row">
|
||
<div class="summarize-panel">
|
||
<div class="summarize-panel-pic">
|
||
<img src="~assets/dashboard/fdl3.png" alt="" />
|
||
</div>
|
||
<div class="summarize-panel-base">
|
||
<div>
|
||
<span class="content-number">{{ realTimeDataForSingle.yearprodenergy }}</span>
|
||
</div>
|
||
<div>{{ realTimeDataForSingleUnit.yearprodenergy }}</div>
|
||
<div>年发电量</div>
|
||
</div>
|
||
</div>
|
||
<div class="summarize-panel">
|
||
<div class="summarize-panel-pic">
|
||
<img src="~assets/dashboard/fdl4.png" alt="" />
|
||
</div>
|
||
<div class="summarize-panel-base">
|
||
<div>
|
||
<span class="content-number">{{ realTimeDataForSingle.ikwhoverall }}</span>
|
||
</div>
|
||
<div>{{ realTimeDataForSingleUnit.ikwhoverall }}</div>
|
||
<div>总发电量</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!--实时告警-->
|
||
<div class="alarm" style="margin-bottom: 0">
|
||
<div class="cardLabel">实时告警</div>
|
||
<el-table
|
||
:data="tableData"
|
||
class="tablePart"
|
||
height="calc(100% - 18px)"
|
||
ref="myTable"
|
||
@mouseover.native="clearScroll"
|
||
@mouseleave.native="createScroll"
|
||
>
|
||
<el-table-column fixed prop="time" label="时间" />
|
||
<el-table-column prop="alertcontent" label="告警信息" />
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
<el-dialog v-model="visible" :title="subSystemName" width="1020" :before-close="handleClose">
|
||
<div class="dialogContent">
|
||
<el-scrollbar>
|
||
<div class="PitchPart">
|
||
<!-- <el-row > -->
|
||
<!-- <el-col :span="12"> -->
|
||
<div class="Pitchitem" v-for="item in subSystemDataList" :key="item.name">
|
||
<span class="PitchitemLeft">{{ item.name }}</span>
|
||
<span class="PitchitemRight">{{ item.value }}</span>
|
||
</div>
|
||
<!-- </el-col> -->
|
||
<!-- </el-row> -->
|
||
</div>
|
||
</el-scrollbar>
|
||
</div>
|
||
</el-dialog>
|
||
<el-dialog v-model="overviewSlotData.visible" title="实时预览">
|
||
<template #header>
|
||
<div class="overviewSlot">
|
||
<span style="font-size: 20px">实时预览</span>
|
||
<div class="radioForOverviewType">
|
||
<el-radio-group v-model="overviewSlotData.type">
|
||
<el-radio value="138">模拟量</el-radio>
|
||
<el-radio value="199">计算量</el-radio>
|
||
<el-radio value="140">状态量</el-radio>
|
||
</el-radio-group>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<Overview v-bind="overviewSlotData"></Overview>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { nextTick, onActivated, onMounted, reactive, ref, computed, watch, onBeforeMount, onUnmounted, VNode, VNodeRef } from 'vue'
|
||
import * as echarts from 'echarts'
|
||
import { useEventListener } from '@vueuse/core'
|
||
import { useI18n } from 'vue-i18n'
|
||
import { DArrowRight, ArrowLeftBold, ArrowRightBold } from '@element-plus/icons-vue'
|
||
import { getRealValueListReq, getRealValueRangeReq } from '/@/api/backend/deviceModel/request'
|
||
import { getModelAttributeListReq } from '/@/api/backend/deviceModel/request'
|
||
import { getAirBlowerListReq } from '/@/api/backend/airBlower/request'
|
||
import { useRoute, useRouter } from 'vue-router'
|
||
import Overview from './overview.vue'
|
||
import { TableInstance } from 'element-plus'
|
||
import { dayjs, ElMessage, ElMessageBox } from 'element-plus'
|
||
import { getRealTimeState, getCutDecimalsValue, malFunctionKeys } from '/@/views/backend/equipment/airBlower/utils'
|
||
import { sendCommandReq, sendManualCommandReq } from '/@/api/backend/control/request'
|
||
import { getAlarmListReq } from '/@/api/backend/alarms/request'
|
||
import { queryfaultCodeDict } from '/@/api/backend/theoreticalpowerCurve/request'
|
||
import { useEnumStore } from '/@/stores/enums'
|
||
import { adminBaseRoutePath } from '/@/router/static/adminBase'
|
||
|
||
const enumStore = useEnumStore()
|
||
|
||
const route = useRoute()
|
||
const router = useRouter()
|
||
const { t } = useI18n()
|
||
|
||
const windBlower = ref()
|
||
const backgroundImgRef = ref()
|
||
const computedHeight = reactive({
|
||
powerHeight: '305px',
|
||
centerHeight: '1100px',
|
||
alarmHeight: '360px',
|
||
backgroundImgHeight: '435px',
|
||
})
|
||
const sizeChange = () => {
|
||
// const rect = windBlower.value?.getBoundingClientRect()
|
||
// if (!rect) return
|
||
// computedHeight.powerHeight = rect.height - 626 + 'px'
|
||
// computedHeight.alarmHeight = rect.height - 570 + 'px'
|
||
// computedHeight.centerHeight = rect.height - 20 + 'px'
|
||
const bgiRect = backgroundImgRef.value?.getBoundingClientRect()
|
||
console.log(bgiRect)
|
||
|
||
if (!bgiRect) return
|
||
computedHeight.backgroundImgHeight = bgiRect.height + 'px'
|
||
console.log(computedHeight.backgroundImgHeight)
|
||
}
|
||
|
||
let timer: any = null
|
||
let myTable = ref<TableInstance>()
|
||
|
||
const overviewData = reactive({
|
||
// processedoperationmode: '-',
|
||
iwindspeed: '-',
|
||
iwinddirection: '-',
|
||
igenspeed: '-',
|
||
igenpower: '-',
|
||
iactivepowersetpointvalue: '-',
|
||
ireactivepower: '-',
|
||
ireactivepowersetpointvalue: '-',
|
||
powerlimitsource: '-',
|
||
ivanedirection: '-',
|
||
ikwhthisday: '-',
|
||
})
|
||
|
||
const realTimeDataForSingle = ref<any>({
|
||
ikwhthisday: '-',
|
||
ikwhoverall: '-',
|
||
igenpower: '-',
|
||
igenspeed: '-',
|
||
ipitchangle: '',
|
||
iwindspeed: '-',
|
||
iwinddirection: '-',
|
||
monthprodenergy: '-',
|
||
yearprodenergy: '-',
|
||
})
|
||
const realTimeDataForSingleUnit = reactive({
|
||
ikwhthisday: 'kWh',
|
||
ikwhoverall: 'kWh',
|
||
igenpower: 'kW',
|
||
igenspeed: 'rpm',
|
||
ipitchangle: '°',
|
||
iwindspeed: 'm/s',
|
||
iwinddirection: '°',
|
||
monthprodenergy: 'kWh',
|
||
yearprodenergy: 'kWh',
|
||
})
|
||
|
||
const state: {
|
||
charts: { powerChart: any; temperatureChart1: any; temperatureChart2: any; temperatureChart3: any; frequencyChart: any }
|
||
remark: string
|
||
workingTimeFormat: string
|
||
pauseWork: boolean
|
||
} = reactive({
|
||
charts: {
|
||
powerChart: null,
|
||
temperatureChart1: null,
|
||
temperatureChart2: null,
|
||
temperatureChart3: null,
|
||
frequencyChart: null,
|
||
// trendChart: null,
|
||
},
|
||
remark: 'dashboard.Loading',
|
||
workingTimeFormat: '',
|
||
pauseWork: false,
|
||
})
|
||
|
||
const powerChartRef = ref<VNodeRef>()
|
||
const powerChartData: { time: any; values: any } = {
|
||
time: {},
|
||
values: {},
|
||
}
|
||
const initpowerChart = () => {
|
||
const powerChart = state.charts.powerChart ?? echarts.init(powerChartRef.value as unknown as HTMLElement)
|
||
|
||
const option = {
|
||
title: {
|
||
show: true,
|
||
text: '功率趋势',
|
||
textStyle: {
|
||
color: '#4E5969',
|
||
fontSize: 14,
|
||
fontFamily: 'PingFangSC-Semibold',
|
||
},
|
||
padding: 10,
|
||
},
|
||
grid: {
|
||
top: 70,
|
||
right: 23,
|
||
bottom: 10,
|
||
left: 18,
|
||
containLabel: true,
|
||
},
|
||
tooltip: {
|
||
trigger: 'axis',
|
||
axisPointer: {
|
||
type: 'line',
|
||
},
|
||
show: true,
|
||
},
|
||
xAxis: {
|
||
type: 'category',
|
||
axisLine: {
|
||
show: true,
|
||
lineStyle: {
|
||
color: '#dadada',
|
||
width: 1,
|
||
type: 'solid',
|
||
},
|
||
},
|
||
axisLabel: {
|
||
//x轴文字的配置
|
||
show: true,
|
||
color: '#4E5969',
|
||
interval: 'auto',
|
||
//rotate: 45
|
||
},
|
||
splitLine: {
|
||
//分割线配置
|
||
show: false,
|
||
lineStyle: {
|
||
color: '#999999',
|
||
},
|
||
},
|
||
data: powerChartData.time.iTheoreticalPower,
|
||
},
|
||
yAxis: [
|
||
{
|
||
type: 'value',
|
||
name: '功率MW',
|
||
nameTextStyle: {
|
||
color: '#4E5969',
|
||
},
|
||
axisLine: {
|
||
show: false,
|
||
lineStyle: {
|
||
color: '#dadada',
|
||
width: 0,
|
||
type: 'solid',
|
||
},
|
||
},
|
||
axisLabel: {
|
||
//x轴文字的配置
|
||
show: true,
|
||
color: '#4E5969',
|
||
},
|
||
axisTick: { show: false },
|
||
splitLine: {
|
||
interval: 50,
|
||
lineStyle: {
|
||
type: 'dashed',
|
||
color: '#dadada',
|
||
},
|
||
},
|
||
},
|
||
{
|
||
type: 'value',
|
||
name: '风速m/s',
|
||
nameTextStyle: {
|
||
color: '#4E5969',
|
||
},
|
||
axisLine: {
|
||
show: false,
|
||
lineStyle: {
|
||
color: '#dadada',
|
||
width: 0,
|
||
type: 'solid',
|
||
},
|
||
},
|
||
axisLabel: {
|
||
//x轴文字的配置
|
||
show: true,
|
||
color: '#4E5969',
|
||
},
|
||
axisTick: { show: false },
|
||
splitLine: {
|
||
interval: 50,
|
||
lineStyle: {
|
||
type: 'dashed',
|
||
color: '#dadada',
|
||
},
|
||
},
|
||
},
|
||
],
|
||
legend: {
|
||
data: ['有功功率', '理论有功功率', '风速'],
|
||
textStyle: {
|
||
color: '#73767a',
|
||
},
|
||
top: 20,
|
||
},
|
||
series: [
|
||
{
|
||
name: '有功功率',
|
||
type: 'line',
|
||
barWidth: 20,
|
||
itemStyle: {
|
||
color: '#00A7EB',
|
||
barBorderRadius: 2,
|
||
},
|
||
smooth: 0.6,
|
||
symbol: 'none',
|
||
data: powerChartData.values?.iGenPower ?? [],
|
||
},
|
||
{
|
||
name: '理论有功功率',
|
||
type: 'line',
|
||
barWidth: 20,
|
||
itemStyle: {
|
||
color: '#62bd25',
|
||
barBorderRadius: 2,
|
||
},
|
||
smooth: 0.6,
|
||
symbol: 'none',
|
||
data: powerChartData.values?.iTheoreticalPower ?? [],
|
||
},
|
||
{
|
||
name: '风速',
|
||
type: 'line',
|
||
yAxisIndex: 1,
|
||
itemStyle: {
|
||
color: '#FF7E00',
|
||
barBorderRadius: 2,
|
||
},
|
||
smooth: 0.6,
|
||
symbol: 'none',
|
||
/*areaStyle: {
|
||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||
{
|
||
offset: 0,
|
||
color: 'rgba(255,126,0,0.8)'
|
||
}
|
||
])
|
||
},*/
|
||
data: powerChartData.values?.iWindSpeed ?? [],
|
||
},
|
||
],
|
||
}
|
||
powerChart.setOption(option)
|
||
state.charts.powerChart = powerChart
|
||
}
|
||
|
||
// const TrendDataForDay: {
|
||
// currentPeriod: {
|
||
// time: string[]
|
||
// value: number[]
|
||
// }
|
||
// samePeriod: {
|
||
// time: string[]
|
||
// value: number[]
|
||
// }
|
||
// } = {
|
||
// currentPeriod: {
|
||
// time: [],
|
||
// value: [],
|
||
// },
|
||
// samePeriod: {
|
||
// time: [],
|
||
// value: [],
|
||
// },
|
||
// }
|
||
|
||
// const TrendDataForMonth = [
|
||
// {
|
||
// currentPeriod: 26.3,
|
||
// samePeriod: 53.5,
|
||
// generationTime: '2024-10-01',
|
||
// },
|
||
// {
|
||
// currentPeriod: 36.3,
|
||
// samePeriod: 53.5,
|
||
// generationTime: '2024-10-02',
|
||
// },
|
||
// {
|
||
// currentPeriod: 46.3,
|
||
// samePeriod: 53.5,
|
||
// generationTime: '2024-10-03',
|
||
// },
|
||
// ]
|
||
|
||
// const trendChartRef = ref<VNodeRef>()
|
||
// const trendChartType = ref<'day' | 'month'>('day')
|
||
// const tabhandleClick = () => {
|
||
// state.charts.trendChart.clear()
|
||
// nextTick(() => {
|
||
// initTrendChart(trendChartType.value)
|
||
// })
|
||
// }
|
||
|
||
// const initTrendChart = (type: 'day' | 'month') => {
|
||
// const currentPeriod: number[] = type === 'day' ? TrendDataForDay.currentPeriod.value : TrendDataForMonth.map((item) => item.currentPeriod)
|
||
// const samePeriod: number[] = type === 'day' ? TrendDataForDay.samePeriod.value : TrendDataForMonth.map((item) => item.samePeriod)
|
||
// const xAxisdata: string[] = type === 'day' ? TrendDataForDay.currentPeriod.time : TrendDataForMonth.map((item) => item.generationTime)
|
||
// const trendChart = state.charts?.trendChart ?? echarts.init(trendChartRef.value as unknown as HTMLElement)
|
||
// const legend = type === 'day' ? ['当天', '环比'] : ['本月', '环比']
|
||
|
||
// const option = {
|
||
// grid: {
|
||
// top: 30,
|
||
// right: 10,
|
||
// bottom: 20,
|
||
// left: 70,
|
||
// borderColor: '#dadada',
|
||
// },
|
||
// tooltip: {
|
||
// trigger: 'axis',
|
||
// axisPointer: {
|
||
// type: 'shadow',
|
||
// },
|
||
// },
|
||
// xAxis: {
|
||
// type: 'category',
|
||
// axisLine: {
|
||
// show: true,
|
||
// lineStyle: {
|
||
// color: '#dadada',
|
||
// width: 1,
|
||
// type: 'solid',
|
||
// },
|
||
// },
|
||
// axisLabel: {
|
||
// //x轴文字的配置
|
||
// show: true,
|
||
// color: '#4E5969',
|
||
// },
|
||
// splitLine: {
|
||
// //分割线配置
|
||
// show: false,
|
||
// lineStyle: {
|
||
// color: '#999999',
|
||
// },
|
||
// },
|
||
// data: xAxisdata,
|
||
// },
|
||
// yAxis: [
|
||
// {
|
||
// type: 'value',
|
||
// name: 'kWh',
|
||
// nameTextStyle: {
|
||
// color: '#4E5969',
|
||
// },
|
||
// axisLine: {
|
||
// show: false,
|
||
// lineStyle: {
|
||
// color: '#dadada',
|
||
// width: 0,
|
||
// type: 'solid',
|
||
// },
|
||
// },
|
||
// axisLabel: {
|
||
// //x轴文字的配置
|
||
// show: true,
|
||
// color: '#4E5969',
|
||
// },
|
||
// axisTick: { show: false },
|
||
// splitLine: {
|
||
// interval: 50,
|
||
// lineStyle: {
|
||
// type: 'dashed',
|
||
// color: '#dadada',
|
||
// },
|
||
// },
|
||
// },
|
||
// ],
|
||
// legend: {
|
||
// data: legend,
|
||
// textStyle: {
|
||
// color: '#73767a',
|
||
// },
|
||
// },
|
||
// series: [
|
||
// {
|
||
// name: legend[0],
|
||
// data: currentPeriod,
|
||
// type: 'bar',
|
||
// smooth: true,
|
||
// itemStyle: {
|
||
// color: '#0277B3',
|
||
// },
|
||
// },
|
||
// {
|
||
// name: legend[1],
|
||
// data: samePeriod,
|
||
// type: 'bar',
|
||
// smooth: true,
|
||
// itemStyle: {
|
||
// color: '#00A096',
|
||
// },
|
||
// },
|
||
// ],
|
||
// }
|
||
// trendChart.setOption(option)
|
||
// state.charts.trendChart = trendChart
|
||
// }
|
||
const temperatureChartsData: { name: string; value: string | number }[] = [
|
||
{
|
||
name: '环境温度(°C)',
|
||
value: 0,
|
||
},
|
||
{
|
||
name: '舱内温度(°C)',
|
||
value: 0,
|
||
},
|
||
{
|
||
name: '塔基柜温度(°C)',
|
||
value: 0,
|
||
},
|
||
]
|
||
const temperatureChartRef1 = ref<VNodeRef>()
|
||
const temperatureChartRef2 = ref<VNodeRef>()
|
||
const temperatureChartRef3 = ref<VNodeRef>()
|
||
const initTemperatureChart = () => {
|
||
const temperatureChart1 = state.charts.temperatureChart1 ?? echarts.init(temperatureChartRef1.value as unknown as HTMLElement)
|
||
const temperatureChart2 = state.charts.temperatureChart2 ?? echarts.init(temperatureChartRef2.value as unknown as HTMLElement)
|
||
const temperatureChart3 = state.charts.temperatureChart3 ?? echarts.init(temperatureChartRef3.value as unknown as HTMLElement)
|
||
const options = []
|
||
for (let i = 0; i < temperatureChartsData.length; i++) {
|
||
const option = {
|
||
grid: {
|
||
top: 30,
|
||
right: 5,
|
||
bottom: 0,
|
||
left: -100,
|
||
containLabel: true,
|
||
},
|
||
xAxis: {
|
||
// type: 'category',
|
||
type: 'value',
|
||
|
||
show: false,
|
||
},
|
||
yAxis: {
|
||
// type: 'value',
|
||
type: 'category',
|
||
|
||
show: false,
|
||
},
|
||
series: [
|
||
{
|
||
name: temperatureChartsData[i].name,
|
||
data: [temperatureChartsData[i].value],
|
||
type: 'bar',
|
||
label: {
|
||
show: true,
|
||
align: 'left',
|
||
// verticalAlign:'top',
|
||
formatter: `{b|{a}} {a|{c}}`,
|
||
rich: {
|
||
a: {
|
||
color: '#333333',
|
||
fontSize: 22,
|
||
},
|
||
b: {
|
||
color: '#4E5969',
|
||
fontSize: 14,
|
||
},
|
||
},
|
||
width: 100,
|
||
height: 22,
|
||
position: 'insideLeft',
|
||
offset: [85, -22],
|
||
},
|
||
itemStyle: {
|
||
color: '#048bd2',
|
||
borderRadius: [0, 4, 4, 0],
|
||
},
|
||
barWidth: 20,
|
||
},
|
||
{
|
||
show: true,
|
||
type: 'bar',
|
||
barGap: '-100%',
|
||
barWidth: 20, // 统计条宽度
|
||
itemStyle: {
|
||
normal: {
|
||
color: '#048bd2',
|
||
opacity: 0.2,
|
||
borderRadius: 4,
|
||
},
|
||
},
|
||
z: 1,
|
||
data: [100],
|
||
},
|
||
],
|
||
aria: {
|
||
enabled: true,
|
||
decal: {
|
||
show: true,
|
||
decals: {
|
||
symbol: 'rect',
|
||
symbolSize: 3,
|
||
dashArrayX: 3,
|
||
rotation: 45,
|
||
color: 'rgba(0, 0, 0, 0.1)',
|
||
},
|
||
},
|
||
},
|
||
}
|
||
options.push(option)
|
||
}
|
||
temperatureChart1.setOption(options[0])
|
||
state.charts.temperatureChart1 = temperatureChart1
|
||
temperatureChart2.setOption(options[1])
|
||
state.charts.temperatureChart2 = temperatureChart2
|
||
temperatureChart3.setOption(options[2])
|
||
state.charts.temperatureChart3 = temperatureChart3
|
||
}
|
||
|
||
var frequencyData: {
|
||
name: string[]
|
||
value: number[]
|
||
} = {
|
||
name: [
|
||
'0~22.5',
|
||
'22.5~45',
|
||
'45~67.5',
|
||
'67.5~90',
|
||
'90~112.5',
|
||
'112.5~135',
|
||
'135~157.5',
|
||
'157.5~180',
|
||
'180~202.5',
|
||
'202.5~225',
|
||
'225~247.5',
|
||
'247.5~270',
|
||
'270~292.5',
|
||
'292.5~315',
|
||
'315~337.5',
|
||
'337.5~360',
|
||
],
|
||
value: [],
|
||
}
|
||
|
||
const frequencyChartRef = ref()
|
||
const initFrequencyChart = () => {
|
||
const frequencyChart = state.charts.frequencyChart ?? echarts.init(frequencyChartRef.value as unknown as HTMLElement)
|
||
// const seriesdata: any = frequencyData.map((item) => item.value)
|
||
|
||
const option = {
|
||
title: [
|
||
{
|
||
text: '风频图',
|
||
textStyle: {
|
||
color: '#4E5969',
|
||
fontSize: 14,
|
||
fontFamily: 'PingFangSC-Semibold',
|
||
},
|
||
padding: 10,
|
||
},
|
||
],
|
||
polar: {
|
||
radius: [0, '70%'],
|
||
},
|
||
radiusAxis: {
|
||
axisLine: {
|
||
show: true,
|
||
lineStyle: {
|
||
color: '#dadada',
|
||
},
|
||
},
|
||
axisLabel: {
|
||
show: true,
|
||
color: 'rgba(0,0,0,0.45)',
|
||
fontSize: 10,
|
||
},
|
||
axisTick: {
|
||
show: true,
|
||
lineStyle: {
|
||
color: '#dadada',
|
||
},
|
||
},
|
||
max: 100,
|
||
},
|
||
angleAxis: {
|
||
min: 0,
|
||
interval: 22.5,
|
||
startAngle: 90,
|
||
type: 'category',
|
||
axisLine: {
|
||
show: true,
|
||
lineStyle: {
|
||
color: '#dadada',
|
||
},
|
||
},
|
||
axisLabel: {
|
||
show: true,
|
||
color: 'rgba(0,0,0,0.45)',
|
||
fontSize: 10,
|
||
boundaryGap: false,
|
||
formatter: function (value: string) {
|
||
const reg = /.*(?=\~)/
|
||
return value.match(reg)![0]
|
||
},
|
||
},
|
||
axisTick: {
|
||
show: false,
|
||
lineStyle: {
|
||
color: '#dadada',
|
||
},
|
||
},
|
||
data: frequencyData.name,
|
||
//startAngle: 75
|
||
},
|
||
tooltip: {},
|
||
series: {
|
||
type: 'bar',
|
||
data: frequencyData.value,
|
||
coordinateSystem: 'polar',
|
||
itemStyle: {
|
||
color: '#0277B3',
|
||
},
|
||
// label: {
|
||
// show: true,
|
||
// position: 'middle',
|
||
// formatter: '{b}: {c}',
|
||
// },
|
||
},
|
||
animation: false,
|
||
}
|
||
frequencyChart.setOption(option)
|
||
state.charts.frequencyChart = frequencyChart
|
||
}
|
||
|
||
const echartsResize = () => {
|
||
nextTick(() => {
|
||
const chartKeys = Object.keys(state.charts) as Array<keyof typeof state.charts>
|
||
chartKeys.forEach((key) => {
|
||
state.charts[key].resize()
|
||
})
|
||
})
|
||
}
|
||
onActivated(() => {
|
||
echartsResize()
|
||
})
|
||
|
||
const tableData = ref<{ time: string; alertcontent: string }[]>([])
|
||
|
||
const clearScroll = () => {
|
||
clearInterval(timer)
|
||
timer = null
|
||
}
|
||
const createScroll = () => {
|
||
clearScroll()
|
||
const table = myTable.value!.layout.table.refs
|
||
const tableWrapper = table.bodyWrapper.firstElementChild!.firstElementChild
|
||
|
||
timer = setInterval(() => {
|
||
tableWrapper!.scrollTop += 1
|
||
if (tableWrapper!.clientHeight + tableWrapper!.scrollTop == tableWrapper!.scrollHeight) {
|
||
tableWrapper!.scrollTop = 0
|
||
}
|
||
}, 30)
|
||
}
|
||
|
||
const realTimeData = ref<any>({
|
||
processedoperationmode: 1111,
|
||
locked: 0,
|
||
})
|
||
|
||
const realTimeDataState = computed(() => {
|
||
switch (realTimeData.value.processedoperationmode) {
|
||
case 20:
|
||
return '并网'
|
||
case 10:
|
||
return '维护'
|
||
case 8:
|
||
return '限功率运行'
|
||
case 0:
|
||
return '离线'
|
||
case 16:
|
||
return '启动'
|
||
case 6:
|
||
return '正常停机'
|
||
case 1:
|
||
return '紧急停机'
|
||
case 2:
|
||
return '停机'
|
||
case 11:
|
||
return '待机'
|
||
case 33:
|
||
return '通讯中断'
|
||
case 1110:
|
||
return '解缆状态'
|
||
case 1111:
|
||
return '电网故障停机'
|
||
case 1112:
|
||
return '安全链停机'
|
||
}
|
||
})
|
||
|
||
const getModelList = () => {
|
||
return new Promise((resolve) => {
|
||
getModelAttributeListReq({ iotModelId: route.query.iotModelId as string }).then((res) => {
|
||
resolve(res.rows)
|
||
})
|
||
})
|
||
}
|
||
|
||
const getRealTimeData = () => {
|
||
return new Promise((resolve) => {
|
||
getRealValueListReq([{ deviceId: route.query.irn as string }]).then((res) => {
|
||
resolve(res.data?.[route.query.irn as string])
|
||
})
|
||
})
|
||
}
|
||
const createRealTimeData = async () => {
|
||
try {
|
||
const modelList: any = await getModelList()
|
||
const realData: any = await getRealTimeData()
|
||
realTimeData.value.processedoperationmode = getRealTimeState(realData)
|
||
realTimeData.value.locked = realData.locked
|
||
|
||
temperatureChartsData[0].value = getCutDecimalsValue(realData.itempoutdoor_1sec)
|
||
temperatureChartsData[1].value = getCutDecimalsValue(realData.itempnacelle_1sec)
|
||
temperatureChartsData[2].value = getCutDecimalsValue(realData.itempcabinettowerbase_1sec)
|
||
|
||
const overviewDatakeys: any = Object.keys(overviewData)
|
||
const sigleDataKeys: any = Object.keys(realTimeDataForSingle.value)
|
||
|
||
const dataFor138And139: { name: string; value: string }[] = []
|
||
const dataFor140: { name: string; value: string }[] = []
|
||
const dataFor199: { name: string; value: string }[] = []
|
||
const realDataForSub: any = subSystem.map(() => ({ type138: [], type140: [], type199: [] }))
|
||
|
||
modelList.forEach((item: any) => {
|
||
const realVal = realData[item.attributeCode.toLowerCase()]
|
||
let val = getCutDecimalsValue(realVal)
|
||
if (enumStore.keys.includes(item.attributeCode)) {
|
||
val = enumStore.data[item.attributeCode][val]
|
||
}
|
||
if (malFunctionKeys.includes(item.attributeCode)) {
|
||
val = malFunctionEnums?.[val] ?? val
|
||
}
|
||
if (sigleDataKeys.includes(item.attributeCode.toLowerCase())) {
|
||
realTimeDataForSingle.value[item.attributeCode.toLowerCase()] = val === '-' ? val : val
|
||
realTimeDataForSingleUnit[item.attributeCode.toLowerCase() as keyof typeof realTimeDataForSingleUnit] = item.unit
|
||
}
|
||
if (overviewDatakeys.includes(item.attributeCode.toLowerCase())) {
|
||
if (enumStore.keys.includes(item.attributeCode)) {
|
||
overviewData[item.attributeCode.toLowerCase() as keyof typeof overviewData] = val as string
|
||
} else {
|
||
overviewData[item.attributeCode.toLowerCase() as keyof typeof overviewData] = val === '-' ? val : val + item.unit
|
||
}
|
||
}
|
||
const showData = {
|
||
name: item.attributeName,
|
||
value: val === '-' ? val : val + (item?.unit ?? ''),
|
||
}
|
||
if (item.attributeType === 138 || item.attributeType === 139) {
|
||
dataFor138And139.push(showData)
|
||
} else if (item.attributeType === 140) {
|
||
dataFor140.push(showData)
|
||
} else if (item.attributeType === 199) {
|
||
dataFor199.push(showData)
|
||
}
|
||
|
||
if (subSystem.includes(item.subSystem)) {
|
||
const index = subSystem.indexOf(item.subSystem)
|
||
if (index >= 0) {
|
||
if (item.attributeType === 138 || item.attributeType === 139) {
|
||
realDataForSub[index].type138.push(showData)
|
||
} else if (item.attributeType === 140) {
|
||
const copyData = {
|
||
name: item.attributeCode + ' ' + item.attributeName,
|
||
value: showData.value,
|
||
}
|
||
realDataForSub[index].type140.push(copyData)
|
||
} else if (item.attributeType === 199) {
|
||
realDataForSub[index].type199.push(showData)
|
||
}
|
||
}
|
||
}
|
||
})
|
||
overviewSlotData.type138 = dataFor138And139
|
||
overviewSlotData.type140 = dataFor140
|
||
overviewSlotData.type199 = dataFor199
|
||
const realDataForSubSystem = realDataForSub.map((item: any) => {
|
||
return [...item.type138, ...item.type140, ...item.type199]
|
||
})
|
||
realTimeForSubSystem.value = realDataForSubSystem
|
||
} catch (err) {
|
||
console.log(err)
|
||
}
|
||
}
|
||
|
||
const subSystemName = ref('')
|
||
|
||
const visible = ref(false)
|
||
const handleClose = (done: () => void) => {
|
||
visible.value = false
|
||
}
|
||
|
||
const realTimeForSubSystem = ref<any>([])
|
||
const curSubSystem = ref(0)
|
||
const subSystemDataList = computed(() => {
|
||
return realTimeForSubSystem.value[curSubSystem.value]
|
||
})
|
||
|
||
const subSystem = ['变桨1', '变桨2', '变桨3', '传动链齿轮箱', '发电机', '机舱', '控制系统', '轮毂', '偏航系统', '气象', '塔基', '箱变']
|
||
|
||
const openSubSystem = (type: number) => {
|
||
subSystemName.value = subSystem[type]
|
||
curSubSystem.value = type
|
||
visible.value = true
|
||
}
|
||
|
||
const overviewSlotData = reactive<{ visible: boolean; type: '138' | '140' | '199'; type138: any[]; type140: any[]; type199: any[] }>({
|
||
visible: false,
|
||
type: '138',
|
||
type138: [],
|
||
type140: [],
|
||
type199: [],
|
||
})
|
||
|
||
let autoUpdateForSecondTimer: any = null
|
||
let autoUpdateTimerForMinuteTimer: any = null
|
||
let autoUpdateTimerForHourTimer: any = null
|
||
const autoUpdate = () => {
|
||
createRealTimeData()
|
||
nextTick(() => {
|
||
initTemperatureChart()
|
||
})
|
||
if (!autoUpdateForSecondTimer) {
|
||
autoUpdateForSecondTimer = setInterval(() => {
|
||
createRealTimeData()
|
||
initTemperatureChart()
|
||
}, 2000)
|
||
}
|
||
if (!autoUpdateTimerForMinuteTimer) {
|
||
autoUpdateTimerForMinuteTimer = setInterval(() => {
|
||
getAllChartData(['power', 'frequency'])
|
||
}, 60000)
|
||
}
|
||
// if (!autoUpdateTimerForHourTimer) {
|
||
// autoUpdateTimerForHourTimer = setInterval(() => {
|
||
// getAllChartData(['trend'])
|
||
// }, 60000 * 30)
|
||
// }
|
||
}
|
||
|
||
const getChartData = <T extends string = any>(params: {
|
||
startTime: number
|
||
endTime: number
|
||
attr: T[]
|
||
interval: string
|
||
}): Promise<{ times: { [K in T]: string[] }; val: { [K in T]: number[] } }> => {
|
||
return new Promise((resolve) => {
|
||
const data = {
|
||
startTime: params.startTime,
|
||
endTime: params.endTime,
|
||
devices: [
|
||
{
|
||
deviceId: route.query.irn as string,
|
||
attributes: params.attr,
|
||
},
|
||
],
|
||
interval: params.interval,
|
||
}
|
||
getRealValueRangeReq(data).then((res) => {
|
||
if (res.success) {
|
||
const data = res.data[route.query.irn as string]
|
||
if (!data) return
|
||
const rangeKeys = Object.keys(data)
|
||
const times: any = {}
|
||
const val: any = {}
|
||
rangeKeys.forEach((key) => {
|
||
times[key] = []
|
||
val[key] = []
|
||
data[key].times.forEach((item: number) => {
|
||
times[key].push(dayjs(item).format('HH:mm'))
|
||
})
|
||
data[key].values.forEach((item: number) => {
|
||
val[key].push(item)
|
||
})
|
||
})
|
||
resolve({ times, val })
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
const getThisDayChartData = () => {
|
||
return new Promise((resolve) => {
|
||
getChartData<'iGenPower' | 'iTheoreticalPower' | 'iWindSpeed'>({
|
||
startTime: new Date(new Date().toLocaleDateString()).getTime(),
|
||
endTime: Date.now(),
|
||
attr: ['iGenPower', 'iTheoreticalPower', 'iWindSpeed'],
|
||
interval: '5m',
|
||
}).then(({ times, val }) => {
|
||
powerChartData.time = { iGenPower: times.iGenPower, iTheoreticalPower: times.iTheoreticalPower, iWindSpeed: times.iWindSpeed }
|
||
powerChartData.values = { iGenPower: val.iGenPower, iTheoreticalPower: val.iTheoreticalPower, iWindSpeed: val.iWindSpeed }
|
||
resolve(true)
|
||
})
|
||
})
|
||
}
|
||
|
||
// const getLastMonthThisDayChartData = () => {
|
||
// return new Promise((resolve) => {
|
||
// const start = dayjs().subtract(1, 'month').startOf('day').valueOf()
|
||
// const end = dayjs().subtract(1, 'month').valueOf()
|
||
// getChartData<'iKWhThisDay'>({
|
||
// startTime: start,
|
||
// endTime: end,
|
||
// attr: ['iKWhThisDay'],
|
||
// interval: '1h',
|
||
// }).then(({ times, val }) => {
|
||
// TrendDataForDay.samePeriod.time = times.iKWhThisDay
|
||
// TrendDataForDay.samePeriod.value = val.iKWhThisDay
|
||
// resolve(true)
|
||
// })
|
||
// })
|
||
// }
|
||
|
||
// const getThisDayChartForHourData = () => {
|
||
// return new Promise((resolve) => {
|
||
// getChartData<'iKWhThisDay'>({
|
||
// startTime: new Date(new Date().toLocaleDateString()).getTime(),
|
||
// endTime: Date.now(),
|
||
// attr: ['iKWhThisDay'],
|
||
// interval: '1h',
|
||
// }).then(({ times, val }) => {
|
||
// TrendDataForDay.currentPeriod.time = times.iKWhThisDay
|
||
// TrendDataForDay.currentPeriod.value = val.iKWhThisDay
|
||
// resolve(true)
|
||
// })
|
||
// })
|
||
// }
|
||
|
||
const getThisDayChartDataForMinute = () => {
|
||
return new Promise((resolve) => {
|
||
getChartData<'iWindDirection'>({
|
||
startTime: new Date(new Date().toLocaleDateString()).getTime(),
|
||
endTime: Date.now(),
|
||
attr: ['iWindDirection'],
|
||
interval: '1m',
|
||
}).then(({ val }) => {
|
||
const len = val.iWindDirection.length
|
||
const result: number[] = new Array(16).fill(0)
|
||
val.iWindDirection.forEach((item: number) => {
|
||
item = item < 0 ? 360 + item : item > 360 ? 360 : item
|
||
const divisor = Math.ceil(item / 22.5) - 1
|
||
result[divisor] += 1
|
||
})
|
||
const percent = result.map((item) => Math.floor((item / len) * 100000) / 1000)
|
||
frequencyData.value = percent
|
||
resolve(true)
|
||
})
|
||
})
|
||
}
|
||
|
||
const getAllChartData = (type: ('power' | 'trend' | 'frequency')[] = ['power', 'trend', 'frequency']) => {
|
||
if (type.includes('power')) {
|
||
getThisDayChartData().then(() => {
|
||
nextTick(() => {
|
||
initpowerChart()
|
||
})
|
||
})
|
||
}
|
||
// if (type.includes('trend')) {
|
||
// const trendDataForLastYear = getLastMonthThisDayChartData()
|
||
// const trendDataForThisDay = getThisDayChartForHourData()
|
||
// Promise.all([trendDataForLastYear, trendDataForThisDay]).then(() => {
|
||
// initTrendChart(trendChartType.value)
|
||
// })
|
||
// }
|
||
if (type.includes('frequency')) {
|
||
getThisDayChartDataForMinute().then((res) => {
|
||
nextTick(() => {
|
||
initFrequencyChart()
|
||
})
|
||
})
|
||
}
|
||
}
|
||
|
||
const sendCommand = (type: 'setTurbineFastStart' | 'setTurbineStop' | 'setTurbineResetStatusCode') => {
|
||
const sendTypeEnum = {
|
||
setTurbineFastStart: '风机快速启动指令',
|
||
setTurbineStop: '风机停机指令',
|
||
setTurbineResetStatusCode: '风机复位故障代码指令',
|
||
}
|
||
ElMessageBox.confirm('确认发送' + sendTypeEnum[type] + '吗?', '', {
|
||
confirmButtonText: '确认',
|
||
cancelButtonText: '取消',
|
||
type: 'warning',
|
||
}).then(() => {
|
||
const serviceName = sendTypeEnum[type]
|
||
const optDesc = serviceName + ',设定值为:1'
|
||
sendCommandReq({
|
||
deviceId: route.query.irn as string,
|
||
serviceCode: type,
|
||
serviceName,
|
||
optDesc,
|
||
opValue: 1,
|
||
}).then((res) => {
|
||
if (res.code == 200) {
|
||
ElMessage.success('指令发送成功')
|
||
} else {
|
||
ElMessage.error('指令发送失败')
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
const sendManualCommand = (type: 1 | 0) => {
|
||
const serviceName = type === 0 ? '风机解锁' : '风机锁定'
|
||
ElMessageBox.confirm('确认' + serviceName + '吗?', '', {
|
||
confirmButtonText: '确认',
|
||
cancelButtonText: '取消',
|
||
type: 'warning',
|
||
}).then(() => {
|
||
sendManualCommandReq({
|
||
deviceId: route.query.irn as string,
|
||
serviceCode: 'Locked',
|
||
serviceName,
|
||
optDesc: serviceName + ',设定值为:' + type,
|
||
opValue: type,
|
||
}).then((res) => {
|
||
if (res.code == 200) {
|
||
ElMessage.success('指令发送成功')
|
||
} else {
|
||
ElMessage.error('指令发送失败')
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
const getAlarmList = () => {
|
||
const start = dayjs().startOf('day').toDate().getTime()
|
||
const end = dayjs().endOf('day').toDate().getTime()
|
||
return getAlarmListReq({
|
||
startTime: start,
|
||
endTime: end,
|
||
deviceCode: [route.query.deviceCode],
|
||
}).then((res) => {
|
||
if (res.rows) {
|
||
tableData.value = res.rows.map((item: any) => {
|
||
return {
|
||
time: dayjs(item.eventTime).format('YYYY-MM-DD HH:mm:ss'),
|
||
alertcontent: item.eventText,
|
||
}
|
||
})
|
||
}
|
||
})
|
||
}
|
||
|
||
let malFunctionEnums: any = {}
|
||
const getMalfunctionEnums = () => {
|
||
const curWindBlower = airBlowerList.value.find((item) => item.irn === route.query.irn)
|
||
queryfaultCodeDict({ madeinfactory: curWindBlower!.madeinfactory, model: curWindBlower!.model }).then((res) => {
|
||
if (res.code == 200) {
|
||
const data: any = {}
|
||
res.data.forEach((item: any) => {
|
||
data[item.code] = item.description
|
||
})
|
||
malFunctionEnums = data
|
||
}
|
||
})
|
||
}
|
||
|
||
const airBlowerList = ref<
|
||
{
|
||
irn: string
|
||
model: string
|
||
name: string
|
||
deviceCode: string
|
||
iotModelId: string
|
||
madeinfactory: string
|
||
}[]
|
||
>([])
|
||
|
||
const getAirBlowerList = () => {
|
||
return getAirBlowerListReq().then((res) => {
|
||
if (res.success) {
|
||
airBlowerList.value = res.data.map((item) => {
|
||
return {
|
||
irn: item.irn,
|
||
model: item.model,
|
||
name: item.name,
|
||
deviceCode: item.deviceCode,
|
||
iotModelId: item.modelId,
|
||
madeinfactory: item.madeinfactory,
|
||
}
|
||
})
|
||
return
|
||
}
|
||
})
|
||
}
|
||
|
||
const beforeAirBlower = computed(() => {
|
||
const len = airBlowerList.value.length
|
||
if (len === 0) return { irn: '', model: '', name: '', deviceCode: '', iotModelId: '' }
|
||
const curIndex = airBlowerList.value.findIndex((item) => item.irn === route.query.irn)
|
||
if (curIndex === 0) return airBlowerList.value[len - 1]
|
||
return airBlowerList.value[curIndex - 1]
|
||
})
|
||
const afterAirBlower = computed(() => {
|
||
const len = airBlowerList.value.length
|
||
if (len === 0) return { irn: '', model: '', name: '', deviceCode: '', iotModelId: '' }
|
||
const curIndex = airBlowerList.value.findIndex((item) => item.irn === route.query.irn)
|
||
if (curIndex === len - 1) return airBlowerList.value[0]
|
||
return airBlowerList.value[curIndex + 1]
|
||
})
|
||
const switchAirBlowerQuery = ref()
|
||
const switchAirblower = (type: 0 | 1) => {
|
||
const data = type === 0 ? beforeAirBlower.value : afterAirBlower.value
|
||
const query = {
|
||
irn: data.irn,
|
||
iotModelId: data.iotModelId,
|
||
deviceCode: data.deviceCode,
|
||
model: data.model,
|
||
name: data.name,
|
||
}
|
||
switchAirBlowerQuery.value = query
|
||
router.push({
|
||
name: 'windTurbine',
|
||
query,
|
||
})
|
||
}
|
||
onMounted(() => {
|
||
window.addEventListener('resize', sizeChange)
|
||
sizeChange()
|
||
getAllChartData()
|
||
useEventListener(window, 'resize', echartsResize)
|
||
autoUpdate()
|
||
getAlarmList().then(() => {
|
||
createScroll()
|
||
})
|
||
getAirBlowerList().then(() => {
|
||
getMalfunctionEnums()
|
||
})
|
||
switchAirBlowerQuery.value = route.query
|
||
})
|
||
|
||
onUnmounted(() => {
|
||
window.removeEventListener('resize', sizeChange)
|
||
autoUpdateForSecondTimer && clearInterval(autoUpdateForSecondTimer)
|
||
autoUpdateTimerForHourTimer && clearInterval(autoUpdateTimerForHourTimer)
|
||
autoUpdateTimerForMinuteTimer && clearInterval(autoUpdateTimerForMinuteTimer)
|
||
const chartKeys = Object.keys(state.charts) as Array<keyof typeof state.charts>
|
||
chartKeys.forEach((key) => {
|
||
state.charts[key] && state.charts[key].dispose()
|
||
state.charts[key] = null
|
||
})
|
||
})
|
||
|
||
watch(
|
||
() => route.query.irn,
|
||
() => {
|
||
autoUpdateForSecondTimer && clearInterval(autoUpdateForSecondTimer)
|
||
autoUpdateForSecondTimer = null
|
||
autoUpdateTimerForHourTimer && clearInterval(autoUpdateTimerForHourTimer)
|
||
autoUpdateTimerForHourTimer = null
|
||
autoUpdateTimerForMinuteTimer && clearInterval(autoUpdateTimerForMinuteTimer)
|
||
autoUpdateTimerForMinuteTimer = null
|
||
const chartKeys = Object.keys(state.charts) as Array<keyof typeof state.charts>
|
||
chartKeys.forEach((key) => {
|
||
state.charts[key] && state.charts[key].dispose()
|
||
state.charts[key] = null
|
||
})
|
||
|
||
nextTick(() => {
|
||
autoUpdate()
|
||
getAlarmList()
|
||
getAllChartData()
|
||
})
|
||
}
|
||
)
|
||
|
||
const openTemperature = (row: any) => {
|
||
if (!router.hasRoute('windBlowerTemperature')) {
|
||
router.addRoute('admin', {
|
||
path: adminBaseRoutePath + '/windBlowerTemperature',
|
||
name: 'windBlowerTemperature',
|
||
component: () => import('/@/views/backend/WindBlower/temperature.vue'),
|
||
meta: {
|
||
title: 'windBlowerTemperature',
|
||
menuDesc: '温度管理',
|
||
addtab: true,
|
||
},
|
||
})
|
||
}
|
||
|
||
router.push({
|
||
name: 'windBlowerTemperature',
|
||
query: {
|
||
...switchAirBlowerQuery.value,
|
||
},
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
$marginNum: 10px;
|
||
$labelHeight: 24px;
|
||
|
||
@mixin cardDefaultStyle {
|
||
padding: 10px;
|
||
border-radius: 10px;
|
||
background-color: #fff;
|
||
}
|
||
@mixin cardlabel {
|
||
.cardLabel {
|
||
width: 100%;
|
||
height: $labelHeight;
|
||
font-size: 18px;
|
||
line-height: 18px;
|
||
font-weight: 600;
|
||
color: #4e5969;
|
||
}
|
||
}
|
||
.radioItem {
|
||
margin-top: -43px;
|
||
float: right;
|
||
}
|
||
.dialogContent {
|
||
width: 100%;
|
||
height: 500px;
|
||
// overflow-y: auto;
|
||
// overflow-x: hidden;
|
||
.PitchPart {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
width: 100%;
|
||
.Pitchitem {
|
||
border: 1px solid #e1edf6;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
width: 50%;
|
||
.PitchitemLeft {
|
||
display: flex;
|
||
align-items: center;
|
||
width: 325px;
|
||
min-height: 50px;
|
||
background: #f7f9fc;
|
||
padding-left: 20px;
|
||
font-size: 14px;
|
||
color: #4e5969;
|
||
letter-spacing: 0;
|
||
font-weight: 500;
|
||
word-break: break-all;
|
||
}
|
||
.PitchitemRight {
|
||
/*width: 180px;*/
|
||
height: 25px;
|
||
line-height: 50px;
|
||
padding-right: 20px;
|
||
font-size: 14px;
|
||
color: #4e5969;
|
||
letter-spacing: 0;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.dialog-footer {
|
||
text-align: center;
|
||
.el-button {
|
||
width: 120px;
|
||
height: 40px;
|
||
}
|
||
}
|
||
.overviewSlot {
|
||
display: flex;
|
||
.radioForOverviewType {
|
||
margin-left: auto;
|
||
}
|
||
}
|
||
|
||
.windBlower {
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: #f2f3f5;
|
||
// overflow: hidden;
|
||
.el-row {
|
||
width: 100%;
|
||
height: 100%;
|
||
.el-col {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
.cardContentLeft {
|
||
margin: 0 5px;
|
||
width: calc(100% - 10px);
|
||
height: 100%;
|
||
.overview {
|
||
width: 100%;
|
||
height: 60%;
|
||
min-height: 450px;
|
||
@include cardDefaultStyle;
|
||
@include cardlabel;
|
||
.overviewDataSection {
|
||
width: 100%;
|
||
height: calc(100% - 42px);
|
||
.overviewDataSectionItem {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 5px;
|
||
padding: 0 10px;
|
||
width: 100%;
|
||
height: calc(9% - 5px);
|
||
min-height: 20px;
|
||
font-size: 14px;
|
||
color: #333333;
|
||
background: #f0f6ff;
|
||
border-radius: 4px;
|
||
}
|
||
}
|
||
.overviewDataBtn {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: end;
|
||
width: 100%;
|
||
height: 18px;
|
||
font-size: 18px;
|
||
.el-icon {
|
||
transform: rotate(90deg);
|
||
}
|
||
:hover {
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
}
|
||
.temperatureList {
|
||
@include cardDefaultStyle;
|
||
@include cardlabel;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-around;
|
||
margin: 10px 0;
|
||
width: 100%;
|
||
height: calc(40% - 20px);
|
||
.chartPart-item {
|
||
// margin: 5px 0;
|
||
width: 100%;
|
||
height: calc(33.3% - 10px);
|
||
background: #f0f6ff;
|
||
border-radius: 8px;
|
||
// text-align: center;
|
||
color: #4e5969;
|
||
.chartParm {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
.frequencyChart {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
}
|
||
// .power {
|
||
// @include cardDefaultStyle;
|
||
// @include cardlabel;
|
||
// margin: 10px 0;
|
||
// width: 100%;
|
||
// height: calc(40% - 20px);
|
||
// // min-height: 285px;
|
||
// // height: v-bind('computedHeight.powerHeight');
|
||
// .chartBox {
|
||
// width: 100%;
|
||
// height: calc(100% - $labelHeight);
|
||
// .power-chart {
|
||
// width: 100%;
|
||
// height: 100%;
|
||
// }
|
||
// }
|
||
// }
|
||
}
|
||
.cardContentCenter {
|
||
@include cardDefaultStyle;
|
||
// display: flex;
|
||
// flex-direction: column;
|
||
// justify-content: space-around;
|
||
margin: 0 5px 10px 5px;
|
||
width: calc(100% - 10px);
|
||
height: calc(100% - 10px);
|
||
// min-height: 900px;
|
||
.controlBackgroundImg {
|
||
position: relative;
|
||
width: 100%;
|
||
aspect-ratio: 43 / 24;
|
||
background: url('/@/assets/WindBlower/bg.png') no-repeat;
|
||
background-size: contain;
|
||
&:hover {
|
||
.switchWindBlower {
|
||
opacity: 1;
|
||
}
|
||
}
|
||
.switchWindBlower {
|
||
position: absolute;
|
||
left: 50%;
|
||
top: 5%;
|
||
transform: translateX(-50%);
|
||
width: 100px;
|
||
height: 40px;
|
||
// background-color: red;
|
||
opacity: 0;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
transition: opacity 0.4s;
|
||
.el-icon:hover {
|
||
cursor: pointer;
|
||
color: rgba(255, 255, 255, 0.7);
|
||
}
|
||
}
|
||
.control-type {
|
||
width: 100%;
|
||
display: flex;
|
||
.control-tag {
|
||
background: #0064aa;
|
||
border-radius: 0 8px 0 0;
|
||
min-width: 80px;
|
||
height: 40px;
|
||
color: #ffffff;
|
||
font-size: 20px;
|
||
border: none;
|
||
margin-left: auto;
|
||
}
|
||
.control-tag-left {
|
||
margin-left: 0;
|
||
border-radius: 8px 0 0 0;
|
||
background-color: #ff4949;
|
||
}
|
||
}
|
||
.btnLeft {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
position: absolute;
|
||
bottom: 0;
|
||
.el-button {
|
||
width: 80px;
|
||
height: 40px;
|
||
// background: rgb(0,100,170);
|
||
border-radius: 6px;
|
||
color: #ffffff;
|
||
border: none;
|
||
margin-bottom: 10px;
|
||
}
|
||
}
|
||
.dot {
|
||
position: absolute;
|
||
width: 15px;
|
||
height: 15px;
|
||
background-color: rgba(255, 255, 255, 0);
|
||
transition: all 0.5s ease;
|
||
background-position: center center;
|
||
background-size: contain;
|
||
background-repeat: no-repeat;
|
||
&:hover {
|
||
transform: scale(1.2);
|
||
cursor: pointer;
|
||
}
|
||
&:nth-of-type(1) {
|
||
top: 25%;
|
||
left: 50%;
|
||
}
|
||
}
|
||
.index-1 {
|
||
left: 24%;
|
||
top: 1%;
|
||
width: 12%;
|
||
height: 48%;
|
||
&:hover {
|
||
transform: scale(1.5);
|
||
background-image: url('/@/assets/WindBlower/9.png');
|
||
}
|
||
}
|
||
.index-2 {
|
||
left: 30%;
|
||
top: 83%;
|
||
width: 15%;
|
||
height: 16%;
|
||
&:hover {
|
||
transform: scale(1.8);
|
||
background-image: url('/@/assets/WindBlower/3.png');
|
||
}
|
||
}
|
||
.index-3 {
|
||
left: 12.5%;
|
||
top: 69%;
|
||
width: 4%;
|
||
height: 25%;
|
||
&:hover {
|
||
transform: scale(3);
|
||
background-image: url('/@/assets/WindBlower/4.png');
|
||
}
|
||
}
|
||
|
||
.index-4 {
|
||
left: 46%;
|
||
top: 49%;
|
||
width: 12%;
|
||
height: 15%;
|
||
&:hover {
|
||
transform: scale(1.8);
|
||
background-image: url('/@/assets/WindBlower/1.png');
|
||
}
|
||
}
|
||
.index-5 {
|
||
left: 66%;
|
||
top: 35%;
|
||
width: 8%;
|
||
height: 14%;
|
||
// transform: rotate(-51deg);
|
||
&:hover {
|
||
transform: scale(1.8);
|
||
background-image: url('/@/assets/WindBlower/7.png');
|
||
}
|
||
}
|
||
.index-6 {
|
||
left: 60%;
|
||
top: 63%;
|
||
width: 27%;
|
||
height: 5%;
|
||
transform: rotate(-15deg);
|
||
&:hover {
|
||
transform: scale(5);
|
||
background-image: url('/@/assets/WindBlower/5.png');
|
||
}
|
||
}
|
||
.index-7 {
|
||
left: 73%;
|
||
top: 48%;
|
||
width: 7%;
|
||
height: 11%;
|
||
transform: rotate(-13deg);
|
||
&:hover {
|
||
transform: scale(2.5);
|
||
background-image: url('/@/assets/WindBlower/6.png');
|
||
}
|
||
}
|
||
|
||
.index-8 {
|
||
left: 23%;
|
||
top: 53%;
|
||
width: 19%;
|
||
height: 26%;
|
||
&:hover {
|
||
background-image: url('/@/assets/WindBlower/2.png');
|
||
}
|
||
}
|
||
.index-9 {
|
||
left: 50%;
|
||
top: 66%;
|
||
width: 9%;
|
||
height: 13%;
|
||
&:hover {
|
||
transform: scale(2);
|
||
background-image: url('/@/assets/WindBlower/10.png');
|
||
}
|
||
}
|
||
|
||
.index-10 {
|
||
left: 67%;
|
||
top: 1%;
|
||
width: 12%;
|
||
height: 12%;
|
||
&:hover {
|
||
transform: scale(2.5);
|
||
background-image: url('/@/assets/WindBlower/8.png');
|
||
}
|
||
}
|
||
|
||
.index-11 {
|
||
right: 16%;
|
||
bottom: 3%;
|
||
width: 13%;
|
||
height: 23%;
|
||
}
|
||
.index-12 {
|
||
right: 2%;
|
||
bottom: 3%;
|
||
width: 13%;
|
||
height: 23%;
|
||
}
|
||
}
|
||
.chartPart {
|
||
margin: 10px 0;
|
||
width: 100%;
|
||
height: calc(100% - 10px - v-bind('computedHeight.backgroundImgHeight'));
|
||
// min-height: 220px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
&:hover {
|
||
cursor: pointer;
|
||
}
|
||
.power {
|
||
margin-bottom: 5px;
|
||
width: 60%;
|
||
height: 100%;
|
||
background-color: #f0f6ff;
|
||
border-radius: 8px;
|
||
.chartBox {
|
||
width: 100%;
|
||
height: 100%;
|
||
.power-chart {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
}
|
||
|
||
.chartPart-item {
|
||
margin: 0 0 5px 5px;
|
||
// width: 25%;
|
||
height: 100%;
|
||
background: #f0f6ff;
|
||
border-radius: 8px;
|
||
color: #4e5969;
|
||
.frequencyChart {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
.item_bar {
|
||
width: 40%;
|
||
}
|
||
}
|
||
}
|
||
.cardContentRight {
|
||
margin: 0 5px;
|
||
width: calc(100% - 10px);
|
||
height: 100%;
|
||
// min-height: 920px;
|
||
.summarize {
|
||
width: 100%;
|
||
height: 40%;
|
||
@include cardDefaultStyle;
|
||
@include cardlabel;
|
||
.summarize-panel-list {
|
||
width: 100%;
|
||
height: calc(100% - $labelHeight);
|
||
.summarize-panel-row {
|
||
display: flex;
|
||
width: 100%;
|
||
height: 50%;
|
||
min-height: 110px;
|
||
.summarize-panel {
|
||
margin: 5px;
|
||
width: calc(50% - 10px);
|
||
height: calc(100% - 10px);
|
||
background-color: #f0f6ff;
|
||
border-radius: 10px;
|
||
.summarize-panel-pic {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
min-height: 36px;
|
||
height: 40%;
|
||
img {
|
||
height: 80%;
|
||
aspect-ratio: 1/1;
|
||
}
|
||
}
|
||
.summarize-panel-base {
|
||
width: 100%;
|
||
height: 60%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
div {
|
||
display: flex;
|
||
justify-content: center;
|
||
height: 30%;
|
||
font-size: 14px;
|
||
color: rgb(78, 89, 105);
|
||
.content-number {
|
||
color: #333333;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
&:first-child {
|
||
height: 40%;
|
||
align-items: center;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.alarm {
|
||
margin: 10px 0;
|
||
width: 100%;
|
||
// min-height: 350px;
|
||
height: calc(60% - 20px);
|
||
@include cardDefaultStyle;
|
||
@include cardlabel;
|
||
}
|
||
}
|
||
}
|
||
</style>
|