联调终端运行评价

This commit is contained in:
GGJ
2025-05-13 15:26:24 +08:00
parent 363c05639b
commit 325aa7d56e
29 changed files with 910 additions and 2075 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -36,9 +36,9 @@ const info = () => {
yAxis: {
type: 'category',
data: dataSource.map(item => item.name),
axisLabel: {
color: '#fff'
},
// axisLabel: {
// color: '#fff'
// },
splitLine: {
show: false
}
@@ -48,9 +48,9 @@ const info = () => {
data: [1,2,3,4],
axisLabel: {
show: true,
textStyle: {
color: '#FFF'
},
// textStyle: {
// color: '#FFF'
// },
// formatter: function (value) {
// }

View File

@@ -1,135 +1,164 @@
<template>
<!-- <div :style="height">
<MyEChart :options="options" />
</div> -->
<div :style="height" class="boxBG">
<!-- <div class="appraise">
<div class="iconfont icon-zonghepingjia1"></div>
<span>综合评价</span>
<span style="color: #00cc00">98</span>
<span style="color: #00b07d"></span>
</div> -->
<div class="appraise">
<div class="iconfont icon-wanzhengshuaifenxi2"></div>
<span>完整率</span>
<span style="color: #00cc00">98</span>
<span style="color: #00b07d"></span>
<div :style="height" style="overflow-y: auto">
<div class="btnsBox">
<el-radio-group v-model="radio2" @change="info">
<el-radio-button label="电压" value="Voltage_Level" />
<el-radio-button label="厂家" value="Manufacturer" />
</el-radio-group>
</div>
<div class="appraise">
<div class="iconfont icon-zaixianshuaibaobiao0"></div>
<div class="boxBG">
<div
class="appraise"
v-for="(item, i) in List"
@click="clickRow(item, i)"
:class="rowColor == i ? 'hoverBox' : ''"
>
<!-- <div class="iconfont icon-wanzhengshuaifenxi2"></div> -->
<span>在线率</span>
<span style="color: #00cc00">98</span>
<span style="color: #00b07d"></span>
<div style="flex: 1">{{ item.name }}</div>
<div style="color: #0fff04; width: 150px">{{ Math.floor(item.evaluate * 100).toFixed(0) / 100 }}</div>
<div style="width: 40px" :style="`color:${ratingColor(item.evaluate)}`">
{{ rating(item.evaluate) }}
</div>
</div>
</div>
<div class="appraise">
<div class="iconfont icon-dianyahegeshuai"></div>
<span>合格率</span>
<span style="color: #00cc00">98</span>
<span style="color: #00b07d"></span>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData'
import { getRunEvaluate } from '@/api/device-boot/runEvaluate'
import { mainHeight } from '@/utils/layout'
const options = ref({})
const emit = defineEmits(['reviewDetails'])
const props = defineProps({
params: {
type: Object,
default: () => {}
}
})
const rowColor = ref(0)
const List: any = ref([])
const dictData = useDictData()
const radio2 = ref('Voltage_Level')
const height = mainHeight(520, 1.5)
const timer: any = ref(null)
const classificationData = dictData.getBasicData('Statistical_Type', ['Report_Type'])
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]
}
}
}
]
getRunEvaluate({
...props.params,
statisticalType: classificationData.filter(item => item.code == radio2.value)[0]
}).then(res => {
clearInterval(timer.value)
List.value = res.data
clickRow(List.value[0], 0)
setTime()
})
}
const setTime = () => {
timer.value = setInterval(() => {
if (rowColor.value == List.value.length - 1) {
rowColor.value = 0
} else {
rowColor.value += 1
}
clickRow(List.value[rowColor.value], rowColor.value)
}, 1000 * 5)
}
const rating = (num: number) => {
if (num >= 90) {
return '优秀'
} else if (num >= 80) {
return '良好'
} else if (num >= 70) {
return '一般'
} else {
return '较差'
}
}
const ratingColor = (num: number) => {
if (num >= 90) {
return '#0fff04'
} else if (num >= 80) {
return '#2b7fd3'
} else if (num >= 70) {
return '#ffcc33'
} else {
return '#97017e'
}
}
const clickRow = (item: any, i: number) => {
rowColor.value = i
emit('reviewDetails', item)
}
onMounted(() => {
info()
onBeforeUnmount(() => {
clearInterval(timer.value)
})
defineExpose({
info
})
</script>
<style lang="scss" scoped>
.btnsBox {
position: absolute;
right: 5px;
top: 0px;
}
::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;
}
}
.boxBG {
display: flex;
// flex-wrap: wrap;
flex-direction: column;
// margin-top: 10px;
justify-content: space-around;
overflow: hidden;
width: 100%;
.appraise {
height: 30px;
// height: 30px;
width: 99%;
background-image: url('@/assets/imgs/bg02.png');
background-size: 100% 100%;
display: inline-block;
height: 20%;
min-height: 80px;
padding: 10px 30px 10px 10px;
margin-top: 10px;
color: #fff;
display: flex;
justify-content: space-around;
// justify-content: space-around;
align-items: center;
font-size: 20px;
span:nth-child(2) {
width: 80px;
font-size: 16px;
div {
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.iconfont {
display: flex;
@@ -145,4 +174,8 @@ onMounted(() => {
}
}
}
.hoverBox {
background-color: var(--el-color-primary-light-5);
// background-image: none !important;
}
</style>

View File

@@ -1,17 +1,22 @@
<template>
<div style="height:150px" class="box">
<div style="height: 150px" class="box1">
<div class="boxDiv">
<div style="color: #07ccca">300</div>
<div style="color: #07ccca">{{ props.params.allNum }}</div>
<img src="@/assets/imgs/ditu.png" />
<div class="mt10 divBot">总数</div>
</div>
<div class="boxDiv">
<div style="color: #339900">250</div>
<div style="color: #339900">{{ props.params.runNum }}</div>
<img src="@/assets/imgs/ditu.png" />
<div class="mt10 divBot">在运</div>
</div>
<div class="boxDiv">
<div style="color: #cc0000">50</div>
<div style="color: #ffbf00">{{ props.params.checkNum }}</div>
<img src="@/assets/imgs/ditu.png" />
<div class="mt10 divBot">调试</div>
</div>
<div class="boxDiv">
<div style="color: #cc0000">{{ props.params.stopRunNum }}</div>
<img src="@/assets/imgs/ditu.png" />
<div class="mt10 divBot">停运</div>
</div>
@@ -23,37 +28,41 @@ import MyEChart from '@/components/echarts/MyEchart.vue'
import { mainHeight } from '@/utils/layout'
import { color } from '@/components/echarts/color'
const height = mainHeight(330, 3)
const props = defineProps({
params: {
type: Object,
default: () => {}
}
})
const info = () => {}
onMounted(() => {
info()
})
</script>
<style lang="scss" scoped>
.box {
.box1 {
display: flex;
align-items: center;
.boxDiv {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
margin-top: 20px;
img {
width: 80%;
width: 90%;
}
div:nth-child(1) {
position: absolute;
font-size: 30px;
top: -10px;
top: -20px;
font-weight: 700;
}
.divBot {
font-size: 16px;
position: absolute;
top: -45px;
top: 10px;
}
color: #fff;
}

View File

@@ -1,12 +1,13 @@
<template>
<div :style="height" class="mt10">
<vxe-table height="auto" v-bind="defaultAttribute" :data="tableData">
<vxe-column type="seq" width="80px" 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-column type="seq" width="70px" title="序号"></vxe-column>
<vxe-column field="name" title="终端名称"></vxe-column>
<vxe-column field="subName" title="所属电站"></vxe-column>
<vxe-column field="integrityRate" title="完整率(%)"></vxe-column>
<vxe-column field="onLineRate" title="在线率(%)"></vxe-column>
<vxe-column field="passRate" title="合格率(%)"></vxe-column>
<vxe-column field="evaluate" title="评分(分)"></vxe-column>
</vxe-table>
</div>
</template>
@@ -14,27 +15,23 @@
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'
import { getRunEvaluateDetail } from '@/api/device-boot/runEvaluate'
const props = defineProps({
params: {
type: Object,
default: () => {}
}
])
})
const tableData = ref([])
const height = mainHeight(360, 3)
const info = () => {}
onMounted(() => {
info()
const info = () => {
getRunEvaluateDetail({ ...props.params, ids: [] }).then(res => {
tableData.value = res.data
})
}
defineExpose({
info
})
</script>
<style lang="scss" scoped>
@@ -51,12 +48,12 @@ onMounted(() => {
background-color: #ffffff00 !important;
}
:deep(.vxe-table--body .vxe-body--row) {
background-color:#ffffff2e !important;
background-color: #ffffff2e !important;
}
:deep(.vxe-table--render-default .vxe-table--body-wrapper table) {
background-color: #00000000 !important;
color: #fff;
color: #000;
}
:deep(
.vxe-table--render-default.border--full .vxe-body--column,
@@ -66,17 +63,14 @@ onMounted(() => {
) {
background-image: linear-gradient(#00fff4, #00fff4), linear-gradient(#00fff4, #00fff4);
}
:deep(
.vxe-table--render-default.border--full .vxe-header--column
) {
: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){
: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;
color: #fff;
}
</style>

View File

@@ -9,114 +9,114 @@ import echarts from '@/components/echarts/echarts'
import { useDictData } from '@/stores/dictData'
import { color } from '@/components/echarts/color'
import { mainHeight } from '@/utils/layout'
import { useConfig } from '@/stores/config'
const config = useConfig()
const height = mainHeight(330, 3)
const chartRef = ref<HTMLDivElement>()
const info = () => {
const info = (item: any) => {
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
},
let everyDepartment = {
stages: [
{ name: '在线率', max: 100 },
{ name: '合格率', max: 100 },
{ name: '完整率', max: 100 }
],
scores: [item.onLineRate, item.passRate, item.integrityRate]
}
function contains(arr, obj) {
var i = arr.length
while (i--) {
if (arr[i].name === obj) {
return i
}
}
return false
}
let option = {
backgroundColor: '',
color: ['#fff'],
radar: {
shape: 'circle',
center: ['50%', '55%'],
center: ['50%', '65%'],
radius: '80%',
triggerEvent: true,
name: {
textStyle: {
color: '#fff',
fontSize: 14
rich: {
a: {
color: '#000',
fontSize: 14,
lineHeight: 20
},
b: {
color: config.layout.elementUiPrimary[0],
fontSize: 16,
align: 'center'
},
triggerEvent: true
},
formatter: (a, index) => {
let values = a.length > 6 ? a.slice(0, 6) + '...' : a
let i = contains(everyDepartment.stages, a) // 处理对应要显示的样式
return `{a| ${values}}{b| ${(everyDepartment.scores[i])}%}`
}
},
indicator: [
{
text: '完整率',
min: 0,
max: 100
},
{
text: '合格率',
min: 0,
max: 100
},
{
text: '在线率',
min: 0,
max: 100
}
],
indicator: everyDepartment.stages,
startAngle: 90,
splitNumber: 5,
splitArea: {
// 坐标轴在 grid 区域中的分隔区域,默认不显示。
show: true,
areaStyle: {
// 分隔区域的样式设置。
color: ['rgba(27, 50, 66, 0.4)']
color: ['#FFFFFF', '#F5F9FF'].reverse()
}
},
axisLabel: {
show: false
},
axisLine: {
//指向外圈文本的分隔线样式
show: true,
lineStyle: {
color: '#5aa3d0'
color: '#D2E4F8'
}
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(99,192,251,0.2)', // 分隔线颜色
width: 2 // 分隔线线宽
color: '#D2E4F8'
}
}
},
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]
}
]
}
series: [
{
type: 'radar',
// 外线框
symbol: 'none',
areaStyle: {
normal: {
color: `${config.layout.elementUiPrimary[0]}69`
}
},
itemStyle: {
color: config.layout.elementUiPrimary[0]
},
data: [
{
value: everyDepartment.scores
}
]
}
]
}
chart.setOption(option)
window.addEventListener('resize', () => {
chart.resize() // 调用 resize 方法
})
}
onMounted(() => {
info()
defineExpose({
info
})
</script>
<style lang="scss" scoped></style>

View File

@@ -8,112 +8,78 @@ import { ref, reactive, onMounted } from 'vue'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { mainHeight } from '@/utils/layout'
import { yMethod } from '@/utils/echartMethod'
import { lastWeekTrend } from '@/api/device-boot/runEvaluate'
const props = defineProps({
params: {
type: Object,
default: () => {}
}
})
const options = ref({})
const height = mainHeight(330, 3)
const height = mainHeight(290, 3)
const info = () => {
let [min, max] = yMethod([80, 99])
options.value = {
xAxis: {
axisLabel: {
show: true,
textStyle: {
color: '#FFF'
lastWeekTrend(props.params).then((res: any) => {
options.value = {
xAxis: {
axisLabel: {
show: true
},
splitLine: {
show: false
},
axisTick: {
show: false
},
axisLine: {
show: true
},
data: res.data.date
},
grid: {
top: '30',
left: '10',
right: '10'
},
toolbox: {
show: false
},
yAxis: {
min: 0,
max: 100,
axisLine: {
show: true
},
splitLine: {
show: false
}
},
splitLine: {
show: false
legend:{
top: '5',
right: '5',
type: 'scroll',
},
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'
options: {
series: []
}
},
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]
}
]
}
}
res.data.name.forEach((item: any, i: number) => {
options.value.options.series.push({
name: item,
type: 'line',
symbol: 'circle',
smooth: true,
showSymbol: false,
data: res.data.score[i]
})
})
})
}
onMounted(() => {
info()
onMounted(() => {})
defineExpose({
info
})
</script>
<style lang="scss" scoped></style>