绘制离线地图

This commit is contained in:
GGJ
2024-12-23 09:29:59 +08:00
parent 8cdf4ca8b6
commit 1f94ac5267
26 changed files with 8578 additions and 101 deletions

View File

@@ -0,0 +1,299 @@
<template>
<!-- 综合评估详情 -->
<el-dialog draggable title="综合评估统计" v-model="dialogVisible" width="1400px">
<div>
<vxe-table v-bind="defaultAttribute" ref="vxeRef" height="300px" :data="tableData">
<vxe-column field="deptName" title="地市" />
<vxe-column field="assessLevel" title="综合评估结论">
<template #default="scope">
<!-- class="conclusion"
:class="
scope.row.assessLevel == '特质'
? 'background1'
: scope.row.assessLevel == '较差'
? 'background2'
: scope.row.assessLevel == '极差'
? 'background3'
: ''
" -->
<span>
{{ scope.row.assessData }}
</span>
</template>
</vxe-column>
<vxe-column field="qualifyData" title="指标合格率(%)" />
<!-- <vxe-colgroup title="评估结论">
<vxe-column field="vdevAssessLevel" title="电压偏差">
<template #default="scope">
<span
class="conclusion"
:class="
scope.row.vdevAssessLevel == '特质'
? 'background1'
: scope.row.vdevAssessLevel == '较差'
? 'background2'
: scope.row.vdevAssessLevel == '极差'
? 'background3'
: ''
"
>
{{ scope.row.vdevAssessLevel }}
</span>
</template>
</vxe-column>
<vxe-column field="freqAssessLevel" title="频率偏差">
<template #default="scope">
<span
class="conclusion"
:class="
scope.row.freqAssessLevel == '特质'
? 'background1'
: scope.row.freqAssessLevel == '较差'
? 'background2'
: scope.row.freqAssessLevel == '极差'
? 'background3'
: ''
"
>
{{ scope.row.freqAssessLevel }}
</span>
</template>
</vxe-column>
<vxe-column field="harmAssessLevel" title="电压总谐波畸变率">
<template #default="scope">
<span
class="conclusion"
:class="
scope.row.harmAssessLevel == '特质'
? 'background1'
: scope.row.harmAssessLevel == '较差'
? 'background2'
: scope.row.harmAssessLevel == '极差'
? 'background3'
: ''
"
>
{{ scope.row.harmAssessLevel }}
</span>
</template>
</vxe-column>
<vxe-column field="flickerAssessLevel" title="电压闪变">
<template #default="scope">
<span
class="conclusion"
:class="
scope.row.flickerAssessLevel == '特质'
? 'background1'
: scope.row.flickerAssessLevel == '较差'
? 'background2'
: scope.row.flickerAssessLevel == '极差'
? 'background3'
: ''
"
>
{{ scope.row.flickerAssessLevel }}
</span>
</template>
</vxe-column>
<vxe-column field="unbalanceAssessLevel" title="三相电压不平衡度">
<template #default="scope">
<span
class="conclusion"
:class="
scope.row.unbalanceAssessLevel == '特质'
? 'background1'
: scope.row.unbalanceAssessLevel == '较差'
? 'background2'
: scope.row.unbalanceAssessLevel == '极差'
? 'background3'
: ''
"
>
{{ scope.row.unbalanceAssessLevel }}
</span>
</template>
</vxe-column>
</vxe-colgroup> -->
</vxe-table>
</div>
<div style="height: 300px; margin-top: 10px; position: relative" v-loading="loading">
<!-- <el-select
v-model="time"
size="small"
@change="analysis"
>
<el-option label="年" value="1" />
<el-option label="月" value="3" />
</el-select> -->
<div style="position: absolute; width: 100px; top: 0px; right: 0px; z-index: 1">
<el-radio-group v-model="city" size="small" @change="analysis">
<el-radio-button label="0"></el-radio-button>
<el-radio-button label="1"></el-radio-button>
</el-radio-group>
<el-radio-group v-model="type" size="small" @change="analysis">
<el-radio-button label="1"></el-radio-button>
<el-radio-button label="3"></el-radio-button>
</el-radio-group>
</div>
<MyEChart style="height: 300px" :options="picEChart" />
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { getAssessDetail, getAssessTrend } from '@/api/device-boot/panorama'
const dialogVisible: any = ref(false)
const rowList: any = ref({})
const type = ref('1')
const city = ref('0')
const loading = ref(false)
const tableData: any = ref([])
const picEChart = ref()
const open = async (row: any) => {
getAssessDetail(row).then(res => {
tableData.value = res.data
})
rowList.value = row
analysis()
dialogVisible.value = true
}
const analysis = () => {
loading.value = true
let time = rowList.value.searchBeginTime.slice(0, 4) + `-01-01`
getAssessTrend({ ...rowList.value, searchBeginTime: time, type: type.value, areaType: city.value }).then(res => {
picEChart.value = {
title: {
text: '各地市综合评估趋势对比'
},
legend: {
right: 120,
top: 20
},
// tooltip: {
// formatter: function (params: any) {
// // console.log(123, params)
// var tips = ''
// for (var i = 0; i < params.length; i++) {
// console.log('🚀 ~ getAssessTrend ~ params[i].value:', params[i].value)
// tips +=
// params[i].seriesName +
// ':' +
// `<span style="color:${
// params[i].value > 4.5
// ? ''
// : params[i].value > 4
// ? ''
// : params[i].value > 3
// ? ''
// : params[i].value > 2
// ? '#97017e'
// : params[i].value > 0
// ? '#cc0000'
// : ''
// }">
// ${
// params[i].value > 4.5
// ? '优质'
// : params[i].value > 4
// ? '良好'
// : params[i].value > 3
// ? '一般'
// : params[i].value > 2
// ? '较差'
// : params[i].value > 0
// ? '极差'
// : ''
// }
// </span>` +
// '</br>'
// }
// return tips
// }
// },
xAxis: {
name: '时间',
data: res.data[0].children.map((item: any) => item.dataTime)
},
grid: {
bottom: '10px',
top: '60px'
},
yAxis: {
name: ''
},
options: {
dataZoom: false,
series: []
}
}
let list: any = []
let time: any = []
let mun: any = []
res.data.forEach((item: any, num: any) => {
time.push(item.deptName)
list.push([])
item.children.forEach((val: any, i: any) => {
mun.push(val.score == 3.14159 ? null : val.score)
list[num].push(val.score == 3.14159 ? null : val.score)
})
})
list.forEach((item: any, i: any) => {
picEChart.value.options.series.push({
name: time[i],
type: 'line',
data: item
})
})
picEChart.value.yAxis.min = Math.min(...mun) < 1 ? 0 : (Math.min(...mun) - 0.5).toFixed(2)
picEChart.value.yAxis.max = Math.max(...mun) > 4.5 ? 5 : (Math.max(...mun) + 0.5).toFixed(2)
loading.value = false
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
:deep(.el-dialog__body) {
max-height: none !important;
}
.conclusion {
display: inline-block;
padding: 0 10px;
height: 24px;
line-height: 24px;
border-radius: 4px;
}
.background1 {
background-color: #339966;
color: #fff;
}
.background2 {
background-color: #97017e;
color: #fff;
}
.background3 {
background-color: #cc0000;
color: #fff;
}
:deep(.el-select) {
min-width: 80px !important;
}
</style>

View File

@@ -0,0 +1,232 @@
<template>
<!-- 监测点详情 -->
<el-dialog draggable title="监测点统计" v-model="dialogVisible" width="1400px" :before-close="handleClose">
<el-row style="height: 300px" :gutter="20">
<el-col :span="12">
<div class="title">
<span>趋势分析</span>
<!-- <el-select v-model="time" style="width: 80px; margin-right: 80px" @change="analysis">
<el-option label="年" value="1" />
<el-option label="月" value="3" />
</el-select> -->
<el-radio-group v-model="time" style="margin-right: 50px" @change="analysis" size="small">
<el-radio-button label="1"></el-radio-button>
<el-radio-button label="3"></el-radio-button>
</el-radio-group>
</div>
<MyEChart style="height: 260px" :options="trendEChart" />
</el-col>
<el-col :span="12">
<div class="title">
<span>分布统计</span>
<el-select
v-model="statisticalType"
value-key="id"
style="width: 120px; margin-right: 80px"
@change="statiStics"
>
<el-option v-for="item in options" :key="item.id" :label="item.name" :value="item" />
</el-select>
</div>
<div class="pie">
<MyEChart style="height: 260px" :options="picEChart" />
</div>
</el-col>
</el-row>
<div>
<div class="title">
<span>区域监测点统计</span>
</div>
<vxe-table v-bind="defaultAttribute" ref="vxeRef" height="325px" :data="tableData">
<vxe-column field="orgName" title="区域" :formatter="formatter" />
<vxe-column field="num" title="监测点个数" sortable :formatter="formatter" />
<vxe-column field="integrityRate" sortable title="完整率(%)" />
<vxe-column field="onLineRate" sortable title="在线率(%)" />
<vxe-column field="outOfStandardRate" sortable title="超标监测点占比(%)" />
</vxe-table>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { useDictData } from '@/stores/dictData'
import { getGridDiagramLineTendency, getGridDiagramLineData, getHalfReport } from '@/api/device-boot/panorama'
const dictData = useDictData()
const dialogVisible: any = ref(false)
const Voltage = dictData.getBasicData('Dev_Voltage_Stand')
const tableData: any = ref([])
const options = dictData.getBasicData('Statistical_Type', ['Report_Type', 'Power_Network'])
const time = ref('1')
const statisticalType = ref(options[0])
const loadTypeArr = dictData.getBasicData('Interference_Source')
const rowList: any = ref({})
const trendEChart: any = ref()
const picEChart = ref()
const open = async (row: any) => {
time.value = '1'
rowList.value = {
deviceInfoParam: {
...row
},
pageNum: 1,
pageSize: 1000,
...row
}
analysis(1)
// 统计
statiStics()
// 监测点列表
getGridDiagramLineData({
...rowList.value,
statisticalType: rowList.value.deviceInfoParam.statisticalType
}).then((res: any) => {
tableData.value = res.data
})
dialogVisible.value = true
}
// 分析
const analysis = (e: any) => {
let time = rowList.value.searchBeginTime.slice(0, 4) + `-01-01`
// 分析
getGridDiagramLineTendency({ ...rowList.value, searchBeginTime: time, type: e }).then(res => {
let name = []
let data = []
let num = 0
for (let k in res.data) {
name.push(k)
// num = num + res.data[k]
data.push(res.data[k])
}
trendEChart.value = {
title: {
text: '在线监测点总数量'
},
xAxis: {
name: '时间',
data: name
},
legend: {
show: false
},
yAxis: {
name: '个'
},
options: {
dataZoom: null,
series: [
{
name: '接入',
type: 'line',
data: data,
smooth: true,
label: {
show: true,
position: 'top',
fontSize: 12
}
}
]
}
}
})
}
// 统计
const statiStics = () => {
getGridDiagramLineData({ ...rowList.value, statisticalType: statisticalType.value }).then(res => {
picEChart.value = {
title: {
text: ''
},
xAxis: {
data: res.data.map((item: any) => item.orgName)
},
yAxis: {
name: '%',
min: 0,
max: 100
},
options: {
dataZoom: null,
series: [
{
name: '数据完整性',
type: 'bar',
data: res.data.map((item: any) => item.integrityRate),
label: {
show: true,
position: 'top',
fontSize: 12
}
},
{
name: '在线率',
type: 'bar',
data: res.data.map((item: any) => item.onLineRate),
label: {
show: true,
position: 'top',
fontSize: 12
}
},
{
name: '超标监测点占比',
type: 'bar',
data: res.data.map((item: any) => item.outOfStandardRate),
label: {
show: true,
position: 'top',
fontSize: 12
}
}
]
}
}
})
}
const formatter = (row: any) => {
if (row.column.field == 'orgName') {
return row.cellValue.match(/[\u4e00-\u9fa5]+/g).join('')
} else if (row.column.field == 'num') {
return row.row.orgName.match(/\(([^]+)\)/)[1]
} else {
return row.cellValue
}
}
const handleClose = () => {
tableData.value = []
dialogVisible.value = false
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
:deep(.el-select) {
min-width: 80px;
}
.title {
display: flex;
justify-content: space-between;
margin: 10px;
span {
font-weight: 550;
font-size: 18px;
}
}
.pie {
display: flex;
justify-content: space-around;
}
:deep(.el-table thead) {
color: #000;
}
</style>

View File

@@ -0,0 +1,378 @@
<template>
<!-- 变电站 -->
<el-dialog draggable title="变电站统计" v-model="dialogVisible" width="1400px" :before-close="handleClose">
<el-row style="height: 300px" :gutter="20">
<el-col :span="12">
<div class="title">
<span>趋势分析</span>
<!-- <el-select v-model="time" style="width: 80px; margin-right: 80px" @change="analysis">
<el-option label="年" value="1" />
<el-option label="月" value="3" />
</el-select> -->
<el-radio-group v-model="time" style="margin-right: 50px" @change="analysis" size="small">
<el-radio-button label="1"></el-radio-button>
<el-radio-button label="3"></el-radio-button>
</el-radio-group>
</div>
<MyEChart style="height: 260px" :options="trendEChart" />
</el-col>
<el-col :span="12">
<div class="title">
<span>
污染告警
<el-popover placement="right" :width="170" trigger="hover">
<template #reference>
<WarningFilled class="WarningFilled" />
</template>
<div class="text">
<span style="color: #00b07d">无污染(0 , 1]</span>
<br />
<span style="color: #3399ff">轻微污染(1 , 1.2]</span>
<br />
<span style="color: #ffcc33">轻度污染(1.2 , 1.6]</span>
<br />
<span style="color: #ff9900">中度污染(1.6 , 2]</span>
<br />
<span style="color: #cc0000">重度污染(2 , +)</span>
</div>
</el-popover>
</span>
<!-- <el-select v-model="contaminate" style="width: 120px; margin-right: 80px" @change="contaminateC">
<el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" />
</el-select> -->
<el-radio-group
v-model="contaminate"
style="margin-right: 50px"
@change="contaminateC"
size="small"
>
<el-radio-button v-for="item in options" :label="item.id">{{ item.name }}</el-radio-button>
</el-radio-group>
</div>
<div class="pie">
<MyEChart
v-for="(item, i) in picEChart"
:style="i == 3 ? `margin-left: 20%;` : ``"
class="MyEChart"
:options="item"
/>
</div>
</el-col>
</el-row>
<div>
<div class="title mb10">
<span>区域变电站统计</span>
</div>
<vxe-table v-bind="defaultAttribute" ref="vxeRef" height="325px" :data="tableData">
<vxe-column field="name" title="区域" />
<vxe-column field="num" sortable title="变电站总数" />
<vxe-column field="num1" sortable title="无污染数量" :formatter="formatter" />
<vxe-column field="num2" sortable title="轻微污染数量" :formatter="formatter" />
<vxe-column field="num3" sortable title="轻度污染数量" :formatter="formatter" />
<vxe-column field="num4" sortable title="中度污染数量" :formatter="formatter" />
<vxe-column field="num5" sortable title="重度污染数量" :formatter="formatter" />
</vxe-table>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { WarningFilled } from '@element-plus/icons-vue'
import { getPollutionAlarmList, getPollutionAlarmData, getGridDiagramSubTendency } from '@/api/device-boot/panorama'
const dictData = useDictData()
const dialogVisible: any = ref(false)
const time = ref('1')
const Voltage = dictData.getBasicData('Dev_Voltage_Stand')
const options: any = dictData.getBasicData('Pollution_Statis').filter(item => {
if (item.code == 'V_Harmonic' || item.code == 'I_All') {
return item
}
})
const contaminate = ref(options[0].id)
const rowList: any = ref({})
const trendEChart: any = ref({})
const tableData: any = ref([])
const picEChart: any = ref([{}, {}, {}, {}, {}])
const open = async (row: any) => {
time.value = '1'
rowList.value = {
deviceInfoParam: {
...row
},
pageNum: 1,
pageSize: 1000,
...row
}
analysis(1)
// 污染
contaminateC()
// 列表
dialogVisible.value = true
}
const contaminateC = () => {
// rowList.value.deviceInfoParam.ids=[contaminate.value]
getPollutionAlarmData({ ...rowList.value, ids: [contaminate.value] }).then(res => {
let data = []
let a1 = 0
let a2 = 0
let a3 = 0
let a4 = 0
let a5 = 0
if (rowList.value.isUpToGrid == 0) {
data = res.data.info
} else {
data = res.data.gwInfo
}
for (let i = 0; i < data.length; i++) {
if (data[i] >= 2) {
++a5
} else if (data[i] >= 1.6 && data[i] < 2) {
++a4
} else if (data[i] >= 1.2 && data[i] < 1.6) {
++a3
} else if (data[i] >= 1 && data[i] < 1.2) {
++a2
} else if (data[i] >= 0 && data[i] < 1) {
++a1
}
}
// console.log('🚀 ~ getPollutionAlarmData ~ a1 / data.length:', a1 / data.length)
let list = [
{
value: ((a1 / data.length || 0) * 100).toFixed(2),
name: `无污染:${a1}`
},
{
value: ((a2 / data.length || 0) * 100).toFixed(2),
name: `轻微污染::${a2}`
},
{
value: ((a3 / data.length || 0) * 100).toFixed(2),
name: `轻度污染:${a3}`
},
{
value: ((a4 / data.length || 0) * 100).toFixed(2),
name: `中度污染:${a4}`
},
{
value: ((a5 / data.length || 0) * 100).toFixed(2),
name: `重度污染:${a5}`
}
]
const color = ['#00B07D', '#3399ff', '#ffcc33', '#ff9900', '#cc0000']
list.forEach((item, i) => {
picEChart.value[i] = {
legend: {
type: 'scroll',
orient: 'vertical',
left: 10,
top: '10%'
},
xAxis: {
show: false
},
yAxis: {
show: false
},
options: {
dataZoom: null,
series: [
{
type: 'gauge',
startAngle: 180,
center: ['50%', '80%'],
radius: '135%',
endAngle: 0,
min: 0,
max: 100,
progress: {
show: true,
width: 15,
itemStyle: {
color: color[i]
}
},
pointer: {
show: false
},
axisLine: {
lineStyle: {
width: 15,
color: [[1, '#f4f4f4']]
}
},
axisTick: {
show: false
},
splitLine: {
show: false
},
axisLabel: {
show: false
// distance: 5,
// color: '#666',
// fontSize: 12,
// formatter: function (value: any) {
// if (value === 0 || value === 100) {
// return value + '%'
// }
// }
},
anchor: {
show: false,
showAbove: false,
size: 25,
itemStyle: {
borderWidth: 60
}
},
title: {
show: true,
offsetCenter: [0, '20%'],
fontSize: 14
},
detail: {
valueAnimation: true,
fontSize: 14,
lineHeight: 20,
color: color[i],
fontWeight: 'bold',
offsetCenter: [0, '-20%'],
formatter: function (value: any) {
return '{a|占比} ' + '\n' + value + '{a|%}'
},
rich: {
a: {
color: '#333',
fontSize: 16,
lineHeight: 30
}
}
},
data: [item]
}
]
}
}
})
})
getPollutionAlarmList({ ...rowList.value, ids: [contaminate.value] }).then(res => {
tableData.value = res.data.map((item: any) => {
return {
name: item[0],
num: item[1],
num1: item[2],
num2: item[3],
num3: item[4],
num4: item[5],
num5: item[6]
}
})
})
}
const analysis = (e: any) => {
let time = rowList.value.searchBeginTime?.slice(0, 4) + `-01-01`
// 分析
getGridDiagramSubTendency({ ...rowList.value, searchBeginTime: time, type: e }).then(res => {
let name = []
let data = []
let num = 0
for (let k in res.data) {
name.push(k)
// num = num + res.data[k]
data.push(res.data[k])
}
trendEChart.value = {
title: {
text: '变电站接入总数量'
},
xAxis: {
name: '时间',
data: name
},
legend: {
show: false
},
yAxis: {
name: '座'
},
options: {
dataZoom: null,
series: [
{
name: '接入',
type: 'line',
data: data,
smooth: true,
label: {
show: true,
position: 'top',
fontSize: 12
}
}
]
}
}
})
}
const formatter = (row: any) => {
if (row.column.field == 'dataV') {
return row.cellValue == 3.14159 ? '/' : row.cellValue
} else if (row.column.field == 'data') {
return row.cellValue == 3.14159 ? '/' : row.cellValue
} else if (row.column.field == 'voltageLevel') {
return Voltage.filter((item: any) => item.id == row.cellValue)[0]?.name
} else {
return row.cellValue
}
}
const handleClose = () => {
tableData.value = []
dialogVisible.value = false
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
:deep(.el-select) {
min-width: 80px;
}
.title {
display: flex;
justify-content: space-between;
position: relative;
span {
font-weight: 550;
font-size: 18px;
}
.WarningFilled {
width: 16px;
cursor: pointer;
}
}
.pie {
display: flex;
flex-wrap: wrap;
.MyEChart {
height: 130px;
width: 30%;
margin-right: 3%;
}
}
:deep(.el-dialog__body) {
max-height: none !important;
}
</style>

View File

@@ -0,0 +1,338 @@
<!-- 稳态 -->
<template>
<!-- 终端 -->
<el-dialog draggable title="稳态电能质量水平评估统计" v-model="dialogVisible" width="1400px">
<el-row style="height: 300px" :gutter="20">
<el-col :span="12">
<div class="title">
<span>稳态电能质量水平评估</span>
</div>
<div class="boxSteps">
<el-steps>
<template v-for="(item, i) in Voltage">
<el-step :class="active == i ? 'highlight' : ''" :title="item.name"
@click="handleClick(i)"></el-step>
</template>
</el-steps>
</div>
<div v-for="(item, i) in evaluationData" class="evaluationData">
<el-row style="width: 100%">
<el-col :span="12" style="display: flex">
<img :src="url[i]" />
<span>{{ item.targetName }}</span>
</el-col>
<el-col :span="12" style="display: flex">
<div style="width: 150px">
均值
<span style="color: #339966">{{ item.avg == 3.14159 ? '--' : item.avg }}</span>
</div>
<div>
标准差
<span style="color: #ff9900">{{ item.avg == 3.14159 ? '--' : item.sd }}</span>
</div>
</el-col>
</el-row>
</div>
</el-col>
<el-col :span="12">
<div class="title">
<span>稳态电能质量超标占比环比变化</span>
</div>
<div class="pie">
<div style="height: 250px; width: 100%" ref="chartRef"></div>
</div>
</el-col>
</el-row>
<div>
<div class="title">
<span>区域稳态电能质量水平评估</span>
</div>
<vxe-table v-bind="defaultAttribute" ref="vxeRef" height="365px" :data="tableData">
<vxe-column field="deptName" title="区域" />
<vxe-column sortable field="onlineNum" title="在线监测点数量(个)" />
<vxe-column sortable field="overNum" title="超标监测点数量(个)" />
<vxe-column sortable field="overRatio" title="超标监测点占比(%)" />
<vxe-colgroup :title="item" v-for="(item, i) in title">
<vxe-column title="监测点数 " field="overNum">
<template #default="scope">
<span>{{ scope.row.list[i].overNum }}</span>
</template>
</vxe-column>
<vxe-column title="天数" field="overDay">
<template #default="scope">
<span>{{ scope.row.list[i].overDay }}</span>
</template>
</vxe-column>
</vxe-colgroup>
</vxe-table>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, nextTick } from 'vue'
import echarts from '@/components/echarts/echarts'
import { useDictData } from '@/stores/dictData'
import { color } from '@/components/echarts/color'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { getEvaluationData, evaluationDetail, evaluationRatio } from '@/api/device-boot/panorama'
const dialogVisible: any = ref(false)
const rowList = ref({})
const active: any = ref(1)
const evaluationData: any = ref([])
const dictData = useDictData()
const Voltage: any = dictData.getBasicData('Dev_Voltage_Stand').filter(item => {
if (item.code == '35kV' || item.code == '500kV' || item.code == '220kV' || item.code == '110kV') {
return item
}
})
const chartRef = ref<HTMLDivElement>()
const url: any = [
new URL(`@/assets/img/PLPC.png`, import.meta.url),
new URL(`@/assets/img/DYPC.png`, import.meta.url),
new URL(`@/assets/img/JBL.png`, import.meta.url),
new URL(`@/assets/img/SXDY.png`, import.meta.url),
new URL(`@/assets/img/SB.png`, import.meta.url)
]
const tableData: any = ref([])
const title = ['电压偏差(超标)', '频率偏差(超标)', '电压总谐波畸变率(超标)', '闪变(超标)', '三相电压不平衡度(超标)']
const echart = (row: any) => {
let maxList: any = []
row.forEach((item: any) => {
maxList.push(...(item.ratioList || [0]))
})
let max = Math.max(...maxList) > 50 ? 100 : 50
let chart = echarts.init(chartRef.value as HTMLDivElement)
let dataname = ['频率偏差(Hz)',
'电压偏差(%)',
'电压总谐波畸变率(%)',
'三相电压不平衡度(%)',
'闪变',
'谐波电压(%)',
'谐波电流(%)',
'间谐波电压(%)',
'负序电流(A)']
// let datamax = [100, 100, 100, 100, 100, 100]
let indicator = []
for (let i = 0; i < dataname.length; i++) {
indicator.push({
name: dataname[i],
max: max
})
}
let option: any = {
tooltip: {
trigger: 'item',
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
position: 'bottom'
},
legend: {
data: row.map((item: any) => item.time),
type: 'scroll',
orient: 'vertical',
icon: 'roundRect',
right: '20',
itemGap: 10,
itemWidth: 16,
itemHeight: 16,
textStyle: {
fontSize: '15',
color: '#656565'
}
},
radar: {
center: ['50%', '60%'],
radius: '60%',
startAngle: 90,
splitNumber: 5,
splitArea: {
areaStyle: {
color: ['#FFFFFF', '#F5F9FF'].reverse()
}
},
axisLabel: {
show: false
},
axisLine: {
show: true,
lineStyle: {
color: '#D2E4F8'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#D2E4F8'
}
},
name: {
formatter: '{value}',
textStyle: {
color: '#656565',
fontSize: 15
}
},
indicator: indicator
},
series: []
}
row.forEach((item: any, i: any) => {
option.series.push({
name: item.time,
type: 'radar',
symbol: 'none',
areaStyle: {
normal: {
color: color[i + 1]
}
},
itemStyle: {
color: color[i + 1]
},
data: [item.ratioList]
})
})
chart.setOption(option)
}
const open = async (row: any) => {
rowList.value = row
dialogVisible.value = true
// 稳态电能质量水平评估
handleClick(0)
//环比
evaluationRatio(row).then(res => {
echart(res.data)
})
// 稳态电能质量水平评估详细列表
evaluationDetail(row).then(res => {
tableData.value = res.data
})
}
// 点击电压等级
const handleClick = (i: any) => {
active.value = i
getEvaluationData({
...rowList.value,
voltageLevel: Voltage[i].id
}).then(res => {
evaluationData.value = res.data
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
:deep(.el-select) {
min-width: 80px;
}
.title {
display: flex;
justify-content: space-between;
margin: 10px;
span {
font-weight: 550;
font-size: 18px;
}
}
.pie {
display: flex;
justify-content: space-around;
}
.evaluationData {
height: 33px;
margin: 8px 30px;
width: 100%;
box-shadow: 1px 1px 1px 1px #e8e3e3;
display: flex;
font-size: 18px;
line-height: 35px;
img {
height: 25px;
width: 25px;
margin: 4px 20px 0px 30px;
}
}
.el-steps {
margin-top: 5px;
}
:deep(.el-step__icon) {
border: none;
background: #ccc;
margin-top: 5px;
width: 15px;
height: 15px;
}
:deep(.el-step__icon-inner) {
display: none;
}
:deep(.boxSteps) {
border-radius: 50px;
width: 60%;
height: 25px;
margin: auto;
margin-top: 30px;
.el-step__title {
line-height: 18px;
font-size: 16px;
margin-left: -10px;
font-weight: 500;
color: #000 !important;
position: relative;
top: -50px;
}
}
:deep(.highlight) {
.el-step__icon {
background: var(--el-color-primary);
}
.el-step__title {
font-weight: 700 !important;
color: var(--el-color-primary) !important;
}
// .is-wait {
// color: var(--el-color-primary) !important;
// }
}
:deep(.el-dialog__body) {
max-height: none !important;
}
</style>

View File

@@ -0,0 +1,78 @@
<!-- 技术 -->
<template>
<el-dialog draggable title="技术监督统计" v-model="dialogVisible" width="1400px">
<div>
<vxe-table v-bind="defaultAttribute" ref="vxeRef" height="320px" :data="tableData">
<vxe-column field="orgName" title="区域" />
<vxe-column field="abnormalNum" title="异常问题总数" />
<vxe-column field="workNum" title="工单总数" />
<!-- <vxe-column field="num" title="已关联工单数" /> -->
<vxe-column field="conversionNum" title="工单转换率(%)" />
<vxe-column field="processedNum" title="已处理工单数" />
<vxe-column field="disposalNum" title="工单处置率(%)" />
</vxe-table>
</div>
<div style="height: 300px; margin-top: 10px">
<MyEChart style="height: 300px" :options="picEChart" />
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { getSupervisionDetailsData, getSupervisionCityDetailsData } from '@/api/device-boot/panorama'
const dialogVisible: any = ref(false)
const tableData: any = ref([])
const picEChart = ref({})
const open = async (row: any) => {
dialogVisible.value = true
getSupervisionDetailsData(row).then(res => {
tableData.value = res.data
})
getSupervisionCityDetailsData(row).then(res => {
picEChart.value = {
title: {
text: ''
},
xAxis: {
name: '',
data: ['技术监督计划', '用户投诉', '在线监测问题','试运行问题']
},
yAxis: {
name: '',
min: 0,
max: 100
},
options: {
dataZoom: null,
series: [
{
name: '问题个数',
type: 'bar',
data: [res.data.survey.abnormalNum, res.data.user.abnormalNum, res.data.onLine.abnormalNum, res.data.trialRun.abnormalNum]
},
{
name: '已处理',
type: 'bar',
data: [res.data.survey.processedNum, res.data.user.processedNum, res.data.onLine.processedNum, res.data.trialRun.processedNum]
}
]
}
}
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
:deep(.el-dialog__body) {
max-height: none !important;
}
</style>

View File

@@ -0,0 +1,153 @@
<!-- 暂态 -->
<template>
<el-dialog draggable title="暂态电能质量水平评估统计" v-model="dialogVisible" width="1400px">
<div>
<vxe-table v-bind="defaultAttribute" ref="vxeRef" height="360px" :data="tableData">
<vxe-column field="name" title="区域" />
<vxe-column sortable field="sagTimes" title="暂降次数" />
<vxe-column sortable field="swellTimes" title="暂升次数" />
<vxe-column sortable field="interruptTimes" title="短时中断次数" />
<vxe-colgroup title="暂态严重度占比">
<vxe-column sortable field="rate90" title="SARFI-90" />
<vxe-column sortable field="rate50" title="SARFI-50" />
<vxe-column sortable field="rate20" title="SARFI-20" />
</vxe-colgroup>
</vxe-table>
</div>
<div style="margin-top: 10px; display: flex">
<!--
-->
<div class="statistics-main">
<div class="statistics-box">
<MyEChart style="height: 250px" :options="picEChart" />
<el-table size="small" height="250px" :data="descentData">
<el-table-column prop="name" label="暂降原因" width="80px" align="center" />
<el-table-column prop="value" label="暂降次数" width="80px" align="center" />
</el-table>
</div>
<div class="statistics-box">
<MyEChart style="height: 250px" :options="picEChart1" />
<el-table size="small" height="250px" :data="resembleData">
<el-table-column prop="name" label="暂降类型" width="80px" align="center" />
<el-table-column prop="value" label="暂降次数" width="80px" align="center" />
</el-table>
</div>
</div>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { getEventReason, getEventDetailByList } from '@/api/device-boot/panorama'
const dialogVisible: any = ref(false)
const tableData: any = ref([])
const descentData = ref([])
const resembleData = ref([])
const picEChart = ref({})
const picEChart1 = ref({})
const open = async (row: any) => {
getEventDetailByList({ ...row, deviceInfoParam: row }).then((res: any) => {
tableData.value = res.data
})
getEventReason(row).then(res => {
descentData.value = res.data.reason
resembleData.value = res.data.type
picEChart.value = {
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: '10px'
},
xAxis: {
show: false
},
yAxis: {
show: false
},
options: {
dataZoom: null,
series: [
{
type: 'pie',
center: ['60%', '50%'],
radius: '50%',
label: {
show: false,
position: 'outside',
textStyle: {
//数值样式
}
},
data: res.data.reason
}
]
}
}
picEChart1.value = {
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: '10px'
},
xAxis: {
show: false
},
yAxis: {
show: false
},
options: {
dataZoom: null,
series: [
{
type: 'pie',
center: ['60%', '50%'],
radius: '50%',
label: {
show: false,
position: 'outside',
textStyle: {
//数值样式
}
},
data: res.data.type
}
]
}
}
})
dialogVisible.value = true
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
.statistics-main {
// height: 300px;
display: grid;
width: 100%;
grid-template-columns: 1fr 1fr;
.statistics-box {
// height: 300px;
// display: flex;
display: grid;
grid-template-columns: 2fr 1fr;
}
}
:deep(.el-dialog__body) {
max-height: none !important;
}
</style>

View File

@@ -0,0 +1,263 @@
<template>
<!-- 终端 -->
<el-dialog draggable title="终端统计" v-model="dialogVisible" width="1400px" :before-close="handleClose">
<el-row style="height: 300px" :gutter="20">
<el-col :span="12">
<div class="title">
<span>趋势分析</span>
<!-- <el-select v-model="time" style="width: 80px; margin-right: 80px" @change="analysis">
<el-option label="年" value="1" />
<el-option label="月" value="3" />
</el-select> -->
<el-radio-group v-model="time" style="margin-right: 50px" @change="analysis" size="small">
<el-radio-button label="1"></el-radio-button>
<el-radio-button label="3"></el-radio-button>
</el-radio-group>
</div>
<MyEChart style="height: 260px" :options="trendEChart" />
</el-col>
<el-col :span="12">
<div class="title">
<span>分布统计</span>
</div>
<div class="pie">
<MyEChart style="height: 260px; width: 50%" :options="picEChart" />
<el-table size="small" height="260px" style="width: 50%" :data="picList">
<el-table-column prop="orgName" width="80px" align="center"></el-table-column>
<el-table-column prop="onlineEvaluate" label="终端评价" align="center">
<template #default="scope">
<span
:style="{
color:
scope.row.onlineEvaluate < 60
? 'red'
: scope.row.onlineEvaluate < 90
? 'orange'
: 'green'
}"
>
{{
scope.row.onlineEvaluate < 60
? '差'
: scope.row.onlineEvaluate < 90
? '良'
: '优'
}}
</span>
</template>
</el-table-column>
<el-table-column prop="devCount" label="在运终端数" align="center" />
<el-table-column prop="devOnCount" label="在线终端数" align="center" />
</el-table>
</div>
</el-col>
</el-row>
<div>
<div class="title">
<span>区域终端统计</span>
</div>
<vxe-table v-bind="defaultAttribute" ref="vxeRef" height="325px" :data="tableData">
<vxe-column field="orgName" title="区域" />
<vxe-column field="runNum" sortable title="运行个数 " />
<vxe-column field="overhaulNum" sortable title="检修个数 " />
<vxe-column field="refundNum" sortable title="退役个数" />
<vxe-column field="onLineRate" sortable title="终端在线率(%)" />
</vxe-table>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useDictData } from '@/stores/dictData'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { getGridDiagramDevTendency, getGridDiagramDevData, getGridDiagramDevDataList } from '@/api/device-boot/panorama'
const dictData = useDictData()
const dialogVisible: any = ref(false)
const time = ref('1')
const rowList: any = ref({})
const tableData: any = ref()
const picList = ref([])
const trendEChart: any = ref({})
const picEChart = ref()
const open = async (row: any) => {
time.value = '1'
rowList.value = {
deviceInfoParam: {
...row
},
pageNum: 1,
pageSize: 1000,
...row
}
// 趋势分析
analysis(1)
dialogVisible.value = true
//分布统计
getGridDiagramDevData(rowList.value).then(res => {
picList.value = res.data
let picData: any = []
res.data.forEach((item: any) => {
picData.push({
value: item.devCount,
name: `${item.orgName}`,
itemStyle: {
color: item.onlineEvaluate < 60 ? 'red' : item.onlineEvaluate < 90 ? 'orange' : 'green'
}
})
})
picEChart.value = {
tooltip: {
trigger: 'item',
formatter: '{b} :在运终端数 {c} 台'
},
legend: {
show: false
},
xAxis: {
show: false
},
yAxis: {
show: false
},
options: {
dataZoom: null,
series: [
{
type: 'pie',
startAngle: 360,
center: ['50%', '55%'],
radius: ['40%', '60%'],
endAngle: 0,
labelLine: {
length: 8,
length2: 30,
show: true
},
label: {
padding: [0, -30],
formatter: '{b}\n\n'
},
itemStyle: {
borderColor: '#fff',
borderWidth: 1
},
data: picData
}
]
}
}
})
// 列表
getGridDiagramDevDataList({
deviceInfoParam: {
...row,
serverName: 'pqs-common',
ids: [row.id],
runFlag: [],
comFlag: [],
manufacturer: dictData.getBasicData('Dev_Manufacturers'),
statisticalType: dictData.getBasicData('Statistical_Type', ['Report_Type'])[0]
},
...row,
serverName: 'pqs-common',
ids: [row.id],
runFlag: [],
comFlag: [],
manufacturer: dictData.getBasicData('Dev_Manufacturers'),
statisticalType: dictData.getBasicData('Statistical_Type', ['Report_Type'])[0]
}).then((res: any) => {
tableData.value = res.data
})
}
const analysis = (e: any) => {
let time = rowList.value.searchBeginTime.slice(0, 4) + `-01-01`
getGridDiagramDevTendency({ ...rowList.value, searchBeginTime: time, type: e }).then(res => {
let name = []
let data = []
let num = 0
for (let k in res.data) {
name.push(k)
// num = num + res.data[k]
data.push(res.data[k])
}
trendEChart.value = {
title: {
text: '终端接入总数量'
},
xAxis: {
name: '时间',
data: name
},
legend: {
show: false
},
yAxis: {
name: '台'
},
options: {
dataZoom: null,
series: [
{
name: '接入',
type: 'line',
data: data,
smooth: true,
label: {
show: true,
position: 'top',
fontSize: 12
}
}
]
}
}
})
}
const formatter = (row: any) => {
if (row.column.field == 'onlineEvaluate') {
return row.cellValue == 3.14159 ? '/' : row.cellValue * 100
} else {
return row.cellValue
}
}
const handleClose = () => {
tableData.value = []
dialogVisible.value = false
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
:deep(.el-select) {
min-width: 80px;
}
.title {
display: flex;
justify-content: space-between;
margin: 10px;
span {
font-weight: 550;
font-size: 18px;
}
}
.pie {
display: flex;
justify-content: space-around;
}
:deep(.el-table thead) {
color: #000;
}
:deep(.el-dialog__body) {
max-height: none !important;
}
</style>