联调终端运行评价

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' 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 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> </template>
</TableHeader> </TableHeader>
<Table ref="tableRef"></Table> <Table ref="tableRef"></Table>
<pushDisplay ref="pushDisplayRef" />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -27,9 +28,11 @@ import TableHeader from '@/components/table/header/index.vue'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { ledgerChangePush } from '@/api/device-boot/terminalTree' import { ledgerChangePush } from '@/api/device-boot/terminalTree'
import pushDisplay from './pushDisplay.vue'
defineOptions({ defineOptions({
name: 'BusinessAdministrator/LogManagement/TerminalLog' name: 'BusinessAdministrator/LogManagement/TerminalLog'
}) })
const pushDisplayRef = ref()
const dictData = useDictData() const dictData = useDictData()
const fontdveoption = dictData.getBasicData('Dev_Ops') const fontdveoption = dictData.getBasicData('Dev_Ops')
@@ -78,7 +81,8 @@ const changePush = () => {
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
ledgerChangePush().then(res => { ledgerChangePush().then(res => {
ElMessage.success(res.message) // ElMessage.success(res.message)
pushDisplayRef.value.open(res.data)
tableStore.index() 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 }"> <template #default="{ node, data }">
<div class="custom-tree-node"> <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> <div>
<!-- <el-button type="primary" v-if="data.id == undefined" link icon="el-icon-Plus" ></el-button> --> <!-- <el-button type="primary" v-if="data.id == undefined" link icon="el-icon-Plus" ></el-button> -->
<el-button <el-button
@@ -191,7 +201,7 @@ const popUps = ref(false)
const tableRef = ref() const tableRef = ref()
const processNo = ref('') const processNo = ref('')
const ruleFormRef = ref() const ruleFormRef = ref()
const dataSource:any = ref([]) const dataSource: any = ref([])
const defaultProps = { const defaultProps = {
children: 'deviceInfoList', children: 'deviceInfoList',
label: 'name' label: 'name'
@@ -483,4 +493,12 @@ const addMenu = () => {}
padding-right: 8px; padding-right: 8px;
width: 300px; width: 300px;
} }
.iconSpan {
display: inline-block;
width: 8px;
height: 8px;
margin-left: 3px;
border-radius: 50%;
margin-bottom: 2px;
}
</style> </style>

View File

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

View File

@@ -88,7 +88,7 @@
> >
<bm-label <bm-label
v-if="zoom > 14" v-if="zoom > 14"
:content="path.lineName" :content="path.deviceName"
:labelStyle="{ :labelStyle="{
color: '#fff', color: '#fff',
border: '0px solid #fff', border: '0px solid #fff',
@@ -106,31 +106,25 @@
<!-- 详情 --> <!-- 详情 -->
<bm-marker :position="infoWindowPoint" :icon="{ url: '1', size: { width: 0, height: 0 } }"> <bm-marker :position="infoWindowPoint" :icon="{ url: '1', size: { width: 0, height: 0 } }">
<bm-info-window :show="infoWindowPoint.show" @close="infoWindowPoint.show = false"> <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.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="网络参数"> <el-descriptions-item label="网络参数">
{{ infoWindowPoint.ip }} {{ infoWindowPoint.ip }}
</el-descriptions-item> </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="生产厂家"> <el-descriptions-item label="生产厂家">
{{ infoWindowPoint.manufacturer }} {{ infoWindowPoint.manufacturer }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="终端状态">
{{
infoWindowPoint.runFlag == 0 ? '投运' : infoWindowPoint.runFlag == 1 ? '热备用' : '停运'
}}
</el-descriptions-item>
<el-descriptions-item label="通讯状态"> <el-descriptions-item label="通讯状态">
{{ infoWindowPoint.comFlag == 0 ? '中断' : '正常' }} {{ infoWindowPoint.comFlag == 0 ? '中断' : '正常' }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item>
<el-button type="primary" size="small" @click="lookPoint(infoWindowPoint)">
查看详情
</el-button>
</el-descriptions-item>
</el-descriptions> </el-descriptions>
<el-descriptions <el-descriptions
:title="infoWindowPoint.subName" :title="infoWindowPoint.subName"
@@ -156,7 +150,7 @@
</div> </div>
<!-- 信息弹框 --> <!-- 信息弹框 -->
<div v-if="zoom <= 9"> <!-- <div v-if="zoom <= 9">
<bm-overlay <bm-overlay
v-for="item in AreaData" v-for="item in AreaData"
pane="labelPane" pane="labelPane"
@@ -200,7 +194,7 @@
</div> </div>
</div> </div>
</bm-overlay> </bm-overlay>
</div> </div> -->
</baidu-map> </baidu-map>
</div> </div>
</template> </template>
@@ -214,9 +208,10 @@ import { useDictData } from '@/stores/dictData'
import { Search } from '@element-plus/icons-vue' import { Search } from '@element-plus/icons-vue'
import { BaiduMap, BmOverlay } from 'vue-baidu-map-3x' import { BaiduMap, BmOverlay } from 'vue-baidu-map-3x'
import { getAssessOverview } from '@/api/device-boot/panorama' import { getAssessOverview } from '@/api/device-boot/panorama'
import { getRunEvaluate } from '@/api/device-boot/runEvaluate'
import { getGridDiagramAreaData } from '@/api/device-boot/panorama' import { getGridDiagramAreaData } from '@/api/device-boot/panorama'
const emit = defineEmits(['changeValue', 'drop', 'show']) const emit = defineEmits(['changeValue', 'drop', 'show'])
import mapJson from './boundary' import mapJson from '@/views/pqs/panorama/components/boundary'
const datePickerRef = ref() const datePickerRef = ref()
const height = mainHeight(90) 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 imgUrl2 = new URL('@/assets/img/JCD-ZS.png', import.meta.url).href
const boundaryList: any = ref([ const boundaryList: any = ref([
{ {
orgName: '唐山', orgName: '大连',
LngLat: [118.335849137, 39.7513593355], LngLat: [122.060077, 39.635794],
boundary: mapJson.tsJSON boundary: mapJson['大连']
}, },
{ {
orgName: '张家口', orgName: '抚顺',
LngLat: [115.032504679, 40.8951549951], LngLat: [124.354599, 41.88962],
boundary: mapJson.zjkJSON boundary: mapJson['抚顺']
}, },
{ {
orgName: '秦皇岛', orgName: '沈阳',
LngLat: [119.185113833, 40.1179119754], LngLat: [123.0389, 41.992993],
boundary: mapJson.qhdJSON boundary: mapJson['沈阳']
}, },
{ {
orgName: '承德', orgName: '丹东',
LngLat: [117.548498365, 41.3775890632], LngLat: [124.585661, 40.645967],
boundary: mapJson.cdJSON boundary: mapJson['丹东']
}, },
{ {
orgName: '廊坊', orgName: '营口',
LngLat: [116.628004129, 39.0589378611], LngLat: [122.225226, 40.433551],
boundary: mapJson.lfJSON 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 zoom = ref(13)
const areaLineInfo = ref<any>([]) const areaLineInfo = ref<any>([])
const siteList = ref<any>([]) const siteList = ref<any>([])
@@ -299,7 +337,7 @@ const addMarkers = async (row?: any, key?: any, num?: any) => {
polyline.value = [] polyline.value = []
areaLineInfo.value = [] areaLineInfo.value = []
let r = 0.0035 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) => { list.forEach((item: any) => {
// 变电站图标 // 变电站图标
item.icon = { item.icon = {
@@ -321,38 +359,19 @@ const addMarkers = async (row?: any, key?: any, num?: any) => {
val.icon = { val.icon = {
url: '', url: '',
size: { size: {
width: 40, width: 35,
height: 40 height: 30
} }
} }
switch (val.runFlag) { switch (val.runFlag) {
case 0: case 0:
// 投运 val.icon.url = new URL('@/assets/terminal0.png', import.meta.url).href
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
}
}
break break
case 1: 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 break
case 2: 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 break
default: default:
break break
@@ -375,6 +394,21 @@ const addMarkers = async (row?: any, key?: any, num?: any) => {
// center.value.lng = areaLineInfo.value[0].lng // center.value.lng = areaLineInfo.value[0].lng
// center.value.lat = areaLineInfo.value[0].lat // 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 // 获取zoom
const syncCenterAndZoom = (e: any) => { const syncCenterAndZoom = (e: any) => {
zoom.value = e.target.getZoom() zoom.value = e.target.getZoom()
@@ -403,16 +437,18 @@ const lookPoint = (e: any) => {
} }
// 搜索 // 搜索
const DeviceQ = () => { const DeviceQ = () => {
console.log(12313, QueryList.value)
showCollapse.value = true showCollapse.value = true
if (inputQuery.value.length == 0) return if (inputQuery.value.length == 0) return
let list = [] let list = []
let regex = new RegExp(inputQuery.value, 'i') let regex = new RegExp(inputQuery.value, 'i')
let data = areaLineInfo.value let data = areaLineInfo.value
.filter((item: any) => regex.test(item.lineName)) .filter((item: any) => regex.test(item.deviceName))
.map((item: any) => { .map((item: any) => {
return { return {
psrName: item.lineName, psrName: item.deviceName,
vlevelName: item.voltageScale, vlevelName: item.voltageScale,
maintOrgName: item.gdName, maintOrgName: item.gdName,
coordinate: [item.lng, item.lat] coordinate: [item.lng, item.lat]
@@ -440,7 +476,7 @@ const flyTo = (e: any, zoom?: number) => {
zoomMap.value = zoom zoomMap.value = zoom
} else { } else {
zoomMap.value = 15 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) { if (data) {
markerClick(data) markerClick(data)
} }
@@ -448,28 +484,15 @@ const flyTo = (e: any, zoom?: number) => {
} }
// 市级统计数据 // 市级统计数据
const grids = (row: any) => { 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 = [] AreaData.value = []
assessList.value = []
// 综合评估 // 综合评估
getAssessOverview(form).then(res => {
assessList.value = res.data?.children
getGridDiagramAreaData({ ...form, deptIndex: deptIndex.value }).then((res: any) => { getRunEvaluate({ ...row, deptIndex: deptIndex.value }).then((res: any) => {
console.log('🚀 ~ getRunEvaluate ~ res:', res)
AreaData.value = res.data AreaData.value = res.data
GridDiagramArea() GridDiagramArea()
}) })
// if (powerManageGridMap.value) powerLoad() // if (powerManageGridMap.value) powerLoad()
})
} }
const radiusPop = (k: any) => { const radiusPop = (k: any) => {
console.log('🚀 ~ radiusPop ~ k:', k) console.log('🚀 ~ radiusPop ~ k:', k)
@@ -477,27 +500,36 @@ const radiusPop = (k: any) => {
} }
const GridDiagramArea = () => { const GridDiagramArea = () => {
boundaryList.value.forEach((item: any) => { boundaryList.value.forEach((item: any) => {
assessList.value.forEach((y: any) => { // assessList.value.forEach((y: any) => {
if (item.orgName == y.name) { // if (item.orgName == y.name) {
if (y.score == 3.14159) { // if (y.score == 3.14159) {
} else if (y.score > 4.5) { // } else if (y.score > 4.5) {
item.background = '#33996699' // item.background = '#33996699'
} else if (y.score > 4) { // } else if (y.score > 4) {
item.background = '#3399ff99' // item.background = '#3399ff99'
} else if (y.score > 3) { // } else if (y.score > 3) {
item.background = '#ffcc3399' // item.background = '#ffcc3399'
} else if (y.score > 2) { // } else if (y.score > 2) {
item.background = '#db088799' // item.background = '#db088799'
} else if (y.score > 0) { // } else if (y.score > 0) {
item.background = '#ff000099' // item.background = '#ff000099'
} // }
} // }
}) // })
AreaData.value.forEach((k: any, i: any) => { AreaData.value.forEach((k: any, i: any) => {
if (item.orgName == k.orgName) { if (item.orgName == k.name) {
for (let kk in item) { for (let kk in item) {
k[kk] = item[kk] 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> </style>
./cds.js./boundary

View File

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

View File

@@ -106,34 +106,34 @@ defineExpose({
right: 5px; right: 5px;
top: 0px; top: 0px;
} }
::v-deep .el-radio-button__inner { // ::v-deep .el-radio-button__inner {
padding: 8px 18px; // padding: 8px 18px;
background: var(--el-color-primary); // background: var(--el-color-primary);
border: 1px solid #00fff4; // border: 1px solid #00fff4;
border-radius: 0; // border-radius: 0;
font-weight: normal; // font-weight: normal;
color: #ffffff; // color: #ffffff;
text-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.73); // text-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.73);
opacity: 0.52; // opacity: 0.52;
} // }
::v-deep .el-radio-button:last-child .el-radio-button__inner { // ::v-deep .el-radio-button:last-child .el-radio-button__inner {
border-radius: 0; // border-radius: 0;
} // }
::v-deep .el-radio-button:first-child .el-radio-button__inner { // ::v-deep .el-radio-button:first-child .el-radio-button__inner {
border-radius: 0; // border-radius: 0;
border-left: 1px solid #00fff4; // border-left: 1px solid #00fff4;
} // }
::v-deep .is-active { // ::v-deep .is-active {
border: 1px solid #00fff4; // border: 1px solid #00fff4;
opacity: 1 !important; // opacity: 1 !important;
color: #ffffff; // color: #ffffff;
background: var(--el-color-primary); // background: var(--el-color-primary);
.el-radio-button__inner { // .el-radio-button__inner {
opacity: 1 !important; // opacity: 1 !important;
border-left: 1px solid #00fff4 !important; // border-left: 1px solid #00fff4 !important;
} // }
} // }
.boxBG { .boxBG {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@@ -4,10 +4,17 @@
<vxe-column type="seq" width="70px" title="序号"></vxe-column> <vxe-column type="seq" width="70px" title="序号"></vxe-column>
<vxe-column field="name" title="终端名称"></vxe-column> <vxe-column field="name" title="终端名称"></vxe-column>
<vxe-column field="subName" title="所属电站"></vxe-column> <vxe-column field="subName" title="所属电站"></vxe-column>
<vxe-colgroup title="运行评价">
<vxe-column field="integrityRate" title="完整率(%)"></vxe-column> <vxe-column field="integrityRate" title="完整率(%)"></vxe-column>
<vxe-column field="onLineRate" title="在线率(%)"></vxe-column> <vxe-column field="onLineRate" title="在线率(%)"></vxe-column>
<vxe-column field="passRate" title="合格率(%)"></vxe-column> <vxe-column field="passRate" title="合格率(%)"></vxe-column>
<vxe-column field="evaluate" 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> </vxe-table>
</div> </div>
</template> </template>
@@ -27,7 +34,7 @@ const height = mainHeight(360, 3)
const info = () => { const info = () => {
getRunEvaluateDetail({ ...props.params, ids: [] }).then(res => { getRunEvaluateDetail({ ...props.params, ids: [] }).then(res => {
tableData.value = res.data tableData.value = res.data.slice(0, 10)
}) })
} }
defineExpose({ defineExpose({
@@ -73,4 +80,7 @@ defineExpose({
background: var(--el-color-primary); background: var(--el-color-primary);
color: #fff; color: #fff;
} }
:dppe(.el-select__wrapper) {
width: 26px !important;
}
</style> </style>

View File

@@ -1,5 +1,21 @@
<template> <template>
<div :style="height"> <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" /> <MyEChart :options="options" />
</div> </div>
</template> </template>
@@ -15,17 +31,34 @@ const props = defineProps({
default: () => {} default: () => {}
} }
}) })
const value: any = ref([])
const List: any = ref([])
const options = ref({}) const options = ref({})
const height = mainHeight(290, 3) const height = mainHeight(290, 3)
const info = () => { const info = () => {
value.value = []
List.value = []
lastWeekTrend(props.params).then((res: any) => { lastWeekTrend(props.params).then((res: any) => {
res.data.name.forEach((item: any, i: number) => {
List.value.push({
name: item,
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 = { options.value = {
xAxis: { xAxis: {
axisLabel: {
show: true
},
splitLine: { splitLine: {
show: false show: false
}, },
@@ -35,7 +68,18 @@ const info = () => {
axisLine: { axisLine: {
show: true show: true
}, },
data: res.data.date 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: { grid: {
top: '30', top: '30',
@@ -56,30 +100,42 @@ const info = () => {
show: false show: false
} }
}, },
legend:{ legend: {
top: '5', top: '5',
right: '5', right: '5',
type: 'scroll', type: 'scroll'
}, },
options: { options: {
series: [] series: []
} }
} }
res.data.name.forEach((item: any, i: number) => { value.value.forEach((item: any, i: number) => {
options.value.options.series.push({ options.value.options.series.push({
name: item, name: item.name,
type: 'line', type: 'line',
symbol: 'circle', symbol: 'circle',
smooth: true, smooth: true,
showSymbol: false, showSymbol: false,
data: res.data.score[i] data: item.score
})
}) })
}) })
console.log(123)
} }
onMounted(() => {}) onMounted(() => {})
defineExpose({ defineExpose({
info info
}) })
</script> </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> </el-form>
</div> </div>
<Map /> <Map ref="mapRef" />
<transition name="slide-left"> <transition name="slide-left">
<div class="left" :style="height" v-if="leftVisible"> <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> <el-button link class="view" icon="el-icon-View" @click="regionEvaluation">详情</el-button>
</div> </div>
<region /> <region :params="tableStore.table.params" ref="regionRef" />
</BorderBox13> </BorderBox13>
<div :style="height3"> <div :style="height3">
<BorderBox13 <BorderBox13
@@ -217,7 +217,7 @@
最近一周终端评价趋势 最近一周终端评价趋势
</div> </div>
<week ref="weekRef" :params="tableStore.table.params"/> <week ref="weekRef" :params="tableStore.table.params" />
</BorderBox13> </BorderBox13>
</div> </div>
</div> </div>
@@ -236,7 +236,7 @@
异常终端详情 异常终端详情
</div> </div>
<terminalDetails ref="terminalDetailsRef" :params="tableStore.table.params" /> <terminalDetails ref="terminalDetailsRef" :params="tableStore.table.params" />
<table /> <!-- <table /> -->
</BorderBox13> </BorderBox13>
</div> </div>
</transition> </transition>
@@ -269,6 +269,7 @@ defineOptions({
name: 'runManage/runEvaluate' name: 'runManage/runEvaluate'
}) })
const runRef = ref() const runRef = ref()
const regionRef = ref()
const weekRef = ref() const weekRef = ref()
const terminalDetailsRef = ref() const terminalDetailsRef = ref()
const config = useConfig() const config = useConfig()
@@ -286,6 +287,9 @@ const tableStore = new TableStore({
loadCallback: () => { loadCallback: () => {
runRef.value.info() runRef.value.info()
weekRef.value.info() weekRef.value.info()
regionRef.value.info()
mapRef.value.addMarkers()
mapRef.value.grids(tableStore.table.params)
terminalDetailsRef.value.info() terminalDetailsRef.value.info()
} }
}) })
@@ -304,7 +308,7 @@ const rightVisible = ref(true)
const centerVisible = ref(true) const centerVisible = ref(true)
const statisticsPopUpBoxRef = ref(true) const statisticsPopUpBoxRef = ref(true)
const regionDetailsRef = ref(true) const regionDetailsRef = ref(true)
const mapRef = ref()
const toggle = () => { const toggle = () => {
leftVisible.value = !leftVisible.value leftVisible.value = !leftVisible.value
rightVisible.value = !rightVisible.value rightVisible.value = !rightVisible.value
@@ -313,7 +317,6 @@ const toggle = () => {
// 区域变化 // 区域变化
const changeValue = (val: any) => { const changeValue = (val: any) => {
tableStore.index() tableStore.index()
} }
// 区域详情 // 区域详情

View File

@@ -3,7 +3,7 @@
<div class="iconBox"> <div class="iconBox">
<div class="div"> <div class="div">
<img src="@/assets/jcd.png" alt="" /> <img src="@/assets/jcd.png" alt="" />
<span>变电站</span> <span>变电站(场站)</span>
</div> </div>
<div class="div"> <div class="div">
<img src="@/assets/rby.png" alt="" /> <img src="@/assets/rby.png" alt="" />
@@ -80,7 +80,7 @@
<bm-info-window :show="infoWindowPoint.show" @close="infoWindowPoint.show = false"> <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 :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.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.voltageName }}</el-descriptions-item>
<el-descriptions-item label="网络参数"> <el-descriptions-item label="网络参数">
{{ infoWindowPoint.ip }} {{ infoWindowPoint.ip }}
@@ -315,4 +315,7 @@ onMounted(() => {
} }
} }
} }
:deep(.el-descriptions__cell) {
white-space: nowrap;
}
</style> </style>

View File

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

View File

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

View File

@@ -1,11 +1,12 @@
<template> <template>
<div> <div>
<el-form :inline="true"> <el-form :inline="true" class="formFlex">
<el-form-item label="日期"> <el-form-item label="日期">
<DatePicker ref="datePickerRef"></DatePicker> <DatePicker ref="datePickerRef"></DatePicker>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item class="mr5">
<el-button type="primary" @click="init">查询</el-button> <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-item>
</el-form> </el-form>
@@ -40,8 +41,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import DatePicker from '@/components/form/datePicker/index.vue' import DatePicker from '@/components/form/datePicker/index.vue'
import { ref, reactive, onMounted, } from 'vue' import { ElMessage } from 'element-plus'
import { getVoltage, getGeneralSituation } from '@/api/event-boot/report' import { ref, reactive, onMounted } from 'vue'
import { getVoltage, getGeneralSituation, getExport } from '@/api/event-boot/report'
import { defaultAttribute } from '@/components/table/defaultAttribute' import { defaultAttribute } from '@/components/table/defaultAttribute'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
const dictData = useDictData() const dictData = useDictData()
@@ -89,7 +91,44 @@ const init = () => {
voltage.value = res[1].data 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(() => { onMounted(() => {
init() init()
}) })
</script> </script>
<style lang="scss" scoped>
.formFlex {
display: flex;
justify-content: space-between;
}
</style>

View File

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

View File

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

View File

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