修改测试问题

This commit is contained in:
guanj
2026-06-11 20:27:37 +08:00
parent bda7373133
commit 1a09c31669
61 changed files with 3393 additions and 2406 deletions

View File

@@ -106,9 +106,9 @@ const tableStore: any = new TableStore({
text: `F47曲线`
},
legend: {
data: ['可容忍事件', '不可容忍事件'],
itemWidth: 10,
itemHeight: 10,
data: ['分割线', '可容忍事件', '不可容忍事件'],
// itemWidth: 10,
// itemHeight: 10,
itemGap: 15
},
tooltip: {
@@ -132,9 +132,14 @@ const tableStore: any = new TableStore({
formatter: function (a: any) {
var relVal = `<strong>${a.seriesName}</strong><br/>`
relVal += "<font style='color:" + "'>发生时间:" + a.value[2] + '</font><br/>'
relVal += "<font style='color:" + "'>持续时间:" + a.value[0] + 's</font><br/>'
relVal += "<font style='color:" + "'>特征幅值:" + Math.floor(a.value[1] * 100) / 100 + '%</font>'
relVal += "<font style='color:" + "'>发生时间" + a.value[2] + '</font><br/>'
relVal += "<font style='color:" + "'>特征幅值:" + Math.floor(a.value[1] * 100) / 100 + '%</font><br/>'
relVal += "<font style='color:" + "'>持续时间:" + a.value[0] + 's</font><br/>'
relVal += "<font style='color:" + "'>监测点名称:" + (a.value[4] || '/') + '</font><br/>'
relVal += "<font style='color:" + "'>设备名称:" + (a.value[5] || '/') + '</font><br/>'
relVal += "<font style='color:" + "'>项目名称:" + (a.value[6] || '/') + '</font><br/>'
relVal += "<font style='color:" + "'>工程名称:" + (a.value[7] || '/') + '</font>'
return relVal
}
},
@@ -171,7 +176,7 @@ const tableStore: any = new TableStore({
dataZoom: null,
series: [
{
name: '边界线',
name: '分割线',
type: 'line',
data: [
[0.05, 0],
@@ -184,6 +189,7 @@ const tableStore: any = new TableStore({
[1000, 80]
],
showSymbol: false,
tooltips: {
show: false
}
@@ -268,8 +274,11 @@ function gongfunction(arr: any) {
let time = arr[i].time
let eventId = arr[i].eventId
let lineName = arr[i].lineName
let equipmentName = arr[i].equipmentName
let projectName = arr[i].projectName
let engineeringName = arr[i].engineeringName
// let index =arr[i].eventDetailIndex;
point = [xx, yy, time, eventId, lineName]
point = [xx, yy, time, eventId, lineName, equipmentName, projectName, engineeringName]
if (xx <= 0.003) {
let line = 0

View File

@@ -0,0 +1,439 @@
<template>
<div>
<!--ITIC曲线 -->
<TableHeader ref="TableHeaderRef" :showReset="false" :timeKeyList="prop.timeKey" @selectChange="selectChange"
datePicker v-if="fullscreen"></TableHeader>
<el-descriptions class="mt2" direction="vertical" :column="4" border>
<el-descriptions-item align="center" label="名称">{{ data.name }}</el-descriptions-item>
<el-descriptions-item align="center" label="事件总数">{{ data.gs }}</el-descriptions-item>
<el-descriptions-item align="center" label="可容忍">{{ data.krr }}</el-descriptions-item>
<el-descriptions-item align="center" label="不可容忍">{{ data.bkrr }}</el-descriptions-item>
</el-descriptions>
<my-echart v-loading="tableStore.table.loading" ref="chartRef" class="tall" :options="echartList" :style="{
width: prop.width,
height: `calc(${prop.height} - 80px - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
}" @chart-click="handleChartClick" />
<el-dialog v-model="isWaveCharts" v-if="isWaveCharts" draggable :title="dialogTitle" append-to-body width="70%">
<waveFormAnalysis v-loading="loading" ref="waveFormAnalysisRef" @handleHideCharts="isWaveCharts = false"
:wp="wp" />
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive, watch, computed, nextTick } from 'vue'
import TableStore from '@/utils/tableStore'
import MyEchart from '@/components/echarts/MyEchart.vue'
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
import TableHeader from '@/components/table/header/index.vue'
import { analyseWave } from '@/api/common'
import { ElMessage } from 'element-plus'
import { getTime } from '@/utils/formatTime'
const prop = defineProps({
w: { type: [String, Number] },
h: { type: [String, Number] },
width: { type: [String, Number] },
height: { type: [String, Number] },
timeKey: { type: Array as () => string[] },
timeValue: { type: Object },
interval: { type: Number }
})
const TableHeaderRef = ref()
const headerHeight = ref(57)
const dialogTitle = ref('波形分析')
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
if (datePickerValue && datePickerValue.timeValue) {
// 更新时间参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
const echartList = ref()
const chartRef = ref()
// 波形
const isWaveCharts = ref(false)
const loading = ref(false)
const wp = ref({})
const boxoList: any = ref({})
const waveFormAnalysisRef: any = ref(null)
const data = reactive({
name: '事件个数',
gs: 0,
krr: 0,
bkrr: 0
})
const tableStore: any = new TableStore({
url: '/cs-harmonic-boot/csevent/f47Curve',
method: 'POST',
showPage: false,
column: [],
beforeSearchFun: () => {
setTime()
},
loadCallback: () => {
const gongData = gongfunction(tableStore.table.data)
data.gs = tableStore.table.data.length
data.krr = gongData.pointI.length
data.bkrr = gongData.pointIun.length
echartList.value = {
title: {
text: `ITIC曲线`
},
legend: {
data: ['上限', '下限', '可容忍事件', '不可容忍事件'],
// itemWidth: 10,
// itemHeight: 10,
itemGap: 15
},
tooltip: {
trigger: 'item',
show: true,
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
formatter: function (a: any) {
var relVal = `<strong>${a.seriesName}</strong><br/>`
relVal += "<font style='color:" + "'>发生时间:" + a.value[2] + '</font><br/>'
relVal += "<font style='color:" + "'>特征幅值:" + Math.floor(a.value[1] * 100) / 100 + '%</font><br/>'
relVal += "<font style='color:" + "'>持续时间:" + a.value[0] + 's</font><br/>'
relVal += "<font style='color:" + "'>监测点名称:" + (a.value[4] || '/') + '</font><br/>'
relVal += "<font style='color:" + "'>设备名称:" + (a.value[5] || '/') + '</font><br/>'
relVal += "<font style='color:" + "'>项目名称:" + (a.value[6] || '/') + '</font><br/>'
relVal += "<font style='color:" + "'>工程名称:" + (a.value[7] || '/') + '</font>'
return relVal
}
},
xAxis: [
{
type: 'log',
min: 0.001,
max: 1000,
splitLine: {
show: false
},
name: 's'
}
],
yAxis: [
{
type: 'value',
splitNumber: 10,
minInterval: 3,
name: '%'
}
],
color: ['#FF8C00', '#00BFFF', 'green', 'red'],
options: {
dataZoom: null,
series: [
{
name: '上限',
type: 'line',
data: [
[0.001, 200],
[0.003, 140],
[0.003, 120],
[0.5, 120],
[0.5, 110],
[10, 110],
[1000, 110]
],
showSymbol: false,
tooltips: {
show: false
}
},
{
name: '下限',
type: 'line',
data: [
[0.02, 0],
[0.02, 70],
[0.5, 70],
[0.5, 80],
[10, 80],
[10, 90],
[1000, 90]
],
showSymbol: false,
tooltips: {
show: false
}
},
{
name: '可容忍事件',
type: 'scatter',
symbol: 'circle',
symbolSize: 8,
data: gongData.pointI,
legendSymbol: 'circle'
},
{
name: '不可容忍事件',
type: 'scatter',
symbol: 'circle',
symbolSize: 8,
data: gongData.pointIun,
legendSymbol: 'rect'
}
]
}
}
}
})
const tableRef = ref()
provide('tableRef', tableRef)
provide('tableStore', tableStore)
const setTime = () => {
const time = getTime(
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
prop.timeKey,
fullscreen.value
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
: prop.timeValue
)
if (Array.isArray(time)) {
tableStore.table.params.searchBeginTime = time[0]
tableStore.table.params.searchEndTime = time[1]
TableHeaderRef.value?.setInterval(time[2] - 0)
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
} else {
console.warn('获取时间失败time 不是一个有效数组')
}
}
function gongfunction(arr: any) {
let standI = 0
let unstandI = 0
let pointIun: any[] = []
let pointI: any[] = []
const total = arr.length
if (total > 0) {
for (let i = 0; i < arr.length; i++) {
const xx = arr[i].persistTime
const yy = arr[i].eventValue
const time = arr[i].time
const eventId = arr[i].eventId
const lineName = arr[i].lineName
let equipmentName = arr[i].equipmentName
let projectName = arr[i].projectName
let engineeringName = arr[i].engineeringName
// let index =arr[i].eventDetailIndex;
const point = [xx, yy, time, eventId, lineName, equipmentName, projectName, engineeringName]
if (xx <= 0.003) {
const line = 230 - 30000 * xx
if (yy > line) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
} else if (xx <= 0.02) {
if (yy > 120) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
} else if (xx <= 0.5) {
if (yy > 120 || yy < 70) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
} else if (xx <= 10) {
if (yy > 110 || yy < 80) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
} else {
if (yy > 110 || yy < 90) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
}
}
}
return {
standI,
unstandI,
pointI,
pointIun
}
}
onMounted(() => {
setTimeout(() => {
tableStore.index()
}, 100)
})
// 点击事件处理函数
const handleChartClick = (params: any) => {
if (params.seriesName === '可容忍事件') {
// 处理可容忍事件点击
dialogTitle.value = '可容忍事件波形分析'
handleTolerableEventClick(params)
} else if (params.seriesName === '不可容忍事件') {
dialogTitle.value = '不可容忍事件波形分析'
// 处理不可容忍事件点击
// ElMessage.info(`点击了不可容忍事件: 持续时间${params.value[0]}s, 幅值${params.value[1].toFixed(2)}%`)
handleTolerableEventClick(params)
}
}
// 可容忍事件点击处理函数
const handleTolerableEventClick = async (row: any) => {
loading.value = true
nextTick(() => {
if (waveFormAnalysisRef.value) {
//waveFormAnalysisRef.value.setHeight(false, 360)
// waveFormAnalysisRef.value.setHeight(999, 130, 1.6666666)
}
})
const messageInstance = ElMessage.info(`正在加载,请稍等...`)
await analyseWave(row.value[3]) //eventId
.then(res => {
row.loading1 = false
if (res != undefined) {
boxoList.value = {
persistTime: row.value[0], //持续时间
featureAmplitude: (row.value[1] / 100), //残余电压
startTime: row.value[2], //时间
lineName: row.value[4] //监测点名称
}
boxoList.value.systemType = 'YPT'
wp.value = res.data
}
isWaveCharts.value = true
loading.value = false
})
.catch(() => {
messageInstance.close()
row.loading1 = false
loading.value = false
})
nextTick(() => {
waveFormAnalysisRef.value && waveFormAnalysisRef.value.setHeight(999, 130, 1.6666666)
waveFormAnalysisRef.value && waveFormAnalysisRef.value.getWpData(wp.value, boxoList.value, true)
})
}
// 不可容忍事件点击处理函数
const handleIntolerableEventClick = (params: any) => {
console.log('不可容忍事件详情:', params)
}
watch(
() => prop.timeKey,
val => {
tableStore.index()
}
)
watch(
() => prop.timeValue,
(newVal, oldVal) => {
// 当外部时间值变化时,更新表格的时间参数
if (newVal && (!oldVal || newVal[0] !== oldVal[0] || newVal[1] !== oldVal[1])) {
tableStore.table.params.searchBeginTime = newVal[0]
tableStore.table.params.searchEndTime = newVal[1]
tableStore.index()
}
},
{
deep: true
}
)
const addMenu = () => { }
</script>
<style lang="scss" scoped></style>

View File

@@ -1,20 +1,10 @@
<template>
<div>
<!--暂降方向统计 -->
<TableHeader
ref="TableHeaderRef"
:showReset="false"
@selectChange="selectChange"
datePicker
:timeKeyList="prop.timeKey"
v-if="fullscreen"
></TableHeader>
<my-echart
v-loading="tableStore.table.loading"
class="tall"
:options="echartList"
:style="{ width: prop.width, height: `calc(${prop.height} )` }"
/>
<TableHeader ref="TableHeaderRef" :showReset="false" @selectChange="selectChange" datePicker
:timeKeyList="prop.timeKey" v-if="fullscreen"></TableHeader>
<my-echart v-loading="tableStore.table.loading" class="tall" :options="echartList"
:style="{ width: prop.width, height: `calc(${prop.height} )` }" />
</div>
</template>
<script setup lang="ts">
@@ -29,7 +19,7 @@ const prop = defineProps({
h: { type: [String, Number] },
width: { type: [String, Number] },
height: { type: [String, Number] },
timeKey: { type: Array as () => string[] },
timeKey: { type: Array as () => string[] },
timeValue: { type: Object },
interval: { type: Number }
})
@@ -126,7 +116,11 @@ const tableStore: any = new TableStore({
title: [
{
text: '暂降方向统计',
left: 'center'
left: 'center',
textStyle: {
color: '#000',
fontSize: '15'
},
},
{
text: total + '次',
@@ -205,6 +199,6 @@ watch(
}
)
const addMenu = () => {}
const addMenu = () => { }
</script>
<style lang="scss" scoped></style>

View File

@@ -81,51 +81,68 @@ const tableStore: any = new TableStore({
{
title: '指标名称',
field: 'name',
minWidth: '90'
minWidth: 120
},
{
title: '越限最高监测点',
field: 'lineName',
minWidth: 120,
formatter: (row: any) => {
return row.cellValue || '/'
}
},
{
title: '设备名称', field: 'devName', minWidth: 130, align: 'center', formatter: (row: any) => {
return row.cellValue || '/'
}
},
{
title: '项目名称', field: 'projectName', minWidth: 130, align: 'center', formatter: (row: any) => {
return row.cellValue || '/'
}
},
{
title: '工程名称', field: 'engineeringName', minWidth: 130, align: 'center', formatter: (row: any) => {
return row.cellValue || '/'
}
},
{
title: '越限最大值',
field: 'maxValue',
minWidth: '70',
minWidth: 100,
render: 'customTemplate',
customTemplate: (row: any) => {
const extentValue =
row.maxValue !== null && row.maxValue !== undefined && row.maxValue !== ''
? Math.floor(row.maxValue * 100) / 100
: '/'
return `<span style='cursor: pointer;text-decoration: underline;'>${extentValue}</span>`
return extentValue=='/' ? '/' : `<span style='cursor: pointer;text-decoration: underline;'>${extentValue}</span>`
}
},
{
title: '国标限值',
field: 'internationalValue',
minWidth: '60'
minWidth: 100, formatter: (row: any) => {
return row.cellValue || '/'
}
},
{
title: '越限程度(%)',
field: 'extent',
minWidth: '70',
minWidth: 100,
formatter: (row: any) => {
return Math.floor(row.cellValue * 100) / 100
return row.cellValue? Math.floor(row.cellValue * 100) / 100 : '/'
}
},
{
title: '越限时间',
field: 'time',
minWidth: '60',
minWidth: 100,
formatter: (row: any) => {
return row.cellValue || '/'
}
},
{
title: '越限最高监测点',
field: 'lineName',
minWidth: '90',
formatter: (row: any) => {
return row.cellValue || '/'
}
}
],
beforeSearchFun: () => {
setTime()

View File

@@ -1,33 +1,44 @@
<template>
<div>
<div class="device-control">
<!--治理效果报表 -->
<TableHeader :showReset="false" :timeKeyList="prop.timeKey" ref="TableHeaderRef" datePicker
@selectChange="selectChange" v-if="fullscreen">
<template v-slot:select>
<el-form-item label="模板策略">
<el-select filterable v-model="tableStore.table.params.tempId" placeholder="请选择模板策略" clearable>
<el-option v-for="item in templateList" :key="item.id" :label="item.excelName"
:value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="监测对象">
<el-select filterable v-model="tableStore.table.params.sensitiveUserId" placeholder="请选择监测对象"
clearable>
<el-option v-for="item in idList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</template>
<template v-slot:operation>
<el-button @click="downloadExcel" class="" type="primary" icon="el-icon-Download">导出</el-button>
</template>
</TableHeader>
<div style="display: flex" >
<div id="luckysheet" :style="{
width: `calc(${prop.width} )`,
height: `calc(${prop.height} - 57px + ${fullscreen ? 0 : 56}px)`
}"></div>
<div v-show="fullscreen">
<!-- <PointTree :height="flag ? 106 : 50" @node-click="nodeClick" @pointTypeChange="pointTypeChange"></PointTree> -->
<APFTree :height="flag ? 126 : 70" @node-click="handleNodeClick" template @init="handleNodeClick"></APFTree>
</div>
<div>
<TableHeader :showReset="false" :timeKeyList="prop.timeKey" ref="TableHeaderRef" datePicker
@selectChange="selectChange" v-if="fullscreen">
<template v-slot:select>
<el-form-item label="模板策略">
<el-select filterable v-model="tableStore.table.params.tempId" placeholder="请选择模板策略" clearable>
<el-option v-for="item in templateList" :key="item.id" :label="item.excelName"
:value="item.id" />
</el-select>
</el-form-item>
<!-- <el-form-item label="监测对象">
<el-select filterable v-model="tableStore.table.params.sensitiveUserId" placeholder="请选择监测对象"
clearable>
<el-option v-for="item in idList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item> -->
</template>
<template v-slot:operation>
<el-button @click="downloadExcel" class="" type="primary" icon="el-icon-Download">导出</el-button>
</template>
</TableHeader>
<div style="display: flex">
<div id="luckysheet" :style="{
width: `calc(${prop.width} - ${fullscreen ? 290 : 0}px)`,
height: `calc(${prop.height} - 57px + ${fullscreen ? 0 : 56}px)`
}" v-if="tableStore.table.data.length"></div>
<el-empty description="暂无报表" v-else style="flex: 1" :style="{
width: `calc(${prop.width} - ${fullscreen ? 290 : 0}px)`,
height: `calc(${prop.height} - 57px + ${fullscreen ? 0 : 56}px)`
}"></el-empty>
</div>
</div>
</div>
</template>
<script setup lang="ts">
@@ -40,6 +51,7 @@ import { querySysExcel } from '@/api/harmonic-boot/luckyexcel'
import { getListByIds } from '@/api/harmonic-boot/cockpit/cockpit'
import { getTime } from '@/utils/formatTime'
import { ElMessage } from 'element-plus'
import APFTree from '@/components/tree/govern/APFTree.vue'
const prop = defineProps({
w: { type: [String, Number] },
h: { type: [String, Number] },
@@ -47,39 +59,38 @@ const prop = defineProps({
height: { type: [String, Number] },
timeKey: { type: Array as () => string[] },
timeValue: { type: Object },
interval: { type: Number }
interval: { type: Number },
flag: { type: Boolean }
})
const TableHeaderRef = ref()
// 报表模板列表
const templateList = ref()
const templateList = ref([])
// 监测对象
const idList = ref()
// 监测对象
const initListByIds = () => {
getListByIds({}).then((res: any) => {
if (res.data?.length > 0) {
idList.value = res.data
if (!tableStore.table.params.sensitiveUserId && idList.value?.length > 0) {
tableStore.table.params.sensitiveUserId = idList.value[0].id
const handleNodeClick = async (data: any) => {
if (templateList.value.length == 0) {
await querySysExcel({}).then(res => {
templateList.value = res.data.filter(item => item.excelType == 4)
if (!tableStore.table.params.tempId && templateList.value?.length > 0) {
tableStore.table.params.tempId = templateList.value[0].id
}
templateListData()
} else {
querySysExcel({}).then(res => {
templateList.value = res.data.filter(item => item.excelType == 4)
if (!tableStore.table.params.tempId && templateList.value?.length > 0) {
tableStore.table.params.tempId = templateList.value[0].id
}
})
tableStore.table.loading = false
}
})
})
}
if (data?.level == 3 || data?.level == 2) {
tableStore.table.params.sensitiveUserId = data.id
await tableStore.index()
} else {
tableStore.table.loading = false
}
}
const templateListData = () => {
querySysExcel({}).then(res => {
templateList.value = res.data.filter(item => item.excelType == 4)
@@ -98,7 +109,7 @@ const downloadExcel = () => {
onMounted(() => {
initListByIds()
// initListByIds()
})
onUnmounted(() => {
destroyLuckysheet()
@@ -180,7 +191,7 @@ watch(
}
)
watch(
() => prop.height,
() => prop.height,
val => {
renderLuckysheetReport('luckysheet', tableStore.table.data, { allowEdit: false })
}
@@ -199,4 +210,11 @@ watch(
// :deep(.el-select) {
// min-width: 80px;
// }
.device-control {
display: flex;
}
:deep(.cn-tree) {
padding: 0 10px 0 0 !important;
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<el-dialog draggable title="趋势图" v-model="dialogVisible" append-to-body width="70%">
<el-dialog draggable :title="dialogTitle" v-model="dialogVisible" append-to-body width="70%">
<!-- 总体指标占比详情谐波含有率 -->
<div>
<TableHeader ref="tableHeaderRef" :showSearch="false" @selectChange="selectChange">
@@ -8,22 +8,10 @@
<DatePicker ref="datePickerRef"></DatePicker>
</el-form-item>
<el-form-item label="统计指标" label-width="80px">
<el-select
multiple
:multiple-limit="2"
collapse-tags
collapse-tags-tooltip
v-model="searchForm.index"
placeholder="请选择统计指标"
@change="onIndexChange($event)"
filterable
>
<el-option
v-for="item in indexOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
<el-select multiple :multiple-limit="2" collapse-tags collapse-tags-tooltip
v-model="searchForm.index" placeholder="请选择统计指标" @change="onIndexChange($event)" filterable>
<el-option v-for="item in indexOptions" :key="item.id" :label="item.name"
:value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item>
@@ -33,12 +21,8 @@
</el-radio-group>
</el-form-item>
<el-form-item label="统计类型">
<el-select
style="min-width: 90px !important"
placeholder="请选择"
v-model="searchForm.valueType"
filterable
>
<el-select style="min-width: 90px !important" placeholder="请选择" v-model="searchForm.valueType"
filterable>
<el-option value="max" label="最大值"></el-option>
<el-option value="min" label="最小值"></el-option>
<el-option value="avg" label="平均值"></el-option>
@@ -46,29 +30,15 @@
</el-select>
</el-form-item>
<el-form-item>
<div
class="history_count"
v-for="(item, index) in countData"
:key="index"
v-show="item.countOptions.length != 0"
>
<div class="history_count" v-for="(item, index) in countData" :key="index"
v-show="item.countOptions.length != 0">
<span class="mr12">
{{ item.name.includes('次数') ? item.name : item.name + '谐波次数' }}
</span>
<el-select
v-model="item.count"
@change="onCountChange($event, index)"
placeholder="请选择谐波次数"
style="width: 100px"
class="mr20"
filterable
>
<el-option
v-for="vv in item.countOptions"
:key="vv"
:label="item.name.includes('间谐波') ? vv - 0.5 : vv"
:value="vv"
></el-option>
<el-select v-model="item.count" @change="onCountChange($event, index)" placeholder="请选择谐波次数"
style="width: 100px" class="mr20" filterable>
<el-option v-for="vv in item.countOptions" :key="vv"
:label="item.name.includes('间谐波') ? vv - 0.5 : vv" :value="vv"></el-option>
</el-select>
</div>
</el-form-item>
@@ -109,6 +79,7 @@ const props = defineProps({
type: Array
}
})
const dialogTitle = ref('趋势图')
const dialogVisible: any = ref(false)
// console.log("🚀 ~ props:", props.TrendList)
@@ -165,14 +136,14 @@ const initCode = (field: string, title: string) => {
let codeKey = field.includes('flickerOvertime')
? '闪变'
: field.includes('uharm')
? '谐波电压'
: field.includes('iharm')
? '谐波电流'
: field.includes('voltageDevOvertime')
? '电压偏差'
: field.includes('ubalanceOvertime')
? '不平衡'
: ''
? '谐波电压'
: field.includes('iharm')
? '谐波电流'
: field.includes('voltageDevOvertime')
? '电压偏差'
: field.includes('ubalanceOvertime')
? '不平衡'
: ''
// const titleMap: Record<string, number> = {
// flickerOvertime: 0,
@@ -506,10 +477,10 @@ const setEchart = () => {
return item.anotherName == '电压负序分量'
? '电压不平衡'
: item.anotherName == '电压正序分量'
? '电压不平衡'
: item.anotherName == '电压零序分量'
? '电压不平衡'
: item.anotherName
? '电压不平衡'
: item.anotherName == '电压零序分量'
? '电压不平衡'
: item.anotherName
})
)
]
@@ -543,10 +514,10 @@ const setEchart = () => {
(kk[0].anotherName == '电压负序分量'
? '电压不平衡'
: kk[0].anotherName == '电压正序分量'
? '电压不平衡'
: kk[0].anotherName == '电压零序分量'
? '电压不平衡'
: kk[0].anotherName)
? '电压不平衡'
: kk[0].anotherName == '电压零序分量'
? '电压不平衡'
: kk[0].anotherName)
)
let seriesList: any = []
@@ -644,7 +615,7 @@ const onIndexChange = (val: any) => {
}
watch(
() => searchForm.value.index,
(val: any, oldval: any) => {},
(val: any, oldval: any) => { },
{
deep: true,
immediate: true
@@ -652,6 +623,7 @@ watch(
)
const openDialog = async (row: any, field: any, title: any) => {
dialogTitle.value = row?.lineName + '_趋势图'
dialogVisible.value = true
trendRequestData.value = row

View File

@@ -1,10 +1,10 @@
<template>
<div>
<!-- 指标越限详情 -->
<el-dialog draggable title="指标越限详情" v-model="dialogVisible" append-to-body width="70%">
<el-dialog draggable :title="title" v-model="dialogVisible" append-to-body width="70%">
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef">
<template v-slot:select>
<el-form-item label="监测点">
<!-- <el-form-item label="监测点">
<el-select
v-model="tableStore.table.params.lineId"
placeholder="请选择监测点"
@@ -18,7 +18,7 @@
:value="item.lineId"
/>
</el-select>
</el-form-item>
</el-form-item> -->
</template>
</TableHeader>
<Table ref="tableRef" @cell-click="cellClickEvent" isGroup :height="height"></Table>
@@ -38,7 +38,7 @@ import { cslineList } from '@/api/harmonic-boot/cockpit/cockpit'
const dialogVisible: any = ref(false)
const harmonicRatioRef: any = ref(null)
const title = ref('指标越限详情')
const options = ref()
const height = mainHeight(0, 2).height as any
const tableHeaderRef = ref()
@@ -76,13 +76,13 @@ const tableStore: any = new TableStore({
{
title: '日期',
field: 'time',
width: '150',
width: '120',
sortable: true
},
{
title: '名称',
field: 'lineName',
width: '150'
width: '120'
},
{
title: '长时闪变越限(%)',
@@ -143,6 +143,7 @@ tableStore.table.params.sortBy = ''
tableStore.table.params.orderBy = ''
const open = async (row: any,searchBeginTime:any,searchEndTime:any,interval:any,list:any) => {
dialogVisible.value = true
title.value = row.lineName + '_指标越限详情'
options.value = list
// initCSlineList()
tableStore.table.params.lineId = row.lineId
@@ -161,7 +162,7 @@ const open = async (row: any,searchBeginTime:any,searchEndTime:any,interval:any,
// 点击行
const cellClickEvent = ({ row, column }: any) => {
if (column.field != 'name' && column.field != 'time') {
if (column.field != 'lineName' &&column.field != 'name' && column.field != 'time') {
dialogFlag.value = true
dialogVisible.value = false
nextTick(() => {

View File

@@ -1,28 +1,14 @@
<template>
<div>
<!--电网侧指标越限统计 -->
<TableHeader
:showReset="false"
ref="TableHeaderRef"
@selectChange="selectChange"
datePicker
:timeKeyList="prop.timeKey"
v-if="fullscreen"
></TableHeader>
<my-echart
class="tall"
:options="echartList"
:style="{
width: prop.width,
height: `calc(${prop.height} / 2 )`
}"
/>
<Table
ref="tableRef"
@cell-click="cellClickEvent"
:height="`calc(${prop.height} / 2 - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`"
isGroup
></Table>
<TableHeader :showReset="false" ref="TableHeaderRef" @selectChange="selectChange" datePicker
:timeKeyList="prop.timeKey" v-if="fullscreen"></TableHeader>
<my-echart class="tall" :options="echartList" :style="{
width: prop.width,
height: `calc(${prop.height} / 2 )`
}" />
<Table ref="tableRef" @cell-click="cellClickEvent"
:height="`calc(${prop.height} / 2 - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`" isGroup></Table>
<!-- 指标越限详情 -->
<OverLimitDetails ref="OverLimitDetailsRef" />
</div>
@@ -141,17 +127,20 @@ const tableStore: any = new TableStore({
}
},
{
title: '名称',
title: '监测点名称',
field: 'lineName',
minWidth: '90'
minWidth: 120
},
{ title: '设备名称', field: 'devName', minWidth: 130, align: 'center', },
{ title: '项目名称', field: 'projectName', minWidth: 130, align: 'center' },
{ title: '工程名称', field: 'engineeringName', minWidth: 130, align: 'center' },
{
title: '越限占比(%)',
children: [
{
title: '长时闪变',
field: 'flicker',
minWidth: '70',
minWidth: '80',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flicker}</span>`
@@ -218,7 +207,7 @@ const cellClickEvent = ({ row, column }: any) => {
tableStore.table.params.searchBeginTime || prop.timeValue?.[0],
tableStore.table.params.searchEndTime || prop.timeValue?.[1],
tableStore.table.params.interval || prop.interval,
tableStore.table.data
tableStore.table.data
)
}
@@ -261,6 +250,6 @@ watch(
}
)
const addMenu = () => {}
const addMenu = () => { }
</script>
<style lang="scss" scoped></style>

View File

@@ -1,47 +1,32 @@
<template>
<div>
<div class="device-control">
<!--指标越限时间分布
-->
<TableHeader
:showReset="false"
:timeKeyList="prop.timeKey"
ref="TableHeaderRef"
@selectChange="selectChange"
datePicker
v-if="fullscreen"
>
<template v-slot:select>
<el-form-item label="监测点">
<el-select size="small" filterable v-model="tableStore.table.params.lineId">
<el-option
v-for="item in lineList"
:key="item.lineId"
:label="item.name"
:value="item.lineId"
/>
</el-select>
</el-form-item>
</template>
</TableHeader>
<div v-loading="tableStore.table.loading">
<my-echart
class="tall"
v-if="lineShow"
:options="echartList1"
:style="{
width: prop.width,
<div v-show="fullscreen">
<PointTree :height="flag ? 106 : 50" @node-click="nodeClick" @pointTypeChange="pointTypeChange"></PointTree>
</div>
<div>
<TableHeader :showReset="false" :timeKeyList="prop.timeKey" ref="TableHeaderRef"
@selectChange="selectChange" datePicker v-if="fullscreen">
<!-- <template v-slot:select>
<el-form-item label="监测点">
<el-select size="small" filterable v-model="tableStore.table.params.lineId">
<el-option v-for="item in lineList" :key="item.lineId" :label="item.name"
:value="item.lineId" />
</el-select>
</el-form-item>
</template> -->
</TableHeader>
<div v-loading="tableStore.table.loading">
<my-echart class="tall" v-if="lineShow" :options="echartList1" :style="{
width: `calc(${prop.width} - ${fullscreen ? 290 : 0}px)`,
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
}"
/>
<el-empty
v-else
description="暂无监测点"
:style="{
width: prop.width,
}" />
<el-empty v-else description="暂无监测点" :style="{
width: `calc(${prop.width} - ${fullscreen ? 290 : 0}px)`,
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
}"
/>
<!-- <my-echart
}" />
<!-- <my-echart
class="mt10"
:options="echartList1"
:style="{
@@ -49,6 +34,7 @@
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
}"
/> -->
</div>
</div>
</div>
</template>
@@ -59,7 +45,7 @@ import TableHeader from '@/components/table/header/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { limitProbabilityData, cslineList } from '@/api/harmonic-boot/cockpit/cockpit'
import { getTime } from '@/utils/formatTime'
import PointTree from '@/components/tree/govern/pointTree.vue'
const prop = defineProps({
w: { type: [String, Number] },
h: { type: [String, Number] },
@@ -67,7 +53,8 @@ const prop = defineProps({
height: { type: [String, Number] },
timeKey: { type: Array as () => string[] },
timeValue: { type: Object },
interval: { type: Number }
interval: { type: Number },
flag: { type: Boolean }
})
// const options = ref(JSON.parse(window.localStorage.getItem('lineIdList') || '[]'))
@@ -106,17 +93,28 @@ const echartList1 = ref()
const probabilityData = ref()
const initLineList = async () => {
cslineList({}).then(res => {
if (res.data.length == 0) {
lineShow.value = false
return (tableStore.table.loading = false)
}
lineShow.value = true
lineList.value = res.data
tableStore.table.params.lineId = lineList.value[0].lineId
// const initLineList = async () => {
// cslineList({}).then(res => {
// if (res.data.length == 0) {
// lineShow.value = false
// return (tableStore.table.loading = false)
// }
// lineShow.value = true
// lineList.value = res.data
// tableStore.table.params.lineId = lineList.value[0].lineId
// tableStore.index()
// })
// }
const nodeClick = (e: any) => {
if (e == undefined) {
}
if (e.level == 3) {
tableStore.table.params.lineId = e.id
tableStore.index()
})
}
}
const pointTypeChange = (val: any, obj: any) => {
nodeClick(obj)
}
// 越限程度概率分布
@@ -438,7 +436,7 @@ const tableStore: any = new TableStore({
provide('tableStore', tableStore)
onMounted(() => {
initLineList()
// initLineList()
})
const setTime = () => {
@@ -475,6 +473,14 @@ watch(
}
)
const addMenu = () => {}
const addMenu = () => { }
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.device-control {
display: flex;
}
:deep(.cn-tree) {
padding: 0 10px 0 0 !important;
}
</style>

View File

@@ -1,46 +1,31 @@
<template>
<div>
<div class="device-control">
<!--指标越限概率分布 -->
<TableHeader
:showReset="false"
:timeKeyList="prop.timeKey"
ref="TableHeaderRef"
@selectChange="selectChange"
datePicker
v-if="fullscreen"
>
<template v-slot:select>
<el-form-item label="监测点">
<el-select size="small" filterable v-model="tableStore.table.params.lineId">
<el-option
v-for="item in lineList"
:key="item.lineId"
:label="item.name"
:value="item.lineId"
/>
</el-select>
</el-form-item>
</template>
</TableHeader>
<div v-loading="tableStore.table.loading">
<my-echart
v-if="lineShow"
class="tall"
:options="echartList"
:style="{
width: prop.width,
<div v-show="fullscreen">
<PointTree :height="flag ? 106 : 50" @node-click="nodeClick" @pointTypeChange="pointTypeChange"></PointTree>
</div>
<div>
<TableHeader :showReset="false" :timeKeyList="prop.timeKey" ref="TableHeaderRef"
@selectChange="selectChange" datePicker v-if="fullscreen">
<!-- <template v-slot:select>
<el-form-item label="监测点">
<el-select size="small" filterable v-model="tableStore.table.params.lineId">
<el-option v-for="item in lineList" :key="item.lineId" :label="item.name"
:value="item.lineId" />
</el-select>
</el-form-item>
</template> -->
</TableHeader>
<div v-loading="tableStore.table.loading">
<my-echart v-if="lineShow" class="tall" :options="echartList" :style="{
width: `calc(${prop.width} - ${fullscreen ? 290 : 0}px)`,
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
}"
/>
<el-empty
v-else
description="暂无监测点"
:style="{
width: prop.width,
}" />
<el-empty v-else description="暂无监测点" :style="{
width: `calc(${prop.width} - ${fullscreen ? 290 : 0}px)`,
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
}"
/>
<!-- <my-echart
}" />
<!-- <my-echart
class="mt10"
:options="echartList1"
:style="{
@@ -48,7 +33,9 @@
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
}"
/> -->
</div>
</div>
</div>
</template>
<script setup lang="ts">
@@ -58,7 +45,7 @@ import TableHeader from '@/components/table/header/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { limitProbabilityData, cslineList } from '@/api/harmonic-boot/cockpit/cockpit'
import { getTime } from '@/utils/formatTime'
import PointTree from '@/components/tree/govern/pointTree.vue'
const prop = defineProps({
w: { type: [String, Number] },
h: { type: [String, Number] },
@@ -66,7 +53,8 @@ const prop = defineProps({
height: { type: [String, Number] },
timeKey: { type: Array as () => string[] },
timeValue: { type: Object },
interval: { type: Number }
interval: { type: Number },
flag: { type: Boolean }
})
const lineShow = ref(true)
// const options = ref(JSON.parse(window.localStorage.getItem('lineIdList') || '[]'))
@@ -105,18 +93,31 @@ const echartList1 = ref()
const probabilityData = ref()
const initLineList = async () => {
cslineList({}).then(res => {
if (res.data.length == 0) {
lineShow.value = false
return (tableStore.table.loading = false)
}
lineShow.value = true
lineList.value = res.data
tableStore.table.params.lineId = lineList.value[0].lineId
// const initLineList = async () => {
// cslineList({}).then(res => {
// if (res.data.length == 0) {
// lineShow.value = false
// return (tableStore.table.loading = false)
// }
// lineShow.value = true
// lineList.value = res.data
// tableStore.table.params.lineId = lineList.value[0].lineId
// tableStore.index()
// })
// }
const nodeClick = (e: any) => {
if (e == undefined) {
}
if (e.level == 3) {
tableStore.table.params.lineId = e.id
tableStore.index()
})
}
}
const pointTypeChange = (val: any, obj: any) => {
nodeClick(obj)
}
// 越限程度概率分布
const initProbabilityData = () => {
@@ -437,7 +438,7 @@ const tableStore: any = new TableStore({
provide('tableStore', tableStore)
onMounted(() => {
initLineList()
// initLineList()
})
const setTime = () => {
@@ -474,6 +475,13 @@ watch(
}
)
const addMenu = () => {}
const addMenu = () => { }
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.device-control {
display: flex;
}
:deep(.cn-tree) {
padding: 0 10px 0 0 !important;
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<el-dialog draggable title="趋势图" v-model="dialogVisible" append-to-body width="70%">
<el-dialog draggable :title="dialogTitle" v-model="dialogVisible" append-to-body width="70%">
<!-- 总体指标占比详情谐波含有率 -->
<div>
<TableHeader ref="tableHeaderRef" :showSearch="false" @selectChange="selectChange">
@@ -8,22 +8,10 @@
<DatePicker ref="datePickerRef"></DatePicker>
</el-form-item>
<el-form-item label="统计指标" label-width="80px">
<el-select
multiple
:multiple-limit="2"
collapse-tags
collapse-tags-tooltip
v-model="searchForm.index"
placeholder="请选择统计指标"
@change="onIndexChange($event)"
filterable
>
<el-option
v-for="item in indexOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
<el-select multiple :multiple-limit="2" collapse-tags collapse-tags-tooltip
v-model="searchForm.index" placeholder="请选择统计指标" @change="onIndexChange($event)" filterable>
<el-option v-for="item in indexOptions" :key="item.id" :label="item.name"
:value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item>
@@ -33,12 +21,8 @@
</el-radio-group>
</el-form-item>
<el-form-item label="统计类型">
<el-select
style="min-width: 120px !important"
placeholder="请选择"
v-model="searchForm.valueType"
filterable
>
<el-select style="min-width: 120px !important" placeholder="请选择" v-model="searchForm.valueType"
filterable>
<el-option value="max" label="最大值"></el-option>
<el-option value="min" label="最小值"></el-option>
<el-option value="avg" label="平均值"></el-option>
@@ -46,29 +30,15 @@
</el-select>
</el-form-item>
<el-form-item>
<div
class="history_count"
v-for="(item, index) in countData"
:key="index"
v-show="item.countOptions.length != 0"
>
<div class="history_count" v-for="(item, index) in countData" :key="index"
v-show="item.countOptions.length != 0">
<span class="mr12">
{{ item.name.includes('次数') ? item.name : item.name + '谐波次数' }}
</span>
<el-select
v-model="item.count"
@change="onCountChange($event, index)"
placeholder="请选择谐波次数"
style="width: 100px"
class="mr20"
filterable
>
<el-option
v-for="vv in item.countOptions"
:key="vv"
:label="item.name.includes('间谐波') ? vv - 0.5 : vv"
:value="vv"
></el-option>
<el-select v-model="item.count" @change="onCountChange($event, index)" placeholder="请选择谐波次数"
style="width: 100px" class="mr20" filterable>
<el-option v-for="vv in item.countOptions" :key="vv"
:label="item.name.includes('间谐波') ? vv - 0.5 : vv" :value="vv"></el-option>
</el-select>
</div>
</el-form-item>
@@ -109,6 +79,7 @@ const props = defineProps({
type: Array
}
})
const dialogTitle = ref('趋势图')
const dialogVisible: any = ref(false)
// console.log("🚀 ~ props:", props.TrendList)
@@ -181,14 +152,14 @@ const initCode = (field: string, title: string) => {
let codeKey = field.includes('flickerOvertime')
? '闪变'
: field.includes('uharm')
? '谐波电压'
: field.includes('iharm')
? '谐波电流'
: field.includes('voltageDevOvertime')
? '电压偏差'
: field.includes('ubalanceOvertime')
? '不平衡'
: ''
? '谐波电压'
: field.includes('iharm')
? '谐波电流'
: field.includes('uaberrance')
? '电压偏差'
: field.includes('ubalanceOvertime')
? '不平衡'
: ''
let defaultIndex = indexOptions.value.findIndex((item: any) => item.name.includes(codeKey)) || 0
searchForm.value.index[0] = indexOptions.value[defaultIndex].id
@@ -505,10 +476,10 @@ const setEchart = () => {
return item.anotherName == '电压负序分量'
? '电压不平衡'
: item.anotherName == '电压正序分量'
? '电压不平衡'
: item.anotherName == '电压零序分量'
? '电压不平衡'
: item.anotherName
? '电压不平衡'
: item.anotherName == '电压零序分量'
? '电压不平衡'
: item.anotherName
})
)
]
@@ -542,10 +513,10 @@ const setEchart = () => {
(kk[0].anotherName == '电压负序分量'
? '电压不平衡'
: kk[0].anotherName == '电压正序分量'
? '电压不平衡'
: kk[0].anotherName == '电压零序分量'
? '电压不平衡'
: kk[0].anotherName)
? '电压不平衡'
: kk[0].anotherName == '电压零序分量'
? '电压不平衡'
: kk[0].anotherName)
)
let seriesList: any = []
@@ -643,7 +614,7 @@ const onIndexChange = (val: any) => {
}
watch(
() => searchForm.value.index,
(val: any, oldval: any) => {},
(val: any, oldval: any) => { },
{
deep: true,
immediate: true
@@ -652,6 +623,8 @@ watch(
const openDialog = async (row: any, field: any, title: any) => {
dialogVisible.value = true
dialogTitle.value = row?.lineName + '_趋势图'
trendRequestData.value = row
nextTick(() => {

View File

@@ -1,9 +1,9 @@
<template>
<div>
<!-- 指标越限详情 -->
<el-dialog draggable title="指标越限详情" v-model="dialogVisible" append-to-body width="70%">
<el-dialog draggable :title="title" v-model="dialogVisible" append-to-body width="70%">
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef">
<template v-slot:select>
<!-- <template v-slot:select>
<el-form-item label="监测点">
<el-select
v-model="tableStore.table.params.lineId"
@@ -19,7 +19,7 @@
/>
</el-select>
</el-form-item>
</template>
</template> -->
</TableHeader>
<Table ref="tableRef" @cell-click="cellClickEvent" isGroup :height="height"></Table>
</el-dialog>
@@ -28,7 +28,7 @@
</div>
</template>
<script setup lang="ts">
import { ref, provide,nextTick } from 'vue'
import { ref, provide, nextTick } from 'vue'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import TableStore from '@/utils/tableStore'
@@ -40,7 +40,7 @@ const dialogVisible: any = ref(false)
const harmonicRatioRef: any = ref(null)
const dialogFlag = ref(false)
const title = ref('指标越限详情')
const options = ref()
const height = mainHeight(0, 2).height as any
const tableHeaderRef = ref()
@@ -77,18 +77,18 @@ const tableStore: any = new TableStore({
{
title: '日期',
field: 'time',
width: '150',
width: '120',
sortable: true
},
{
title: '名称',
title: '监测点名称',
field: 'lineName',
width: '150'
width: '120'
},
{
title: '越限(分钟)',
title: '长时闪变越限(分钟)',
field: 'flickerOvertime',
width: '90',
width: '100',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>`
@@ -130,7 +130,7 @@ const tableStore: any = new TableStore({
// }
// }
],
beforeSearchFun: () => {
beforeSearchFun: () => {
},
loadCallback: () => {
}
@@ -140,15 +140,17 @@ const tableStore: any = new TableStore({
provide('tableStore', tableStore)
tableStore.table.params.sortBy = ''
tableStore.table.params.orderBy = ''
const open = async (row: any,searchBeginTime:any,searchEndTime:any,data:any=[]) => {
const open = async (row: any, searchBeginTime: any, searchEndTime: any, data: any = []) => {
console.log("🚀 ~ open ~ row:", row)
dialogVisible.value = true
// initCSlineList()
options.value = data
title.value = row.lineName + '_指标越限详情'
tableStore.table.params.lineId = row.lineId
nextTick(() => {
tableHeaderRef.value.setTimeInterval([searchBeginTime, searchEndTime])
tableStore.table.params.searchBeginTime =searchBeginTime
tableStore.table.params.searchBeginTime = searchBeginTime
tableStore.table.params.searchEndTime = searchEndTime
tableStore.index()
})
@@ -157,11 +159,11 @@ const open = async (row: any,searchBeginTime:any,searchEndTime:any,data:any=[])
// 点击行
const cellClickEvent = ({ row, column }: any) => {
if (column.field != 'name' && column.field != 'time') {
if (column.field != 'lineName' && column.field != 'name' && column.field != 'time') {
dialogFlag.value = true
dialogVisible.value = false
nextTick(() => {
harmonicRatioRef.value.openDialog(row,column.field,column.title.replace(/次/g, ""))
harmonicRatioRef.value.openDialog(row, column.field, column.title.replace(/次/g, ""))
})
}

View File

@@ -1,25 +1,17 @@
<template>
<div>
<!--主要监测点列表 -->
<TableHeader
:showReset="false"
:timeKeyList="prop.timeKey"
@selectChange="selectChange"
v-if="fullscreen"
ref="TableHeaderRef"
>
<TableHeader :showReset="false" :timeKeyList="prop.timeKey" @selectChange="selectChange" v-if="fullscreen"
ref="TableHeaderRef">
<template v-slot:select>
<el-form-item label="关键字筛选">
<el-input maxlength="32" show-word-limit v-model="tableStore.table.params.keywords" clearable placeholder="请输入监测点名称" />
<el-input maxlength="32" show-word-limit v-model="tableStore.table.params.keywords" clearable
placeholder="请输入监测点名称" />
</el-form-item>
</template>
</TableHeader>
<Table
ref="tableRef"
@cell-click="cellClickEvent"
:height="`calc(${prop.height} - ${headerHeight}px + ${fullscreen ? -58 : 56}px )`"
></Table>
<Table ref="tableRef" @cell-click="cellClickEvent"
:height="`calc(${prop.height} - ${headerHeight}px + ${fullscreen ? -58 : 56}px )`"></Table>
<!-- 指标越限详情 -->
<OverLimitDetails ref="OverLimitDetailsRef" />
</div>
@@ -41,7 +33,8 @@ const prop = defineProps({
height: { type: [String, Number] },
timeKey: { type: Array as () => string[] },
timeValue: { type: Object },
interval: { type: Number }
interval: { type: Number },
flag: { type: Boolean }
})
const OverLimitDetailsRef = ref()
const headerHeight = ref(57)
@@ -90,17 +83,17 @@ const tableStore: any = new TableStore({
{
title: '监测点名称',
field: 'lineName',
minWidth: '90',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.lineName}</span>`
}
},
minWidth: 120,
},
{ title: '设备名称', field: 'devName', minWidth: 130, align: 'center' },
{ title: '项目名称', field: 'projectName', minWidth: 130, align: 'center' },
{ title: '工程名称', field: 'engineeringName', minWidth: 130, align: 'center' },
{
title: '监测对象类型',
field: 'objType',
minWidth: '90',
minWidth: '100',
formatter: (row: any) => {
return row.cellValue || '/'
}
@@ -114,7 +107,11 @@ const tableStore: any = new TableStore({
}
},
{ title: '主要存在的电能质量问题', field: 'problems', minWidth: '150', showOverflow: true }
{
title: '主要存在的电能质量问题', field: 'problems', minWidth: '250', render: 'customTemplate', customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.problems}</span>`
}
}
],
beforeSearchFun: () => {
setTime()
@@ -131,12 +128,12 @@ provide('tableStore', tableStore)
// 点击行
const cellClickEvent = ({ row, column }: any) => {
if (column.field == 'lineName') {
let time = getTimeOfTheMonth('3');
if (column.field == 'problems') {
let time = getTimeOfTheMonth('3');
OverLimitDetailsRef.value.open(
row,
time[0],
time[0],
time[1],
tableStore.table.data
)
@@ -176,7 +173,13 @@ watch(
deep: true
}
)
watch(
() => prop.flag,
val => {
tableStore.showPage = fullscreen.value ? true : false
}
)
const addMenu = () => {}
const addMenu = () => { }
</script>
<style lang="scss" scoped></style>

View File

@@ -220,16 +220,33 @@ const setEchart = () => {
}
: {}
],
grid: {
left: '10px',
right: '20px'
},
// grid: {
// left: '10px',
// right: '30px',
// },
options: {
// dataZoom: [
// {
// type: 'inside',
// start: 0,
// end: 100,
// filterMode: 'filter'
// },
// {
// type: 'slider',
// start: 0,
// end: 100,
// height: 13,
// bottom: '20px',
// filterMode: 'filter'
// }
// ],
series: [
{
type: 'bar',
name: powerName, // 动态设置功率名称
data: [],
clip: true,
itemStyle: {
normal: {
color: function (params: any) {
@@ -248,7 +265,7 @@ const setEchart = () => {
type: 'line',
step: 'end',
showSymbol: false,
// smooth: true,
clip: true,
data: [],
yAxisIndex: 1
}

View File

@@ -1,10 +1,10 @@
<template>
<div>
<!-- 指标越限详情 -->
<el-dialog draggable title="指标越限详情" v-model="dialogVisible" append-to-body width="70%">
<el-dialog draggable :title="title" v-model="dialogVisible" append-to-body width="70%">
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef">
<template v-slot:select>
<el-form-item label="监测点">
<!-- <el-form-item label="监测点">
<el-select
v-model="tableStore.table.params.lineId"
placeholder="请选择监测点"
@@ -18,7 +18,7 @@
:value="item.lineId"
/>
</el-select>
</el-form-item>
</el-form-item> -->
</template>
</TableHeader>
<Table ref="tableRef" @cell-click="cellClickEvent" isGroup :height="height"></Table>
@@ -38,7 +38,7 @@ import { cslineList ,governLineList} from '@/api/harmonic-boot/cockpit/cockpit'
const dialogVisible: any = ref(false)
const harmonicRatioRef: any = ref(null)
const title = ref('指标越限详情')
const options = ref()
const height = mainHeight(0, 2).height as any
const tableHeaderRef = ref()
@@ -76,13 +76,13 @@ const tableStore: any = new TableStore({
{
title: '日期',
field: 'time',
width: '150',
width: '120',
sortable: true
},
{
title: '名称',
field: 'lineName',
width: '150'
width: '120'
},
{
title: '长时闪变越限(%)',
@@ -144,6 +144,7 @@ tableStore.table.params.orderBy = ''
const time:any=ref([])
const open = async (row: any,searchBeginTime:any,searchEndTime:any) => {
dialogVisible.value = true
title.value = row.lineName + '_指标越限详情'
time.value=[searchBeginTime,searchEndTime]
initCSlineList()
tableStore.table.params.lineId = row.lineId
@@ -159,7 +160,7 @@ const open = async (row: any,searchBeginTime:any,searchEndTime:any) => {
// 点击行
const cellClickEvent = ({ row, column }: any) => {
if (column.field != 'name' && column.field != 'time') {
if (column.field != 'lineName' && column.field != 'name' && column.field != 'time') {
dialogFlag.value = true
dialogVisible.value = false
nextTick(() => {

View File

@@ -1,55 +1,26 @@
<template>
<div>
<!-- 监测点列表 -->
<TableHeader
ref="TableHeaderRef"
:showReset="false"
@selectChange="selectChange"
v-if="fullscreen"
:timeKeyList="prop.timeKey"
>
<TableHeader ref="TableHeaderRef" :showReset="false" @selectChange="selectChange" v-if="fullscreen"
:timeKeyList="prop.timeKey">
<template #select>
<el-form-item label="关键字筛选">
<el-input maxlength="32" show-word-limit
style="width: 240px"
v-model.trim="tableStore.table.params.searchValue"
clearable
placeholder="请输入监测点名称"
/>
<el-input maxlength="32" show-word-limit style="width: 240px"
v-model.trim="tableStore.table.params.searchValue" clearable placeholder="请输入监测点名称" />
</el-form-item>
</template>
</TableHeader>
<Table
ref="tableRef"
@cell-click="cellClickEvent"
:height="`calc(${prop.height} - ${headerHeight}px + ${fullscreen ? -58 : 56}px )`"
></Table>
<Table ref="tableRef" @cell-click="cellClickEvent"
:height="`calc(${prop.height} - ${headerHeight}px + ${fullscreen ? -58 : 56}px )`"></Table>
<!-- 指标越限详情 -->
<OverLimitDetails ref="OverLimitDetailsRef" />
<!-- 上传对话框 -->
<el-dialog
v-model="uploadDialogVisible"
title="上传报告"
append-to-body
width="500px"
@closed="handleDialogClosed"
>
<el-upload
ref="uploadRef"
class="upload-demo"
action=""
accept=".doc,.docx,.PDF"
:on-change="handleChange"
:before-upload="beforeUpload"
:limit="1"
:auto-upload="false"
:on-exceed="handleExceed"
:on-remove="handleRemove"
:file-list="fileList"
>
<el-dialog v-model="uploadDialogVisible" title="上传报告" append-to-body width="500px" @closed="handleDialogClosed">
<el-upload ref="uploadRef" class="upload-demo" action="" accept=".doc,.docx,.PDF" :on-change="handleChange"
:before-upload="beforeUpload" :limit="1" :auto-upload="false" :on-exceed="handleExceed"
:on-remove="handleRemove" :file-list="fileList">
<el-button type="primary">点击上传</el-button>
<template #tip>
<div class="el-upload__tip">请上传Word或PDF文件</div>
@@ -73,7 +44,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import OverLimitDetails from '@/components/cockpit/monitoringPointList/components/overLimitDetails.vue'
import TableHeader from '@/components/table/header/index.vue'
import { uploadReport, getReportUrl } from '@/api/harmonic-boot/cockpit/cockpit'
import { getTime } from '@/utils/formatTime'
const prop = defineProps({
w: { type: [String, Number] },
@@ -82,7 +53,8 @@ const prop = defineProps({
height: { type: [String, Number] },
timeKey: { type: Array as () => string[] },
timeValue: { type: Object },
interval: { type: Number }
interval: { type: Number },
flag: { type: Boolean }
})
const headerHeight = ref(57)
@@ -135,16 +107,19 @@ const tableStore: any = new TableStore({
{
title: '监测点名称',
field: 'lineName',
minWidth: '120',
minWidth: 120,
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.lineName}</span>`
}
},
{ title: '设备名称', field: 'devName', minWidth: 130, align: 'center' },
{ title: '项目名称', field: 'projectName', minWidth: 130, align: 'center' },
{ title: '工程名称', field: 'engineeringName', minWidth: 130, align: 'center' },
{
title: '监测类型',
field: 'position',
minWidth: '80',
minWidth: '100',
formatter: (row: any) => {
return row.cellValue || '/'
}
@@ -162,28 +137,22 @@ const tableStore: any = new TableStore({
title: '监测点状态',
field: 'runStatus',
render: 'tag',
width: 100,
width: 90,
custom: {
停运: 'danger',
退运: 'danger',
运行: 'success',
在线: 'success',
中断: 'warning',
离线: 'danger',
检修: 'warning',
调试: 'warning',
// 0运行1检修2停运3调试4退运
0: 'success',
1: 'warning',
2: 'danger',
3: 'warning',
4: 'info',
null: 'info'
},
replaceValue: {
运行: '运行',
在线: '在线',
退运: '退运',
停运: '停运',
中断: '中断',
检修: '检修',
离线: '离线',
调试: '调试',
0: '运行',
1: '检修',
2: '运',
3: '调试',
4: '退运',
null: '/'
}
},
@@ -192,21 +161,21 @@ const tableStore: any = new TableStore({
field: 'volGrade',
minWidth: '80',
formatter: (row: any) => {
return row.cellValue == 0 ? '/' : row.cellValue || '/'
return row.cellValue == 0 ? '/' : row.cellValue || '/'
}
},
{
title: '治理对象',
field: 'sensitiveUser',
minWidth: '90',
minWidth: '100',
formatter: (row: any) => {
return row.cellValue || '/'
}
},
{
title: '是否治理',
title: '治理方案',
field: 'govern',
minWidth: '80',
formatter: (row: any) => {
@@ -241,7 +210,7 @@ const tableStore: any = new TableStore({
// }
// },
{
title: '报告',
title: '治理前报告',
field: 'reportFilePath',
minWidth: '150',
formatter: (row: any) => {
@@ -347,7 +316,7 @@ const downloadTheReport = (lineId: string, name: string) => {
forceDownloadPdf(res.data, name.split('/').pop() || '')
})
}
const forceDownloadPdf = async (pdfUrl:any, fileName = '文件.pdf') => {
const forceDownloadPdf = async (pdfUrl: any, fileName = '文件.pdf') => {
try {
// 1. 请求 PDF 并转为 Blob关键绕开浏览器直接解析
const response = await fetch(pdfUrl, {
@@ -374,9 +343,9 @@ const forceDownloadPdf = async (pdfUrl:any, fileName = '文件.pdf') => {
// 4. 清理资源(避免内存泄漏)
document.body.removeChild(a)
URL.revokeObjectURL(blobUrl)
setTimeout(() => {
ElMessage.success('下载成功')
}, 2000)
setTimeout(() => {
ElMessage.success('下载成功')
}, 2000)
} catch (error) {
console.error('下载失败:', error)
// ElMessage.error('文件下载失败,请检查网络或文件地址') // 适配 Element Plus
@@ -456,6 +425,12 @@ const handleUpload = async () => {
onMounted(() => {
tableStore.index()
})
watch(
() => prop.flag,
val => {
tableStore.showPage = fullscreen.value ? true : false
}
)
watch(
() => prop.timeKey,
val => {

View File

@@ -1,10 +1,10 @@
<template>
<div>
<!-- 指标越限详情 -->
<el-dialog draggable title="指标越限详情" v-model="dialogVisible" append-to-body width="70%">
<el-dialog draggable :title="title" v-model="dialogVisible" append-to-body width="70%">
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef">
<template v-slot:select>
<el-form-item label="监测点">
<!-- <el-form-item label="监测点">
<el-select
v-model="tableStore.table.params.lineId"
placeholder="请选择监测点"
@@ -18,7 +18,7 @@
:value="item.lineId"
/>
</el-select>
</el-form-item>
</el-form-item> -->
</template>
</TableHeader>
<Table ref="tableRef" @cell-click="cellClickEvent" isGroup :height="height"></Table>
@@ -38,7 +38,7 @@ import { cslineList } from '@/api/harmonic-boot/cockpit/cockpit'
const dialogVisible: any = ref(false)
const harmonicRatioRef: any = ref(null)
const title = ref('指标越限详情')
const options = ref()
const height = mainHeight(0, 2).height as any
const tableHeaderRef = ref()
@@ -76,13 +76,13 @@ const tableStore: any = new TableStore({
{
title: '日期',
field: 'time',
width: '150',
width: '120',
sortable: true
},
{
title: '名称',
field: 'lineName',
width: '150'
width: '120'
},
{
title: '长时闪变越限(%)',
@@ -144,6 +144,7 @@ tableStore.table.params.orderBy = ''
const open = async (row: any,searchBeginTime:any,searchEndTime:any,data: any) => {
dialogVisible.value = true
// initCSlineList()
title.value = row.lineName + '_指标越限详情'
options.value = data
tableStore.table.params.lineId = row.lineId
@@ -158,7 +159,7 @@ const open = async (row: any,searchBeginTime:any,searchEndTime:any,data: any) =>
// 点击行
const cellClickEvent = ({ row, column }: any) => {
if (column.field != 'name' && column.field != 'time') {
if (column.field != 'lineName' && column.field != 'name' && column.field != 'time') {
dialogFlag.value = true
dialogVisible.value = false
nextTick(() => {

View File

@@ -142,17 +142,20 @@ const tableStore: any = new TableStore({
}
},
{
title: '名称',
title: '监测点名称',
field: 'lineName',
minWidth: '90'
minWidth: 120
},
{ title: '设备名称', field: 'devName', minWidth: 130, align: 'center' },
{ title: '项目名称', field: 'projectName', minWidth: 130, align: 'center' },
{ title: '工程名称', field: 'engineeringName', minWidth: 130, align: 'center' },
{
title: '越限占比(%)',
children: [
{
title: '长时闪变',
field: 'flicker',
minWidth: '70',
minWidth: '80',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flicker}</span>`

View File

@@ -1,32 +1,17 @@
<template>
<div>
<!--敏感负荷列表 -->
<TableHeader
ref="TableHeaderRef"
:showReset="false"
@selectChange="selectChange"
v-if="fullscreen"
:timeKeyList="prop.timeKey"
>
<TableHeader ref="TableHeaderRef" :showReset="false" @selectChange="selectChange" v-if="fullscreen"
:timeKeyList="prop.timeKey">
<template #select>
<el-form-item label="关键字筛选">
<el-input maxlength="32" show-word-limit
style="width: 240px"
v-model.trim="tableStore.table.params.searchValue"
clearable
placeholder="请输入敏感负荷名称"
/>
<el-input maxlength="32" show-word-limit style="width: 240px"
v-model.trim="tableStore.table.params.searchValue" clearable placeholder="请输入敏感用户名称" />
</el-form-item>
</template>
</TableHeader>
<Table
ref="tableRef"
@cell-click="cellClickEvent"
:height="`calc(${prop.height} - ${headerHeight}px + ${fullscreen ? -58 : 56}px )`"
isGroup
></Table>
<Table ref="tableRef" @cell-click="cellClickEvent"
:height="`calc(${prop.height} - ${headerHeight}px + ${fullscreen ? -58 : 56}px )`" isGroup></Table>
</div>
</template>
<script setup lang="ts">
@@ -44,7 +29,8 @@ const prop = defineProps({
height: { type: [String, Number] },
timeKey: { type: Array as () => string[] },
timeValue: { type: Object },
interval: { type: Number }
interval: { type: Number },
flag: { type: Boolean }
})
const headerHeight = ref(57)
@@ -91,13 +77,13 @@ const tableStore: any = new TableStore({
}
},
{
title: '敏感负荷名称',
title: '敏感用户名称',
field: 'name',
minWidth: '90'
},
{
title: '敏感负荷类型',
title: '敏感用户类型',
field: 'loadType',
minWidth: '70',
formatter: row => {
@@ -125,7 +111,7 @@ const tableStore: any = new TableStore({
setTime()
},
loadCallback: () => {}
loadCallback: () => { }
})
tableStore.table.params.searchValue = ''
const tableRef = ref()
@@ -179,5 +165,11 @@ watch(
deep: true
}
)
watch(
() => prop.flag,
val => {
tableStore.showPage = fullscreen.value ? true : false
}
)
</script>
<style lang="scss" scoped></style>

View File

@@ -1,203 +1,155 @@
<template>
<div>
<!-- 暂态事件详情 -->
<el-dialog draggable title="暂态事件详情 " v-model="dialogVisible" append-to-body width="70%">
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef" @selectChange="selectChange">
<template v-slot:select>
<el-form-item label="监测点" v-if="props.showLine">
<el-select v-model="tableStore.table.params.lineId" filterable placeholder="请选择监测点名称">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="暂态类型">
<el-select
v-model="tableStore.table.params.eventType"
style="min-width: 150px"
clearable
placeholder="请选择暂态类型"
>
<el-option
v-for="item in eventList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-dialog draggable title="暂态事件" v-model="dialogVisible" append-to-body width="70%">
<TableHeader datePicker showExport ref="tableHeaderRef" @selectChange="selectChange"
@onResetForm="onResetForm">
<template v-slot:operation>
<el-button type="primary" icon="el-icon-Operation" @click="openFilterDialog">事件筛选</el-button>
</template>
</TableHeader>
<MultiCondition v-model:visible="filterVisible" :params="tableStore.table.params" ref="multiConditionRef"
@confirm="onFilterConfirm" />
<Table ref="tableRef" isGroup :height="heightRef"></Table>
</el-dialog>
<!-- 查看波形 -->
<el-dialog
v-model="isWaveCharts"
draggable
title="波形分析"
append-to-body
v-if="isWaveCharts"
width="70%"
@close="handleHideCharts"
>
<waveFormAnalysis
v-loading="loading"
ref="waveFormAnalysisRef"
@handleHideCharts="handleHideCharts"
:wp="wp"
/>
<el-dialog v-model="isWaveCharts" draggable title="波形分析" append-to-body width="70%" @close="handleHideCharts">
<waveFormAnalysis v-loading="loading" v-if="isWaveCharts" ref="waveFormAnalysisRef"
@handleHideCharts="handleHideCharts" :wp="wp" />
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, provide } from 'vue'
import { ref, provide, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import TableStore from '@/utils/tableStore'
import { mainHeight } from '@/utils/layout'
import MultiCondition from '@/views/govern/alarm/multiCondition.vue'
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
import { analyseWave } from '@/api/common'
import { getSimpleLine } from '@/api/harmonic-boot/cockpit/cockpit'
interface Props {
showLine?: boolean
}
import { getFileZip } from '@/api/cs-harmonic-boot/datatrend'
import { useDictData } from '@/stores/dictData'
const props = withDefaults(defineProps<Props>(), {
showLine: true
})
const dialogVisible: any = ref(false)
const waveFormAnalysisRef: any = ref(null)
// 波形
const dialogVisible = ref(false)
const waveFormAnalysisRef = ref()
const isWaveCharts = ref(false)
const loading = ref(false)
const wp = ref({})
const boxoList: any = ref({})
const tableHeaderRef = ref()
const filterVisible = ref(false)
const multiConditionRef = ref<InstanceType<typeof MultiCondition>>()
const currentOpenTime = ref('')
const dictData = useDictData()
const ReasonList: any = dictData.getBasicData('Event_Reason')
const EventTypeList: any = dictData.getBasicData('Event_Type')
const options = ref()
const heightRef = ref(mainHeight(168, 2.1).height)
const selectChange = (flag: boolean, h: any) => {
const selectChange = (_flag: boolean, h: number) => {
heightRef.value = mainHeight(h, 2.1).height
}
const eventList = [
{ label: '电压暂降', value: '1' },
{ label: '电压中断', value: '2' },
{ label: '电压暂升', value: '3' }
]
const getSimpleLineList = async () => {
const res = await getSimpleLine()
options.value = res.data
}
const tableStore: any = new TableStore({
url: '/cs-harmonic-boot/event/pageEvent',
url: '/cs-harmonic-boot/eventUser/queryEventpageWeb',
method: 'POST',
showPage: true,
exportName: '暂态事件详情',
exportName: '暂态事件',
column: [
{
field: 'index',
title: '序号',
width: '80',
width: 80,
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{
title: '暂态时间',
field: 'startTime',
minWidth: '180'
},
{
title: '测点名称',
field: 'lineName',
minWidth: '150'
},
{
title: '暂态类型',
field: 'tag',
minWidth: '100'
},
{
title: '特征幅值(%)',
field: 'amplitude',
minWidth: '100'
},
{
title: '暂降深度(%)',
field: 'depth',
minWidth: '100',
formatter: (row: any) => {
// 当暂态类型不是电压暂升时,计算暂降深度 = 100 - 特征幅值
if (row.row.tag !== '电压暂升') {
const amplitude = parseFloat(row.row.amplitude)
if (!isNaN(amplitude)) {
return 100 - amplitude
}
return '-'
} else {
// 电压暂升时不显示暂降深度
return '/'
}
}
},
{
title: '持续时间(S)',
field: 'persistTime',
minWidth: '100'
},
{ title: '发生时刻', field: 'startTime', align: 'center', minWidth: 180, sortable: true },
{ title: '暂降幅值(%)', minWidth: 120, field: 'evtParamVVaDepth', align: 'center', sortable: true },
{ title: '持续时间(s)', field: 'evtParamTm', minWidth: 110, align: 'center', sortable: true },
{
title: '严重度',
field: 'severity',
minWidth: '80'
minWidth: 80,
align: 'center',
sortable: true,
formatter: (row: any) => row.cellValue ? row.cellValue : '/'
},
{ title: '相别', field: 'evtParamPhase', minWidth: 80, align: 'center' },
{ title: '触发类型', field: 'showName', minWidth: 100, align: 'center' },
{
title: '暂降原因',
field: 'advanceReason',
minWidth: 100,
align: 'center',
formatter: (row: any) => ReasonList.find((item: any) => item.id == row.cellValue)?.name || '未知'
},
{
title: '波形',
minWidth: '100',
title: '暂降类型',
field: 'advanceType',
minWidth: 100,
align: 'center',
formatter: (row: any) => EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '未知'
},
{ title: '监测点名称', field: 'lineName', minWidth: 130, align: 'center' },
{ title: '电压等级(kV)', field: 'lineVoltage', minWidth: 120, align: 'center', sortable: true },
{ title: '设备名称', field: 'equipmentName', minWidth: 130, align: 'center' },
{ title: '项目名称', field: 'projectName', minWidth: 130, align: 'center' },
{ title: '工程名称', field: 'engineeringName', minWidth: 130, align: 'center' },
{
title: '发生位置',
field: 'sagSource',
minWidth: 120,
align: 'center',
formatter: (row: any) => row.cellValue == 1 ? '上游' : row.cellValue == 2 ? '下游' : '未知'
},
{
title: '操作',
fixed: 'right',
align: 'center',
width: 150,
render: 'buttons',
buttons: [
{
name: 'edit',
text: '波形分析',
text: '暂无波形',
type: 'info',
icon: 'el-icon-DataLine',
render: 'basicButton',
disabled: row => {
return row.wavePath
},
},
{
name: 'edit',
title: '波形分析',
type: 'primary',
icon: 'el-icon-DataLine',
render: 'basicButton',
loading: 'loading1',
disabled: row => {
return !row.wavePath
},
click: async row => {
disabled: (row: any) => !row.wavePath,
click: async (row: any) => {
row.loading1 = true
dialogVisible.value = false
// 在打开弹窗时立即设置高度
nextTick(() => {
if (waveFormAnalysisRef.value) {
// waveFormAnalysisRef.value.setHeight(false, 360)
waveFormAnalysisRef.value.setHeight(999, 130, 1.6666666)
}
})
await analyseWave(row.id)
.then(res => {
isWaveCharts.value = true
loading.value = true
row.loading1 = false
if (res != undefined) {
boxoList.value = row
// boxoList.value = {
// ...row,
// duration: row.persistTime // 将 persistTime 值赋给 duration
// }
boxoList.value.featureAmplitude = (row.amplitude - 0) / 100
// row.evtParamVVaDepth != '-' ? row.evtParamVVaDepth - 0 : null
boxoList.value.systemType = 'YPT'
loading.value = true
isWaveCharts.value = true
boxoList.value = {
...row,
engineeringName: row.projectName,
persistTime: row.evtParamTm,
featureAmplitude:
row.evtParamVVaDepth != '-' ? (row.evtParamVVaDepth - 0) / 100 : null,
systemType: 'YPT',
}
wp.value = res.data
}
loading.value = false
@@ -208,40 +160,142 @@ const tableStore: any = new TableStore({
})
nextTick(() => {
waveFormAnalysisRef.value &&
if (waveFormAnalysisRef.value) {
waveFormAnalysisRef.value.getWpData(wp.value, boxoList.value, true)
waveFormAnalysisRef.value.setHeight(999, 130, 1.6666666)
}
})
}
},
{
name: 'edit',
text: '暂无波形',
type: 'info',
icon: 'el-icon-DataLine',
title: '波形下载',
type: 'primary',
icon: 'el-icon-Check',
loading: 'loading2',
render: 'basicButton',
disabled: row => {
return row.wavePath
disabled: (row: any) => !row.wavePath,
click: (row: any) => {
row.loading2 = true
ElMessage.info('下载中......')
getFileZip({ eventId: row.id }).then(res => {
const blob = new Blob([res as unknown as BlobPart], { type: 'application/zip' })
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = row.wavePath.split('/')[2] || '波形文件'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
ElMessage.success('波形下载成功')
row.loading2 = false
}).catch(() => {
row.loading2 = false
})
}
}
]
}
],
beforeSearchFun: () => {},
loadCallback: () => {}
beforeSearchFun: () => { },
resetCallback: () => {
restoreOpenDayTime()
},
loadCallback: () => {
tableStore.table.data.forEach((item: any) => {
item.loading = false
item.evtParamTm =
item.evtParamTm.split('s')[0] != '-' ? (item.evtParamTm.split('s')[0] - 0).toFixed(2) : '-'
item.evtParamVVaDepth =
item.evtParamVVaDepth.split('%')[0] != '-'
? (item.evtParamVVaDepth.split('%')[0] - 0).toFixed(2)
: '-'
})
}
})
tableStore.table.params.eventType = ''
tableStore.table.params.type = 0
Object.assign(tableStore.table.params, {
featureAmplitudeMin: undefined,
featureAmplitudeMax: undefined,
evtParamTmMin: undefined,
evtParamTmMax: undefined,
severityMin: undefined,
severityMax: undefined,
fileFlag: ''
})
provide('tableStore', tableStore)
const open = async (time: any) => {
tableStore.table.params.eventType = ''
dialogVisible.value = true
getSimpleLineList()
tableStore.table.params.lineId = ''
const resetFilterParams = () => {
Object.assign(tableStore.table.params, {
featureAmplitudeMin: undefined,
featureAmplitudeMax: undefined,
evtParamTmMin: undefined,
evtParamTmMax: undefined,
severityMin: undefined,
severityMax: undefined,
fileFlag: ''
})
}
const restoreOpenDayTime = () => {
if (!currentOpenTime.value || !tableHeaderRef.value) return
tableHeaderRef.value.setInterval(5)
tableHeaderRef.value.setTimeInterval([currentOpenTime.value, currentOpenTime.value])
tableStore.table.params.searchBeginTime = currentOpenTime.value
tableStore.table.params.searchEndTime = currentOpenTime.value
}
const syncInitDataForReset = () => {
if (!tableStore.initData) return
Object.assign(tableStore.initData, {
searchBeginTime: currentOpenTime.value,
searchEndTime: currentOpenTime.value,
startTime: currentOpenTime.value,
endTime: currentOpenTime.value,
featureAmplitudeMin: undefined,
featureAmplitudeMax: undefined,
evtParamTmMin: undefined,
evtParamTmMax: undefined,
severityMin: undefined,
severityMax: undefined,
fileFlag: ''
})
}
const openFilterDialog = () => {
filterVisible.value = true
}
const onFilterConfirm = () => {
tableStore.onTableAction('search', {})
}
const onResetForm = () => {
filterVisible.value = false
resetFilterParams()
multiConditionRef.value?.reset()
syncInitDataForReset()
nextTick(() => {
tableHeaderRef.value.setInterval(5)
tableHeaderRef.value.setTimeInterval([time, time])
tableStore.table.params.searchBeginTime = time
tableStore.table.params.searchEndTime = time
restoreOpenDayTime()
})
}
const open = (time: string) => {
currentOpenTime.value = time
dialogVisible.value = true
filterVisible.value = false
resetFilterParams()
multiConditionRef.value?.reset()
tableStore.table.params.pageNum = 1
nextTick(() => {
restoreOpenDayTime()
tableStore.index()
nextTick(() => {
syncInitDataForReset()
})
})
}
@@ -252,4 +306,5 @@ const handleHideCharts = () => {
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@@ -58,7 +58,7 @@
</template>
</el-calendar>
<!-- 暂态事件列表 -->
<TransientList ref="transientListRef" :showLine="false" />
<TransientList ref="transientListRef" />
</div>
</template>
<script setup lang="ts">

View File

@@ -1,22 +1,12 @@
<template>
<div>
<!--暂态事件概率分布 -->
<TableHeader
ref="TableHeaderRef"
:timeKeyList="prop.timeKey"
:showReset="false"
@selectChange="selectChange"
datePicker
v-if="fullscreen"
></TableHeader>
<my-echart
class="tall"
:options="echartList"
:style="{
width: prop.width,
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
}"
/>
<TableHeader ref="TableHeaderRef" :timeKeyList="prop.timeKey" :showReset="false" @selectChange="selectChange"
datePicker v-if="fullscreen"></TableHeader>
<my-echart class="tall" :options="echartList" :style="{
width: prop.width,
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
}" />
<!-- <my-echart
class="mt10"
:options="echartList1"
@@ -170,7 +160,11 @@ const tableStore: any = new TableStore({
},
title: {
text: '暂态事件概率分布',
x: 'center'
x: 'center',
textStyle: {
color: '#000',
fontSize: '15'
},
},
visualMap: {
max: 500,
@@ -206,22 +200,22 @@ const tableStore: any = new TableStore({
},
grid3D: {
viewControl: {
projection: 'perspective',
distance: 260,
rotateSensitivity: 10,
zoomSensitivity: 2
projection: 'perspective',
distance: 260,
rotateSensitivity: 10,
zoomSensitivity: 2
},
boxWidth: 150,
boxDepth: 100,
boxHeight: 100,
light: {
main: {
intensity: 1.2
},
boxWidth: 150,
boxDepth: 100,
boxHeight: 100,
light: {
main: {
intensity: 1.2
},
ambient: {
intensity: 0.4
}
ambient: {
intensity: 0.4
}
}
},
series: [
{
@@ -242,7 +236,7 @@ const tableStore: any = new TableStore({
echartList1.value = {
title: {
text: '越限时间概率分布'
text: '暂态事件概率分布',
},
xAxis: {
type: 'category',

View File

@@ -1,197 +1,178 @@
<template>
<div>
<!-- 暂态事件详情 -->
<el-dialog draggable title="暂态事件详情 " v-model="dialogVisible" append-to-body width="70%">
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef" @selectChange="selectChange">
<template v-slot:select>
<el-form-item label="监测点">
<el-select filterable v-model="tableStore.table.params.lineId" placeholder="请选择监测点名称">
<el-option
v-for="item in options"
:key="item.lineId"
:label="item.name"
:value="item.lineId"
/>
</el-select>
</el-form-item>
<el-form-item label="暂态类型">
<el-select
v-model="tableStore.table.params.eventType"
style="min-width: 150px"
clearable
placeholder="请选择暂态类型"
>
<el-option
v-for="item in eventList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-dialog draggable :title="title" v-model="dialogVisible" append-to-body width="70%">
<TableHeader datePicker showExport ref="tableHeaderRef" @selectChange="selectChange"
@onResetForm="onResetForm">
<template v-slot:operation>
<el-button type="primary" icon="el-icon-Operation" @click="openFilterDialog">事件筛选</el-button>
</template>
</TableHeader>
<MultiCondition
v-model:visible="filterVisible"
:fixed-target="filterTarget"
:params="tableStore.table.params"
ref="multiConditionRef"
@confirm="onFilterConfirm"
/>
<Table ref="tableRef" isGroup :height="heightRef"></Table>
</el-dialog>
<!-- 查看波形 -->
<el-dialog
v-model="isWaveCharts"
draggable
title="波形分析"
append-to-body
width="70%"
@close="handleHideCharts"
>
<waveFormAnalysis
v-loading="loading"
v-if="isWaveCharts"
ref="waveFormAnalysisRef"
@handleHideCharts="handleHideCharts"
:wp="wp"
/>
<el-dialog v-model="isWaveCharts" draggable title="波形分析" append-to-body width="70%" @close="handleHideCharts">
<waveFormAnalysis v-loading="loading" v-if="isWaveCharts" ref="waveFormAnalysisRef"
@handleHideCharts="handleHideCharts" :wp="wp" />
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, provide } from 'vue'
import { ref, provide, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import TableStore from '@/utils/tableStore'
import { mainHeight } from '@/utils/layout'
import MultiCondition from '@/views/govern/alarm/multiCondition.vue'
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
import { analyseWave } from '@/api/common'
import { getSimpleLine } from '@/api/harmonic-boot/cockpit/cockpit'
import { getFileZip } from '@/api/cs-harmonic-boot/datatrend'
import { useDictData } from '@/stores/dictData'
const dialogVisible: any = ref(false)
const waveFormAnalysisRef: any = ref(null)
// 波形
const dialogVisible = ref(false)
const waveFormAnalysisRef = ref()
const isWaveCharts = ref(false)
const loading = ref(false)
const wp = ref({})
const boxoList: any = ref({})
const title = ref('暂态事件')
const tableHeaderRef = ref()
const filterVisible = ref(false)
const filterTarget = ref('')
const multiConditionRef = ref<InstanceType<typeof MultiCondition>>()
const dictData = useDictData()
const ReasonList: any = dictData.getBasicData('Event_Reason')
const EventTypeList: any = dictData.getBasicData('Event_Type')
const options = ref()
const heightRef = ref(mainHeight(168, 2.2).height)
const selectChange = (flag: boolean, h: any) => {
const tableParams = ref<any>({})
const selectChange = (_flag: boolean, h: number) => {
heightRef.value = mainHeight(h, 2.2).height
}
const eventList = [
{ label: '电压暂降', value: '1' },
{ label: '电压中断', value: '2' },
{ label: '电压暂升', value: '3' }
]
const getSimpleLineList = async () => {
const res = await getSimpleLine()
options.value = res.data
}
const tableStore: any = new TableStore({
url: '/cs-harmonic-boot/event/pageEvent',
url: '/cs-device-boot/csGroup/deviceDataByType',
method: 'POST',
showPage: true,
exportName: '主要监测点列表',
exportName: '暂态事件',
column: [
{
field: 'index',
title: '序号',
width: '80',
width: 80,
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ field: 'startTime', title: '发生时刻', minWidth: 180, sortable: true },
{
title: '暂态时间',
field: 'startTime',
minWidth: '180'
},
{
title: '测点名称',
field: 'lineName',
minWidth: '150'
},
{
title: '暂态类型',
field: 'tag',
minWidth: '100'
},
{
title: '特征幅值(%)',
field: 'amplitude',
minWidth: '100'
},
{
title: '暂降深度(%)',
field: 'depth',
minWidth: '100',
field: 'featureAmplitude',
title: '暂降幅值(%)',
minWidth: 120,
sortable: true,
formatter: (row: any) => {
// 当暂态类型不是电压暂升时,计算暂降深度 = 100 - 特征幅值
if (row.row.tag !== '电压暂升') {
const amplitude = parseFloat(row.row.amplitude)
if (!isNaN(amplitude)) {
return 100 - amplitude
}
return '-'
} else {
// 电压暂升时不显示暂降深度
return '/'
row.cellValue = row.cellValue != null ? Number(row.cellValue).toFixed(2) : '/'
if (String(row.cellValue).split('.')[1] == '00') {
row.cellValue = String(row.cellValue).split('.')[0]
}
return row.cellValue
}
},
{
title: '持续时间(S)',
field: 'persistTime',
minWidth: '100'
title: '持续时间(s)',
minWidth: 110,
formatter: (row: any) => row.cellValue ? (row.cellValue - 0).toFixed(2) : '/',
sortable: true
},
{
field: 'phaseType',
title: '相别',
minWidth: 80,
formatter: (row: any) => row.cellValue || '/'
},
{
title: '严重度',
field: 'severity',
minWidth: '80'
minWidth: 80,
align: 'center',
sortable: true,
formatter: (row: any) => row.cellValue ? row.cellValue : '/'
},
{ field: 'showName', title: '触发类型', minWidth: 100 },
{
title: '暂降原因',
field: 'advanceReason',
minWidth: 100,
align: 'center',
formatter: (row: any) => ReasonList.find((item: any) => item.id == row.cellValue)?.name || '未知'
},
{
title: '波形',
width: '90',
title: '暂降类型',
field: 'advanceType',
minWidth: 100,
align: 'center',
formatter: (row: any) => EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '未知'
},
{ title: '电压等级(kV)', field: 'lineVoltage', minWidth: 120, align: 'center', sortable: true },
{
title: '发生位置',
field: 'sagSource',
minWidth: 120,
align: 'center',
formatter: (row: any) => row.cellValue == 1 ? '上游' : row.cellValue == 2 ? '下游' : '未知'
},
{
title: '操作',
fixed: 'right',
width: 150,
render: 'buttons',
buttons: [
{
name: 'edit',
text: '波形分析',
type: 'primary',
text: '暂无波形',
type: 'info',
icon: 'el-icon-DataLine',
render: 'basicButton',
loading: 'loading1',
disabled: row => {
return !row.wavePath
},
click: async row => {
return row.wavePath
}
},
{
name: 'edit',
title: '波形分析',
type: 'primary',
icon: 'el-icon-Check',
render: 'basicButton',
loading: 'loading1',
disabled: (row: any) => !row.wavePath,
click: async (row: any) => {
row.loading1 = true
// 在打开弹窗时立即设置高度
nextTick(() => {
if (waveFormAnalysisRef.value) {
// waveFormAnalysisRef.value.setHeight(false, 360)
waveFormAnalysisRef.value.setHeight(999, 130, 1.6666666)
}
})
await analyseWave(row.id)
.then(res => {
loading.value = true
isWaveCharts.value = true
dialogVisible.value = false
row.loading1 = false
if (res != undefined) {
boxoList.value = row
// boxoList.value = {
// ...row,
// duration: row.persistTime // 将 persistTime 值赋给 duration
// }
// boxoList.value.featureAmplitude =
// row.evtParamVVaDepth != '-' ? row.evtParamVVaDepth - 0 : null
boxoList.value.featureAmplitude = (row.amplitude - 0) / 100
boxoList.value.systemType = 'YPT'
loading.value = true
isWaveCharts.value = true
dialogVisible.value = false
boxoList.value = {
...row,
systemType: 'YPT',
engineeringName: tableParams.value.projectName,
featureAmplitude:
row.featureAmplitude != null ? Number(row.featureAmplitude / 100) : '-',
persistTime: row.persistTime ? row.persistTime.toFixed(2) : '-',
}
wp.value = res.data
}
loading.value = false
@@ -202,34 +183,108 @@ const tableStore: any = new TableStore({
})
nextTick(() => {
waveFormAnalysisRef.value &&
waveFormAnalysisRef.value.getWpData(wp.value, boxoList.value, true)
if (waveFormAnalysisRef.value) {
waveFormAnalysisRef.value.getWpData(wp.value, boxoList.value)
waveFormAnalysisRef.value.setHeight(999, 130, 1.6666666)
}
})
}
},
{
name: 'edit',
text: '暂无波形',
type: 'info',
icon: 'el-icon-DataLine',
title: '波形下载',
type: 'primary',
loading: 'loading2',
icon: 'el-icon-Check',
render: 'basicButton',
disabled: row => {
return row.wavePath
disabled: (row: any) => !row.wavePath,
click: (row: any) => {
row.loading2 = true
ElMessage.info('下载中......')
getFileZip({ eventId: row.id }).then(res => {
const blob = new Blob([res as unknown as BlobPart], { type: 'application/zip' })
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = row.wavePath.split('/')[2] || '波形文件'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
ElMessage.success('波形下载成功')
row.loading2 = false
}).catch(() => {
row.loading2 = false
})
}
}
]
}
],
beforeSearchFun: () => {},
loadCallback: () => {}
beforeSearchFun: () => {
tableStore.table.params.devId = tableParams.value.devId
tableStore.table.params.lineId = tableParams.value.lineId
tableStore.table.params.list = tableParams.value.list
tableStore.table.params.type = 3
},
loadCallback: () => { }
})
tableStore.table.params.eventType = ''
tableStore.table.params.type = 3
Object.assign(tableStore.table.params, {
featureAmplitudeMin: undefined,
featureAmplitudeMax: undefined,
evtParamTmMin: undefined,
evtParamTmMax: undefined,
severityMin: undefined,
severityMax: undefined,
fileFlag: ''
})
provide('tableStore', tableStore)
const open = async (row: any, searchBeginTime: any, searchEndTime: any) => {
tableStore.table.params.eventType = ''
const resetFilterParams = () => {
Object.assign(tableStore.table.params, {
featureAmplitudeMin: undefined,
featureAmplitudeMax: undefined,
evtParamTmMin: undefined,
evtParamTmMax: undefined,
severityMin: undefined,
severityMax: undefined,
fileFlag: ''
})
}
const openFilterDialog = () => {
filterVisible.value = true
}
const onFilterConfirm = () => {
tableStore.onTableAction('search', {})
}
const onResetForm = () => {
filterVisible.value = false
resetFilterParams()
multiConditionRef.value?.reset()
tableStore.index()
}
const open = (row: any, searchBeginTime: any, searchEndTime: any, type?: string) => {
filterTarget.value = type || ''
title.value = row.name + '_暂态事件'
dialogVisible.value = true
getSimpleLineList()
tableStore.table.params.lineId = row.id
filterVisible.value = false
resetFilterParams()
multiConditionRef.value?.reset()
const lineId = row.id || row.lineId
tableParams.value = {
lineId,
devId: row.devId,
engineeringName: row.engineeringName,
list: row.devId ? [{ lineId, devId: row.devId }] : undefined,
}
tableStore.table.params.pageNum = 1
nextTick(() => {
tableHeaderRef.value.setTimeInterval([searchBeginTime, searchEndTime])
tableStore.table.params.searchBeginTime = searchBeginTime
@@ -245,4 +300,5 @@ const handleHideCharts = () => {
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@@ -1,27 +1,14 @@
<template>
<div>
<!--暂态事件统计 -->
<TableHeader
ref="TableHeaderRef"
:showReset="false"
@selectChange="selectChange"
datePicker
v-if="fullscreen" :timeKeyList="prop.timeKey"
></TableHeader>
<my-echart
class="tall"
:options="echartList"
:style="{
width: prop.width,
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
}"
/>
<Table
ref="tableRef"
@cell-click="cellClickEvent"
:height="`calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`"
isGroup
></Table>
<TableHeader ref="TableHeaderRef" :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen"
:timeKeyList="prop.timeKey"></TableHeader>
<my-echart class="tall" :options="echartList" :style="{
width: prop.width,
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
}" />
<Table ref="tableRef" @cell-click="cellClickEvent"
:height="`calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`" isGroup></Table>
<TransientStatisticsDetail ref="transientStatisticsDetailRef"></TransientStatisticsDetail>
</div>
</template>
@@ -41,7 +28,7 @@ const prop = defineProps({
h: { type: [String, Number] },
width: { type: [String, Number] },
height: { type: [String, Number] },
timeKey: { type: Array as () => string[] },
timeKey: { type: Array as () => string[] },
timeValue: { type: Object },
interval: { type: Number }
})
@@ -129,7 +116,11 @@ const eventEcharts = () => {
title: [
{
text: '暂态事件统计',
left: 'center'
left: 'center',
textStyle: {
color: '#000',
fontSize: '15'
},
},
{
text: rawData.eventOff + rawData.eventDown + rawData.eventUp + '次',
@@ -173,15 +164,30 @@ const tableStore: any = new TableStore({
}
},
{
title: '名称',
title: '监测点名称',
field: 'name',
minWidth: '90'
minWidth: 120
},
{
title: '设备名称', field: 'devName', minWidth: 130, align: 'center', formatter: (row: any) => {
return row.cellValue || '/'
}
},
{
title: '项目名称', field: 'projectName', minWidth: 130, align: 'center', formatter: (row: any) => {
return row.cellValue || '/'
}
},
{
title: '工程名称', field: 'engineeringName', minWidth: 130, align: 'center', formatter: (row: any) => {
return row.cellValue || '/'
}
},
{
title: '电压中断(次)',
field: 'eventOff',
minWidth: '70',
minWidth: '90',
sortable: true,
render: 'customTemplate',
customTemplate: (row: any) => {
@@ -191,7 +197,7 @@ const tableStore: any = new TableStore({
{
title: '电压暂降(次)',
field: 'eventDown',
minWidth: '80',
minWidth: '90',
sortable: true,
render: 'customTemplate',
customTemplate: (row: any) => {
@@ -201,7 +207,7 @@ const tableStore: any = new TableStore({
{
title: '电压暂升(次)',
field: 'eventUp',
minWidth: '80',
minWidth: '90',
sortable: true,
render: 'customTemplate',
customTemplate: (row: any) => {
@@ -224,11 +230,13 @@ provide('tableStore', tableStore)
// 点击行
const cellClickEvent = ({ row, column }: any) => {
if (column.field != 'name') {
if (column.field != 'name' && column.field != 'devName' && column.field != 'projectName' && column.field != 'engineeringName') {
transientStatisticsDetailRef.value.open(
row,
tableStore.table.params.searchBeginTime || prop.timeValue?.[0],
tableStore.table.params.searchEndTime || prop.timeValue?.[1]
tableStore.table.params.searchEndTime || prop.timeValue?.[1],
column.field=='eventOff'?'中断':column.field=='eventDown'?'暂降':column.field=='eventUp'?'暂升':''
)
}
}

View File

@@ -1,26 +1,22 @@
<template>
<div>
<div class="device-control">
<!--趋势对比 -->
<TableHeader
datePicker
ref="TableHeaderRef"
:timeKeyList="prop.timeKey"
:showReset="false"
@selectChange="selectChange"
v-if="fullscreen"
>
<template v-slot:select>
<el-form-item label="监测对象">
<el-select
filterable
v-model="tableStore.table.params.sensitiveUserId"
placeholder="请选择监测对象"
clearable
>
<el-option v-for="item in idList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<!-- <el-form-item label="监测点名称">
<div v-show="fullscreen">
<!-- <PointTree :height="flag ? 106 : 50" @node-click="nodeClick" @pointTypeChange="pointTypeChange"></PointTree> -->
<APFTree :height="flag ? 126 : 70" @node-click="handleNodeClick" @init="handleNodeClick"></APFTree>
</div>
<div>
<TableHeader datePicker ref="TableHeaderRef" :timeKeyList="prop.timeKey" :showReset="false"
@selectChange="selectChange" v-if="fullscreen">
<template v-slot:select>
<!-- <el-form-item label="监测对象">
<el-select filterable v-model="tableStore.table.params.sensitiveUserId" placeholder="请选择监测对象"
clearable>
<el-option v-for="item in idList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item> -->
<!-- <el-form-item label="监测点名称">
<el-select v-model="tableStore.table.params.lineId" placeholder="请选择监测点名称" clearable>
<el-option
v-for="item in lineIdList"
@@ -30,57 +26,45 @@
/>
</el-select>
</el-form-item> -->
<el-form-item label="电能质量指标">
<el-select v-model="tableStore.table.params.indicator" placeholder="请选择电能质量指标" clearable>
<el-option v-for="item in indicatorList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item>
<el-radio-group v-model="tableStore.table.params.dataLevel">
<el-radio-button label="一次值" value="Primary" />
<el-radio-button label="二次值" value="Secondary" />
</el-radio-group>
</el-form-item>
<el-form-item label="统计类型">
<el-select
style="min-width: 120px !important"
placeholder="请选择"
v-model="tableStore.table.params.valueType"
>
<el-option value="max" label="最大值"></el-option>
<el-option value="min" label="最小值"></el-option>
<el-option value="avg" label="平均值"></el-option>
<el-option value="cp95" label="cp95"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<div v-if="shouldShowHarmonicCount()" style="display: flex; color: var(--el-text-color-regular)">
<span style="width: 160px">{{ getHarmonicTypeName() }}谐波次数</span>
<el-select
v-model="tableStore.table.params.harmonicCount"
placeholder="请选择谐波次数"
style="min-width: 80px !important"
>
<el-option
v-for="num in harmonicCountOptions"
:key="num"
:label="num"
:value="num"
></el-option>
<el-form-item label="电能质量指标">
<el-select v-model="tableStore.table.params.indicator" placeholder="请选择电能质量指标" clearable>
<el-option v-for="item in indicatorList" :key="item.id" :label="item.name"
:value="item.id" />
</el-select>
</div>
</el-form-item>
</template>
</TableHeader>
<my-echart
v-loading="tableStore.table.loading"
class="tall"
:options="echartList"
:style="{
width: prop.width,
</el-form-item>
<el-form-item>
<el-radio-group v-model="tableStore.table.params.dataLevel" @change="tableStore.index()">
<el-radio-button label="一次值" value="Primary" />
<el-radio-button label="二次值" value="Secondary" />
</el-radio-group>
</el-form-item>
<el-form-item label="统计类型">
<el-select style="min-width: 120px !important" placeholder="请选择"
v-model="tableStore.table.params.valueType">
<el-option value="max" label="最大值"></el-option>
<el-option value="min" label="最小值"></el-option>
<el-option value="avg" label="平均值"></el-option>
<el-option value="cp95" label="cp95"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<div v-if="shouldShowHarmonicCount()"
style="display: flex; color: var(--el-text-color-regular)">
<span style="width: 160px">{{ getHarmonicTypeName() }}谐波次数</span>
<el-select v-model="tableStore.table.params.harmonicCount" placeholder="请选择谐波次数"
style="min-width: 80px !important">
<el-option v-for="num in harmonicCountOptions" :key="num" :label="num"
:value="num"></el-option>
</el-select>
</div>
</el-form-item>
</template>
</TableHeader>
<my-echart v-loading="tableStore.table.loading" class="tall" :options="echartList" :style="{
width: `calc(${prop.width} - ${fullscreen ? 290 : 0}px)`,
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
}"
/>
}" />
</div>
<!-- <el-empty description="暂无数据" /> -->
</div>
</template>
@@ -94,7 +78,7 @@ import { queryByCode, queryCsDictTree } from '@/api/system-boot/dictTree'
import { getListByIds } from '@/api/harmonic-boot/cockpit/cockpit'
import { getTime } from '@/utils/formatTime'
import { yMethod, exportCSV } from '@/utils/echartMethod'
import { max } from 'lodash'
import APFTree from '@/components/tree/govern/APFTree.vue'
const prop = defineProps({
w: { type: [String, Number] },
h: { type: [String, Number] },
@@ -102,7 +86,8 @@ const prop = defineProps({
height: { type: [String, Number] },
timeKey: { type: Array as () => string[] },
timeValue: { type: Object },
interval: { type: Number }
interval: { type: Number },
flag: { type: Boolean }
})
const TableHeaderRef = ref()
@@ -136,12 +121,26 @@ const initListByIds = () => {
getListByIds({}).then((res: any) => {
if (res.data?.length > 0) {
idList.value = res.data
initCode()
} else {
tableStore.index()
}
})
}
const handleNodeClick = async (data: any) => {
if (data?.level == 3 || data?.level == 2) {
tableStore.table.params.sensitiveUserId = data.id
await tableStore.index()
} else {
tableStore.table.loading = false
}
}
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
@@ -158,7 +157,7 @@ const initCode = () => {
indicatorList.value = item.data
tableStore.table.params.indicator = indicatorList.value[0].id
nextTick(() => {
tableStore.index()
// tableStore.index()
})
})
})
@@ -192,7 +191,7 @@ const setEchart = () => {
if (!afterGroupedByPhase[phase]) {
afterGroupedByPhase[phase] = []
}
afterGroupedByPhase[phase].push([item.time, item.statisticalData, item.unit, 'dotted'])
afterGroupedByPhase[phase].push([item.time, item.statisticalData, item.unit, 'dashed'])
})
// 构建系列数据
@@ -224,7 +223,6 @@ const setEchart = () => {
},
lineStyle: {
type: 'solid', // 实线
width: 2 // 线条宽度
},
yAxisIndex: 0
})
@@ -249,7 +247,6 @@ const setEchart = () => {
},
lineStyle: {
type: 'dashed', // 虚线
width: 2 // 线条宽度
},
yAxisIndex: 0
})
@@ -285,9 +282,9 @@ const setEchart = () => {
return {
name: item.name,
icon: isBefore
? 'rect'
: 'path://M0,2 L8,2 L8,6 L0,6 Z M12,2 L20,2 L20,6 L12,6 Z M24,2 L32,2 L32,6 L24,6 Z M36,2 L44,2 L44,6 L36,6 Z', // 矩形组成的粗虚线
// icon: isBefore
// ? 'rect'
// : 'path://M0,2 L8,2 L8,6 L0,6 Z M12,2 L20,2 L20,6 L12,6 Z M24,2 L32,2 L32,6 L24,6 Z M36,2 L44,2 L44,6 L36,6 Z', // 矩形组成的粗虚线
itemStyle: {
color: color // 明确指定图例图标的颜色
},
@@ -297,7 +294,7 @@ const setEchart = () => {
}
}
})
let [min, max] = yMethod(
let [min, max] = yMethod(
[...chartsListBefore.value.map((item: any) => item.statisticalData),
...chartsListAfter.value.map((item: any) => item.statisticalData)]
)
@@ -326,21 +323,28 @@ const setEchart = () => {
let str = `${xname}<br>`
params.forEach((el: any, index: any) => {
let marker = ''
if (el.value[3] == 'dashed') {
for (let i = 0; i < 3; i++) {
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
}
} else {
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`//`<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
}
str += `${marker}${el.seriesName.split('(')[0]}${
el.value[1] != null ? el.value[1] + ' ' + (el.value[2] == null ? '' : el.value[2]) : '-'
}<br>`
str += `${marker}${el.seriesName.split('(')[0]}${el.value[1] != null ? el.value[1] + ' ' + (el.value[2] == null ? '' : el.value[2]) : '-'
}<br>`
})
return str
}
},
legend: {
data: legendData,
icon: 'rect',
// icon: 'rect',
itemWidth: 18,
itemHeight: 3,
type: 'scroll',
itemStyle: {
borderWidth: 0
},
@@ -379,9 +383,9 @@ const tableStore: any = new TableStore({
column: [],
beforeSearchFun: () => {
setTime()
if (!tableStore.table.params.sensitiveUserId && idList.value?.length > 0) {
tableStore.table.params.sensitiveUserId = idList.value[0].id
}
// if (!tableStore.table.params.sensitiveUserId && idList.value?.length > 0) {
// tableStore.table.params.sensitiveUserId = idList.value[0].id
// }
let lists: any = []
// 处理电能质量指标
const selectedIndicator = indicatorList.value?.find(
@@ -420,7 +424,8 @@ tableStore.table.params.valueType = 'avg'
provide('tableStore', tableStore)
onMounted(() => {
initListByIds()
initCode()
// initListByIds()
})
const setTime = () => {
@@ -504,4 +509,11 @@ watch(
// :deep(.el-select) {
// min-width: 80px;
// }
.device-control {
display: flex;
}
:deep(.cn-tree) {
padding: 0 10px 0 0 !important;
}
</style>

View File

@@ -45,7 +45,7 @@ const initChart = () => {
color: '#000',
textStyle: {
color: '#000',
fontSize: '18'
fontSize: '15'
},
// },
...(props.options?.title || null)
@@ -108,14 +108,14 @@ const initChart = () => {
bottom: '20px',
end: 100,
filterMode: 'none'
filterMode: 'filter'
},
{
start: 0,
height: 13,
bottom: '20px',
end: 100,
filterMode: 'none'
filterMode: 'filter'
}
// {
// show: true,

View File

@@ -684,7 +684,7 @@ const initWave = (
align: 'left'
},
textStyle: {
fontSize: '16px',
fontSize: '14px',
color: props.DColor ? '#000' : echartsColor.WordColor
}
},
@@ -809,13 +809,15 @@ const initWave = (
height: 13,
start: 0,
bottom: '20px',
end: 100
end: 100,
filterMode: 'filter'
},
{
start: 0,
height: 13,
bottom: '20px',
end: 100
end: 100,
filterMode: 'filter'
}
],
series: [
@@ -1027,7 +1029,7 @@ const drawPics = (
left: 'center',
text: '', //titlename || title,
textStyle: {
fontSize: '16px',
fontSize: '15px',
color: props.DColor ? '#000' : echartsColor.WordColor
}
},

View File

@@ -448,7 +448,7 @@ const initWave = (
left: 'center',
text: titleText,
textStyle: {
fontSize: '16px',
fontSize: '14px',
color: props.DColor ? '#000' : echartsColor.WordColor
}
},
@@ -565,13 +565,15 @@ const initWave = (
height: 13,
start: 0,
bottom: '20px',
end: 100
end: 100,
filterMode: 'filter'
},
{
start: 0,
height: 13,
bottom: '20px',
end: 100
end: 100,
filterMode: 'filter'
}
],
series: [

View File

@@ -31,7 +31,7 @@
</el-button>
<el-button
@click="onComSearch"
v-if="showSearch"
v-if="showSearch &&showQuery"
:loading="tableStore.table.loading"
type="primary"
:icon="Search"
@@ -102,6 +102,7 @@ interface Props {
showSearch?: boolean
nextFlag?: boolean //控制时间是否可以往后推
theCurrentTime?: boolean //控制时间前3天展示上个月时间
showQuery?: boolean //是否显示查詢
showReset?: boolean //是否显示重置
showExport?: boolean //导出控制
timeCacheFlag?: boolean //是否取缓存时间
@@ -115,6 +116,7 @@ const props = withDefaults(defineProps<Props>(), {
nextFlag: false,
theCurrentTime: true,
showReset: true,
showQuery: true,
showExport: false,
timeCacheFlag: true,
timeKeyList: () => ['1', '2', '3', '4', '5'] // 修改为箭头函数返回空数组

View File

@@ -0,0 +1,168 @@
<template>
<div class="apf-tree">
<div class="cn-tree" :style="{ height: `calc(100vh - 125px - ${height}px)` }">
<div style="display: flex; align-items: center" class="mb10">
<el-input maxlength="32" show-word-limit v-model.trim="filterText" placeholder="请输入内容" clearable>
<template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" />
</template>
</el-input>
</div>
<el-tree style="flex: 1; overflow: auto" :props="defaultProps" highlight-current
:filter-node-method="filterNode" node-key="id" default-expand-all :data="tree" ref="treRef"
@node-click="clickNode" :expand-on-click-node="false">
<template #default="{ node, data: nodeData }">
<span class="custom-tree-node">
<Icon :name="nodeData.icon" style="font-size: 16px" :style="{ color: nodeData.color }"
v-if="nodeData.icon" />
<span style="margin-left: 5px">{{ node.label }}</span>
</span>
</template>
</el-tree>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, nextTick } from 'vue'
import { ElTree } from 'element-plus'
import { getUserDevTree } from '@/api/cs-device-boot/csLedger'
import { useConfig } from '@/stores/config'
import { querySysExcel } from '@/api/harmonic-boot/luckyexcel'
import { useDictData } from '@/stores/dictData'
import { createLineTreeDecorators } from './lineTreeUtils'
import { bootstrapWithTemplate } from './treeCommonUtils'
import { createTreeFilterNode } from './treeFilterUtils'
interface Props {
template?: boolean
type?: string
height?: number
}
const props = withDefaults(defineProps<Props>(), { template: false, type: 'apf', height: 0 })
defineOptions({ name: 'govern/APFTree', inheritAttrs: false })
const emit = defineEmits(['init', 'node-click', 'deviceTypeChange', 'Policy'])
const config = useConfig()
const dictData = useDictData()
const tree = ref<any[]>([])
const treRef = ref<InstanceType<typeof ElTree>>()
const filterText = ref('')
const defaultProps = { children: 'children', label: 'name', value: 'id' }
const decorators = createLineTreeDecorators(() => config.getColorVal('elementUiPrimary'))
const filterNode = createTreeFilterNode()
watch(filterText, val => treRef.value?.filter(val))
/** 将 { 用户名: 设备[] | null } 转为两级树 */
function transformUserDevTree(data: Record<string, any[] | null>) {
const nodes: any[] = []
const devices: any[] = []
const { primary, statusColor, applyMeta } = decorators
if (!data || typeof data !== 'object') {
return { nodes, devices }
}
Object.entries(data).forEach(([userName, deviceList]) => {
const hasDevices = Array.isArray(deviceList) && deviceList.length > 0
const userId = hasDevices ? deviceList[0]?.monitorUser || userName : `apf-user-${userName}`
const children = hasDevices
? deviceList.map((device: any) => {
const node = {
...device,
level: 2,
pid: userId,
pname: userName
}
applyMeta(node, {
icon: 'el-icon-Platform',
color: statusColor(device.runStatus)
})
devices.push(node)
return node
})
: undefined
const userNode: any = {
id: userId,
name: userName,
level: 1,
...(children ? { children } : {})
}
applyMeta(userNode, { icon: 'el-icon-User', color: primary(), disabled: true })
nodes.push(userNode)
})
return { nodes, devices }
}
async function selectFirstDevice(devices: any[]) {
const node = devices[0]
if (!node) {
emit('init', { ...node })
return
}
await nextTick()
treRef.value?.setCurrentKey(node.id)
emit('init', { level: 2, ...node })
}
async function loadTree() {
tree.value = []
const res = await getUserDevTree({ type: props.type })
const { nodes, devices } = transformUserDevTree(res.data)
tree.value = nodes
await selectFirstDevice(devices)
}
const clickNode = (node: any) => {
if (node?.children?.length) return
emit('node-click', node)
}
bootstrapWithTemplate(
props.template,
loadTree,
() => querySysExcel({ id: dictData.state.area[0]?.id }),
data => emit('Policy', data)
)
watch(() => props.type, () => {
loadTree()
})
</script>
<style lang="scss" scoped>
.apf-tree {
width: 280px;
flex-shrink: 0;
}
.cn-tree {
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 10px;
overflow-y: auto;
:deep(.el-tree) {
border: 1px solid var(--el-border-color);
}
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
background-color: var(--el-color-primary-light-7);
}
.custom-tree-node {
display: flex;
}
}
</style>