优化波形

This commit is contained in:
guanj
2026-06-16 08:36:22 +08:00
parent 765507398e
commit 56b8158f4a
25 changed files with 3704 additions and 3437 deletions

View File

@@ -30,7 +30,7 @@ import { downloadFile } from '@/api/system-boot/file'
import { previewFile } from '@/utils/fileDownLoad'
const { push, options, currentRoute } = useRouter()
const VITE_FLAG = import.meta.env.VITE_NAME == 'jibei'
const VITE_FLAG = false//import.meta.env.VITE_NAME == 'jibei'
// const url = 'http://192.168.1.22:9009/excelreport' + currentRoute.value.href?.split('?')[1]
const url = ref('')
const excelOptions = ref({})

View File

@@ -0,0 +1,322 @@
// 辅助函数
const getMax = (temp, tempA, tempB, tempC) => {
temp = temp > tempA ? temp : tempA
temp = temp > tempB ? temp : tempB
if (tempC !== undefined) {
temp = temp > tempC ? temp : tempC
}
return temp
}
const getMaxTwo = (temp, tempA, tempB) => {
temp = temp > tempA ? temp : tempA
temp = temp > tempB ? temp : tempB
return temp
}
const getMin = (temp, tempA, tempB, tempC) => {
temp = temp < tempA ? temp : tempA
temp = temp < tempB ? temp : tempB
if (tempC !== undefined) {
temp = temp < tempC ? temp : tempC
}
return temp
}
const getMinOpen = (temp, tempA, tempB) => {
temp = temp < tempA ? temp : tempA
temp = temp < tempB ? temp : tempB
return temp
}
// 数据处理函数
const fliteWaveData = (wp, step, iphasicValue, isOpen) => {
const rmsData = wp.listRmsData
const pt = Number(wp.pt) / 1000
const ct = Number(wp.ct)
const titleList = wp.waveTitle
let xishu = pt
let aTitle = '',
bTitle = '',
cTitle = '',
unit = '电压'
let rmsvFirstX = 0,
rmsvFirstY = 0,
rmsvSecondX = 0,
rmsvSecondY = 0,
firstZhou = 'a',
secondeZhou = 'a'
let ifmax = 0,
ifmin = 0,
ismax = 0,
ismin = 0,
rfmax = 0,
rfmin = 0,
rsmax = 0,
rsmin = 0
const shunshiFA = []
const shunshiFB = []
const shunshiFC = []
const shunshiSA = []
const shunshiSB = []
const shunshiSC = []
const rmsFA = []
const rmsFB = []
const rmsFC = []
const rmsSA = []
const rmsSB = []
const rmsSC = []
if (titleList[iphasicValue * step + 1]?.substring(0, 1) !== 'U') {
xishu = ct
unit = '电流'
}
for (let i = 1; i <= iphasicValue; i++) {
switch (i) {
case 1:
aTitle = titleList[iphasicValue * step + i]?.substring(1) || ''
break
case 2:
bTitle = titleList[iphasicValue * step + i]?.substring(1) || ''
break
case 3:
cTitle = titleList[iphasicValue * step + i]?.substring(1) || ''
break
}
}
if (rmsData[0] && rmsData[0][iphasicValue * step + 1] !== undefined) {
rfmax = rmsData[0][iphasicValue * step + 1] * xishu
rfmin = rmsData[0][iphasicValue * step + 1] * xishu
rmsvFirstY = rmsData[0][iphasicValue * step + 1] * xishu
rmsvFirstX = rmsData[0][0]
rsmax = rmsData[0][iphasicValue * step + 1]
rsmin = rmsData[0][iphasicValue * step + 1]
rmsvSecondY = rmsData[0][iphasicValue * step + 1]
rmsvSecondX = rmsData[0][0]
}
for (let rms = 0; rms < rmsData.length; rms++) {
if (!rmsData[rms] || rmsData[rms][iphasicValue * step + 1] === undefined) {
break
}
switch (iphasicValue) {
case 1:
const rmsFirstA = rmsData[rms][iphasicValue * step + 1] * xishu
rmsFA.push([rmsData[rms][0], rmsFirstA])
rfmax = rfmax > rmsFirstA ? rfmax : rmsFirstA
rfmin = rfmin < rmsFirstA ? rfmin : rmsFirstA
if (rfmin < rmsvFirstY) {
rmsvFirstY = rfmin
firstZhou = 'a'
rmsvFirstX = rmsData[rms][0]
}
const rmsSecondA = rmsData[rms][iphasicValue * step + 1]
rmsSA.push([rmsData[rms][0], rmsSecondA])
rsmax = rsmax > rmsSecondA ? rsmax : rmsSecondA
rsmin = rsmin < rmsSecondA ? rsmin : rmsSecondA
if (rsmin < rmsvSecondY) {
rmsvSecondY = rsmin
secondeZhou = 'a'
rmsvSecondX = rmsData[rms][0]
}
break
case 2:
const rmsFirstA2 = rmsData[rms][iphasicValue * step + 1] * xishu
const rmsFirstB2 = rmsData[rms][iphasicValue * step + 2] * xishu
rmsFA.push([rmsData[rms][0], rmsFirstA2])
rmsFB.push([rmsData[rms][0], rmsFirstB2])
rfmax = getMaxTwo(rfmax, rmsFirstA2, rmsFirstB2)
rfmin = getMinOpen(rfmin, rmsFirstA2, rmsFirstB2)
if (rfmin < rmsvFirstY) {
rmsvFirstY = rfmin
if (rfmin === rmsFirstA2) {
firstZhou = 'a'
} else if (rfmin === rmsFirstB2) {
firstZhou = 'b'
}
rmsvFirstX = rmsData[rms][0]
}
const rmsSecondA2 = rmsData[rms][iphasicValue * step + 1]
const rmsSecondB2 = rmsData[rms][iphasicValue * step + 2]
rmsSA.push([rmsData[rms][0], rmsSecondA2])
rmsSB.push([rmsData[rms][0], rmsSecondB2])
rsmax = getMaxTwo(rsmax, rmsSecondA2, rmsSecondB2)
rsmin = getMinOpen(rsmin, rmsSecondA2, rmsSecondB2)
if (rsmin < rmsvSecondY) {
rmsvSecondY = rsmin
if (rsmin === rmsSecondA2) {
secondeZhou = 'a'
} else if (rsmin === rmsSecondB2) {
secondeZhou = 'b'
}
rmsvSecondX = rmsData[rms][0]
}
break
case 3:
const rmsFirstA3 = rmsData[rms][iphasicValue * step + 1] * xishu
const rmsFirstB3 = rmsData[rms][iphasicValue * step + 2] * xishu
const rmsFirstC3 = rmsData[rms][iphasicValue * step + 3] * xishu
rmsFA.push([rmsData[rms][0], rmsFirstA3])
rmsFB.push([rmsData[rms][0], rmsFirstB3])
rmsFC.push([rmsData[rms][0], rmsFirstC3])
rfmax = getMax(rfmax, rmsFirstA3, rmsFirstB3, rmsFirstC3)
rfmin = isOpen
? getMinOpen(rfmin, rmsFirstA3, rmsFirstC3)
: getMin(rfmin, rmsFirstA3, rmsFirstB3, rmsFirstC3)
if (rfmin < rmsvFirstY) {
rmsvFirstY = rfmin
if (rfmin === rmsFirstA3) {
firstZhou = 'a'
} else if (rfmin === rmsFirstB3) {
firstZhou = 'b'
} else {
firstZhou = 'c'
}
rmsvFirstX = rmsData[rms][0]
}
const rmsSecondA3 = rmsData[rms][iphasicValue * step + 1]
const rmsSecondB3 = rmsData[rms][iphasicValue * step + 2]
const rmsSecondC3 = rmsData[rms][iphasicValue * step + 3]
rmsSA.push([rmsData[rms][0], rmsSecondA3])
rmsSB.push([rmsData[rms][0], rmsSecondB3])
rmsSC.push([rmsData[rms][0], rmsSecondC3])
rsmax = getMax(rsmax, rmsSecondA3, rmsSecondB3, rmsSecondC3)
rsmin = isOpen
? getMinOpen(rsmin, rmsSecondA3, rmsSecondC3)
: getMin(rsmin, rmsSecondA3, rmsSecondB3, rmsSecondC3)
if (rsmin < rmsvSecondY) {
rmsvSecondY = rsmin
if (rsmin === rmsSecondA3) {
secondeZhou = 'a'
} else if (rsmin === rmsSecondB3) {
secondeZhou = 'b'
} else {
secondeZhou = 'c'
}
rmsvSecondX = rmsData[rms][0]
}
break
}
}
const instantF = { max: ifmax, min: ifmin }
const instantS = { max: ismax, min: ismin }
const RMSF = { max: rfmax, min: rfmin }
const RMSS = { max: rsmax, min: rsmin }
const RMSFMinDetail = { rmsvFirstX, rmsvFirstY, firstZhou }
const RMSSMinDetail = { rmsvSecondX, rmsvSecondY, secondeZhou }
const shunshiF = { shunshiFA, shunshiFB, shunshiFC }
const shunshiS = { shunshiSA, shunshiSB, shunshiSC }
const RMSFWave = { rmsFA, rmsFB, rmsFC }
const RMSSWave = { rmsSA, rmsSB, rmsSC }
const title = { aTitle, bTitle, cTitle, unit }
return {
instantF,
instantS,
RMSF,
RMSS,
RMSFMinDetail,
RMSSMinDetail,
shunshiF,
shunshiS,
RMSFWave,
RMSSWave,
title,
unit
}
}
// 监听消息
self.onmessage = function (e) {
const { wp, isOpen, value, boxoList, requestId } = e.data
try {
const iphasicValue = wp.iphasic || 1
const picCounts = (wp.waveTitle.length - 1) / iphasicValue
const waveDatas = []
for (let i = 0; i < picCounts; i++) {
const data = fliteWaveData(wp, i, iphasicValue, isOpen, boxoList)
waveDatas.push(data)
}
// 处理标题
let titles = ''
if (boxoList.systemType == 'pms') {
titles =
'变电站名称:' +
boxoList.powerStationName +
' 监测点名称:' +
boxoList.measurementPointName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'%  持续时间:' +
boxoList.duration +
's'
} else if (boxoList.systemType == 'ZL') {
titles =
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
' 监测点名称:' +
boxoList.equipmentName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
boxoList.evtParamVVaDepth +
'% 持续时间:' +
boxoList.evtParamTm +
's'
} else if (boxoList.systemType == 'YPT') {
titles =
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
' 监测点名称:' +
boxoList.lineName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'% 持续时间:' +
boxoList.persistTime +
's'
} else {
titles =
' 变电站名称:' +
boxoList.subName +
' 监测点名称:' +
boxoList.lineName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'% 持续时间:' +
boxoList.duration +
's'
}
// 发送处理结果回主线程
self.postMessage({
requestId,
titles: titles,
success: true,
waveDatas,
time: wp.time,
type: wp.waveType,
severity: wp.yzd,
iphasic: iphasicValue
})
} catch (error) {
self.postMessage({
requestId,
success: false,
error: error.message
})
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,207 @@
// waveData.worker.js
self.addEventListener('message', function (e) {
const { wp, value, iphasic, isOpen, boxoList, requestId } = e.data
// 处理波形数据的函数
const fliteWaveData = (wp, step) => {
// 将原有的fliteWaveData函数实现复制到这里
const shunData = wp.listWaveData
const pt = Number(wp.pt) / 1000
const ct = Number(wp.ct)
const titleList = wp.waveTitle
let xishu = pt
let aTitle = '',
bTitle = '',
cTitle = '',
unit = '电压'
let ifmax = 0,
ifmin = 0,
ismax = 0,
ismin = 0
const shunshiFA = []
const shunshiFB = []
const shunshiFC = []
const shunshiSA = []
const shunshiSB = []
const shunshiSC = []
if (shunData.length > 0) {
if (titleList[iphasic * step + 1]?.substring(0, 1) !== 'U') {
xishu = ct
unit = '电流'
}
for (let i = 1; i <= iphasic; i++) {
switch (i) {
case 1:
aTitle = titleList[iphasic * step + i]?.substring(1) || ''
break
case 2:
bTitle = titleList[iphasic * step + i]?.substring(1) || ''
break
case 3:
cTitle = titleList[iphasic * step + i]?.substring(1) || ''
break
}
}
if (shunData[0][iphasic * step + 1] !== undefined) {
ifmax = shunData[0][iphasic * step + 1] * xishu
ifmin = shunData[0][iphasic * step + 1] * xishu
ismax = shunData[0][iphasic * step + 1]
ismin = shunData[0][iphasic * step + 1]
}
for (let shun = 0; shun < shunData.length; shun++) {
if (shunData[shun][iphasic * step + 1] === undefined) {
break
}
switch (iphasic) {
case 1:
const shunFirstA = shunData[shun][iphasic * step + 1] * xishu
shunshiFA.push([shunData[shun][0], shunFirstA])
ifmax = Math.max(ifmax, shunFirstA)
ifmin = Math.min(ifmin, shunFirstA)
const shunSecondA = shunData[shun][iphasic * step + 1]
shunshiSA.push([shunData[shun][0], shunSecondA])
ismax = Math.max(ismax, shunSecondA)
ismin = Math.min(ismin, shunSecondA)
break
case 2:
const shunFirstA2 = shunData[shun][iphasic * step + 1] * xishu
const shunFirstB2 = shunData[shun][iphasic * step + 2] * xishu
shunshiFA.push([shunData[shun][0], shunFirstA2])
shunshiFB.push([shunData[shun][0], shunFirstB2])
ifmax = Math.max(ifmax, shunFirstA2, shunFirstB2)
ifmin = Math.min(ifmin, shunFirstA2, shunFirstB2)
const shunSecondA2 = shunData[shun][iphasic * step + 1]
const shunSecondB2 = shunData[shun][iphasic * step + 2]
shunshiSA.push([shunData[shun][0], shunSecondA2])
shunshiSB.push([shunData[shun][0], shunSecondB2])
ismax = Math.max(ismax, shunSecondA2, shunSecondB2)
ismin = Math.min(ismin, shunSecondA2, shunSecondB2)
break
case 3:
const shunFirstA3 = shunData[shun][iphasic * step + 1] * xishu
const shunFirstB3 = shunData[shun][iphasic * step + 2] * xishu
const shunFirstC3 = shunData[shun][iphasic * step + 3] * xishu
shunshiFA.push([shunData[shun][0], shunFirstA3])
shunshiFB.push([shunData[shun][0], shunFirstB3])
shunshiFC.push([shunData[shun][0], shunFirstC3])
ifmax = Math.max(ifmax, shunFirstA3, shunFirstB3, shunFirstC3)
ifmin = isOpen
? Math.min(ifmin, shunFirstA3, shunFirstC3)
: Math.min(ifmin, shunFirstA3, shunFirstB3, shunFirstC3)
const shunSecondA3 = shunData[shun][iphasic * step + 1]
const shunSecondB3 = shunData[shun][iphasic * step + 2]
const shunSecondC3 = shunData[shun][iphasic * step + 3]
shunshiSA.push([shunData[shun][0], shunSecondA3])
shunshiSB.push([shunData[shun][0], shunSecondB3])
shunshiSC.push([shunData[shun][0], shunSecondC3])
ismax = Math.max(ismax, shunSecondA3, shunSecondB3, shunSecondC3)
ismin = isOpen
? Math.min(ismin, shunSecondA3, shunSecondC3)
: Math.min(ismin, shunSecondA3, shunSecondB3, shunSecondC3)
break
}
}
}
const instantF = { max: ifmax, min: ifmin }
const instantS = { max: ismax, min: ismin }
const shunshiF = { shunshiFA, shunshiFB, shunshiFC }
const shunshiS = { shunshiSA, shunshiSB, shunshiSC }
const title = { aTitle, bTitle, cTitle, unit }
return { instantF, instantS, shunshiF, shunshiS, title, unit }
}
// 处理标题
let titles = ''
if (boxoList.systemType == 'pms') {
titles =
'变电站名称:' +
boxoList.powerStationName +
' 监测点名称:' +
boxoList.measurementPointName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'% 持续时间:' +
boxoList.duration +
's'
} else if (boxoList.systemType == 'ZL') {
titles =
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
' 监测点名称:' +
boxoList.equipmentName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
boxoList.evtParamVVaDepth +
'% 持续时间:' +
boxoList.evtParamTm +
's'
} else if (boxoList.systemType == 'YPT') {
titles =
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
' 监测点名称:' +
boxoList.lineName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'% 持续时间:' +
boxoList.persistTime +
's'
} else {
titles =
'变电站名称:' +
boxoList.subName +
' 监测点名称:' +
boxoList.lineName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'% 持续时间:' +
boxoList.duration +
's'
}
const iphasicValue = wp.iphasic || 1
const picCounts = (wp.waveTitle.length - 1) / iphasicValue
const waveDatas = []
for (let i = 0; i < picCounts; i++) {
const data = fliteWaveData(wp, i)
waveDatas.push(data)
}
const time = wp.time
const type = wp.waveType
let severity = wp.yzd
if (severity < 0) {
severity = '/'
type = '/'
}
// 将处理结果发送回主线程
self.postMessage({
requestId,
success: true,
waveDatas,
time,
type,
severity,
titles,
iphasic: iphasicValue
})
})

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
<div v-if="view2">
<el-row>
<el-col :span="12">
<span style="font-size: 14px; line-height: 30px">值类型选择:</span>
<!-- <span style="font-size: 14px; line-height: 30px">值类型选择:</span>
<el-select
style="min-width: 200px; width: 200px"
@change="changeView"
@@ -15,7 +15,11 @@
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-select> -->
<el-radio-group v-model.trim="value" @change="changeView">
<el-radio-button label="一次值" :value="1" />
<el-radio-button label="二次值" :value="2" />
</el-radio-group>
<!-- <el-button v-if="view2 && senior" class="ml10" type="primary" @click="AdvancedAnalytics">
高级分析
</el-button> -->
@@ -24,37 +28,18 @@
<el-button @click="backbxlb" icon="el-icon-Back" style="float: right">返回</el-button>
</el-col>
</el-row>
<div v-loading="loading" style="height: calc(100vh - 190px)">
<el-tabs v-if="view4" class="default-main" v-model="bxactiveName" @tab-click="bxhandleClick">
<el-tab-pane
label="瞬时波形"
name="ssbx"
class="boxbx pt10 pb10"
:style="'height:' + bxecharts + ';overflow-y: scroll;'"
>
<shushiboxi
ref="shushiboxiRef"
v-if="bxactiveName == 'ssbx' && showBoxi"
:value="value"
:parentHeight="parentHeight"
:boxoList="boxoList"
:wp="wp"
></shushiboxi>
<div v-loading="loading" style="height: calc(100vh - 190px)" class="mt10">
<el-tabs v-if="view4" type="border-card" v-model="bxactiveName"
@tab-click="bxhandleClick">
<el-tab-pane label="瞬时波形" name="ssbx" class="boxbx pt10 pb10"
:style="'height:' + bxecharts + ';overflow-y: scroll;'">
<shushiboxi ref="shushiboxiRef" v-if="bxactiveName == 'ssbx' && showBoxi" :value="value"
:parentHeight="parentHeight" :boxoList="boxoList" :wp="wp"></shushiboxi>
</el-tab-pane>
<el-tab-pane
label="RMS波形"
class="boxbx pt10 pb10"
name="rmsbx"
:style="'height:' + bxecharts + ';overflow-y: scroll;'"
>
<rmsboxi
ref="rmsboxiRef"
v-if="bxactiveName == 'rmsbx' && showBoxi"
:value="value"
:parentHeight="parentHeight"
:boxoList="boxoList"
:wp="wp"
></rmsboxi>
<el-tab-pane label="RMS波形" class="boxbx pt10 pb10" name="rmsbx"
:style="'height:' + bxecharts + ';overflow-y: scroll;'">
<rmsboxi ref="rmsboxiRef" v-if="bxactiveName == 'rmsbx' && showBoxi" :value="value"
:parentHeight="parentHeight" :boxoList="boxoList" :wp="wp"></rmsboxi>
</el-tab-pane>
</el-tabs>
<el-empty v-else description="暂无数据" style="height: calc(100vh - 190px)" />
@@ -100,7 +85,7 @@ const options = ref([
}
])
const shushiboxiRef = ref()
const bxecharts = ref(mainHeight(95).height as any)
const bxecharts = ref(mainHeight(145).height as any)
const view2 = ref(true)
const boxoList: any = ref(null)
const wp = ref(null)
@@ -128,9 +113,6 @@ const open = async (row: any) => {
})
}
const bxhandleClick = (tab: any) => {
if (shushiboxiRef.value) shushiboxiRef.value.backbxlb()
if (rmsboxiRef.value) rmsboxiRef.value.backbxlb()
loading.value = true
if (tab.name == 'ssbx') {
bxactiveName.value = 'ssbx'
@@ -145,8 +127,7 @@ const bxhandleClick = (tab: any) => {
const backbxlb = () => {
boxoList.value = null
wp.value = null
if (shushiboxiRef.value) shushiboxiRef.value.backbxlb()
if (rmsboxiRef.value) rmsboxiRef.value.backbxlb()
emit('backbxlb')
}

View File

@@ -1,24 +1,44 @@
<template>
<div :style="{ height: typeof props.height === 'string' ? props.height : tableStore.table.height }">
<vxe-table ref="tableRef" height="auto" :key="key" :data="tableStore.table.data"
v-loading="tableStore.table.loading" v-bind="Object.assign({}, defaultAttribute, $attrs)"
@checkbox-all="selectChangeEvent" @checkbox-change="selectChangeEvent" :showOverflow="showOverflow"
@sort-change="handleSortChange">
<vxe-table
ref="tableRef"
height="auto"
:key="key"
:data="tableStore.table.data"
v-loading="tableStore.table.loading"
v-bind="Object.assign({}, defaultAttribute, $attrs)"
@checkbox-all="selectChangeEvent"
@checkbox-change="selectChangeEvent"
:showOverflow="showOverflow"
>
<!-- @sort-change="handleSortChange" -->
<!-- Column 组件内部是 el-table-column -->
<template v-if="isGroup">
<GroupColumn :column="tableStore.table.column" />
</template>
<template v-else>
<Column :attr="item" :key="key + '-column'" v-for="(item, key) in tableStore.table.column"
:tree-node="item.treeNode">
<Column
:attr="item"
:key="key + '-column'"
v-for="(item, key) in tableStore.table.column"
:tree-node="item.treeNode"
>
<!-- tableStore 预设的列 render 方案 -->
<template v-if="item.render" #default="scope">
<FieldRender :field="item" :row="scope.row" :column="scope.column" :index="scope.rowIndex" :key="key +
'-' +
item.render +
'-' +
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
" />
<FieldRender
:field="item"
:row="scope.row"
:column="scope.column"
:index="scope.rowIndex"
:key="
key +
'-' +
item.render +
'-' +
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
"
/>
</template>
</Column>
</template>
@@ -27,11 +47,16 @@
</div>
<div v-if="tableStore.showPage" class="table-pagination">
<el-pagination :currentPage="tableStore.table.params!.pageNum" :page-size="tableStore.table.params!.pageSize"
:page-sizes="pageSizes" background
<el-pagination
:currentPage="tableStore.table.params!.pageNum"
:page-size="tableStore.table.params!.pageSize"
:page-sizes="pageSizes"
background
:layout="config.layout.shrink ? 'prev, next, jumper' : 'sizes,total, ->, prev, pager, next, jumper'"
:total="tableStore.table.total" @size-change="onTableSizeChange"
@current-change="onTableCurrentChange"></el-pagination>
:total="tableStore.table.total"
@size-change="onTableSizeChange"
@current-change="onTableCurrentChange"
></el-pagination>
</div>
<slot name="footer"></slot>
</template>

View File

@@ -11,25 +11,25 @@
:data="eventList.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
>
<!-- <vxe-column type="seq" width="70px" title="序号"></vxe-column> -->
<vxe-column field="time" width="180px" sortable title="发生时刻"></vxe-column>
<vxe-column field="lineName" title="监测点"></vxe-column>
<vxe-column field="powerCompany" title="变电站" width="100px"></vxe-column>
<vxe-column field="powerCompany" title="供电公司" width="100px"></vxe-column>
<vxe-column field="persistTime" width="120px" sortable title="持续时间(s)">
<template #default="{ row }">
{{ Math.floor(row.persistTime * 1000) / 1000 }}
</template>
</vxe-column>
<vxe-column field="time" width="180px" sortable title="暂降发生时刻"></vxe-column>
<vxe-column field="eventValue" width="160px" sortable title="暂降(骤升)幅值(%)">
<template #default="{ row }">
{{ Math.floor(row.eventValue * 10000) / 100 }}
</template>
</vxe-column>
<vxe-column field="persistTime" width="120px" sortable title="持续时间(s)">
<template #default="{ row }">
{{ Math.floor(row.persistTime * 1000) / 1000 }}
</template>
</vxe-column>
<vxe-column field="eventType" width="100px" title="触发类型">
<template #default="{ row }">
{{ event.filter(item => item.id == row.eventType)[0]?.name || '/' }}
</template>
</vxe-column>
<vxe-column field="powerCompany" title="变电站" width="100px"></vxe-column>
<vxe-column field="powerCompany" title="供电公司" width="100px"></vxe-column>
<vxe-column field="lineName" title="监测点"></vxe-column>
</vxe-table>
<div class="table-pagination mt10">
<el-pagination
@@ -99,7 +99,6 @@ const dataSocket = reactive({
// }
const socket = async () => {
const url = localStorage.getItem('WebSocketUrl3') || 'null' //'ws://192.168.2.130:10203/event/'
// const url = 'ws://192.168.1.68:10203/event/'

View File

@@ -0,0 +1,59 @@
const AXIS_DECIMALS = 2
export function roundAxisValue(val: number, decimals = AXIS_DECIMALS): number {
if (!Number.isFinite(val)) return 0
const factor = 10 ** decimals
return Math.round(val * factor) / factor
}
/** Y 轴刻度:最多 2 位小数,末尾 0 去掉(如 1.00 → 10.10 → 0.1 */
export function formatAxisLabel(value: number): string {
if (!Number.isFinite(value)) return '0'
return String(Number(roundAxisValue(value).toFixed(AXIS_DECIMALS)))
}
/** 瞬间波形 Y 轴范围 */
export function calcShuYAxisRange(dataMin: number, dataMax: number): { min: number; max: number } {
const min = Number(dataMin)
const max = Number(dataMax)
if (!Number.isFinite(min) || !Number.isFinite(max)) {
return { min: 0, max: 1 }
}
let axisMax = max * 1.1
let axisMin = min > 0 ? min - min * 0.1 : min * 1.1
if (axisMax <= axisMin) {
const pad = Math.abs(max) * 0.1 || 0.01
axisMax = max + pad
axisMin = min - pad
}
return {
min: roundAxisValue(axisMin),
max: roundAxisValue(axisMax)
}
}
/** RMS 波形 Y 轴范围 */
export function calcRmsYAxisRange(dataMin: number, dataMax: number): { min: number; max: number } {
const min = Number(dataMin)
const max = Number(dataMax)
if (!Number.isFinite(min) || !Number.isFinite(max)) {
return { min: 0, max: 1 }
}
let axisMax = max * 1.06 * 1.1
let axisMin = min - min * 0.2
if (axisMax <= axisMin) {
const pad = Math.abs(max - min) * 0.1 || Math.abs(max) * 0.1 || 0.01
axisMax = max + pad
axisMin = min - pad
}
return {
min: roundAxisValue(axisMin),
max: roundAxisValue(axisMax)
}
}

42
src/utils/waveCache.ts Normal file
View File

@@ -0,0 +1,42 @@
const MAX_CACHE_SIZE = 30
const cache = new Map<string, unknown>()
function dataFingerprint(data: unknown[][] | undefined): string {
if (!data?.length) return '0'
const first = data[0]
const last = data[data.length - 1]
return `${data.length}:${first?.[0]}:${last?.[0]}`
}
export function buildWaveCacheKey(
type: 'shu' | 'rms',
wp: Record<string, any> | undefined,
value: number,
isOpen: boolean,
boxoList: Record<string, any>
): string {
if (!wp) return ''
const waveFp =
type === 'shu' ? dataFingerprint(wp.listWaveData) : dataFingerprint(wp.listRmsData)
const boxoFp = boxoList?.startTime ?? boxoList?.lineName ?? boxoList?.equipmentName ?? ''
return `${type}|${wp.time}|${wp.waveType}|${wp.iphasic}|${value}|${isOpen}|${waveFp}|${boxoFp}`
}
export function getWaveCache<T>(key: string): T | null {
if (!key || !cache.has(key)) return null
const value = cache.get(key) as T
cache.delete(key)
cache.set(key, value)
return value
}
export function setWaveCache(key: string, value: unknown): void {
if (!key) return
if (cache.has(key)) cache.delete(key)
cache.set(key, value)
while (cache.size > MAX_CACHE_SIZE) {
const oldest = cache.keys().next().value
if (oldest !== undefined) cache.delete(oldest)
}
}

View File

@@ -0,0 +1,96 @@
import { toRaw } from 'vue'
type WorkerMessageHandler = (data: any) => void
let shuWorker: Worker | null = null
let rmsWorker: Worker | null = null
/** 递归剥离 Vue 响应式代理,得到可 structuredClone 的纯对象 */
export function toPlainDeep<T>(value: T): T {
const raw = toRaw(value as object) as T
if (Array.isArray(raw)) {
return raw.map(item => toPlainDeep(item)) as T
}
if (raw !== null && typeof raw === 'object') {
const out: Record<string, unknown> = {}
for (const [key, val] of Object.entries(raw)) {
out[key] = toPlainDeep(val)
}
return out as T
}
return raw
}
const BOXO_LIST_KEYS = [
'systemType',
'powerStationName',
'measurementPointName',
'startTime',
'featureAmplitude',
'duration',
'engineeringName',
'equipmentName',
'evtParamVVaDepth',
'evtParamTm',
'lineName',
'persistTime',
'subName'
] as const
export function buildWorkerPayload(
type: 'shu' | 'rms',
wp: Record<string, any>,
boxoList: Record<string, any>,
extras: { requestId: number; value: number; isOpen: boolean; iphasic?: number }
) {
const plainWp = toPlainDeep(wp)
const wpPayload: Record<string, unknown> = {
pt: plainWp.pt,
ct: plainWp.ct,
waveTitle: plainWp.waveTitle,
iphasic: plainWp.iphasic,
time: plainWp.time,
waveType: plainWp.waveType,
yzd: plainWp.yzd
}
if (type === 'shu') {
wpPayload.listWaveData = plainWp.listWaveData
} else {
wpPayload.listRmsData = plainWp.listRmsData
}
const plainBoxo: Record<string, unknown> = {}
const rawBoxo = toPlainDeep(boxoList)
for (const key of BOXO_LIST_KEYS) {
if (rawBoxo[key] !== undefined) {
plainBoxo[key] = rawBoxo[key]
}
}
return {
requestId: extras.requestId,
value: extras.value,
isOpen: extras.isOpen,
iphasic: extras.iphasic,
wp: wpPayload,
boxoList: plainBoxo
}
}
export function getShuWorker(onMessage: WorkerMessageHandler): Worker {
if (!shuWorker) {
shuWorker = new Worker(new URL('../components/echarts/shuWorker.js', import.meta.url))
}
shuWorker.onmessage = e => onMessage(e.data)
shuWorker.onerror = error => console.error('Shu worker error:', error)
return shuWorker
}
export function getRmsWorker(onMessage: WorkerMessageHandler): Worker {
if (!rmsWorker) {
rmsWorker = new Worker(new URL('../components/echarts/rmsWorker.js', import.meta.url))
}
rmsWorker.onmessage = e => onMessage(e.data)
rmsWorker.onerror = error => console.error('Rms worker error:', error)
return rmsWorker
}

View File

@@ -58,7 +58,7 @@ export default class SocketService {
}
// 处理连接成功事件
private handleOpen(): void {
ElMessage.success('webSocket连接服务端成功了')
// ElMessage.success('webSocket连接服务端成功了')
console.log('连接服务端成功了')
this.connected = true
this.connectRetryCount = 0
@@ -110,7 +110,7 @@ export default class SocketService {
}
} else {
this.callBackMapping['message']!({ Flag: false })
ElMessage.error(event.data)
// ElMessage.error(event.data)
}
}

View File

@@ -1,423 +1,423 @@
<template>
<div class="default-main">
<TableHeader datePicker theCurrentTime area ref="header">
<!-- <template v-slot:select>
</template> -->
</TableHeader>
<div v-loading="tableStore.table.loading">
<el-row :gutter="10" class="pd10">
<el-col :span="11" style="position: relative">
<el-card>
<el-radio-group
v-model="tableStore.table.params.type"
class="group"
@change="tableStore.index()"
>
<el-radio-button label="风电场" value="1" />
<el-radio-button label="光伏电站" value="2" />
</el-radio-group>
<MyEchartMap
ref="EchartMap"
:options="echartMapList"
class="map"
@eliminate="eliminate"
@getRegionByRegion="getRegionByRegion"
@clickMap="clickMap"
/>
</el-card>
</el-col>
<el-col :span="13">
<el-card>
<template #header>
<div class="card-header">
<span>暂降列表</span>
</div>
</template>
<!-- <h3 class="mb10">暂降列表</h3> -->
<div class="tall1">
<vxe-table
height="auto"
auto-resize
:data="distributionData"
v-loading="loading"
v-bind="defaultAttribute"
>
<vxe-column
field="newStationName"
title="新能源站名称"
min-width="150px"
show-overflow-tooltip
></vxe-column>
<vxe-column field="startTime" title="暂降发生时刻" min-width="150px"></vxe-column>
<vxe-column
field="featureAmplitude"
title="暂降(骤升)幅值(%)"
sortable
min-width="150px"
></vxe-column>
<vxe-column
field="advanceReason"
title="暂降原因"
sortable
:formatter="formFilter"
min-width="100px"
></vxe-column>
<vxe-column field="severity" title="严重度" min-width="100px" sortable></vxe-column>
<vxe-column title="操作" width="80px">
<template #default="{ row }">
<el-button
type="primary"
v-if="row.wavePath != null"
size="small"
link
@click="boxi(row)"
>
查看波形
</el-button>
<el-button v-else disabled size="small" link>暂无波形</el-button>
</template>
</vxe-column>
</vxe-table>
</div>
</el-card>
<el-card class="mt10">
<template #header>
<div class="card-header">
<span>暂降波形</span>
</div>
</template>
<div class="tall" v-loading="loading1">
<!-- <h3 class="mb10">暂降波形</h3> -->
<div v-if="wp != null">
<rmsboxi :value="1" :height="height" :boxoList="boxoList" :wp="wp" />
</div>
<el-empty v-else description="暂无数据" class="custom-empty" />
</div>
</el-card>
</el-col>
</el-row>
</div>
</div>
</template>
<script setup lang="ts">
import TableHeader from '@/components/table/header/index.vue'
import { useDictData } from '@/stores/dictData'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import MyEchartMap from '@/components/echarts/MyEchartMap.vue'
import TableStore from '@/utils/tableStore'
import { voltageRideThroughEventQueryPage } from '@/api/event-boot/highAndLowPressure'
import { getMonitorEventAnalyseWave, getTransientDetailById } from '@/api/event-boot/transient'
import rmsboxi from '@/components/echarts/rmsboxi.vue'
import { ref, onMounted, provide } from 'vue'
import { mainHeight } from '@/utils/layout'
import { FormItem } from 'vxe-table'
defineOptions({
name: 'newEnergy/highAndLowPressure'
})
const EchartMap = ref()
const dictData = useDictData()
const reason = dictData.getBasicData('Event_Reason')
const triggerType = dictData.getBasicData('Event_Statis')
const echartMapList: any = ref({})
const header = ref()
const distributionData: any = ref([])
const loading = ref(false)
const loading1 = ref(false)
const boxoList = ref(null)
const wp = ref(null)
const tableStore = new TableStore({
url: '/event-boot/voltageRideThrough/view',
method: 'POST',
column: [],
beforeSearchFun: () => {
tableStore.table.params.areaId = tableStore.table.params.deptIndex
},
loadCallback: () => {
// 处理地图数据
map(tableStore.table.data)
// tabulation(tableStore.table.data)
EchartMap.value.GetEchar(header.value.areaRef.areaName)
if (tableStore.table.data.length > 0) {
tabulation({ data: tableStore.table.data[0], seriesName: '高压' })
}
}
})
const height = mainHeight(200, 2).height
provide('tableStore', tableStore)
tableStore.table.params.type = '1'
// 地图点击事件
const getRegionByRegion = (list: any) => {
tableStore.table.params.deptIndex = list.id
tableStore.onTableAction('search', {})
}
// 消除点
const eliminate = (name: string) => {
echartMapList.value.options.series = []
EchartMap.value.GetEchar(name)
}
// 地图数处理
const map = (res: any) => {
echartMapList.value = {
title: {
text: '高/低电压穿越'
},
tooltip: {
trigger: 'item',
formatter: function (params) {
if (params.seriesType == 'bar3D') {
return [params.seriesName, params.name + '' + params.value[2] + (params.value[3] || '')].join(
'<br />'
)
}
}
},
legend: {
selectedMode: false
},
geo3D: {
show: true,
// name: '浙江',
itemStyle: {
color: getComputedStyle(document.documentElement).getPropertyValue('--el-color-primary-light-3'),
borderWidth: 1,
borderColor: '#fff'
},
emphasis: {
label: { show: true, fontSize: 16 },
itemStyle: {
color: getComputedStyle(document.documentElement).getPropertyValue('--el-color-primary-light-7')
}
},
viewControl: {
alpha: 60,
distance: 120,
panMouseButton: 'right', //平移操作使用的鼠标按键
rotateMouseButton: 'left' //旋转操作使用的鼠标按键
},
label: {
show: true,
color: '#000',
fontSize: 14,
distance: 0,
textStyle: {
color: '#000',
backgroundColor: '#000'
}
},
data: [
{ name: '低压', field: 'lowPressure', unit: '次' },
{ name: '高压', field: 'highPressure', unit: '次' }
]
},
options: {
series: [
{
name: '低压',
type: 'bar3D',
coordinateSystem: 'geo3D',
shading: 'lambert',
label: {
show: true,
position: 'top',
formatter: params => {
return params.value[2]
}
},
data:
res.length == 0
? []
: res.map((item: any) => {
return {
...item,
value: [item.lng, item.lat, item.lowPressure || 0]
}
}),
// data:[],
barSize: 1,
minHeight: 1,
itemStyle: {
color: '#77DA63'
},
emphasis: {
label: { show: true }
}
},
{
name: '高压',
type: 'bar3D',
coordinateSystem: 'geo3D',
shading: 'lambert',
label: {
show: true,
// position: 'top',
formatter: params => {
return params.value[2]
}
},
data:
res.length == 0
? []
: res.map((item: any) => {
return {
...item,
value: [item.lng - 0.1, item.lat, item.highPressure || 0]
}
}),
// [
// {
// adcode: 330400,
// name: '大连',
// wcs: 10,
// mbs: 40,
// wcl: 100,
// value: [121.67391, 38.947468, 40, '']
// }
// ],
barSize: 1,
minHeight: 1,
itemStyle: {
color: '#FFBF00'
},
emphasis: {
label: { show: true }
}
}
]
}
}
}
// 点击地图
const clickMap = (e: any) => {
tabulation(e)
}
// 表格数据处理
const tabulation = (e: any) => {
console.log()
loading.value = true
voltageRideThroughEventQueryPage({
...tableStore.table.params,
areaId: e.data.id,
frequencyType:
e.seriesName == '高压'
? triggerType.filter(item => item.code == 'Voltage_Rise')[0].id
: triggerType.filter(item => item.code == 'Voltage_Dip')[0].id
})
.then(res => {
distributionData.value = res.data
for (let i = 0; i < res.data.length; i++) {
if (res.data[i].wavePath != null) {
boxi(res.data[i])
break
}
}
// res.data.forEach((item: any) => {
// if (item.wavePath != null) {
// boxi(item)
// return
// }
// })
// 。wavePath
loading.value = false
})
.catch(() => {
loading.value = false
})
}
const formFilter = (row: any) => {
if (row.column.property == 'advanceReason') {
let title = ''
reason.forEach(item => {
if (item.id == row.row.advanceReason) {
title = item.name
} else if (row.row.advanceReason == null || row.row.advanceReason == '') {
title = '/'
}
})
return title
} else {
return row.row[row.column.property]
}
}
// 查看波形数据
const boxi = async (row: any) => {
loading1.value = true
wp.value = null
await getTransientDetailById({
eventId: row.eventId,
sysType: 0,
smallType: 0
}).then(res => {
boxoList.value = res.data
})
await getMonitorEventAnalyseWave({
id: row.eventId,
systemType: 0,
type: 0
}).then(res => {
if (res != undefined) {
wp.value = res.data
}
loading1.value = false
})
}
onMounted(() => {
tableStore.index()
})
const layout = mainHeight(83) as any
const layout1 = mainHeight(93) as any
</script>
<style lang="scss" scoped>
.map {
height: calc(v-bind('layout1.height') - 30px);
}
.tall {
height: calc((v-bind('layout1.height') - 100px) / 2);
}
.tall1 {
height: calc((v-bind('layout1.height') - 100px) / 2 - 50px);
}
.group {
position: absolute;
top: 15px;
right: 20px;
z-index: 10;
}
:deep(.el-card__body) {
padding: 10px;
}
/* 自定义 el-empty 的样式 */
:deep(.custom-empty) {
display: flex;
justify-content: center;
align-items: center;
height: 100%; /* 调整高度 */
padding: 20px; /* 调整内边距 */
.el-empty__image {
display: none; /* 隐藏默认图片 */
}
.el-empty__description {
font-size: 14px; /* 调整字体大小 */
color: var(--vxe-font-color);
}
}
</style>
<template>
<div class="default-main">
<TableHeader datePicker theCurrentTime area ref="header">
<!-- <template v-slot:select>
</template> -->
</TableHeader>
<div v-loading="tableStore.table.loading">
<el-row :gutter="10" class="pd10">
<el-col :span="11" style="position: relative">
<el-card>
<el-radio-group
v-model="tableStore.table.params.type"
class="group"
@change="tableStore.index()"
>
<el-radio-button label="风电场" value="1" />
<el-radio-button label="光伏电站" value="2" />
</el-radio-group>
<MyEchartMap
ref="EchartMap"
:options="echartMapList"
class="map"
@eliminate="eliminate"
@getRegionByRegion="getRegionByRegion"
@clickMap="clickMap"
/>
</el-card>
</el-col>
<el-col :span="13">
<el-card>
<template #header>
<div class="card-header">
<span>暂降列表</span>
</div>
</template>
<!-- <h3 class="mb10">暂降列表</h3> -->
<div class="tall1">
<vxe-table
height="auto"
auto-resize
:data="distributionData"
v-loading="loading"
v-bind="defaultAttribute"
>
<vxe-column
field="newStationName"
title="新能源站名称"
min-width="150px"
show-overflow-tooltip
></vxe-column>
<vxe-column field="startTime" title="暂降发生时刻" min-width="180px" sortable></vxe-column>
<vxe-column
field="featureAmplitude"
title="暂降(骤升)幅值(%)"
sortable
min-width="160px"
></vxe-column>
<vxe-column
field="advanceReason"
title="暂降原因"
sortable
:formatter="formFilter"
min-width="100px"
></vxe-column>
<vxe-column field="severity" title="严重度" min-width="100px" sortable></vxe-column>
<vxe-column title="操作" width="80px">
<template #default="{ row }">
<el-button
type="primary"
v-if="row.wavePath != null"
size="small"
link
@click="boxi(row)"
>
查看波形
</el-button>
<el-button v-else disabled size="small" link>暂无波形</el-button>
</template>
</vxe-column>
</vxe-table>
</div>
</el-card>
<el-card class="mt10">
<template #header>
<div class="card-header">
<span>暂降波形</span>
</div>
</template>
<div class="tall" v-loading="loading1">
<!-- <h3 class="mb10">暂降波形</h3> -->
<div v-if="wp != null">
<rmsboxi :value="1" :height="height" :boxoList="boxoList" :wp="wp" />
</div>
<el-empty v-else description="暂无数据" class="custom-empty" />
</div>
</el-card>
</el-col>
</el-row>
</div>
</div>
</template>
<script setup lang="ts">
import TableHeader from '@/components/table/header/index.vue'
import { useDictData } from '@/stores/dictData'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import MyEchartMap from '@/components/echarts/MyEchartMap.vue'
import TableStore from '@/utils/tableStore'
import { voltageRideThroughEventQueryPage } from '@/api/event-boot/highAndLowPressure'
import { getMonitorEventAnalyseWave, getTransientDetailById } from '@/api/event-boot/transient'
import rmsboxi from '@/components/echarts/rmsboxi.vue'
import { ref, onMounted, provide } from 'vue'
import { mainHeight } from '@/utils/layout'
import { FormItem } from 'vxe-table'
defineOptions({
name: 'newEnergy/highAndLowPressure'
})
const EchartMap = ref()
const dictData = useDictData()
const reason = dictData.getBasicData('Event_Reason')
const triggerType = dictData.getBasicData('Event_Statis')
const echartMapList: any = ref({})
const header = ref()
const distributionData: any = ref([])
const loading = ref(false)
const loading1 = ref(false)
const boxoList = ref(null)
const wp = ref(null)
const tableStore = new TableStore({
url: '/event-boot/voltageRideThrough/view',
method: 'POST',
column: [],
beforeSearchFun: () => {
tableStore.table.params.areaId = tableStore.table.params.deptIndex
},
loadCallback: () => {
// 处理地图数据
map(tableStore.table.data)
// tabulation(tableStore.table.data)
EchartMap.value.GetEchar(header.value.areaRef.areaName)
if (tableStore.table.data.length > 0) {
tabulation({ data: tableStore.table.data[0], seriesName: '高压' })
}
}
})
const height = mainHeight(200, 2).height
provide('tableStore', tableStore)
tableStore.table.params.type = '1'
// 地图点击事件
const getRegionByRegion = (list: any) => {
tableStore.table.params.deptIndex = list.id
tableStore.onTableAction('search', {})
}
// 消除点
const eliminate = (name: string) => {
echartMapList.value.options.series = []
EchartMap.value.GetEchar(name)
}
// 地图数处理
const map = (res: any) => {
echartMapList.value = {
title: {
text: '高/低电压穿越'
},
tooltip: {
trigger: 'item',
formatter: function (params) {
if (params.seriesType == 'bar3D') {
return [params.seriesName, params.name + '' + params.value[2] + (params.value[3] || '')].join(
'<br />'
)
}
}
},
legend: {
selectedMode: false
},
geo3D: {
show: true,
// name: '浙江',
itemStyle: {
color: getComputedStyle(document.documentElement).getPropertyValue('--el-color-primary-light-3'),
borderWidth: 1,
borderColor: '#fff'
},
emphasis: {
label: { show: true, fontSize: 16 },
itemStyle: {
color: getComputedStyle(document.documentElement).getPropertyValue('--el-color-primary-light-7')
}
},
viewControl: {
alpha: 60,
distance: 120,
panMouseButton: 'right', //平移操作使用的鼠标按键
rotateMouseButton: 'left' //旋转操作使用的鼠标按键
},
label: {
show: true,
color: '#000',
fontSize: 14,
distance: 0,
textStyle: {
color: '#000',
backgroundColor: '#000'
}
},
data: [
{ name: '低压', field: 'lowPressure', unit: '次' },
{ name: '高压', field: 'highPressure', unit: '次' }
]
},
options: {
series: [
{
name: '低压',
type: 'bar3D',
coordinateSystem: 'geo3D',
shading: 'lambert',
label: {
show: true,
position: 'top',
formatter: params => {
return params.value[2]
}
},
data:
res.length == 0
? []
: res.map((item: any) => {
return {
...item,
value: [item.lng, item.lat, item.lowPressure || 0]
}
}),
// data:[],
barSize: 1,
minHeight: 1,
itemStyle: {
color: '#77DA63'
},
emphasis: {
label: { show: true }
}
},
{
name: '高压',
type: 'bar3D',
coordinateSystem: 'geo3D',
shading: 'lambert',
label: {
show: true,
// position: 'top',
formatter: params => {
return params.value[2]
}
},
data:
res.length == 0
? []
: res.map((item: any) => {
return {
...item,
value: [item.lng - 0.1, item.lat, item.highPressure || 0]
}
}),
// [
// {
// adcode: 330400,
// name: '大连',
// wcs: 10,
// mbs: 40,
// wcl: 100,
// value: [121.67391, 38.947468, 40, '']
// }
// ],
barSize: 1,
minHeight: 1,
itemStyle: {
color: '#FFBF00'
},
emphasis: {
label: { show: true }
}
}
]
}
}
}
// 点击地图
const clickMap = (e: any) => {
tabulation(e)
}
// 表格数据处理
const tabulation = (e: any) => {
console.log()
loading.value = true
voltageRideThroughEventQueryPage({
...tableStore.table.params,
areaId: e.data.id,
frequencyType:
e.seriesName == '高压'
? triggerType.filter(item => item.code == 'Voltage_Rise')[0].id
: triggerType.filter(item => item.code == 'Voltage_Dip')[0].id
})
.then(res => {
distributionData.value = res.data
for (let i = 0; i < res.data.length; i++) {
if (res.data[i].wavePath != null) {
boxi(res.data[i])
break
}
}
// res.data.forEach((item: any) => {
// if (item.wavePath != null) {
// boxi(item)
// return
// }
// })
// 。wavePath
loading.value = false
})
.catch(() => {
loading.value = false
})
}
const formFilter = (row: any) => {
if (row.column.property == 'advanceReason') {
let title = ''
reason.forEach(item => {
if (item.id == row.row.advanceReason) {
title = item.name
} else if (row.row.advanceReason == null || row.row.advanceReason == '') {
title = '/'
}
})
return title
} else {
return row.row[row.column.property]
}
}
// 查看波形数据
const boxi = async (row: any) => {
loading1.value = true
wp.value = null
await getTransientDetailById({
eventId: row.eventId,
sysType: 0,
smallType: 0
}).then(res => {
boxoList.value = res.data
})
await getMonitorEventAnalyseWave({
id: row.eventId,
systemType: 0,
type: 0
}).then(res => {
if (res != undefined) {
wp.value = res.data
}
loading1.value = false
})
}
onMounted(() => {
tableStore.index()
})
const layout = mainHeight(83) as any
const layout1 = mainHeight(93) as any
</script>
<style lang="scss" scoped>
.map {
height: calc(v-bind('layout1.height') - 30px);
}
.tall {
height: calc((v-bind('layout1.height') - 100px) / 2);
}
.tall1 {
height: calc((v-bind('layout1.height') - 100px) / 2 - 50px);
}
.group {
position: absolute;
top: 15px;
right: 20px;
z-index: 10;
}
:deep(.el-card__body) {
padding: 10px;
}
/* 自定义 el-empty 的样式 */
:deep(.custom-empty) {
display: flex;
justify-content: center;
align-items: center;
height: 100%; /* 调整高度 */
padding: 20px; /* 调整内边距 */
.el-empty__image {
display: none; /* 隐藏默认图片 */
}
.el-empty__description {
font-size: 14px; /* 调整字体大小 */
color: var(--vxe-font-color);
}
}
</style>

View File

@@ -79,7 +79,7 @@ onMounted(() => {
})
const urlKey=ref('')
const VITE_FLAG = import.meta.env.VITE_NAME == 'jibei'
const VITE_FLAG = false//import.meta.env.VITE_NAME == 'jibei'
const handleNodeClick = (data: any, node: any) => {
// console.log("🚀 ~ handleNodeClick ~ data:", data)
dotList.value = data

View File

@@ -4,7 +4,13 @@
<TableHeader datePicker area showExport>
<template #select>
<el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" placeholder="输入关键字筛选" clearable maxlength="32" show-word-limit/>
<el-input
v-model="tableStore.table.params.searchValue"
placeholder="输入关键字筛选"
clearable
maxlength="32"
show-word-limit
/>
</el-form-item>
<el-form-item label="统计类型">
<el-select
@@ -127,7 +133,7 @@ const tableStore = new TableStore({
{ field: 'lineName', title: '监测点名称', minWidth: '180' },
{ field: 'gdName', title: '供电公司', minWidth: '120' },
{ field: 'subName', title: '变电站', minWidth: '150' },
{ field: 'ip', title: '网络参数' ,width:'120px' },
{ field: 'ip', title: '网络参数', width: '120px' },
{ field: 'scale', title: '电压等级', minWidth: '110' },
{
field: 'advanceType',
@@ -137,7 +143,7 @@ const tableStore = new TableStore({
return row.cellValue || '其他'
}
},
{
{
field: 'eventType',
title: '触发类型',
minWidth: '120',
@@ -153,7 +159,7 @@ const tableStore = new TableStore({
return row.cellValue || '其他'
}
},
// {
// field: 'severity', title: '严重度', minWidth: "80", formatter: (row: any) => {
// return row.cellValue.toFixed(2)
@@ -180,7 +186,8 @@ const tableStore = new TableStore({
{ field: 'duration', title: '持续时间(s)', minWidth: '100' },
{
title: '操作',fixed: 'right',
title: '操作',
fixed: 'right',
width: '120',
render: 'buttons',
buttons: [
@@ -278,6 +285,7 @@ const download = () => {
document.body.appendChild(link)
link.click() //执行下载
document.body.removeChild(link) //释放标签
ElMessage.success('波形下载成功')
})
}
</script>

View File

@@ -1,5 +1,6 @@
<template>
<div class="default-main online">
<div class="online_header">
<TableHeader date-picker ref="tableHeaderRef">
<template #select>
@@ -54,6 +55,14 @@
:value="item"></el-option>
</el-select>
</el-form-item>
<el-form-item label="通讯状态">
<el-select v-model="tableStore.table.params.comFlagStatus" clearable placeholder="请选择通讯状态"
style="width: 100%" >
<el-option label="正常" value="1" />
<el-option label="中断" value="0" />
</el-select>
</el-form-item>
<el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="请输入关键字"></el-input>
</el-form-item>
@@ -313,6 +322,7 @@ tableStore.table.params.statisticalType = []
tableStore.table.params.scale = []
tableStore.table.params.manufacturer = []
tableStore.table.params.loadType = []
tableStore.table.params.comFlagStatus=''
provide('tableStore', tableStore)
const tree2List = (list: any, id?: string) => {
//存储结果的数组
@@ -479,13 +489,13 @@ const socket = async (form: any) => {
await dataSocket.socketServe.send(form)
logList.value.push({
type: '',
time: formatDate(new Date(), 'YYYY-MM-DD hh:mm:ss'),
time: formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss'),
name: '开始补召,请稍等...',
})
await dataSocket.socketServe.registerCallBack('message', (res: any) => {
logList.value.push({
type: res.code == 500 ? 'error' : '',
time: formatDate(new Date(), 'YYYY-MM-DD hh:mm:ss'),
time: formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss'),
name: res.message
})

View File

@@ -10,39 +10,81 @@
</el-radio-group>
</el-form-item>
<el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="输入关键字筛选"
style="width: 200px" maxlength="32" show-word-limit />
<el-input
v-model="tableStore.table.params.searchValue"
clearable
placeholder="输入关键字筛选"
style="width: 200px"
maxlength="32"
show-word-limit
/>
</el-form-item>
<el-form-item label="触发类型">
<el-select v-model="tableStore.table.params.waveType" placeholder="请选择触发类型" clearable multiple
collapse-tags style="width: 100%">
<el-option v-for="item in triggeroptions" :key="item.id" :label="item.name"
:value="item.id"></el-option>
<el-select
v-model="tableStore.table.params.waveType"
placeholder="请选择触发类型"
clearable
multiple
collapse-tags
style="width: 100%"
>
<el-option
v-for="item in triggeroptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="是否有波形">
<el-select v-model="tableStore.table.params.fileFlag" placeholder="请选择是否存在波形" clearable
style="width: 100%">
<el-option v-for="item in wareaoptions" :key="item.id" :label="item.label"
:value="item.id"></el-option>
<el-select
v-model="tableStore.table.params.fileFlag"
placeholder="请选择是否存在波形"
clearable
style="width: 100%"
>
<el-option
v-for="item in wareaoptions"
:key="item.id"
:label="item.label"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="暂态持续时间(s)">
<el-input v-model="tableStore.table.params.persistMin" placeholder="请输入X秒"
onkeyup="value=value.replace(/[^\d.]/g,'')" clearable style="width: 94px"></el-input>
<el-input
v-model="tableStore.table.params.persistMin"
placeholder="请输入X秒"
onkeyup="value=value.replace(/[^\d.]/g,'')"
clearable
style="width: 94px"
></el-input>
<el-tag style="margin-left: 5px">&lt; 时间数 &lt;</el-tag>
<el-input v-model="tableStore.table.params.persistMax" placeholder="请输入X秒"
onkeyup="value=value.replace(/[^\d.]/g,'')" clearable
style="margin-left: 5px; width: 94px"></el-input>
<el-input
v-model="tableStore.table.params.persistMax"
placeholder="请输入X秒"
onkeyup="value=value.replace(/[^\d.]/g,'')"
clearable
style="margin-left: 5px; width: 94px"
></el-input>
</el-form-item>
<el-form-item label="事件严重度">
<el-input v-model="tableStore.table.params.severityMin" placeholder="请输入正负数"
onkeyup="value=value.replace(/[^\d\.-]/g,'')" clearable style="width: 94px"></el-input>
<el-input
v-model="tableStore.table.params.severityMin"
placeholder="请输入正负数"
onkeyup="value=value.replace(/[^\d\.-]/g,'')"
clearable
style="width: 94px"
></el-input>
<el-tag style="margin-left: 5px">&lt; 严重度 &lt;</el-tag>
<el-input v-model="tableStore.table.params.severityMax" placeholder="请输入正负数"
onkeyup="value=value.replace(/[^\d\.-]/g,'')" clearable
style="margin-left: 5px; width: 94px"></el-input>
<el-input
v-model="tableStore.table.params.severityMax"
placeholder="请输入正负数"
onkeyup="value=value.replace(/[^\d\.-]/g,'')"
clearable
style="margin-left: 5px; width: 94px"
></el-input>
</el-form-item>
<!-- <el-form-item label="触发类型:">
@@ -53,23 +95,52 @@
</el-select>
</el-form-item> -->
<el-form-item label="暂态原因">
<el-select v-model="tableStore.table.params.eventReason" placeholder="请选择暂态原因" clearable
multiple collapse-tags style="width: 100%">
<el-option v-for="item in reasonoptions" :key="item.id" :label="item.name"
:value="item.id"></el-option>
<el-select
v-model="tableStore.table.params.eventReason"
placeholder="请选择暂态原因"
clearable
multiple
collapse-tags
style="width: 100%"
>
<el-option
v-for="item in reasonoptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="暂态核实原因">
<el-select v-model="tableStore.table.params.verifyReason" placeholder="请选择暂态核实原因" clearable
multiple collapse-tags collapse-tags-tooltip>
<el-option v-for="item in verifyReasonList" :key="item.id" :label="item.name"
:value="item.id"></el-option>
<el-select
v-model="tableStore.table.params.verifyReason"
placeholder="请选择暂态核实原因"
clearable
multiple
collapse-tags
collapse-tags-tooltip
>
<el-option
v-for="item in verifyReasonList"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="变电站(监测点)">
<el-cascader v-model="tableStore.table.params.lineIds" :options="options" :props="defaultProps"
collapse-tags-tooltip style="width: 257px" filterable clearable collapse-tags
placeholder="请选择变电站(监测点)" :show-all-levels="true" />
<el-cascader
v-model="tableStore.table.params.lineIds"
:options="options"
:props="defaultProps"
collapse-tags-tooltip
style="width: 257px"
filterable
clearable
collapse-tags
placeholder="请选择变电站(监测点)"
:show-all-levels="true"
/>
</el-form-item>
</template>
<template #operation>
@@ -146,33 +217,17 @@ const tableStore = new TableStore({
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ field: 'startTime', title: '暂降发生时刻', minWidth: '200' },
{ field: 'gdName', title: '供电公司', minWidth: '100' },
{ field: 'subName', title: '变电站', minWidth: '200' },
{ field: 'ip', title: '网络参数', width: '120px' },
{ field: 'lineName', title: '监测点', minWidth: '100' },
{ field: 'scale', title: '电压等级(kV)', minWidth: '120' },
{
field: 'verifyReason',
title: '暂态核实原因',
minWidth: '120',
formatter: function (row) {
return verifyReasonList.filter(item => item.id == row.cellValue)[0]?.name || '/' //row.cellValue ? row.cellValue : '/'
}
},
// {
// field: 'verifyReasonDetail', title: '暂降核实原因详情', minWidth: '200', formatter: function (row) {
// return row.cellValue ? row.cellValue : '/'
// }
// },
{ field: 'startTime', title: '暂降发生时刻', minWidth: '200', sortable: true },
{
field: 'featureAmplitude',
title: '暂降(骤升)幅值(%)',
minWidth: '130',
minWidth: '160',
sortable: true,
formatter: (row: any) => {
return Math.floor(row.cellValue * 10000) / 100
}
},
{ field: 'duration', title: '持续时间(s)', minWidth: 120, sortable: true },
{
field: 'eventType',
title: '触发类型',
@@ -182,17 +237,32 @@ const tableStore = new TableStore({
return triggeroptions.filter(item => item.id == row.eventType)[0]?.name
}
},
// { field: 'advanceType', title: '触发类型', minWidth: '100', },
{ field: 'advanceReason', title: '暂态原因', minWidth: '100' },
{
field: 'depth',
title: '暂降深度(%)',
minWidth: '100',
minWidth: 120,
formatter: ({ row }: any) =>
row.featureAmplitude < 1 ? 100 - (row.featureAmplitude * 100).toFixed(0) : '/'
},
{ field: 'duration', title: '持续时间(s)', minWidth: '100' },
{ field: 'advanceReason', title: '暂态原因', minWidth: '100' },
{
field: 'verifyReason',
title: '暂态核实原因',
minWidth: '120',
formatter: function (row) {
return verifyReasonList.filter(item => item.id == row.cellValue)[0]?.name || '/' //row.cellValue ? row.cellValue : '/'
}
},
{ field: 'gdName', title: '供电公司', minWidth: '100' },
{ field: 'subName', title: '变电站', minWidth: '200' },
{ field: 'lineName', title: '监测点', minWidth: '100' },
{ field: 'ip', title: '网络参数', width: '120px' },
{ field: 'scale', title: '电压等级(kV)', minWidth: '130', sortable: true },
// { field: 'advanceType', title: '触发类型', minWidth: '100', },
{
field: 'severity',
title: '严重度',
@@ -201,7 +271,8 @@ const tableStore = new TableStore({
},
{
title: '操作', fixed: 'right',
title: '操作',
fixed: 'right',
width: '150',
render: 'buttons',
@@ -259,7 +330,7 @@ const tableStore = new TableStore({
}
],
loadCallback: () => { }
loadCallback: () => {}
})
const options = ref([])
const defaultProps = {
@@ -353,6 +424,7 @@ const download = () => {
document.body.appendChild(link)
link.click() //执行下载
document.body.removeChild(link) //释放标签
ElMessage.success('波形下载成功')
})
}
</script>

View File

@@ -3,9 +3,9 @@
<div v-show="view">
<TableHeader datePicker :showReset="false" showExport ref="TableHeaderRef">
<template #select>
<!-- <el-form-item label="筛选数据">-->
<!-- <el-input v-model="tableStore.table.params.searchValue" clearable placeholder="输入关键字筛选" />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="筛选数据">-->
<!-- <el-input v-model="tableStore.table.params.searchValue" clearable placeholder="输入关键字筛选" />-->
<!-- </el-form-item>-->
</template>
<template #operation>
<el-button icon="el-icon-Tickets" type="primary" @click="analysis1">分析记录管理</el-button>
@@ -29,7 +29,7 @@
</template>
</vxe-column>
</vxe-table>
<el-pagination
<el-pagination
class="mt10"
:currentPage="form.pageNum"
:page-size="form.pageSize"
@@ -39,7 +39,7 @@
:total="total"
@size-change="onTableSizeChange"
@current-change="onTableCurrentChange"
></el-pagination>
></el-pagination>
</el-dialog>
</div>
<div :style="{ height: pageHeight.height }" style="padding: 10px; overflow: hidden" v-if="!view">
@@ -70,7 +70,7 @@ const loading = ref(false)
const view = ref(true)
const view2 = ref(false)
const TableHeaderRef = ref()
const waveFormRef = ref()
const waveFormRef = ref()
const tableStore = new TableStore({
url: '/advance-boot/process/querySagEventsPage',
method: 'POST',
@@ -83,19 +83,23 @@ const tableStore = new TableStore({
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ field: 'startTime', title: '发生时间' },
{ field: 'duration', title: '持续时间(s)' },
{ field: 'startTime', title: '暂降发生时刻', sortable: true, minWidth: 200 },
{
field: 'featureAmplitude',
title: '暂降(骤升)幅值(%)'
title: '暂降(骤升)幅值(%)',
sortable: true,
minWidth: 160
},
{ field: 'gdName', title: '供电公司' },
{ field: 'subName', title: '变电站' },
{ field: 'lineName', title: '监测点' },
{ field: 'duration', title: '持续时间(s)', sortable: true, minWidth: 120 },
{ field: 'gdName', title: '供电公司', minWidth: 140 },
{ field: 'subName', title: '变电站', minWidth: 140 },
{ field: 'lineName', title: '监测点', minWidth: 140 },
{
field: 'dealFlag',
title: '暂降特征幅值计算',
render: 'tag',
minWidth: 160,
custom: {
0: 'warning',
1: 'success',
@@ -115,6 +119,7 @@ const tableStore = new TableStore({
field: 'fileFlag',
title: '录波文件',
render: 'tag',
minWidth: 140,
custom: {
0: 'warning',
1: 'success'
@@ -125,7 +130,8 @@ const tableStore = new TableStore({
}
},
{
title: '操作',fixed: 'right',
title: '操作',
fixed: 'right',
width: '120',
render: 'buttons',
buttons: [
@@ -140,9 +146,9 @@ const tableStore = new TableStore({
render: 'basicButton',
click: async row => {
view.value = false
setTimeout(() => {
waveFormRef.value.open(row)
},100)
setTimeout(() => {
waveFormRef.value.open(row)
}, 100)
// row.loading = true
// boxoList.value = row
// await getMonitorEventAnalyseWave({ id: row.eventId, systemType: 0 })
@@ -173,7 +179,7 @@ const tableStore = new TableStore({
}
],
loadCallback: () => { }
loadCallback: () => {}
})
tableStore.table.params.searchValue = ''
const bxactiveName = ref('ssbx')
@@ -190,25 +196,21 @@ provide('tableStore', tableStore)
onMounted(() => {
TableHeaderRef.value.setTheDate(1)
nextTick(() => {
// tableStore.index()
TableHeaderRef.value.onComSearch()
})
})
// 分页
const onTableSizeChange = (val: number) => {
form.value.pageSize = val
form.value.pageNum = 1 // 改变每页条数时回到第一页
loadAnalysisData() // 重新加载数据
form.value.pageSize = val
form.value.pageNum = 1 // 改变每页条数时回到第一页
loadAnalysisData() // 重新加载数据
}
const onTableCurrentChange = (val: number) => {
form.value.pageNum = val
loadAnalysisData() // 重新加载数据
loadAnalysisData() // 重新加载数据
}
// 封装数据加载逻辑
@@ -230,13 +232,12 @@ const loadAnalysisData = async () => {
//分析记录管理
const analysis1 = async () => {
// 初始化分页参数
// 初始化分页参数
form.value.pageNum = 1
await loadAnalysisData()
dialogAnalysis.value = true
}
// 启动关联分析
const firing = () => {
processEvents({
@@ -257,7 +258,7 @@ const details = (row: any) => {
type: 'success',
message: res.message
})
// 重新加载当前页的数据
// 重新加载当前页的数据
loadAnalysisData()
})
}
@@ -266,6 +267,4 @@ const backbxlb = () => {
view.value = true
view2.value = false
}
</script>

View File

@@ -3,7 +3,13 @@
<TableHeader datePicker ref="TableHeaderRef">
<template #select>
<el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="输入事件关联分析描述" maxlength="32" show-word-limit/>
<el-input
v-model="tableStore.table.params.searchValue"
clearable
placeholder="输入事件关联分析描述"
maxlength="32"
show-word-limit
/>
</el-form-item>
</template>
<template #operation>
@@ -35,25 +41,18 @@
</vxe-table-column>
<vxe-table-column
field="startTime"
title="发生时"
title="暂降发生时"
align="center"
sortable
width="200"
:show-overflow="true"
></vxe-table-column>
<vxe-table-column field="gdName" title="供电公司" align="center"></vxe-table-column>
<vxe-table-column
field="subName"
:show-overflow="true"
title="变电站"
align="center"
></vxe-table-column>
<vxe-table-column field="lineName" title="监测点" align="center"></vxe-table-column>
<vxe-table-column field="voltageId" title="电压等级(kV)" align="center"></vxe-table-column>
<vxe-table-column field="featureAmplitude" title="暂降(骤升)幅值(%)" align="center" width="140">
<vxe-table-column field="featureAmplitude" title="暂降(骤升)幅值(%)" sortable align="center" width="160">
<template #default="{ row }">
<span>{{ (row.featureAmplitude * 100).toFixed(2) }}</span>
</template>
</vxe-table-column>
<vxe-table-column field="duration" title="持续时间(s)" align="center" width="120"></vxe-table-column>
<vxe-table-column field="duration" title="持续时间(s)" sortable align="center" width="120"></vxe-table-column>
<vxe-table-column
field="advanceType"
title="触发类型"
@@ -68,6 +67,15 @@
width="120"
:formatter="formFilter"
></vxe-table-column>
<vxe-table-column field="gdName" title="供电公司" align="center"></vxe-table-column>
<vxe-table-column
field="subName"
:show-overflow="true"
title="变电站"
align="center"
></vxe-table-column>
<vxe-table-column field="lineName" title="监测点" align="center"></vxe-table-column>
<vxe-table-column field="voltageId" title="电压等级(kV)" align="center"></vxe-table-column>
</vxe-table>
<el-pagination
class="mt10"
@@ -131,7 +139,8 @@ const tableStore = new TableStore({
title: '事件关联分析描述'
},
{
title: '操作',fixed: 'right',
title: '操作',
fixed: 'right',
width: '200',
render: 'buttons',
buttons: [
@@ -176,7 +185,6 @@ const bxcontrast = () => {
}
}
// 波形分析
const source = () => {
queryEventDetailByAssId(form.value).then(res => {
@@ -245,14 +253,14 @@ const exportEvent = () => {
}
// 导出波形分析
const positioningexport = () => {
const selectedRecords = positioningtableRef.value.getCheckboxRecords();
const selectedRecords = positioningtableRef.value.getCheckboxRecords()
if (selectedRecords.length === 0) {
ElMessage({
message: '请先选择要导出的数据!',
type: 'warning'
});
return;
})
return
}
positioningtableRef.value.exportData({

View File

@@ -27,22 +27,23 @@
<span>{{ (form.pageNum - 1) * form.pageSize + row.rowIndex + 1 }}</span>
</template>
</vxe-table-column>
<vxe-table-column field="startTime" title="发生时" align="center"
<vxe-table-column field="startTime" title="暂降发生时" align="center" sortable width="200"
:show-overflow="true"></vxe-table-column>
<vxe-table-column field="gdName" title="供电公司" align="center"></vxe-table-column>
<vxe-table-column field="subName" :show-overflow="true" title="变电站" align="center"></vxe-table-column>
<vxe-table-column field="lineName" title="监测点" align="center"></vxe-table-column>
<vxe-table-column field="voltageId" title="电压等级(kV)" align="center"></vxe-table-column>
<vxe-table-column field="featureAmplitude" title="暂降(骤升)幅值(%)" align="center" width="140">
<vxe-table-column field="featureAmplitude" title="暂降(骤升)幅值(%)" sortable align="center" width="160">
<template #default="{ row }">
<span>{{ (row.featureAmplitude * 100).toFixed(2) }}</span>
</template>
</vxe-table-column>
<vxe-table-column field="duration" title="持续时间(s)" align="center" width="120"></vxe-table-column>
<vxe-table-column field="duration" title="持续时间(s)" align="center" sortable width="120"></vxe-table-column>
<vxe-table-column field="advanceType" title="触发类型" align="center" width="120"
:formatter="formFilter"></vxe-table-column>
<vxe-table-column field="advanceReason" title="暂降原因" align="center" width="120"
:formatter="formFilter"></vxe-table-column>
<vxe-table-column field="gdName" title="供电公司" align="center"></vxe-table-column>
<vxe-table-column field="subName" :show-overflow="true" title="变电站" align="center"></vxe-table-column>
<vxe-table-column field="lineName" title="监测点" align="center"></vxe-table-column>
<vxe-table-column field="voltageId" title="电压等级(kV)" align="center"></vxe-table-column>
</vxe-table>
<el-pagination class="mt10" :currentPage="form.pageNum" :page-size="form.pageSize"
:page-sizes="[10, 20, 50, 100]" background :layout="'sizes,total, ->, prev, pager, next, jumper'"

View File

@@ -56,37 +56,40 @@ const tableStore = new TableStore({
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ title: '变电站名称', field: 'subName', minWidth: '140' },
{ title: '监测点名称', field: 'lineName', minWidth: '130' },
{ title: '网络参数', field: 'ip', width: '120px' },
{ title: '电压等级(kV)', field: 'voltageScale', width: '120' },
{ title: '暂降发生时刻', field: 'startTime', width: '200' },
// { title: '触发类型', field: 'advanceType', minWidth: '130' },
{ title: '暂降原因', field: 'advanceReason', minWidth: '130' },
{
title: '触发类型',
field: 'eventType',
minWidth: '80',
formatter: (row: any) => {
return eventTypeOptions.find(item => item.id === row.cellValue)?.name || '/'
}
},
{ title: '暂降发生时刻', field: 'startTime', width: '200', sortable: true, },
{
title: '暂降(骤升)幅值(%)',
field: 'featureAmplitude',
minWidth: '140',
minWidth: '160',
sortable: true,
formatter: (row: any) => {
return Math.floor(row.cellValue * 10000) / 100
}
},
{ title: '持续时间(s)', field: 'duration', minWidth: '100' },
{ title: '持续时间(s)', field: 'duration', minWidth: '120' , sortable: true, },
{
title: '触发类型',
field: 'eventType',
minWidth: '100',
formatter: (row: any) => {
return eventTypeOptions.find(item => item.id === row.cellValue)?.name || '/'
}
},
{ title: '暂降原因', field: 'advanceReason', minWidth: '130' },
{ title: '变电站名称', field: 'subName', minWidth: '140' },
{ title: '监测点名称', field: 'lineName', minWidth: '130' },
{ title: '网络参数', field: 'ip', width: '120px' },
{ title: '电压等级(kV)', field: 'voltageScale', width: '120' },
// { title: '触发类型', field: 'advanceType', minWidth: '130' },
// { title: '严重度', field: 'severity', minWidth: '80' },
{
title: '操作',fixed: 'right',
title: '操作',
fixed: 'right',
width: '180',
render: 'buttons',
buttons: [
{
name: 'edit',
@@ -127,7 +130,6 @@ const tableStore = new TableStore({
],
beforeSearchFun: () => {
tableStore.table.params.lineId = monitoringPoint.state.lineId
},
loadCallback: () => {}
})
@@ -174,6 +176,7 @@ const download = () => {
document.body.appendChild(link)
link.click() //执行下载
document.body.removeChild(link) //释放标签
ElMessage.success('波形下载成功')
})
}
</script>

View File

@@ -3,21 +3,21 @@
<div style="height: 40vh">
<vxe-table v-loading="loading" height="auto" auto-resize :data="tableData" v-bind="defaultAttribute">
<vxe-column type="seq" title="序号" width="80px"></vxe-column>
<vxe-column field="startTime" title="发生时" width="180"></vxe-column>
<vxe-column field="duration" title="持续时间(s)" width="100"></vxe-column>
<vxe-column field="gdName" title="供电公司" min-width="150"></vxe-column>
<vxe-column field="subName" title="变电站" min-width="150"></vxe-column>
<vxe-column field="lineName" title="监测点" min-width="150"></vxe-column>
<vxe-column field="startTime" title="暂降发生时" width="200" sortable></vxe-column>
<vxe-column field="featureAmplitude" title="暂降(骤升)幅值(%)" width="160" sortable>
<template #default="{ row }">
{{ (row.featureAmplitude * 100).toFixed(2) }}
</template>
</vxe-column>
<vxe-column field="duration" title="持续时间(s)" width="120" sortable></vxe-column>
<vxe-column field="advanceType" title="触发类型" width="100">
<template #default="{ row }">
{{ type.find(item => item.id === row.advanceType)?.name }}
</template>
</vxe-column>
<vxe-column field="featureAmplitude" title="暂降(骤升)幅值(%)" width="150">
<template #default="{ row }">
{{ (row.featureAmplitude * 100).toFixed(2) }}
</template>
</vxe-column>
<vxe-column field="gdName" title="供电公司" min-width="140"></vxe-column>
<vxe-column field="subName" title="变电站" min-width="140"></vxe-column>
<vxe-column field="lineName" title="监测点名称" min-width="140"></vxe-column>
</vxe-table>
</div>
</el-dialog>

View File

@@ -23,14 +23,15 @@
<div style="flex: 1; overflow: hidden">
<vxe-table height="auto" auto-resize :data="tableData" v-bind="defaultAttribute">
<vxe-column type="seq" title="序号" width="70px"></vxe-column>
<vxe-column field="startTime" title="发生时刻" width="200"></vxe-column>
<vxe-column field="lineName" title="监测点" width="120"></vxe-column>
<vxe-column field="featureAmplitude" title="暂降(骤升)幅值(%)">
<vxe-column field="startTime" title="暂降发生时刻" width="200" sortable></vxe-column>
<vxe-column field="featureAmplitude" title="暂降(骤升)幅值(%)" width="160" sortable>
<template #default="{ row }">
{{ row.featureAmplitude.toFixed(2) }}
</template>
</vxe-column>
<vxe-column field="duration" title="持续时间(s)"></vxe-column>
<vxe-column field="duration" title="持续时间(s)" sortable width="120"></vxe-column>
<vxe-column field="lineName" title="监测点" width="120"></vxe-column>
</vxe-table>
</div>
</div>

View File

@@ -1,6 +1,6 @@
<template>
<div class="default-main">
<TableHeader date-picker area >
<TableHeader date-picker area>
<template v-slot:select>
<el-form-item label="统计类型">
<el-radio-group v-model="tableStore.table.params.comFlag">
@@ -48,10 +48,12 @@
</el-form-item>
</template>
<template #operation>
<el-button icon="el-icon-Download" type="primary" @click="exportEvent" :loading="loading">导出</el-button>
<el-button icon="el-icon-Download" type="primary" @click="exportEvent" :loading="loading">
报告生成
</el-button>
</template>
</TableHeader>
<Table ref="tableRef" />
<Table ref="tableRef" :checkboxConfig="checkboxConfig" />
</div>
</template>
<script setup lang="tsx">
@@ -64,7 +66,7 @@ import { getEventReport } from '@/api/event-boot/report'
import { ElMessage } from 'element-plus'
defineOptions({
name: 'Operationmanagement/terminalmanagement'
name: 'TransientReport/eventreports'
})
const dictData = useDictData()
const triggerType = dictData.getBasicData('Event_Statis')
@@ -82,6 +84,7 @@ const tableStore = new TableStore({
url: '/event-boot/report/getEventReport',
method: 'POST',
column: [
{ width: '60', type: 'checkbox' },
{
title: '序号',
@@ -93,19 +96,34 @@ const tableStore = new TableStore({
},
{
field: 'startTime',
title: '发生时刻',
title: '暂降发生时刻',
width: '180',
sortable: true,
formatter: (row: any) => {
return row.cellValue ? row.cellValue.replace('T', ' ') : '/'
}
},
{ field: 'gdName', title: '供电公司', minWidth: '120' },
{ field: 'subName', title: '变电站', minWidth: '120' },
{ field: 'ip', title: '网络参数', width: '120px' },
{ field: 'lineName', title: '监测点', minWidth: '120' },
{
field: 'featureAmplitude',
title: '暂降(骤升)幅值(%)',
width: '160',
sortable: true,
formatter: (row: any) => {
// return (row.cellValue * 100).toFixed(0)
return Math.floor(row.cellValue * 10000) / 100
}
},
{
field: 'duration',
title: '持续时间(s)',
width: '120',
sortable: true
},
{
field: 'eventType',
title: '触发类型',minWidth: '100' ,
title: '触发类型',
minWidth: '100',
formatter: (row: any) => {
return triggerType.filter(item => item.id === row.cellValue)[0].name
}
@@ -113,33 +131,30 @@ const tableStore = new TableStore({
{
field: 'advanceType',
title: '暂态类型',
minWidth: '100'
minWidth: '100',
formatter: (row: any) => {
return row.cellValue ? row.cellValue : '/'
}
},
{
field: 'advanceReason',
title: '暂态原因',
minWidth: '100'
minWidth: '100',
formatter: (row: any) => {
return row.cellValue ? row.cellValue : '/'
}
},
{ field: 'gdName', title: '供电公司', minWidth: '120' },
{ field: 'subName', title: '变电站', minWidth: '120' },
{ field: 'lineName', title: '监测点', minWidth: '120' },
{ field: 'ip', title: '网络参数', width: '120px' },
{
field: 'voltageScale',
title: '电压等级',
minWidth: '100'
},
{
field: 'featureAmplitude',
title: '暂降(骤升)幅值(%)',
width: '140',
formatter: (row: any) => {
// return (row.cellValue * 100).toFixed(0)
return Math.floor(row.cellValue * 10000) / 100
}
},
{
field: 'duration',
title: '持续时间(s)',
width: '100'
}
// { field: 'severity', title: '严重度' }
]
})
@@ -156,7 +171,11 @@ tableStore.table.params.statisticalType = dictData.getBasicData('Statistical_Typ
'Voltage_Level',
'Load_Type'
])[0]
const checkboxConfig = reactive<VxeTablePropTypes.CheckboxConfig<any>>({
checkMethod: ({ row }) => {
return row.fileFlag === 1
}
})
provide('tableStore', tableStore)
onMounted(() => {
@@ -178,15 +197,17 @@ const exportEvent = () => {
// }
// })
// })
const ids = tableStore.table.data.map((item: any) => item.eventId);
if (!tableStore.table.selection.length) {
ElMessage.warning('请选择数据')
return
}
const ids = tableStore.table.selection.map((item: any) => item.eventId)
loading.value = true
ElMessage('生成报告中,请稍等!')
getEventReport(ids)
.then((res: any) => {
if (res == undefined) {
if (res == undefined) {
loading.value = false
return
}
@@ -197,14 +218,14 @@ const exportEvent = () => {
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') // 创建a标签
link.href = url
link.download = '事件报告' // 设置下载的文件名
link.download = '事件报告' // 设置下载的文件名
document.body.appendChild(link)
link.click() //执行下载
document.body.removeChild(link)
loading.value = false
}) .catch(() => {
})
.catch(() => {
loading.value = false
})
}
</script>

View File

@@ -56,19 +56,20 @@ const list = ref([
)
}
},
{ field: 'startTime', title: '暂态事件发生时刻', width: '200' },
{ field: 'gdName', title: '供电公司' },
{ field: 'subName', title: '变电站' },
{ field: 'lineName', title: '监测点' },
{ field: 'voltageScale', title: '监测点电压等级' },
{ field: 'loadType', title: '干扰源类型' },
{ field: 'startTime', title: '暂态发生时刻', width: '200',sortable: true, },
{
field: 'featureAmplitude',
title: '暂降(骤升)幅值(%)',
title: '暂降(骤升)幅值(%)',sortable: true,width: '160',
formatter: ({ row }: any) => (row.featureAmplitude * 100).toFixed(2)
},
{ field: 'duration', title: '持续时间(s)' },
{ field: 'severity', title: '暂态事件严重度' }
{ field: 'duration', title: '持续时间(s)',sortable: true,width: '120', },
{ field: 'gdName', title: '供电公司' ,minWidth: '120'},
{ field: 'subName', title: '变电站' ,minWidth: '120'},
{ field: 'lineName', title: '监测点' ,minWidth: '120'},
{ field: 'voltageScale', title: '监测点电压等级' ,minWidth: '120'},
{ field: 'loadType', title: '干扰源类型' ,minWidth: '120'},
{ field: 'severity', title: '暂态事件严重度' ,minWidth: '120'}
]
}
]
@@ -86,7 +87,16 @@ const list = ref([
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ field: 'startTime', title: '暂降事件发生时刻', width: '200' },
{ field: 'startTime', title: '暂降发生时刻', width: '200',sortable: true, },
{
field: 'featureAmplitude',
title: '暂降(骤升)幅值(%)',
width: '160',sortable: true,
formatter: (row: any) => {
return Math.floor(row.cellValue * 10000) / 100
}
},
{ field: 'duration', title: '持续时间(s)', width: '120',sortable: true, },
{ field: 'gdName', title: '供电公司', width: '150' },
{ field: 'subName', title: '变电站', minWidth: '150' },
{ field: 'lineName', title: '监测点', minWidth: '150' },
@@ -99,15 +109,7 @@ const list = ref([
{ field: 'voltageScale', title: '电压等级', width: '80' },
{ field: 'loadType', title: '干扰源类型', width: '150' },
{
field: 'featureAmplitude',
title: '暂降(骤升)幅值(%)',
width: '150',
formatter: (row: any) => {
return Math.floor(row.cellValue * 10000) / 100
}
},
{ field: 'duration', title: '持续时间(s)', width: '120' },
{ field: 'advanceType', title: '暂降类型(机器判断)', width: '150' }
]
},