联调数据清洗页面 绘制终端运行评价页面

This commit is contained in:
GGJ
2025-04-03 16:08:47 +08:00
parent 3c84c41d35
commit 69aece65c1
34 changed files with 3005 additions and 2337 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,124 @@
<template>
<div class="mt10 mr5 btnsBox">
<el-radio-group v-model="radio2">
<el-radio-button label="区域" value="1" />
<el-radio-button label="变电站" value="2" />
<el-radio-button label="用户" value="3" />
</el-radio-group>
</div>
<div :style="height">
<MyEChart :options="options" />
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { mainHeight } from '@/utils/layout'
const radio2 = ref('1')
const height = mainHeight(300, 1.5)
const options = ref({})
const info = () => {
let dataSource = [
{ value: '90', name: '张家口' },
{ value: '80', name: '廊坊' },
{ value: '70', name: '秦皇岛' },
{ value: '60', name: '唐山' },
{ value: '50', name: '承德' },
]
options.value = {
xAxis: {
type: 'value',
axisLabel: {
show: true,
textStyle: {
color: '#FFF'
}
},
splitLine: {
show: false
},
axisTick: {
show: false
},
axisLine: {
show: true
}
},
grid: {
top: '10'
},
toolbox: {
show: false
},
options: {
yAxis: {
type: 'category',
data: dataSource.map(item => item.name),
axisLabel: {
color: '#fff'
},
splitLine: {
show: false
}
},
dataZoom: null,
series: [
{
type: 'bar',
itemStyle: {
color: function (params) {
return params.value >= 90
? '#009900'
: params.value >= 60
? '#FFCC00'
: params.value > 0
? '#CC0000'
: '#CCC'
}
},
data: dataSource.map(item => item.value)
}
]
}
}
}
onMounted(() => {
info()
})
</script>
<style lang="scss" scoped>
.btnsBox {
display: flex;
justify-content: end;
}
::v-deep .el-radio-button__inner {
padding: 8px 18px;
background: var(--el-color-primary);
border: 1px solid #00fff4;
border-radius: 0;
font-weight: normal;
color: #ffffff;
text-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.73);
opacity: 0.52;
}
::v-deep .el-radio-button:last-child .el-radio-button__inner {
border-radius: 0;
}
::v-deep .el-radio-button:first-child .el-radio-button__inner {
border-radius: 0;
border-left: 1px solid #00fff4;
}
::v-deep .is-active {
border: 1px solid #00fff4;
opacity: 1 !important;
color: #ffffff;
background: var(--el-color-primary);
.el-radio-button__inner{
opacity: 1 !important;
border-left: 1px solid #00fff4 !important;
}
}
</style>

View File

@@ -0,0 +1,138 @@
<template>
<div :style="height">
<MyEChart :options="options" />
</div>
<div class="boxBG">
<div class="appraise">
<div class="iconfont icon-wanzhengshuaifenxi2"></div>
<div class="right">
<span>完整率</span>
<span></span>
</div>
</div>
<div class="appraise">
<div class="iconfont icon-zaixianshuaibaobiao0"></div>
<div class="right">
<span>在线率</span>
<span></span>
</div>
</div>
<div class="appraise">
<div class="iconfont icon-dianyahegeshuai"></div>
<div class="right">
<span>合格率</span>
<span></span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { mainHeight } from '@/utils/layout'
const options = ref({})
const height = mainHeight(650, 1.5)
const info = () => {
options.value = {
xAxis: {
axisLabel: {
show: true,
textStyle: {
color: '#FFF'
}
},
splitLine: {
show: false
},
axisTick: {
show: false
},
axisLine: {
show: true
},
data: ['运行', '调试', '停运']
},
grid: {
top: '30'
},
toolbox: {
show: false
},
yAxis: {
axisLine: {
show: true
},
axisLabel: {
color: '#fff'
},
splitLine: {
show: false
}
},
options: {
dataZoom: null,
series: [
{
type: 'bar',
data: [45, 5, 1],
itemStyle: {
color: function (params) {
// 根据索引返回不同颜色
var colorList = ['#00CC00', '#FF9900', '#CC0000']
return colorList[params.dataIndex]
}
}
}
]
}
}
}
onMounted(() => {
info()
})
</script>
<style lang="scss" scoped>
.boxBG {
display: flex;
justify-content: space-around;
.appraise {
width: 30%;
background-image: url('@/assets/imgs/bg02.png');
background-size: 100% 100%;
display: inline-block;
height: 80px;
color: #fff;
display: flex;
justify-content: center;
.right {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 14px;
span:nth-child(2) {
font-size: 20px;
font-weight: 600;
margin-top: 5px;
color: #00cc00;
}
}
.iconfont {
width: 50px;
height: 50px;
background-color: var(--el-color-primary);
font-size: 30px;
text-align: center;
line-height: 50px;
border-radius: 10px;
margin: 15px 10px 15px 0;
}
}
}
</style>

View File

@@ -0,0 +1,61 @@
<template>
<div style="height:150px" class="box">
<div class="boxDiv">
<div style="color: #07ccca">300</div>
<img src="@/assets/imgs/ditu.png" />
<div class="mt10 divBot">总数</div>
</div>
<div class="boxDiv">
<div style="color: #339900">250</div>
<img src="@/assets/imgs/ditu.png" />
<div class="mt10 divBot">在运</div>
</div>
<div class="boxDiv">
<div style="color: #cc0000">50</div>
<img src="@/assets/imgs/ditu.png" />
<div class="mt10 divBot">停运</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { mainHeight } from '@/utils/layout'
import { color } from '@/components/echarts/color'
const height = mainHeight(330, 3)
const info = () => {}
onMounted(() => {
info()
})
</script>
<style lang="scss" scoped>
.box {
display: flex;
align-items: center;
.boxDiv {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
margin-top: 20px;
img {
width: 80%;
}
div:nth-child(1) {
position: absolute;
font-size: 30px;
top: -10px;
font-weight: 700;
}
.divBot {
font-size: 16px;
position: absolute;
top: -45px;
}
color: #fff;
}
}
</style>

View File

@@ -0,0 +1,82 @@
<template>
<div :style="height" class="mt10">
<vxe-table height="auto" v-bind="defaultAttribute" :data="tableData">
<vxe-column type="seq" title="序号"></vxe-column>
<vxe-column field="a" title="终端名称"></vxe-column>
<vxe-column field="b" title="所属电站"></vxe-column>
<vxe-column field="c" title="完整性"></vxe-column>
<vxe-column field="d" title="在线率"></vxe-column>
<vxe-column field="e" title="合格率"></vxe-column>
</vxe-table>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { mainHeight } from '@/utils/layout'
import { defaultAttribute } from '@/components/table/defaultAttribute'
const tableData = ref([
{
a: '025875',
b: '测试变电站1',
c: '60',
d: '95',
e: '66'
},
{
a: '025876',
b: '测试变电站2',
c: '60',
d: '95',
e: '66'
}
])
const height = mainHeight(360, 3)
const info = () => {}
onMounted(() => {
info()
})
</script>
<style lang="scss" scoped>
// :deep(.vxe-header--row) {
// background: #071de2 !important;
// color: #fff !important;
// }
/*调整表格 单元格背景颜色*/
:deep(.vxe-table .vxe-table--body-wrapper, .vxe-table .vxe-table--footer-wrapper) {
background: #ffffff00 !important;
}
:deep(.vxe-table--render-wrapper) {
background-color: #ffffff00 !important;
}
:deep(.vxe-table--body .vxe-body--row) {
background-color:#ffffff2e !important;
}
:deep(.vxe-table--render-default .vxe-table--body-wrapper table) {
background-color: #00000000 !important;
color: #fff;
}
:deep(
.vxe-table--render-default.border--full .vxe-body--column,
.vxe-table--render-default.border--full .vxe-footer--column,
.vxe-table--render-default.border--full .vxe-header--column,
) {
background-image: linear-gradient(#00fff4, #00fff4), linear-gradient(#00fff4, #00fff4);
}
:deep(
.vxe-table--render-default.border--full .vxe-header--column
) {
background-image: linear-gradient(#00fff4, #00fff4), linear-gradient(#00fff4, #00fff4) !important;
}
:deep(.vxe-table--render-default .vxe-table--border-line){
border: var(--vxe-table-border-width) solid #00fff4;
}
:deep(.vxe-header--row) {
background: var(--el-color-primary);
color:#fff;
}
</style>

View File

@@ -0,0 +1,122 @@
<template>
<div>
<div :style="height" style="width: 100%" ref="chartRef"></div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import echarts from '@/components/echarts/echarts'
import { useDictData } from '@/stores/dictData'
import { color } from '@/components/echarts/color'
import { mainHeight } from '@/utils/layout'
const height = mainHeight(330, 3)
const chartRef = ref<HTMLDivElement>()
const info = () => {
let chart = echarts.init(chartRef.value as HTMLDivElement)
let option = {
toolbox: {
show: false
},
tooltip: {
trigger: 'item',
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 14
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
confine: true
},
radar: {
shape: 'circle',
center: ['50%', '55%'],
name: {
textStyle: {
color: '#fff',
fontSize: 14
}
},
indicator: [
{
text: '完整率',
min: 0,
max: 100
},
{
text: '合格率',
min: 0,
max: 100
},
{
text: '在线率',
min: 0,
max: 100
}
],
splitArea: {
// 坐标轴在 grid 区域中的分隔区域,默认不显示。
show: true,
areaStyle: {
// 分隔区域的样式设置。
color: ['rgba(27, 50, 66, 0.4)']
}
},
axisLine: {
//指向外圈文本的分隔线样式
lineStyle: {
color: '#5aa3d0'
}
},
splitLine: {
lineStyle: {
color: 'rgba(99,192,251,0.2)', // 分隔线颜色
width: 2 // 分隔线线宽
}
}
},
series: {
name: '',
type: 'radar',
symbolSize: 8,
itemStyle: {
borderColor: color[1],
borderWidth: 2
},
areaStyle: {
normal: {
width: 1,
opacity: 0.3
}
},
data: [
{
itemStyle: {
normal: {
color: color[1]
}
},
value: [20, 33, 80]
}
]
}
}
chart.setOption(option)
}
onMounted(() => {
info()
})
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,119 @@
<template>
<div :style="height">
<MyEChart :options="options" />
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { mainHeight } from '@/utils/layout'
import { yMethod } from '@/utils/echartMethod'
const options = ref({})
const height = mainHeight(330, 3)
const info = () => {
let [min, max] = yMethod([80, 99])
options.value = {
xAxis: {
axisLabel: {
show: true,
textStyle: {
color: '#FFF'
}
},
splitLine: {
show: false
},
axisTick: {
show: false
},
axisLine: {
show: true
},
data: ['03-24', '03-25', '03-26', '03-27', '03-28', '03-29', '03-30']
},
legend: {
textStyle: {
color: '#fff'
}
},
grid: {
top: '50',
left: '20',
right: '20'
},
toolbox: {
show: false
},
yAxis: {
min: min,
max: 100,
axisLine: {
show: true
},
axisLabel: {
color: '#fff'
},
splitLine: {
show: false
}
},
// color: [color[1]],
// ['承德', '唐山', '秦皇岛', '廊坊', '张家口']
options: {
dataZoom: null,
series: [
{
name: '承德',
type: 'line',
symbol: 'circle',
smooth: true,
showSymbol: false,
data: [80, 82, 90, 92, 97,100,100]
},
{
name: '唐山',
type: 'line',
symbol: 'circle',
smooth: true,
showSymbol: false,
data: [83, 84, 91, 93, 98,100,100]
},
{
name: '秦皇岛',
type: 'line',
symbol: 'circle',
smooth: true,
showSymbol: false,
data: [84, 82, 90, 90, 95,100,100]
},
{
name: '廊坊',
type: 'line',
symbol: 'circle',
smooth: true,
showSymbol: false,
data: [87, 82, 90, 94, 97,100,100]
},
{
name: '张家口',
type: 'line',
symbol: 'circle',
smooth: true,
showSymbol: false,
data: [90, 92, 95, 97, 100,100,100]
}
]
}
}
}
onMounted(() => {
info()
})
</script>
<style lang="scss" scoped></style>

View File

@@ -20,9 +20,108 @@
</template>
<template v-slot:operation>
<el-button type="primary" class="ml10" @click="toggle" :icon="leftVisible ? 'el-icon-Hide' : 'el-icon-View'">
<el-button
type="primary"
class="ml10"
@click="toggle"
:icon="leftVisible ? 'el-icon-Hide' : 'el-icon-View'"
>
{{ leftVisible ? '隐藏' : '显示' }}
</el-button>
<el-tooltip placement="left-start">
<InfoFilled style="height: 20px" class="ml10" />
<!-- <el-button circle icon="el-icon-InfoFilled" /> -->
<template #content>
<div style="font-size: 16px " class="mt10 mb10">
<div>终端在线率</div>
<div class="em1">定义终端在指定时间段内处于在线状态的时间比例</div>
<div class="em1">计算方法在线率=终端在线时间/总监测时间×100%</div>
<div class="em1">评价标准</div>
<div class="em2">
<span style="color: #00b07d">优秀</span>
 在线率 95%
</div>
<div class="em2">
<span style="color: #2b7fd3">良好</span>
 90% 在线率 < 95
</div>
<div class="em2">
<span style="color: #ffcc33">一般</span>
 80% 在线率 < 90%
</div>
<div class="em2">
<span style="color: #97017e">较差</span>
 在线率 < 80%
</div>
<div class="mt10">数据完整性</div>
<div class="em1">定义终端上传数据的完整性和连续性</div>
<div class="em1">计算方法数据完整性=实际上传数据量/预期上传数据量×100%</div>
<div class="em1">评价标准</div>
<div class="em2">
<span style="color: #00b07d">优秀</span>
 完整性 98%
</div>
<div class="em2">
<span style="color: #2b7fd3">良好</span>
 95% 完整性 < 98%
</div>
<div class="em2">
<span style="color: #ffcc33">一般</span>
 90% 完整性 < 95%
</div>
<div class="em2">
<span style="color: #97017e">较差</span>
 完整性 < 90%
</div>
<div class="mt10">数据合格率</div>
<div class="em1">定义终端上传数据的合格率(以谐波电压为代表)</div>
<div class="em1">计算方法合格率=合格数据量/总数据量×100%</div>
<div class="em1">评价标准</div>
<div class="em2">
<span style="color: #00b07d">优秀</span>
 完整性 98%
</div>
<div class="em2">
<span style="color: #2b7fd3">良好</span>
 95% 完整性 < 98%
</div>
<div class="em2">
<span style="color: #ffcc33">一般</span>
 90% 完整性 < 95%
</div>
<div class="em2">
<span style="color: #97017e">较差</span>
 完整性 < 90%
</div>
<div class="mt10">综合评价方法</div>
<div class="em1">权重分配:根据各维度的重要性分配不同的权重例如:</div>
<div class="em2">终端在线率:20%</div>
<div class="em2">数据完整性:50%</div>
<div class="em2">数据合格率:30%</div>
<div class="em1">综合评分:综合评分=(单项评分x权重)</div>
<div class="em1">评价等级:</div>
<div class="em2">
<span style="color: #00b07d">优秀</span>
 综合评分 90
</div>
<div class="em2">
<span style="color: #2b7fd3">良好</span>
 80 综合评分 < 90
</div>
<div class="em2">
<span style="color: #ffcc33">一般</span>
 70 综合评分 < 80
</div>
<div class="em2">
<span style="color: #97017e">较差</span>
 综合评分 < 70
</div>
</div>
</template>
</el-tooltip>
</template>
</TableHeader>
<Map />
@@ -30,6 +129,7 @@
<transition name="slide-left">
<div class="left" :style="height" v-if="leftVisible">
<BorderBox13
style="height: 200px"
:color="[color[0], color[0]]"
class="box"
:backgroundColor="`${color[0]}24`"
@@ -39,10 +139,12 @@
<span class="iconfont icon-zhongduantongji-xian"></span>
终端统计
</div>
<statistics />
</BorderBox13>
<BorderBox13
:color="[color[0], color[0]]"
class="box"
style="flex: 1"
:backgroundColor="`${color[0]}24`"
title="终端运行评价"
>
@@ -50,8 +152,10 @@
<span class="iconfont icon-daipingjia"></span>
终端运行评价
</div>
<run />
</BorderBox13>
<BorderBox13
:style="height3"
:color="[color[0], color[0]]"
class="box"
:backgroundColor="`${color[0]}24`"
@@ -61,6 +165,7 @@
<span class="iconfont icon-a-qushi1"></span>
最近一周终端评价趋势
</div>
<week />
</BorderBox13>
</div>
</transition>
@@ -77,18 +182,23 @@
<span class="iconfont icon-a-ziyuan118"></span>
区域终端运行评价
</div>
<region />
</BorderBox13>
<BorderBox13
:color="[color[0], color[0]]"
class="box"
:backgroundColor="`${color[0]}24`"
title="终端运行评价详情"
>
<div class="title">
<span class="iconfont icon-yunhangxiangqing"></span>
终端运行评价详情
</div>
</BorderBox13>
<div :style="height3">
<BorderBox13
style="height: 100%"
:color="[color[0], color[0]]"
class="box"
:backgroundColor="`${color[0]}24`"
title="终端运行评价详情"
>
<div class="title">
<span class="iconfont icon-yunhangxiangqing"></span>
终端运行评价详情
</div>
<terminalOperation />
</BorderBox13>
</div>
</div>
</transition>
@@ -104,6 +214,8 @@
<span class="iconfont icon-yichangxiangqing-xian"></span>
异常终端详情
</div>
<terminalDetails />
<table />
</BorderBox13>
</div>
</transition>
@@ -118,6 +230,13 @@ import { mainHeight } from '@/utils/layout'
import Map from './components/map.vue'
import { BorderBox13 } from '@kjgl77/datav-vue3'
import { useConfig } from '@/stores/config'
import terminalOperation from './components/terminalOperation.vue'
import region from './components/region.vue'
import { InfoFilled } from '@element-plus/icons-vue'
import week from './components/week.vue'
import terminalDetails from './components/terminalDetails.vue'
import statistics from './components/statistics.vue'
import run from './components/run.vue'
const config = useConfig()
const color = config.layout.elementUiPrimary
const dictData = useDictData()
@@ -257,4 +376,12 @@ onMounted(() => {
transform: translateY(100%);
opacity: 0;
}
.em1 {
margin-top: 5px;
text-indent: 1em;
}
.em2 {
margin-top: 5px;
text-indent: 2em;
}
</style>