联调终端运行评价

This commit is contained in:
GGJ
2025-05-15 14:52:02 +08:00
parent 325aa7d56e
commit 67718efe57
22 changed files with 672 additions and 330 deletions

View File

@@ -15,3 +15,11 @@ export function ledgerChangePush() {
method: 'post'
})
}
// 台账变更推送
export function getPushResult(data: any) {
return request({
url: '/device-boot/device/getPushResult',
method: 'post',
params: data
})
}

View File

@@ -61,3 +61,12 @@ export function getTransientValue(data: any) {
data
})
}
// 周报导出
export function getExport(data: any) {
return createAxios({
url: '/event-boot/report/getExport',
method: 'post',
data,
responseType: 'blob'
})
}

BIN
src/assets/terminal0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

BIN
src/assets/terminal1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

BIN
src/assets/terminal2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 B

View File

@@ -16,6 +16,7 @@
</template>
</TableHeader>
<Table ref="tableRef"></Table>
<pushDisplay ref="pushDisplayRef" />
</div>
</template>
<script setup lang="ts">
@@ -27,9 +28,11 @@ import TableHeader from '@/components/table/header/index.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { ledgerChangePush } from '@/api/device-boot/terminalTree'
import pushDisplay from './pushDisplay.vue'
defineOptions({
name: 'BusinessAdministrator/LogManagement/TerminalLog'
})
const pushDisplayRef = ref()
const dictData = useDictData()
const fontdveoption = dictData.getBasicData('Dev_Ops')
@@ -78,7 +81,8 @@ const changePush = () => {
type: 'warning'
}).then(() => {
ledgerChangePush().then(res => {
ElMessage.success(res.message)
// ElMessage.success(res.message)
pushDisplayRef.value.open(res.data)
tableStore.index()
})
})

View File

@@ -0,0 +1,108 @@
<!--生产线的新增编辑弹出框-->
<template>
<el-dialog draggable v-model="productLineVisible" :title="title" style="width: 600px">
<div v-for="(item, index) in List" :key="index">
<div style="display: flex">
<span class="span">{{ item.command }}</span>
<span
v-if="item.result == 2"
v-loading="true"
:element-loading-svg="svg"
class="custom-loading-svg"
element-loading-svg-view-box="-10, -10, 50, 50"
></span>
<CircleCheckFilled class="ml5" v-if="item.result == 1" style="width: 16px; color: #0e8780" />
<CircleCloseFilled class="ml5" v-if="item.result == 0" style="width: 16px; color: #ff0000" />
</div>
<div v-if="item.result != 2" class="text mt5">
<span class="span">推送结果</span>
<span :style="item.result == 1 ? 'color: #0e8780' : 'color: #ff0000'">
{{ item.text }}
</span>
</div>
<el-divider />
</div>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, inject } from 'vue'
import { ElMessage } from 'element-plus'
import { CircleCheckFilled, CircleCloseFilled } from '@element-plus/icons-vue'
import { getPushResult } from '@/api/device-boot/terminalTree'
const productLineVisible = ref(false)
const title = ref('台账变更推送')
const List: any = ref([])
const svg = `
<path class="path" d="
M 30 15
L 28 17
M 25.61 25.61
A 15 15, 0, 0, 1, 15 30
A 15 15, 0, 1, 1, 27.99 7.5
L 15 15
" style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
`
const time: any = ref(null)
const val = ref(0)
const open = async (data: any) => {
List.value = []
val.value = 0
List.value = data
productLineVisible.value = true
query()
time.value = setInterval(() => {
query()
}, 1000 * 5)
}
const query = () => {
val.value += 1
if (val.value == 6) {
clearInterval(time.value)
time.value = null
val.value = 0
List.value.forEach((item: any) => {
if (item.result == 2) {
item.result = 0
item.text = '推送超时!'
}
})
}
List.value.forEach(async (item: any) => {
getPushResult({
guid: item.guid
}).then((res: any) => {
item.result = res.data.code
item.text = res.data.result
})
})
}
defineExpose({ open })
</script>
<style scoped>
.el-upload-list__item {
transition: none !important;
}
.el-select {
min-width: 180px;
}
:deep(.el-divider--horizontal) {
margin: 10px 0;
}
:deep(.circular) {
height: 30px;
width: 30px;
margin-top: 5px;
}
.text {
text-indent: 1em;
}
.span {
font-weight: 600;
font-size: 14px;
}
</style>

View File

@@ -57,7 +57,17 @@
>
<template #default="{ node, data }">
<div class="custom-tree-node">
<span>{{ node.label }}</span>
<span>
<span v-if="data.processState != null">
{{ node.label }}
</span>
<span v-else>{{ data.subName }}_{{ data.name }}</span>
<span
v-if="data.processState != null"
class="iconSpan"
:style="{ background: data.processState == 0 ? '#ff0000' : '#00b07d' }"
></span>
</span>
<div>
<!-- <el-button type="primary" v-if="data.id == undefined" link icon="el-icon-Plus" ></el-button> -->
<el-button
@@ -191,7 +201,7 @@ const popUps = ref(false)
const tableRef = ref()
const processNo = ref('')
const ruleFormRef = ref()
const dataSource:any = ref([])
const dataSource: any = ref([])
const defaultProps = {
children: 'deviceInfoList',
label: 'name'
@@ -483,4 +493,12 @@ const addMenu = () => {}
padding-right: 8px;
width: 300px;
}
.iconSpan {
display: inline-block;
width: 8px;
height: 8px;
margin-left: 3px;
border-radius: 50%;
margin-bottom: 2px;
}
</style>

View File

@@ -108,7 +108,7 @@
<bm-info-window :show="infoWindowPoint.show" @close="infoWindowPoint.show = false">
<el-descriptions :title="infoWindowPoint.lineName" :column="1" v-if="infoWindowPoint.lineId">
<el-descriptions-item label="供电公司">{{ infoWindowPoint.gdName }}</el-descriptions-item>
<el-descriptions-item label="变电站">{{ infoWindowPoint.subName }}</el-descriptions-item>
<el-descriptions-item label="变电站(场站)">{{ infoWindowPoint.subName }}</el-descriptions-item>
<el-descriptions-item label="母线">{{ infoWindowPoint.voltageName }}</el-descriptions-item>
<el-descriptions-item label="网络参数">
{{ infoWindowPoint.ip }}
@@ -637,5 +637,8 @@ defineExpose({ addMarkers, locatePositions, reset, grids, radiusPop, flyTo })
}
}
}
:deep(.el-descriptions__cell) {
white-space: nowrap;
}
</style>
./cds.js./boundary

View File

@@ -88,7 +88,7 @@
>
<bm-label
v-if="zoom > 14"
:content="path.lineName"
:content="path.deviceName"
:labelStyle="{
color: '#fff',
border: '0px solid #fff',
@@ -106,31 +106,25 @@
<!-- 详情 -->
<bm-marker :position="infoWindowPoint" :icon="{ url: '1', size: { width: 0, height: 0 } }">
<bm-info-window :show="infoWindowPoint.show" @close="infoWindowPoint.show = false">
<el-descriptions :title="infoWindowPoint.lineName" :column="1" v-if="infoWindowPoint.lineId">
<el-descriptions
style="width: auto"
:title="infoWindowPoint.deviceName"
:column="1"
v-if="infoWindowPoint.lineId"
>
<el-descriptions-item label="供电公司">{{ infoWindowPoint.gdName }}</el-descriptions-item>
<el-descriptions-item label="变电站">{{ infoWindowPoint.subName }}</el-descriptions-item>
<el-descriptions-item label="母线">{{ infoWindowPoint.voltageName }}</el-descriptions-item>
<el-descriptions-item label="变电站(场站)">{{ infoWindowPoint.subName }}</el-descriptions-item>
<el-descriptions-item label="网络参数">
{{ infoWindowPoint.ip }}
</el-descriptions-item>
<el-descriptions-item label="PT变化">{{ infoWindowPoint.pt2 }}</el-descriptions-item>
<el-descriptions-item label="CT变化">{{ infoWindowPoint.ct2 }}</el-descriptions-item>
<el-descriptions-item label="生产厂家">
{{ infoWindowPoint.manufacturer }}
</el-descriptions-item>
<el-descriptions-item label="终端状态">
{{
infoWindowPoint.runFlag == 0 ? '投运' : infoWindowPoint.runFlag == 1 ? '热备用' : '停运'
}}
</el-descriptions-item>
<el-descriptions-item label="通讯状态">
{{ infoWindowPoint.comFlag == 0 ? '中断' : '正常' }}
</el-descriptions-item>
<el-descriptions-item>
<el-button type="primary" size="small" @click="lookPoint(infoWindowPoint)">
查看详情
</el-button>
</el-descriptions-item>
</el-descriptions>
<el-descriptions
:title="infoWindowPoint.subName"
@@ -156,7 +150,7 @@
</div>
<!-- 信息弹框 -->
<div v-if="zoom <= 9">
<!-- <div v-if="zoom <= 9">
<bm-overlay
v-for="item in AreaData"
pane="labelPane"
@@ -200,7 +194,7 @@
</div>
</div>
</bm-overlay>
</div>
</div> -->
</baidu-map>
</div>
</template>
@@ -214,9 +208,10 @@ import { useDictData } from '@/stores/dictData'
import { Search } from '@element-plus/icons-vue'
import { BaiduMap, BmOverlay } from 'vue-baidu-map-3x'
import { getAssessOverview } from '@/api/device-boot/panorama'
import { getRunEvaluate } from '@/api/device-boot/runEvaluate'
import { getGridDiagramAreaData } from '@/api/device-boot/panorama'
const emit = defineEmits(['changeValue', 'drop', 'show'])
import mapJson from './boundary'
import mapJson from '@/views/pqs/panorama/components/boundary'
const datePickerRef = ref()
const height = mainHeight(90)
// 页面中直接引入就可以
@@ -238,34 +233,77 @@ const imgUrl1 = new URL('@/assets/img/ZD-ZS.png', import.meta.url).href
const imgUrl2 = new URL('@/assets/img/JCD-ZS.png', import.meta.url).href
const boundaryList: any = ref([
{
orgName: '唐山',
LngLat: [118.335849137, 39.7513593355],
boundary: mapJson.tsJSON
orgName: '大连',
LngLat: [122.060077, 39.635794],
boundary: mapJson['大连']
},
{
orgName: '张家口',
LngLat: [115.032504679, 40.8951549951],
boundary: mapJson.zjkJSON
orgName: '抚顺',
LngLat: [124.354599, 41.88962],
boundary: mapJson['抚顺']
},
{
orgName: '秦皇岛',
LngLat: [119.185113833, 40.1179119754],
boundary: mapJson.qhdJSON
orgName: '沈阳',
LngLat: [123.0389, 41.992993],
boundary: mapJson['沈阳']
},
{
orgName: '承德',
LngLat: [117.548498365, 41.3775890632],
boundary: mapJson.cdJSON
orgName: '丹东',
LngLat: [124.585661, 40.645967],
boundary: mapJson['丹东']
},
{
orgName: '廊坊',
LngLat: [116.628004129, 39.0589378611],
boundary: mapJson.lfJSON
orgName: '营口',
LngLat: [122.225226, 40.433551],
boundary: mapJson['营口']
},
{
orgName: '盘锦',
LngLat: [121.875362, 41.075416],
boundary: mapJson['盘锦']
},
{
orgName: '铁岭',
LngLat: [124.229492, 42.731873],
boundary: mapJson['铁岭']
},
{
orgName: '朝阳',
LngLat: [119.640944, 41.39657],
boundary: mapJson['朝阳']
},
{
orgName: '葫芦岛',
LngLat: [119.850873, 40.728517],
boundary: mapJson['葫芦岛']
},
{
orgName: '锦州',
LngLat: [121.42, 41.58],
boundary: mapJson['锦州']
},
{
orgName: '阜新',
LngLat: [121.658585, 42.350951],
boundary: mapJson['阜新']
},
{
orgName: '本溪',
LngLat: [124.390785, 41.197021],
boundary: mapJson['本溪']
},
{
orgName: '辽阳',
LngLat: [123.090785, 41.297021],
boundary: mapJson['辽阳']
},
{
orgName: '鞍山',
LngLat: [122.808845, 40.840049],
boundary: mapJson['鞍山']
}
])
const zoom = ref(13)
const areaLineInfo = ref<any>([])
const siteList = ref<any>([])
@@ -299,7 +337,7 @@ const addMarkers = async (row?: any, key?: any, num?: any) => {
polyline.value = []
areaLineInfo.value = []
let r = 0.0035
let list = data.filter((item: any) => item.lng != 0)
let list = filterUniqueDeviceNames(data.filter((item: any) => item.lng != 0))
list.forEach((item: any) => {
// 变电站图标
item.icon = {
@@ -321,38 +359,19 @@ const addMarkers = async (row?: any, key?: any, num?: any) => {
val.icon = {
url: '',
size: {
width: 40,
height: 40
width: 35,
height: 30
}
}
switch (val.runFlag) {
case 0:
// 投运
if (val.comFlag == 0) {
// 异常
if (val.noDealCount > 0) {
// 异常有暂降
val.icon.url = new URL('@/assets/txycyzj.gif', import.meta.url).href
} else if (val.noDealCount == 0) {
// 异常无暂降
val.icon.url = new URL('@/assets/txzdwzj.png', import.meta.url).href
}
} else if (val.comFlag == 1) {
// 正常
if (val.noDealCount > 0) {
// 正常有暂降
val.icon.url = new URL('@/assets/txzcyzj.gif', import.meta.url).href
} else if (val.noDealCount == 0) {
// 正常无暂降
val.icon.url = new URL('@/assets/txzcwzj.png', import.meta.url).href
}
}
val.icon.url = new URL('@/assets/terminal0.png', import.meta.url).href
break
case 1:
val.icon.url = new URL('@/assets/rby.png', import.meta.url).href
val.icon.url = new URL('@/assets/terminal1.png', import.meta.url).href
break
case 2:
val.icon.url = new URL('@/assets/ty.png', import.meta.url).href
val.icon.url = new URL('@/assets/terminal2.png', import.meta.url).href
break
default:
break
@@ -375,6 +394,21 @@ const addMarkers = async (row?: any, key?: any, num?: any) => {
// center.value.lng = areaLineInfo.value[0].lng
// center.value.lat = areaLineInfo.value[0].lat
}
// 过滤终端
const filterUniqueDeviceNames = data => {
return data.map(item => {
const uniqueChildren = item.children.reduce((acc, curr) => {
if (!acc.some(child => child.deviceName === curr.deviceName)) {
acc.push(curr)
}
return acc
}, [])
return {
...item,
children: uniqueChildren
}
})
}
// 获取zoom
const syncCenterAndZoom = (e: any) => {
zoom.value = e.target.getZoom()
@@ -403,16 +437,18 @@ const lookPoint = (e: any) => {
}
// 搜索
const DeviceQ = () => {
console.log(12313, QueryList.value)
showCollapse.value = true
if (inputQuery.value.length == 0) return
let list = []
let regex = new RegExp(inputQuery.value, 'i')
let data = areaLineInfo.value
.filter((item: any) => regex.test(item.lineName))
.filter((item: any) => regex.test(item.deviceName))
.map((item: any) => {
return {
psrName: item.lineName,
psrName: item.deviceName,
vlevelName: item.voltageScale,
maintOrgName: item.gdName,
coordinate: [item.lng, item.lat]
@@ -440,7 +476,7 @@ const flyTo = (e: any, zoom?: number) => {
zoomMap.value = zoom
} else {
zoomMap.value = 15
let data = areaLineInfo.value.filter((item: any) => regex.test(item.lineName))[0]
let data = areaLineInfo.value.filter((item: any) => regex.test(item.deviceName))[0]
if (data) {
markerClick(data)
}
@@ -448,28 +484,15 @@ const flyTo = (e: any, zoom?: number) => {
}
// 市级统计数据
const grids = (row: any) => {
let form = {
...row,
id: row.orgNo,
deptIndex: row.orgNo,
orgId: row.orgNo,
ids: [],
statisticalType: dictData.getBasicData('Statistical_Type', ['Report_Type'])[0],
isUpToGrid: row.isUpToGrid,
monitorFlag: row.isUpToGrid == 0 ? null : row.isUpToGrid
}
AreaData.value = []
assessList.value = []
// 综合评估
getAssessOverview(form).then(res => {
assessList.value = res.data?.children
getGridDiagramAreaData({ ...form, deptIndex: deptIndex.value }).then((res: any) => {
AreaData.value = res.data
GridDiagramArea()
})
// if (powerManageGridMap.value) powerLoad()
getRunEvaluate({ ...row, deptIndex: deptIndex.value }).then((res: any) => {
console.log('🚀 ~ getRunEvaluate ~ res:', res)
AreaData.value = res.data
GridDiagramArea()
})
// if (powerManageGridMap.value) powerLoad()
}
const radiusPop = (k: any) => {
console.log('🚀 ~ radiusPop ~ k:', k)
@@ -477,27 +500,36 @@ const radiusPop = (k: any) => {
}
const GridDiagramArea = () => {
boundaryList.value.forEach((item: any) => {
assessList.value.forEach((y: any) => {
if (item.orgName == y.name) {
if (y.score == 3.14159) {
} else if (y.score > 4.5) {
item.background = '#33996699'
} else if (y.score > 4) {
item.background = '#3399ff99'
} else if (y.score > 3) {
item.background = '#ffcc3399'
} else if (y.score > 2) {
item.background = '#db088799'
} else if (y.score > 0) {
item.background = '#ff000099'
}
}
})
// assessList.value.forEach((y: any) => {
// if (item.orgName == y.name) {
// if (y.score == 3.14159) {
// } else if (y.score > 4.5) {
// item.background = '#33996699'
// } else if (y.score > 4) {
// item.background = '#3399ff99'
// } else if (y.score > 3) {
// item.background = '#ffcc3399'
// } else if (y.score > 2) {
// item.background = '#db088799'
// } else if (y.score > 0) {
// item.background = '#ff000099'
// }
// }
// })
AreaData.value.forEach((k: any, i: any) => {
if (item.orgName == k.orgName) {
if (item.orgName == k.name) {
for (let kk in item) {
k[kk] = item[kk]
}
if (k.evaluate >= 90) {
k.background = '#0fff04'
} else if (k.evaluate >= 80) {
k.background = '#2b7fd3'
} else if (k.evaluate >= 70) {
k.background = '#ffcc33'
} else {
k.background = '#97017e'
}
}
})
})
@@ -567,5 +599,7 @@ defineExpose({ addMarkers, locatePositions, reset, grids, radiusPop, flyTo })
}
}
}
:deep(.el-descriptions__cell) {
white-space: nowrap;
}
</style>
./cds.js./boundary

View File

@@ -1,135 +1,167 @@
<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 :style="height" style="overflow-y: auto" class="pd10">
<!-- <MyEChart :options="options" /> -->
<div v-for="(item, index) in List">
<div class="box">
<div class="div">{{ item.name }}({{ item.count }})</div>
<!-- <el-progress style="flex: 1" :percentage="(item.count / total).toFixed(2) * 100">
<span>{{ item.count }}</span>
</el-progress> -->
<el-progress style="flex: 1" :percentage="item.score" :color="ratingColor(item.score)">
<span :style="`color:${ratingColor(item.score)}`">{{ item.score }}</span>
</el-progress>
</div>
<el-divider />
</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 radio2 = ref('1')
const height = mainHeight(300, 1.5)
import { areaTerminalStatistic } from '@/api/device-boot/runEvaluate'
const height = mainHeight(220, 1.5)
const props = defineProps({
params: {
type: Object,
default: () => {}
}
})
const List: any = ref([])
const total: any = ref(0)
const options = ref({})
const format = percentage => percentage + '分'
const info = () => {
let dataSource = [
{ value: '90', name: '张家口' },
{ value: '80', name: '廊坊' },
{ value: '70', name: '秦皇岛' },
{ value: '60', name: '唐山' },
{ value: '50', name: '承德' }
]
options.value = {
grid: {
top: '10'
},
toolbox: {
show: false
},
options: {
yAxis: {
type: 'category',
data: dataSource.map(item => item.name),
// axisLabel: {
// color: '#fff'
// },
splitLine: {
show: false
}
},
xAxis: {
type: 'value',
data: [1,2,3,4],
axisLabel: {
show: true,
// textStyle: {
// color: '#FFF'
// },
// formatter: function (value) {
areaTerminalStatistic(props.params).then(res => {
total.value = res.data.reduce((sum, item) => sum + Number(item.count), 0)
List.value = res.data
})
// let dataSource = [
// { value: '90', name: '张家口' },
// { value: '80', name: '廊坊' },
// { value: '70', name: '秦皇岛' },
// { value: '60', name: '唐山' },
// { value: '50', name: '承德' }
// ]
// options.value = {
// grid: {
// top: '10'
// },
// toolbox: {
// show: false
// },
// options: {
// yAxis: {
// type: 'category',
// data: dataSource.map(item => item.name),
// // axisLabel: {
// // color: '#fff'
// // },
// splitLine: {
// show: false
// }
// },
// xAxis: {
// type: 'value',
// data: [1, 2, 3, 4],
// axisLabel: {
// show: true
// // textStyle: {
// // color: '#FFF'
// // },
// // formatter: function (value) {
// }
},
splitLine: {
show: false
},
axisTick: {
show: false
},
axisLine: {
show: true
}
},
dataZoom: null,
series: [
{
type: 'bar',
itemStyle: {
color: function (params) {
return params.value >= 90
? '#00b07d'
: params.value >= 80
? '#2b7fd3'
: params.value >= 70
? '#ffcc33'
: '#97017e'
}
},
markLine: {
silent: false,
symbol: 'circle',
data: [
{
name: '',
yAxis: 100,
lineStyle: {
color:'#009900'
},
label: {
show: true,
formatter: '优质',
color:'#009900'
}
},
{
name: '',
yAxis: 90,
lineStyle: {
color:'#77DA63'
},
label: {
show: true,
color:'#77DA63',
formatter: '良好'
}
},
{
name: '',
yAxis: 60,
lineStyle: {
color:'#FFCC00'
},
label: {
show: true,
color:'#FFCC00',
formatter: '合格'
}
}
]
},
data: dataSource.map(item => item.value)
}
]
}
// // }
// },
// splitLine: {
// show: false
// },
// axisTick: {
// show: false
// },
// axisLine: {
// show: true
// }
// },
// dataZoom: null,
// series: [
// {
// type: 'bar',
// itemStyle: {
// color: function (params) {
// return params.value >= 90
// ? '#00b07d'
// : params.value >= 80
// ? '#2b7fd3'
// : params.value >= 70
// ? '#ffcc33'
// : '#97017e'
// }
// },
// markLine: {
// silent: false,
// symbol: 'circle',
// data: [
// {
// name: '',
// yAxis: 100,
// lineStyle: {
// color: '#009900'
// },
// label: {
// show: true,
// formatter: '优质',
// color: '#009900'
// }
// },
// {
// name: '',
// yAxis: 90,
// lineStyle: {
// color: '#77DA63'
// },
// label: {
// show: true,
// color: '#77DA63',
// formatter: '良好'
// }
// },
// {
// name: '',
// yAxis: 60,
// lineStyle: {
// color: '#FFCC00'
// },
// label: {
// show: true,
// color: '#FFCC00',
// formatter: '合格'
// }
// }
// ]
// },
// data: dataSource.map(item => item.value)
// }
// ]
// }
// }
}
const ratingColor = (num: number) => {
if (num >= 90) {
return '#0fff04'
} else if (num >= 80) {
return '#2b7fd3'
} else if (num >= 70) {
return '#ffcc33'
} else {
return '#97017e'
}
}
onMounted(() => {
info()
// info()
})
defineExpose({
info
})
</script>
<style lang="scss" scoped>
@@ -165,4 +197,13 @@ onMounted(() => {
border-left: 1px solid #00fff4 !important;
}
}
.box {
// display: flex;
.div {
// width: 100px;
}
}
:deep(.el-divider--horizontal) {
margin: 10px 0;
}
</style>

View File

@@ -106,34 +106,34 @@ defineExpose({
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);
// ::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;
}
}
// .el-radio-button__inner {
// opacity: 1 !important;
// border-left: 1px solid #00fff4 !important;
// }
// }
.boxBG {
display: flex;
flex-direction: column;

View File

@@ -4,10 +4,17 @@
<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-colgroup title="运行评价">
<vxe-column field="integrityRate" title="完整率(%)"></vxe-column>
<vxe-column field="onLineRate" title="在线率(%)"></vxe-column>
<vxe-column field="passRate" title="合格率(%)"></vxe-column>
</vxe-colgroup>
<vxe-column field="evaluate" title="评分(分)">
<template v-slot="{ row }">
{{ Math.floor(row.evaluate * 100).toFixed(0) / 100 }}
</template>
</vxe-column>
</vxe-table>
</div>
</template>
@@ -27,7 +34,7 @@ const height = mainHeight(360, 3)
const info = () => {
getRunEvaluateDetail({ ...props.params, ids: [] }).then(res => {
tableData.value = res.data
tableData.value = res.data.slice(0, 10)
})
}
defineExpose({
@@ -73,4 +80,7 @@ defineExpose({
background: var(--el-color-primary);
color: #fff;
}
:dppe(.el-select__wrapper) {
width: 26px !important;
}
</style>

View File

@@ -1,5 +1,21 @@
<template>
<div :style="height">
<el-select
class="selectBox"
v-model="value"
placeholder="请选择"
size="small"
value-key="id"
multiple
collapse-tags
collapse-tags-tooltip
:multiple-limit="6"
filterable
style="width: 130px"
@change="change"
>
<el-option v-for="item in List" :key="item.id" :label="item.name" :value="item" />
</el-select>
<MyEChart :options="options" />
</div>
</template>
@@ -15,71 +31,111 @@ const props = defineProps({
default: () => {}
}
})
const value: any = ref([])
const List: any = ref([])
const options = ref({})
const height = mainHeight(290, 3)
const info = () => {
value.value = []
List.value = []
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
}
},
legend:{
top: '5',
right: '5',
type: 'scroll',
},
options: {
series: []
}
}
res.data.name.forEach((item: any, i: number) => {
options.value.options.series.push({
List.value.push({
name: item,
type: 'line',
symbol: 'circle',
smooth: true,
showSymbol: false,
data: res.data.score[i]
score: res.data.score[i],
date: res.data.date,
id: i
})
})
for (let i = 0; i < 6; i++) {
if (i < List.value.length) {
value.value.push(List.value[i])
}
}
change()
})
}
const change = () => {
options.value = {
xAxis: {
splitLine: {
show: false
},
axisTick: {
show: false
},
axisLine: {
show: true
},
data: value.value[0]?.date,
axisLabel: {
formatter: function (value) {
let time = ''
if (value.slice(-2) == '01') {
time = value
} else {
time = value.slice(5, 10)
}
return time
}
}
},
grid: {
top: '30',
left: '10',
right: '10'
},
toolbox: {
show: false
},
yAxis: {
min: 0,
max: 100,
axisLine: {
show: true
},
splitLine: {
show: false
}
},
legend: {
top: '5',
right: '5',
type: 'scroll'
},
options: {
series: []
}
}
value.value.forEach((item: any, i: number) => {
options.value.options.series.push({
name: item.name,
type: 'line',
symbol: 'circle',
smooth: true,
showSymbol: false,
data: item.score
})
})
console.log(123)
}
onMounted(() => {})
defineExpose({
info
})
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.selectBox {
position: absolute;
top: 1px;
right: 10px;
}
:deep(.el-tag) {
max-width: 110px !important;
}
:deep(.el-select) {
min-width: 190px;
}
</style>

View File

@@ -139,7 +139,7 @@
</el-form>
</div>
<Map />
<Map ref="mapRef" />
<transition name="slide-left">
<div class="left" :style="height" v-if="leftVisible">
@@ -202,7 +202,7 @@
区域终端运行评价
<el-button link class="view" icon="el-icon-View" @click="regionEvaluation">详情</el-button>
</div>
<region />
<region :params="tableStore.table.params" ref="regionRef" />
</BorderBox13>
<div :style="height3">
<BorderBox13
@@ -217,7 +217,7 @@
最近一周终端评价趋势
</div>
<week ref="weekRef" :params="tableStore.table.params"/>
<week ref="weekRef" :params="tableStore.table.params" />
</BorderBox13>
</div>
</div>
@@ -236,7 +236,7 @@
异常终端详情
</div>
<terminalDetails ref="terminalDetailsRef" :params="tableStore.table.params" />
<table />
<!-- <table /> -->
</BorderBox13>
</div>
</transition>
@@ -269,6 +269,7 @@ defineOptions({
name: 'runManage/runEvaluate'
})
const runRef = ref()
const regionRef = ref()
const weekRef = ref()
const terminalDetailsRef = ref()
const config = useConfig()
@@ -286,6 +287,9 @@ const tableStore = new TableStore({
loadCallback: () => {
runRef.value.info()
weekRef.value.info()
regionRef.value.info()
mapRef.value.addMarkers()
mapRef.value.grids(tableStore.table.params)
terminalDetailsRef.value.info()
}
})
@@ -304,7 +308,7 @@ const rightVisible = ref(true)
const centerVisible = ref(true)
const statisticsPopUpBoxRef = ref(true)
const regionDetailsRef = ref(true)
const mapRef = ref()
const toggle = () => {
leftVisible.value = !leftVisible.value
rightVisible.value = !rightVisible.value
@@ -313,7 +317,6 @@ const toggle = () => {
// 区域变化
const changeValue = (val: any) => {
tableStore.index()
}
// 区域详情

View File

@@ -3,7 +3,7 @@
<div class="iconBox">
<div class="div">
<img src="@/assets/jcd.png" alt="" />
<span>变电站</span>
<span>变电站(场站)</span>
</div>
<div class="div">
<img src="@/assets/rby.png" alt="" />
@@ -80,7 +80,7 @@
<bm-info-window :show="infoWindowPoint.show" @close="infoWindowPoint.show = false">
<el-descriptions :title="infoWindowPoint.lineName" style="min-width: 240px;" :column="1" v-if="infoWindowPoint.lineId">
<el-descriptions-item label="供电公司">{{ infoWindowPoint.gdName }}</el-descriptions-item>
<el-descriptions-item label="变电站">{{ infoWindowPoint.subName }}</el-descriptions-item>
<el-descriptions-item label="变电站(场站)">{{ infoWindowPoint.subName }}</el-descriptions-item>
<el-descriptions-item label="母线">{{ infoWindowPoint.voltageName }}</el-descriptions-item>
<el-descriptions-item label="网络参数">
{{ infoWindowPoint.ip }}
@@ -315,4 +315,7 @@ onMounted(() => {
}
}
}
:deep(.el-descriptions__cell) {
white-space: nowrap;
}
</style>

View File

@@ -7,7 +7,7 @@
<div class="iconBox">
<div class="div">
<img src="@/assets/jcd.png" alt="" />
<span>变电站</span>
<span>变电站(场站)</span>
</div>
<div class="div">
<img src="@/assets/rby.png" alt="" />
@@ -101,7 +101,7 @@
<bm-info-window :show="infoWindowPoint.show" @close="infoWindowPoint.show = false">
<el-descriptions :title="infoWindowPoint.lineName" :column="1" v-if="infoWindowPoint.lineId">
<el-descriptions-item label="供电公司">{{ infoWindowPoint.gdName }}</el-descriptions-item>
<el-descriptions-item label="变电站">{{ infoWindowPoint.subName }}</el-descriptions-item>
<el-descriptions-item label="变电站(场站)">{{ infoWindowPoint.subName }}</el-descriptions-item>
<el-descriptions-item label="母线">{{ infoWindowPoint.voltageName }}</el-descriptions-item>
<el-descriptions-item label="网络参数">
{{ infoWindowPoint.ip }}
@@ -375,4 +375,7 @@ onMounted(() => {
}
}
}
:deep(.el-descriptions__cell) {
white-space: nowrap;
}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div>
<TableHeader date-picker>
<TableHeader date-picker :showReset="false">
<template #operation>
<el-button icon="el-icon-Download" type="primary" @click="exportEvent">导出</el-button>
</template>

View File

@@ -1,11 +1,12 @@
<template>
<div>
<el-form :inline="true">
<el-form :inline="true" class="formFlex">
<el-form-item label="日期">
<DatePicker ref="datePickerRef"></DatePicker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="init">查询</el-button>
<el-form-item class="mr5">
<el-button type="primary" @click="init" icon="el-icon-Search">查询</el-button>
<el-button icon="el-icon-Download" type="primary" @click="exportEvent">导出</el-button>
</el-form-item>
</el-form>
@@ -40,8 +41,9 @@
<script setup lang="ts">
import { useDictData } from '@/stores/dictData'
import DatePicker from '@/components/form/datePicker/index.vue'
import { ref, reactive, onMounted, } from 'vue'
import { getVoltage, getGeneralSituation } from '@/api/event-boot/report'
import { ElMessage } from 'element-plus'
import { ref, reactive, onMounted } from 'vue'
import { getVoltage, getGeneralSituation, getExport } from '@/api/event-boot/report'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { mainHeight } from '@/utils/layout'
const dictData = useDictData()
@@ -89,7 +91,44 @@ const init = () => {
voltage.value = res[1].data
})
}
const exportEvent = () => {
ElMessage({
message: '正在导出中'
})
getExport({
...formData,
statisticalType: dictData.getBasicData('Statistical_Type', [
'Report_Type',
'Manufacturer',
'Voltage_Level',
'Load_Type'
])[0]
}).then(res => {
const link = document.createElement('a')
let blob = new Blob([res], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'
})
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
link.setAttribute('download', '暂态总体概况.xlsx') // 文件名可自定义
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
ElMessage({
message: '导出成功',
type: 'success'
})
})
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
.formFlex {
display: flex;
justify-content: space-between;
}
</style>

View File

@@ -1,11 +1,11 @@
<template>
<div>
<el-form :inline="true">
<el-form :inline="true" class="formFlex">
<el-form-item label="日期">
<DatePicker ref="datePickerRef"></DatePicker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="init">查询</el-button>
<el-form-item class="mr5">
<el-button type="primary" @click="init" icon="el-icon-Search">查询</el-button>
</el-form-item>
</el-form>
@@ -266,4 +266,8 @@ const layout = mainHeight(150) as any
width: 100%;
height: calc(v-bind('layout.height') / 2);
}
.formFlex {
display: flex;
justify-content: space-between;
}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div>
<TableHeader date-picker>
<TableHeader date-picker :showReset="false">
<template #operation>
<el-button icon="el-icon-Download" type="primary" @click="exportEvent">导出</el-button>
</template>

View File

@@ -76,7 +76,6 @@ const list = ref([
{
name: '详细事件列表',
id: '4',
url: '/event-boot/report/getContinueTime',
column: [
{