9 Commits

Author SHA1 Message Date
guanj
1ec3bd11a0 修改半月报导出功能 2025-11-04 09:48:23 +08:00
guanj
d553754847 修改组态展示地址 2025-11-03 10:39:06 +08:00
guanj
dc44e16d4d 历史趋势添加缺失数据功能 2025-10-31 13:41:48 +08:00
sjl
13c0a28c95 在线设备录入左侧树微调 2025-10-31 11:23:28 +08:00
sjl
443d5ab2bd 节点展开 2025-10-31 10:53:17 +08:00
sjl
288f4254b0 治理设备状态 2025-10-31 10:23:22 +08:00
sjl
130db82e41 事件补召,前置调整 2025-10-30 16:35:49 +08:00
stt
55a30a323d 稳态、暂态电能质量,稳态质量效果各个弹框 2025-10-28 11:23:17 +08:00
stt
608be23687 暂态电能质量分析页面添加各个列表详情弹框 2025-10-27 08:50:03 +08:00
31 changed files with 3958 additions and 2668 deletions

View File

@@ -47,11 +47,13 @@ export function restartProcess(data: any) {
} }
//更新进程号 //更新进程号
export function updateProcess(data: any) { export function updateProcess(data:any) {
return createAxios({ return createAxios({
url: '/cs-device-boot/node/updateDevProcessNo', url: '/cs-device-boot/node/updateDevNode',
method: 'post', method: 'post',
params: data data: data
}) })
} }

View File

@@ -8,10 +8,16 @@
<el-descriptions-item align="center" label="不可容忍">{{ data.bkrr }}</el-descriptions-item> <el-descriptions-item align="center" label="不可容忍">{{ data.bkrr }}</el-descriptions-item>
</el-descriptions> </el-descriptions>
<my-echart <my-echart
ref="chartRef"
class="tall" class="tall"
:options="echartList" :options="echartList"
:style="{ width: prop.width, height: `calc(${prop.height} - 80px)` }" :style="{ width: prop.width, height: `calc(${prop.height} - 80px)` }"
@chart-click="handleChartClick"
/> />
<el-dialog v-model="isWaveCharts" draggable title="瞬时/RMS波形" append-to-body width="70%">
<waveFormAnalysis v-loading="loading" v-if="isWaveCharts" ref="waveFormAnalysisRef"
@handleHideCharts="isWaveCharts = false" :wp="wp" />
</el-dialog>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -22,6 +28,7 @@ import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime' import { getTimeOfTheMonth } from '@/utils/formatTime'
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue';
const prop = defineProps({ const prop = defineProps({
width: { type: String }, width: { type: String },
height: { type: String }, height: { type: String },
@@ -30,6 +37,15 @@ const prop = defineProps({
}) })
const echartList = ref({}) const echartList = ref({})
const chartRef = ref()
// 波形
const isWaveCharts = ref(false)
const loading = ref(false)
const wp = ref({})
const OverLimitDetailsRef = ref() const OverLimitDetailsRef = ref()
const data = reactive({ const data = reactive({
name: '事件个数', name: '事件个数',
@@ -64,7 +80,11 @@ const tableStore: any = new TableStore({
text: `F47曲线` text: `F47曲线`
}, },
legend: { legend: {
data: ['上限', '下限', '可容忍事件', '不可容忍事件'] // data: ['上限', '下限', '可容忍事件', '不可容忍事件'],
data: ['可容忍事件', '不可容忍事件'],
itemWidth: 10,
itemHeight: 10,
itemGap: 15
}, },
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
@@ -141,13 +161,40 @@ const tableStore: any = new TableStore({
name: '可容忍事件', name: '可容忍事件',
type: 'scatter', type: 'scatter',
symbol: 'circle', symbol: 'circle',
data: gongData.pointF symbolSize: 8,
// data: gongData.pointF,
data: [
[0.2, 10, '2023-01-01 10:00:00'],
[0.4, 50, '2023-01-01 11:00:00']
],
legendSymbol: 'circle',
emphasis: {
focus: 'series',
itemStyle: {
borderColor: '#fff',
borderWidth: 2,
shadowBlur: 10,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
tooltip: {
show: true,
trigger: 'item',
formatter: function (params: any) {
return `<strong>可容忍事件</strong><br/>
持续时间: ${params.value[0]}s<br/>
特征幅值: ${params.value[1].toFixed(2)}%<br/>
发生时间: ${params.value[2] || 'N/A'}`
}
}
}, },
{ {
name: '不可容忍事件', name: '不可容忍事件',
type: 'scatter', type: 'scatter',
symbol: 'circle', symbol: 'rect',
data: gongData.pointFun symbolSize: 8,
data: gongData.pointFun,
legendSymbol: 'rect'
} }
] ]
} }
@@ -323,6 +370,32 @@ onMounted(() => {
tableStore.index() tableStore.index()
}, 100) }, 100)
}) })
// 点击事件处理函数
const handleChartClick = (params: any) => {
if (params.seriesName === '可容忍事件') {
// 处理可容忍事件点击
ElMessage.info(`点击了可容忍事件: 持续时间${params.value[0]}s, 幅值${params.value[1].toFixed(2)}%`)
handleTolerableEventClick(params)
} else if (params.seriesName === '不可容忍事件') {
// 处理不可容忍事件点击
ElMessage.info(`点击了不可容忍事件: 持续时间${params.value[0]}s, 幅值${params.value[1].toFixed(2)}%`)
handleIntolerableEventClick(params)
}
}
// 可容忍事件点击处理函数
const handleTolerableEventClick = (params: any) => {
console.log('可容忍事件详情:', params)
isWaveCharts.value = true
}
// 不可容忍事件点击处理函数
const handleIntolerableEventClick = (params: any) => {
console.log('不可容忍事件详情:', params)
}
watch( watch(
() => prop.timeKey, () => prop.timeKey,
val => { val => {

View File

@@ -0,0 +1,151 @@
<template>
<!-- 指标日趋势图 -->
<el-dialog draggable title="指标日趋势图" v-model="dialogVisible" append-to-body width="70%">
<my-echart
class="tall"
:options="echartList"
style="width: 98%; height: 320px"
/>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import TableStore from '@/utils/tableStore'
import TableHeader from '@/components/table/header/index.vue'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useConfig } from '@/stores/config'
const prop = defineProps({
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const dialogVisible: any = ref(false)
const config = useConfig()
const echartList = ref({
title: {
text: '35kV进线谐波含有率',
},
xAxis: {
type: 'time',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
},
yAxis: [{}, {}],
grid: {
left: '10px',
right: '20px'
},
options: {
series: [
{
// name: '暂降次数',
type: 'bar',
name: '有功功率',
data: [
['2025-10-16 07:00:00', 10],
['2025-10-16 07:15:00', 10],
['2025-10-16 07:30:00', 10],
['2025-10-16 07:45:00', 10],
['2025-10-16 08:00:00', 30],
['2025-10-16 08:15:00', 50],
['2025-10-16 08:30:00', 60],
['2025-10-16 08:45:00', 70],
['2025-10-16 09:00:00', 100],
['2025-10-16 09:15:00', 120],
['2025-10-16 09:30:00', 130],
['2025-10-16 09:45:00', 140],
['2025-10-16 10:00:00', 160],
['2025-10-16 10:15:00', 160],
['2025-10-16 10:30:00', 130],
['2025-10-16 10:45:00', 120],
['2025-10-16 11:00:00', 140],
['2025-10-16 11:15:00', 80],
['2025-10-16 11:30:00', 70],
['2025-10-16 11:45:00', 90],
['2025-10-16 12:00:00', 60],
['2025-10-16 12:15:00', 60],
['2025-10-16 12:30:00', 60],
['2025-10-16 12:45:00', 60]
],
itemStyle: {
normal: {
//这里是颜色
color: function (params: any) {
if (params.value[1] == 0 || params.value[1] == 3.14159) {
return '#ccc'
} else {
return config.layout.elementUiPrimary[0]
}
}
}
},
yAxisIndex: 0
},
{
name: '谐波总畸变率',
type: 'line',
showSymbol: false,
smooth: true,
data: [
['2025-10-16 07:00:00', 0],
['2025-10-16 07:15:00', 0],
['2025-10-16 07:30:00', 0],
['2025-10-16 07:45:00', 0],
['2025-10-16 08:00:00', 0],
['2025-10-16 08:15:00', 0.1],
['2025-10-16 08:30:00', 0.1],
['2025-10-16 08:45:00', 0.1],
['2025-10-16 09:00:00', 1],
['2025-10-16 09:15:00', 1],
['2025-10-16 09:30:00', 1],
['2025-10-16 09:45:00', 1],
['2025-10-16 10:00:00', 0.8],
['2025-10-16 10:15:00', 0.8],
['2025-10-16 10:30:00', 0.8],
['2025-10-16 10:45:00', 0.8],
['2025-10-16 11:00:00', 0.8],
['2025-10-16 11:15:00', 0.1],
['2025-10-16 11:30:00', 0.1],
['2025-10-16 11:45:00', 0.1],
['2025-10-16 12:00:00', 0],
['2025-10-16 12:15:00', 0],
['2025-10-16 12:30:00', 0],
['2025-10-16 12:45:00', 0]
],
yAxisIndex: 1
}
]
}
})
onMounted(() => {
})
const open = async (row: any) => {
dialogVisible.value = true
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
:deep(.el-select) {
min-width: 80px;
}
</style>

View File

@@ -7,8 +7,8 @@
:style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }" :style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }"
/> />
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} / 2 )`" isGroup></Table> <Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} / 2 )`" isGroup></Table>
<!-- 指标越限详情 --> <!-- 指标日趋势图 -->
<OverLimitDetails ref="OverLimitDetailsRef" /> <DailyTrendChart ref="dailyTrendChartRef" />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -19,7 +19,7 @@ import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime' import { getTimeOfTheMonth } from '@/utils/formatTime'
import OverLimitDetails from '@/components/cockpit/listOfMainMonitoringPoints/components/overLimitDetails.vue' import DailyTrendChart from '@/components/cockpit/exceedanceLevel/components/dailyTrendChart.vue'
const prop = defineProps({ const prop = defineProps({
width: { type: String }, width: { type: String },
height: { type: String }, height: { type: String },
@@ -66,7 +66,7 @@ const echartList = ref({
] ]
} }
}) })
const OverLimitDetailsRef = ref() const dailyTrendChartRef = ref()
const tableStore: any = new TableStore({ const tableStore: any = new TableStore({
url: '/user-boot/dept/deptTree', url: '/user-boot/dept/deptTree',
method: 'POST', method: 'POST',
@@ -178,7 +178,7 @@ provide('tableStore', tableStore)
const cellClickEvent = ({ row, column }: any) => { const cellClickEvent = ({ row, column }: any) => {
if (column.field != 'name') { if (column.field != 'name') {
console.log(row) console.log(row)
OverLimitDetailsRef.value.open(row) dailyTrendChartRef.value.open(row)
} }
} }

View File

@@ -0,0 +1,254 @@
<template>
<!-- 总体指标占比详情谐波含有率 -->
<el-dialog draggable title="谐波电压/电流含有率" v-model="dialogVisible" append-to-body width="70%">
<TableHeader datePicker showExport :showReset="false" @selectChange="selectChange">
<template v-slot:select>
<el-form-item label="谐波次数">
<el-select
v-model="tableStore.table.params.searchValue"
placeholder="请选择谐波次数"
style="width: 240px"
>
<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.searchValue"
placeholder="请选择指标类型"
style="width: 240px"
>
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</template>
</TableHeader>
<my-echart
class="tall"
:options="echartList"
style="width: 98%; height: 320px"
/>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import TableStore from '@/utils/tableStore'
import TableHeader from '@/components/table/header/index.vue'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useConfig } from '@/stores/config'
const prop = defineProps({
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const dialogVisible: any = ref(false)
const options = [
{
value: '35kV进线',
label: '35kV进线'
}
]
const config = useConfig()
const powerList: any = ref([
{
label: '三相总有功功率',
value: '1'
},
{
label: '三相总无功功率',
value: '2'
}
])
const exceedingTheLimitList: any = ref([
{
label: '越限',
value: '1'
},
{
label: '不越限',
value: '0'
}
])
const indicatorList: any = ref([
{
label: '谐波电压总畸变率',
value: '1'
},
{
label: '各次谐波电压',
value: '2'
},
{
label: '各次谐波电压',
value: '3'
},
{
label: '三相电压不平衡',
value: '4'
}
])
const echartList = ref({
title: {
text: '35kV进线谐波含有率',
},
xAxis: {
type: 'time',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
},
yAxis: [{}, {}],
grid: {
left: '10px',
right: '20px'
},
options: {
series: [
{
// name: '暂降次数',
type: 'bar',
name: '有功功率',
data: [
['2025-10-16 07:00:00', 10],
['2025-10-16 07:15:00', 10],
['2025-10-16 07:30:00', 10],
['2025-10-16 07:45:00', 10],
['2025-10-16 08:00:00', 30],
['2025-10-16 08:15:00', 50],
['2025-10-16 08:30:00', 60],
['2025-10-16 08:45:00', 70],
['2025-10-16 09:00:00', 100],
['2025-10-16 09:15:00', 120],
['2025-10-16 09:30:00', 130],
['2025-10-16 09:45:00', 140],
['2025-10-16 10:00:00', 160],
['2025-10-16 10:15:00', 160],
['2025-10-16 10:30:00', 130],
['2025-10-16 10:45:00', 120],
['2025-10-16 11:00:00', 140],
['2025-10-16 11:15:00', 80],
['2025-10-16 11:30:00', 70],
['2025-10-16 11:45:00', 90],
['2025-10-16 12:00:00', 60],
['2025-10-16 12:15:00', 60],
['2025-10-16 12:30:00', 60],
['2025-10-16 12:45:00', 60]
],
itemStyle: {
normal: {
//这里是颜色
color: function (params: any) {
if (params.value[1] == 0 || params.value[1] == 3.14159) {
return '#ccc'
} else {
return config.layout.elementUiPrimary[0]
}
}
}
},
yAxisIndex: 0
},
{
name: '谐波总畸变率',
type: 'line',
showSymbol: false,
smooth: true,
data: [
['2025-10-16 07:00:00', 0],
['2025-10-16 07:15:00', 0],
['2025-10-16 07:30:00', 0],
['2025-10-16 07:45:00', 0],
['2025-10-16 08:00:00', 0],
['2025-10-16 08:15:00', 0.1],
['2025-10-16 08:30:00', 0.1],
['2025-10-16 08:45:00', 0.1],
['2025-10-16 09:00:00', 1],
['2025-10-16 09:15:00', 1],
['2025-10-16 09:30:00', 1],
['2025-10-16 09:45:00', 1],
['2025-10-16 10:00:00', 0.8],
['2025-10-16 10:15:00', 0.8],
['2025-10-16 10:30:00', 0.8],
['2025-10-16 10:45:00', 0.8],
['2025-10-16 11:00:00', 0.8],
['2025-10-16 11:15:00', 0.1],
['2025-10-16 11:30:00', 0.1],
['2025-10-16 11:45:00', 0.1],
['2025-10-16 12:00:00', 0],
['2025-10-16 12:15:00', 0],
['2025-10-16 12:30:00', 0],
['2025-10-16 12:45:00', 0]
],
yAxisIndex: 1
}
]
}
})
const headerHeight = ref(57)
const selectChange = (showSelect: any, height: any) => {
headerHeight.value = height
}
const tableStore: any = new TableStore({
url: '/user-boot/role/selectRoleDetail?id=0',
method: 'POST',
showPage: false,
exportName: '主要监测点列表',
column: [],
beforeSearchFun: () => {},
loadCallback: () => {
tableStore.table.height = `calc(${prop.height} - 80px)`
}
})
const tableRef = ref()
provide('tableRef', tableRef)
tableStore.table.params.power = '1'
tableStore.table.params.indicator = '1'
tableStore.table.params.exceedingTheLimit = '1'
tableStore.table.params.searchValue = ''
provide('tableStore', tableStore)
onMounted(() => {
tableStore.index()
})
watch(
() => prop.timeKey,
val => {
tableStore.index()
}
)
watch(
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
(newVal, oldVal) => {
tableStore.index()
},
{
deep: true // 若 timeValue 是对象/数组,需开启深度监听
}
)
const openDialog = async (row: any) => {
dialogVisible.value = true
tableStore.index()
}
defineExpose({ openDialog })
</script>
<style lang="scss" scoped>
:deep(.el-select) {
min-width: 80px;
}
</style>

View File

@@ -1,21 +1,30 @@
<template> <template>
<!-- 综合评估详情 --> <div>
<el-dialog draggable title="指标合格率统计" v-model="dialogVisible" append-to-body width="70%"> <!-- 综合评估详情 -->
<TableHeader datePicker showExport :showReset="false"> <el-dialog draggable title="指标合格率统计" v-model="dialogVisible" append-to-body width="70%">
<template v-slot:select> <TableHeader datePicker showExport :showReset="false">
<el-form-item label="监测点名称"> <template v-slot:select>
<el-select <el-form-item label="监测点名称">
v-model="tableStore.table.params.searchValue" <el-select
placeholder="请选择监测点名称" v-model="tableStore.table.params.searchValue"
style="width: 240px" placeholder="请选择监测点名称"
> style="width: 240px"
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> >
</el-select> <el-option
</el-form-item> v-for="item in options"
</template> :key="item.value"
</TableHeader> :label="item.label"
<Table ref="tableRef" isGroup :height="height"></Table> :value="item.value"
</el-dialog> />
</el-select>
</el-form-item>
</template>
</TableHeader>
<Table ref="tableRef" @cell-click="cellClickEvent" isGroup :height="height"></Table>
</el-dialog>
<!-- 谐波电流谐波电压占有率 -->
<HarmonicRatio ref="harmonicRatioRef" />
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, provide } from 'vue' import { ref, provide } from 'vue'
@@ -23,7 +32,9 @@ import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
import HarmonicRatio from '@/components/cockpit/listOfMainMonitoringPoints/components/harmonicRatio.vue'
const dialogVisible: any = ref(false) const dialogVisible: any = ref(false)
const harmonicRatioRef: any = ref(null)
const options = [ const options = [
{ {
value: '35kV进线', value: '35kV进线',
@@ -38,7 +49,11 @@ const loop50 = (key: string) => {
title: i + '次', title: i + '次',
// field: key + i, // field: key + i,
field: 'flicker', field: 'flicker',
width: '80' width: '80',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flicker}</span>`
}
}) })
} }
return list return list
@@ -71,7 +86,11 @@ const tableStore: any = new TableStore({
{ {
title: '闪变越限(分钟)', title: '闪变越限(分钟)',
field: 'flicker', field: 'flicker',
width: '80' width: '80',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flicker}</span>`
}
}, },
{ {
title: '谐波电压越限(分钟)', title: '谐波电压越限(分钟)',
@@ -103,21 +122,18 @@ const tableStore: any = new TableStore({
{ {
time: '2024-01-01 00:00:00', time: '2024-01-01 00:00:00',
name: '35kV进线', name: '35kV进线',
flicker: '0', flicker: '0'
}, },
{ {
time: '2024-01-01 00:00:00', time: '2024-01-01 00:00:00',
name: '35kV进线', name: '35kV进线',
flicker: '0', flicker: '0'
}, },
{ {
time: '2024-01-01 00:00:00', time: '2024-01-01 00:00:00',
name: '35kV进线', name: '35kV进线',
flicker: '0', flicker: '0'
}
},
] ]
} }
}) })
@@ -129,6 +145,14 @@ const open = async (row: any) => {
tableStore.index() tableStore.index()
} }
// 点击行
const cellClickEvent = ({ row, column }: any) => {
if (column.field != 'name' && column.field != 'time') {
harmonicRatioRef.value.openDialog(row)
}
}
defineExpose({ open }) defineExpose({ open })
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@@ -63,8 +63,8 @@ const tableStore: any = new TableStore({
minWidth: '80', minWidth: '80',
render: 'customTemplate', render: 'customTemplate',
customTemplate: (row: any) => { customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type2}</span>` return `<span style='cursor: pointer;text-decoration: underline;' onclick="handleReportClick('${row.name}')">${row.type2}</span>`
} },
}, },
{ title: '监测点名称', field: 'type3', minWidth: '70' }, { title: '监测点名称', field: 'type3', minWidth: '70' },
{ title: '监测类型', field: 'type4', minWidth: '60' }, { title: '监测类型', field: 'type4', minWidth: '60' },
@@ -164,6 +164,30 @@ watch(
} }
) )
const addMenu = () => {} const handleReportClick = (id: string) => {
const row = tableStore.table.data.find((item: any) => item.id === id)
if (row && row.type2 !== '/') {
// 示例:触发下载逻辑(根据你注释掉的代码)
// getFileZip({ eventId: id }).then(res => {
// let blob = new Blob([res], { type: 'application/zip' })
// const url = window.URL.createObjectURL(blob)
// const link = document.createElement('a')
// link.href = url
// link.download = row.wavePath?.split('/')[2] || '报告文件.zip'
// link.click()
// })
console.log('点击了报告:', row.type2)
} else {
ElMessage.warning('暂无报告可下载')
}
}
// 挂载到 window 供 HTML 调用
window.handleReportClick = handleReportClick
// 组件销毁时清理全局方法
onBeforeUnmount(() => {
delete window.handleReportClick
})
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@@ -0,0 +1,131 @@
<template>
<div>
<!-- 暂态事件列表 -->
<el-dialog draggable title="暂态事件列表" v-model="dialogVisible" append-to-body width="70%">
<!-- <TableHeader datePicker showExport :showReset="false">
<template v-slot:select>
<el-form-item label="监测点名称">
<el-select
v-model="tableStore.table.params.searchValue"
placeholder="请选择监测点名称"
style="width: 240px"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</template>
</TableHeader> -->
<Table ref="tableRef" isGroup :height="height"></Table>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, provide } from 'vue'
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'
const dialogVisible: any = ref(false)
const harmonicRatioRef: any = ref(null)
const options = [
{
value: '35kV进线',
label: '35kV进线'
}
]
const height = mainHeight(0, 2).height as any
const tableStore: any = new TableStore({
url: '/user-boot/role/selectRoleDetail?id=0',
method: 'POST',
publicHeight: 30,
showPage: false,
exportName: '主要监测点列表',
column: [
{
field: 'index',
title: '序号',
width: '80',
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{
title: '暂态时间',
field: 'time',
},
{
title: '测点名称',
field: 'name',
width: '150'
},
{
title: '暂态类型',
field: 'flicker',
width: '100',
},
{
title: '特征幅值(%)',
field: 'flicker',
width: '100'
},
{
title: '暂降深度(%)',
field: 'flicker',
width: '100'
},
{
title: '持续时间(S)',
field: 'flicker',
width: '100'
},
{
title: '严重度',
field: 'flicker',
width: '80'
},
],
beforeSearchFun: () => {},
loadCallback: () => {
tableStore.table.data = [
{
time: '2024-01-01 00:00:00',
name: '35kV进线',
flicker: '0'
},
{
time: '2024-01-01 00:00:00',
name: '35kV进线',
flicker: '0'
},
{
time: '2024-01-01 00:00:00',
name: '35kV进线',
flicker: '0'
}
]
}
})
tableStore.table.params.searchValue = ''
provide('tableStore', tableStore)
const open = async (row: any) => {
dialogVisible.value = true
tableStore.index()
}
// 点击行
const cellClickEvent = ({ row, column }: any) => {
if (column.field != 'name') {
harmonicRatioRef.value.openDialog(row)
}
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@@ -23,10 +23,11 @@
</div> </div>
</template> </template>
<div <div
style="text-decoration: underline"
:style="{ height: `calc(${prop.height} / 5 - 47px)`, overflow: 'auto' }" :style="{ height: `calc(${prop.height} / 5 - 47px)`, overflow: 'auto' }"
v-for="item in list?.filter(item => item.time == data.day)" v-for="item in list?.filter(item => item.time == data.day)"
> >
<div>电压暂降:{{ item.type || '' }}</div> <div @click="descentClick">电压暂降:{{ item.type || '' }}</div>
<div>电压中断:{{ item.type1 || '' }}</div> <div>电压中断:{{ item.type1 || '' }}</div>
<div>电压暂升:{{ item.type2 || '' }}</div> <div>电压暂升:{{ item.type2 || '' }}</div>
</div> </div>
@@ -34,6 +35,8 @@
</div> </div>
</template> </template>
</el-calendar> </el-calendar>
<!-- 暂态事件列表 -->
<TransientList ref="transientListRef" />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -45,6 +48,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime' import { getTimeOfTheMonth } from '@/utils/formatTime'
import { overflow } from 'html2canvas/dist/types/css/property-descriptors/overflow' import { overflow } from 'html2canvas/dist/types/css/property-descriptors/overflow'
import { dayjs } from 'element-plus' import { dayjs } from 'element-plus'
import TransientList from './components/transientList.vue'
dayjs.en.weekStart = 1 //设置日历的周起始日为星期一 dayjs.en.weekStart = 1 //设置日历的周起始日为星期一
const value = ref(new Date()) const value = ref(new Date())
@@ -54,6 +58,8 @@ const prop = defineProps({
timeKey: { type: String }, timeKey: { type: String },
timeValue: { type: Object } timeValue: { type: Object }
}) })
const transientListRef = ref()
const list = ref([ const list = ref([
{ {
time: '2025-10-01', time: '2025-10-01',
@@ -154,7 +160,12 @@ watch(
} }
) )
const addMenu = () => {} // 电压暂降点击事件
const descentClick = () => {
transientListRef.value.open()
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.el-calendar) { :deep(.el-calendar) {

View File

@@ -0,0 +1,150 @@
<template>
<div>
<!-- 暂态事件详情 -->
<el-dialog draggable title="暂态事件详情 " v-model="dialogVisible" append-to-body width="70%">
<TableHeader datePicker showExport :showReset="false">
<template v-slot:select>
<el-form-item label="监测点名称">
<el-select
v-model="tableStore.table.params.searchValue"
placeholder="请选择监测点名称"
style="width: 240px"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</template>
</TableHeader>
<Table ref="tableRef" @cell-click="cellClickEvent" isGroup :height="height"></Table>
</el-dialog>
<!-- 查看波形 -->
<HarmonicRatio ref="harmonicRatioRef" />
</div>
</template>
<script setup lang="ts">
import { ref, provide } from 'vue'
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 HarmonicRatio from '@/components/cockpit/listOfMainMonitoringPoints/components/harmonicRatio.vue'
const dialogVisible: any = ref(false)
const harmonicRatioRef: any = ref(null)
const options = [
{
value: '35kV进线',
label: '35kV进线'
}
]
const height = mainHeight(0, 2).height as any
const tableStore: any = new TableStore({
url: '/user-boot/role/selectRoleDetail?id=0',
method: 'POST',
publicHeight: 30,
showPage: false,
exportName: '主要监测点列表',
column: [
{
field: 'index',
title: '序号',
width: '80',
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{
title: '暂态时间',
field: 'time',
},
{
title: '测点名称',
field: 'name',
width: '150'
},
{
title: '暂态类型',
field: 'flicker',
width: '100',
},
{
title: '特征幅值(%)',
field: 'flicker',
width: '100'
},
{
title: '暂降深度(%)',
field: 'flicker',
width: '100'
},
{
title: '持续时间(S)',
field: 'flicker',
width: '100'
},
{
title: '严重度',
field: 'flicker',
width: '80'
},
{
title: '波形',
width: '100',
render: 'buttons',
buttons: [
{
name: 'check',
title: '查看波形',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton',
click: row => {
}
}
]
}
],
beforeSearchFun: () => {},
loadCallback: () => {
tableStore.table.data = [
{
time: '2024-01-01 00:00:00',
name: '35kV进线',
flicker: '0'
},
{
time: '2024-01-01 00:00:00',
name: '35kV进线',
flicker: '0'
},
{
time: '2024-01-01 00:00:00',
name: '35kV进线',
flicker: '0'
}
]
}
})
tableStore.table.params.searchValue = ''
provide('tableStore', tableStore)
const open = async (row: any) => {
dialogVisible.value = true
tableStore.index()
}
// 点击行
const cellClickEvent = ({ row, column }: any) => {
if (column.field != 'name') {
harmonicRatioRef.value.openDialog(row)
}
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@@ -7,6 +7,7 @@
:style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }" :style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }"
/> />
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} / 2 )`" isGroup></Table> <Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} / 2 )`" isGroup></Table>
<TransientStatisticsDetail ref="transientStatisticsDetailRef"></TransientStatisticsDetail>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -18,6 +19,7 @@ import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime' import { getTimeOfTheMonth } from '@/utils/formatTime'
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
import TransientStatisticsDetail from './components/transientStatisticsDetail.vue'
const config = useConfig() const config = useConfig()
const prop = defineProps({ const prop = defineProps({
width: { type: String }, width: { type: String },
@@ -95,7 +97,7 @@ const echartList = ref({
] ]
} }
}) })
const OverLimitDetailsRef = ref() const transientStatisticsDetailRef = ref()
const tableStore: any = new TableStore({ const tableStore: any = new TableStore({
url: '/user-boot/dept/deptTree', url: '/user-boot/dept/deptTree',
method: 'POST', method: 'POST',
@@ -187,8 +189,7 @@ provide('tableStore', tableStore)
// 点击行 // 点击行
const cellClickEvent = ({ row, column }: any) => { const cellClickEvent = ({ row, column }: any) => {
if (column.field != 'name') { if (column.field != 'name') {
console.log(row) transientStatisticsDetailRef.value.open(row)
OverLimitDetailsRef.value.open(row)
} }
} }

View File

@@ -15,6 +15,7 @@ import { color, gradeColor3 } from './color'
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
// import { nextTick } from 'process' // import { nextTick } from 'process'
const emit = defineEmits(['chartClick'])
const config = useConfig() const config = useConfig()
color[0] = config.layout.elementUiPrimary[0] color[0] = config.layout.elementUiPrimary[0]
const chartRef = ref<HTMLDivElement>() const chartRef = ref<HTMLDivElement>()
@@ -89,7 +90,7 @@ const initChart = () => {
...(props.options?.legend || null) ...(props.options?.legend || null)
}, },
grid: { grid: {
top: '50px', top: '50px',
left: '30px', left: '30px',
right: '70px', right: '70px',
bottom: props.options?.options?.dataZoom === null ? '10px' : '40px', bottom: props.options?.options?.dataZoom === null ? '10px' : '40px',
@@ -131,6 +132,10 @@ const initChart = () => {
// 处理柱状图 // 处理柱状图
chart.setOption(options, true) chart.setOption(options, true)
chart.group = 'group' chart.group = 'group'
// 添加点击事件
chart.on('click', function (params: any) {
emit('chartClick', params)
})
setTimeout(() => { setTimeout(() => {
chart.resize() chart.resize()
}, 0) }, 0)

View File

@@ -31,7 +31,7 @@
<el-tree <el-tree
:style="{ height: bxsDeviceData.length != 0 ? 'calc(100vh - 340px)' : 'calc(100vh - 278px)' }" :style="{ height: bxsDeviceData.length != 0 ? 'calc(100vh - 340px)' : 'calc(100vh - 278px)' }"
ref="treeRef1" :props="defaultProps" highlight-current :filter-node-method="filterNode" ref="treeRef1" :props="defaultProps" highlight-current :filter-node-method="filterNode"
node-key="id" default-expand-all v-bind="$attrs" :data="zlDevList" style="overflow: auto"> node-key="id" :default-expand-all="false" v-bind="$attrs" :data="zlDevList" style="overflow: auto">
<template #default="{ node, data }"> <template #default="{ node, data }">
<span class="custom-tree-node"> <span class="custom-tree-node">
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }" <Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
@@ -44,7 +44,7 @@
<el-collapse-item title="便携式设备" name="1" v-if="bxsDeviceData.length != 0"> <el-collapse-item title="便携式设备" name="1" v-if="bxsDeviceData.length != 0">
<el-tree <el-tree
:style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 280px)' : 'calc(100vh - 238px)' }" :style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 280px)' : 'calc(100vh - 238px)' }"
ref="treeRef2" :props="defaultProps" highlight-current default-expand-all ref="treeRef2" :props="defaultProps" highlight-current :default-expand-all="false"
:filter-node-method="filterNode" node-key="id" :data="bxsDeviceData" v-bind="$attrs" :filter-node-method="filterNode" node-key="id" :data="bxsDeviceData" v-bind="$attrs"
style="overflow: auto"> style="overflow: auto">
<template #default="{ node, data }"> <template #default="{ node, data }">
@@ -59,7 +59,7 @@
<el-collapse-item title="在线设备" name="2" v-if="frontDeviceData.length != 0"> <el-collapse-item title="在线设备" name="2" v-if="frontDeviceData.length != 0">
<el-tree <el-tree
:style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 280px)' : 'calc(100vh - 238px)' }" :style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 280px)' : 'calc(100vh - 238px)' }"
ref="treeRef3" :props="defaultProps" highlight-current default-expand-all ref="treeRef3" :props="defaultProps" highlight-current :default-expand-all="false"
:filter-node-method="filterNode" node-key="id" :data="frontDeviceData" v-bind="$attrs" :filter-node-method="filterNode" node-key="id" :data="frontDeviceData" v-bind="$attrs"
style="overflow: auto"> style="overflow: auto">
<template #default="{ node, data }"> <template #default="{ node, data }">
@@ -124,6 +124,7 @@ watch(
item.children.map((vv: any) => { item.children.map((vv: any) => {
zlDeviceData.value.push(vv) zlDeviceData.value.push(vv)
}) })
zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value))
} else if (item.name == '便携式设备') { } else if (item.name == '便携式设备') {
bxsDeviceData.value = [] bxsDeviceData.value = []
item.children.map((vv: any) => { item.children.map((vv: any) => {
@@ -156,8 +157,6 @@ watch(filterText, val => {
} }
}) })
watch(process, val => { watch(process, val => {
if (val == '') { if (val == '') {
zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value)) zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value))
} else { } else {
@@ -177,10 +176,10 @@ function filterProcess(nodes: any) {
const children = node.children ? filterProcess(node.children) : [] const children = node.children ? filterProcess(node.children) : []
// 如果当前节点的process=4或者有子节点满足条件则保留当前节点 // 如果当前节点的process=4或者有子节点满足条件则保留当前节点
if (node.process == process.value || children.length > 0) { if ( node.process == process.value || children.length > 0) {
return { return {
...node, ...node,
children: node.children children: children
} }
} }

View File

@@ -50,6 +50,7 @@ getDeviceTree().then(res => {
item2.color = config.getColorVal('elementUiPrimary') item2.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => { item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-Platform' item3.icon = 'el-icon-Platform'
item3.level = 2
item3.color = config.getColorVal('elementUiPrimary') item3.color = config.getColorVal('elementUiPrimary')
if (item3.comFlag === 1) { if (item3.comFlag === 1) {
item3.color = '#e26257 !important' item3.color = '#e26257 !important'

View File

@@ -46,7 +46,7 @@ const info = () => {
item2.color = config.getColorVal('elementUiPrimary') item2.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => { item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-Platform' item3.icon = 'el-icon-Platform'
item3.level = 1 item3.level = 2
item3.color = item3.color =
item3.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important' item3.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
item3.children.forEach((item4: any) => { item3.children.forEach((item4: any) => {

View File

@@ -28,7 +28,8 @@
<el-tree <el-tree
:style="{ height: bxsDeviceData.length != 0 ? 'calc(100vh - 340px)' : 'calc(100vh - 278px)' }" :style="{ height: bxsDeviceData.length != 0 ? 'calc(100vh - 340px)' : 'calc(100vh - 278px)' }"
ref="treeRef1" :props="defaultProps" highlight-current :filter-node-method="filterNode" ref="treeRef1" :props="defaultProps" highlight-current :filter-node-method="filterNode"
node-key="id" default-expand-all v-bind="$attrs" :data="zlDevList" style="overflow: auto"> node-key="id" v-bind="$attrs" :data="zlDevList" style="overflow: auto"
:default-expand-all="false">
<template #default="{ node, data }"> <template #default="{ node, data }">
<span class="custom-tree-node"> <span class="custom-tree-node">
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }" <Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
@@ -41,9 +42,9 @@
<el-collapse-item title="便携式设备" name="1" v-if="bxsDeviceData.length != 0"> <el-collapse-item title="便携式设备" name="1" v-if="bxsDeviceData.length != 0">
<el-tree <el-tree
:style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 330px)' : 'calc(100vh - 238px)' }" :style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 330px)' : 'calc(100vh - 238px)' }"
ref="treeRef2" :props="defaultProps" highlight-current default-expand-all ref="treeRef2" :props="defaultProps" highlight-current :default-expand-all="false"
:filter-node-method="filterNode" node-key="id" :data="bxsDeviceData" v-bind="$attrs" :filter-node-method="filterNode" node-key="id" :data="bxsDeviceData" v-bind="$attrs"
style="overflow: auto"> style="overflow: auto" >
<template #default="{ node, data }"> <template #default="{ node, data }">
<span class="custom-tree-node"> <span class="custom-tree-node">
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }" <Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
@@ -56,7 +57,7 @@
<el-collapse-item title="在线设备" name="2" v-if="yqfDeviceData.length != 0"> <el-collapse-item title="在线设备" name="2" v-if="yqfDeviceData.length != 0">
<el-tree <el-tree
:style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 330px)' : 'calc(100vh - 238px)' }" :style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 330px)' : 'calc(100vh - 238px)' }"
ref="treeRef3" :props="defaultProps" highlight-current default-expand-all ref="treeRef3" :props="defaultProps" highlight-current :default-expand-all="false"
:filter-node-method="filterNode" node-key="id" :data="yqfDeviceData" v-bind="$attrs" :filter-node-method="filterNode" node-key="id" :data="yqfDeviceData" v-bind="$attrs"
style="overflow: auto"> style="overflow: auto">
<template #default="{ node, data }"> <template #default="{ node, data }">
@@ -76,7 +77,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import useCurrentInstance from '@/utils/useCurrentInstance' import useCurrentInstance from '@/utils/useCurrentInstance'
import { ElTree } from 'element-plus' import { ElTree } from 'element-plus'
import { el } from 'element-plus/es/locale' import { el, fa } from 'element-plus/es/locale'
import { ref, watch, defineEmits, onMounted, nextTick, computed } from 'vue' import { ref, watch, defineEmits, onMounted, nextTick, computed } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
defineOptions({ defineOptions({
@@ -117,13 +118,14 @@ watch(
() => props.data, () => props.data,
(val, oldVal) => { (val, oldVal) => {
if (val && val.length != 0) { if (val && val.length != 0) {
val.map((item: any) => { val.map((item: any) => {
if (item.name == '治理设备') { if (item.name == '治理设备') {
zlDeviceData.value = [] zlDeviceData.value = []
item.children.map((vv: any) => { item.children.map((vv: any) => {
zlDeviceData.value.push(vv) zlDeviceData.value.push(vv)
}) })
// console.log('🚀 ~ item.children.map ~ zlDeviceData.value:', zlDeviceData.value) zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value))
} else if (item.name == '便携式设备') { } else if (item.name == '便携式设备') {
bxsDeviceData.value = [] bxsDeviceData.value = []
item.children.map((vv: any) => { item.children.map((vv: any) => {
@@ -155,18 +157,23 @@ watch(filterText, val => {
} }
}) })
watch(process, val => { watch(process, val => {
if (val == '') { if (val == '') {
zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value)) zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value))
} else { } else {
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value))) zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
} }
setTimeout(() => { setTimeout(() => {
changeDevice(activeName.value) changeDevice(activeName.value)
}, 0) }, 0)
}) })
const changeDevice = (val: any) => { const changeDevice = (val: any) => {
console.log('changeDevice', val)
let arr1: any = [] let arr1: any = []
//zlDeviceData //zlDeviceData
zlDevList.value.forEach((item: any) => { zlDevList.value.forEach((item: any) => {
@@ -231,6 +238,7 @@ const filterNode = (value: string, data: any, node: any) => {
return chooseNode(value, data, node) return chooseNode(value, data, node)
} }
} }
function filterProcess(nodes: any) { function filterProcess(nodes: any) {
if (process.value == '') { if (process.value == '') {
return nodes return nodes
@@ -240,20 +248,58 @@ function filterProcess(nodes: any) {
// 递归处理子节点 // 递归处理子节点
const children = node.children ? filterProcess(node.children) : [] const children = node.children ? filterProcess(node.children) : []
// 如果当前节点的process=4或者有子节点满足条件则保留当前节点 // 对于装置层级level=2只保留 process 值匹配的节点
if (node.level === 2) {
if (node.process == process.value) {
return {
...node,
children: children
}
}
return null
}
if (node.process == process.value || children.length > 0) { // 对于其他节点:
// 1. 如果有满足条件的子节点则保留
// 2. 如果本身 process 值匹配则保留
// 3. 如果是叶子节点也保留(监测点通常没有子节点)
if (children.length > 0 || node.process == process.value ||
(!node.children || node.children.length === 0)) {
return { return {
...node, ...node,
children: node.children children: children
} }
} }
// 否则过滤掉当前节点
return null return null
}) })
.filter(Boolean) // 移除null节点 .filter(Boolean) // 移除null节点
} }
// function filterProcess(nodes: any) {
// if (process.value == '') {
// return nodes
// }
// return nodes
// .map(node => {
// // 递归处理子节点
// const children = node.children ? filterProcess(node.children) : []
// // 如果当前节点的process=4或者有子节点满足条件则保留当前节点
// if (node.process == process.value || children.length > 0) {
// return {
// ...node,
// children: node.children
// }
// }
// // 否则过滤掉当前节点
// return null
// })
// .filter(Boolean) // 移除null节点
// }
// 过滤父节点 / 子节点 (如果输入的参数是父节点且能匹配则返回该节点以及其下的所有子节点如果参数是子节点则返回该节点的父节点。name是中文字符enName是英文字符. // 过滤父节点 / 子节点 (如果输入的参数是父节点且能匹配则返回该节点以及其下的所有子节点如果参数是子节点则返回该节点的父节点。name是中文字符enName是英文字符.
const chooseNode = (value: string, data: any, node: any) => { const chooseNode = (value: string, data: any, node: any) => {
if (data.name.indexOf(value) !== -1) { if (data.name.indexOf(value) !== -1) {
@@ -288,7 +334,9 @@ const treeRef2 = ref<InstanceType<typeof ElTree>>()
const treeRef3 = ref<InstanceType<typeof ElTree>>() const treeRef3 = ref<InstanceType<typeof ElTree>>()
defineExpose({ treeRef1, treeRef2 }) defineExpose({ treeRef1, treeRef2 })
onMounted(() => { onMounted(() => {
setTimeout(() => { setTimeout(() => {
if (zlDeviceData.value.length != 0) { if (zlDeviceData.value.length != 0) {
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value))) zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
activeName.value = '0' activeName.value = '0'

View File

@@ -1,157 +1,296 @@
const dataProcessing = (arr: any[]) => { const dataProcessing = (arr: any[]) => {
return arr return arr
.filter(item => typeof item === 'number' || (typeof item === 'string' && !isNaN(parseFloat(item)))) .filter(item => typeof item === 'number' || (typeof item === 'string' && !isNaN(parseFloat(item))))
.map(item => (typeof item === 'number' ? item : parseFloat(item))) .map(item => (typeof item === 'number' ? item : parseFloat(item)))
} }
const calculateValue = (o:number,value: number, num: number, isMin: boolean) => { const calculateValue = (o: number, value: number, num: number, isMin: boolean) => {
if (value === 0) { if (value === 0) {
return 0 return 0
}else if(value>0&& Math.abs(value)<1 && isMin==true){ } else if (value > 0 && Math.abs(value) < 1 && isMin == true) {
return 0 return 0
}else if(value>-1&& value<0 && isMin==false){ } else if (value > -1 && value < 0 && isMin == false) {
return 0 return 0
} }
let base let base
if (Math.abs(o) >= 100) { if (Math.abs(o) >= 100) {
base = 100 base = 100
} else if (Math.abs(o) >= 10) { } else if (Math.abs(o) >= 10) {
base = 10 base = 10
} else if (Math.abs(o) >= 1) { } else if (Math.abs(o) >= 1) {
base = 1 base = 1
} else { } else {
base = 0.1 base = 0.1
} }
let calculatedValue let calculatedValue
if (isMin) { if (isMin) {
if (value < 0) { if (value < 0) {
calculatedValue = value + num * value calculatedValue = value + num * value
} else { } else {
calculatedValue = value - num * value calculatedValue = value - num * value
} }
} else { } else {
if (value < 0) { if (value < 0) {
calculatedValue = value - num * value calculatedValue = value - num * value
} else { } else {
calculatedValue = value + num * value calculatedValue = value + num * value
} }
} }
if (base === 0.1) { if (base === 0.1) {
return parseFloat(calculatedValue.toFixed(1)) return parseFloat(calculatedValue.toFixed(1))
} else if (isMin) { } else if (isMin) {
return Math.floor(calculatedValue / base) * base return Math.floor(calculatedValue / base) * base
} else { } else {
return Math.ceil(calculatedValue / base) * base return Math.ceil(calculatedValue / base) * base
} }
} }
// 处理y轴最大最小值 // 处理y轴最大最小值
export const yMethod = (arr: any) => { export const yMethod = (arr: any) => {
let num = 0.2 let num = 0.2
let numList = dataProcessing(arr) let numList = dataProcessing(arr)
let maxValue = 0 let maxValue = 0
let minValue = 0 let minValue = 0
let max = 0 let max = 0
let min = 0 let min = 0
maxValue = Math.max(...numList) maxValue = Math.max(...numList)
minValue = Math.min(...numList) minValue = Math.min(...numList)
const o=maxValue-minValue const o = maxValue - minValue
min = calculateValue( o,minValue, num, true) min = calculateValue(o, minValue, num, true)
max = calculateValue(o,maxValue, num, false) max = calculateValue(o, maxValue, num, false)
// if (-100 >= minValue) { // if (-100 >= minValue) {
// min = Math.floor((minValue + num * minValue) / 100) * 100 // min = Math.floor((minValue + num * minValue) / 100) * 100
// } else if (-10 >= minValue && minValue > -100) { // } else if (-10 >= minValue && minValue > -100) {
// min = Math.floor((minValue + num * minValue) / 10) * 10 // min = Math.floor((minValue + num * minValue) / 10) * 10
// } else if (-1 >= minValue && minValue > -10) { // } else if (-1 >= minValue && minValue > -10) {
// min = Math.floor(minValue + num * minValue) // min = Math.floor(minValue + num * minValue)
// } else if (0 > minValue && minValue > -1) { // } else if (0 > minValue && minValue > -1) {
// min = parseFloat((minValue + num * minValue).toFixed(1)) // min = parseFloat((minValue + num * minValue).toFixed(1))
// } else if (minValue == 0) { // } else if (minValue == 0) {
// min = 0 // min = 0
// } else if (0 < minValue && minValue < 1) { // } else if (0 < minValue && minValue < 1) {
// min = parseFloat((minValue - num * minValue).toFixed(1)) // min = parseFloat((minValue - num * minValue).toFixed(1))
// } else if (1 <= minValue && minValue < 10) { // } else if (1 <= minValue && minValue < 10) {
// min = Math.floor(minValue - num * minValue) // min = Math.floor(minValue - num * minValue)
// } else if (10 <= minValue && minValue < 100) { // } else if (10 <= minValue && minValue < 100) {
// min = Math.floor((minValue - num * minValue) / 10) * 10 // min = Math.floor((minValue - num * minValue) / 10) * 10
// } else if (100 <= minValue) { // } else if (100 <= minValue) {
// min = Math.floor((minValue - num * minValue) / 100) * 100 // min = Math.floor((minValue - num * minValue) / 100) * 100
// } // }
// if (-100 >= maxValue) { // if (-100 >= maxValue) {
// max = Math.ceil((maxValue - num * maxValue) / 100) * 100 // max = Math.ceil((maxValue - num * maxValue) / 100) * 100
// } else if (-10 >= maxValue && maxValue > -100) { // } else if (-10 >= maxValue && maxValue > -100) {
// max = Math.ceil((maxValue - num * maxValue) / 10) * 10 // max = Math.ceil((maxValue - num * maxValue) / 10) * 10
// } else if (-1 >= maxValue && maxValue > -10) { // } else if (-1 >= maxValue && maxValue > -10) {
// max = Math.ceil(maxValue - num * maxValue) // max = Math.ceil(maxValue - num * maxValue)
// } else if (0 > maxValue && maxValue > -1) { // } else if (0 > maxValue && maxValue > -1) {
// max = parseFloat((maxValue - num * maxValue).toFixed(1)) // max = parseFloat((maxValue - num * maxValue).toFixed(1))
// } else if (maxValue == 0) { // } else if (maxValue == 0) {
// max = 0 // max = 0
// } else if (0 < maxValue && maxValue < 1) { // } else if (0 < maxValue && maxValue < 1) {
// max = parseFloat((maxValue + num * maxValue).toFixed(1)) // max = parseFloat((maxValue + num * maxValue).toFixed(1))
// } else if (1 <= maxValue && maxValue < 10) { // } else if (1 <= maxValue && maxValue < 10) {
// max = Math.ceil(maxValue + num * maxValue) // max = Math.ceil(maxValue + num * maxValue)
// } else if (10 <= maxValue && maxValue < 100) { // } else if (10 <= maxValue && maxValue < 100) {
// max = Math.ceil((maxValue + num * maxValue) / 10) * 10 // max = Math.ceil((maxValue + num * maxValue) / 10) * 10
// } else if (100 <= maxValue) { // } else if (100 <= maxValue) {
// max = Math.ceil((maxValue + num * maxValue) / 100) * 100 // max = Math.ceil((maxValue + num * maxValue) / 100) * 100
// } // }
// if (maxValue > 1000 || minValue < -1000) { // if (maxValue > 1000 || minValue < -1000) {
// max = Math.ceil(maxValue / 100) * 100 // max = Math.ceil(maxValue / 100) * 100
// if (minValue == 0) { // if (minValue == 0) {
// min = 0 // min = 0
// } else { // } else {
// min = Math.floor(minValue / 100) * 100 // min = Math.floor(minValue / 100) * 100
// } // }
// } else if (maxValue < 60 && minValue > 40) { // } else if (maxValue < 60 && minValue > 40) {
// max = 60 // max = 60
// min = 40 // min = 40
// } else if (maxValue == minValue && maxValue < 10 && minValue > 0) { // } else if (maxValue == minValue && maxValue < 10 && minValue > 0) {
// max = Math.ceil(maxValue / 10) * 10 // max = Math.ceil(maxValue / 10) * 10
// min = Math.floor(minValue / 10) * 10 // min = Math.floor(minValue / 10) * 10
// } else if (maxValue == minValue && maxValue != 0 && minValue != 0) { // } else if (maxValue == minValue && maxValue != 0 && minValue != 0) {
// max = Math.ceil(maxValue / 10 + 1) * 10 // max = Math.ceil(maxValue / 10 + 1) * 10
// min = Math.floor(minValue / 10 - 1) * 10 // min = Math.floor(minValue / 10 - 1) * 10
// } else { // } else {
// max = Math.ceil(maxValue / 10) * 10 // max = Math.ceil(maxValue / 10) * 10
// min = Math.floor(minValue / 10) * 10 // min = Math.floor(minValue / 10) * 10
// } // }
// if (maxValue > 0 && maxValue < 1) { // if (maxValue > 0 && maxValue < 1) {
// max = 1 // max = 1
// } else if (max == 0 && minValue > -1 && minValue < 0) { // } else if (max == 0 && minValue > -1 && minValue < 0) {
// min = -1 // min = -1
// } // }
return [min, max] return [min, max]
} }
/**
/** * title['A相','B相',]
* title['A相','B相',] * data[[1,2],[3,4]]
* data[[1,2],[3,4]] */
*/ // 导出csv文件
// 导出csv文件 const convertToCSV = (title: object, data: any) => {
const convertToCSV = (title: object, data: any) => { let csv = ''
console.log('🚀 ~ convertToCSV ~ data:', data) // 添加列头
let csv = '' csv += ',' + title.join(',') + '\n'
// 添加列头 // 遍历数据并添加到CSV字符串中
csv += ',' + title.join(',') + '\n' data?.map(item => {
// 遍历数据并添加到CSV字符串中 csv += '\u200B' + item.join(',') + '\n'
data?.map(item => { })
csv += item.join(',') + '\n' return csv
}) }
return csv export const exportCSV = (title: object, data: any, filename: string) => {
} const csv = convertToCSV(title, data)
export const exportCSV = (title: object, data: any, filename: string) => { const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
const csv = convertToCSV(title, data) const link = document.createElement('a')
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }) link.href = URL.createObjectURL(blob)
const link = document.createElement('a') link.download = filename
link.href = URL.createObjectURL(blob) link.click()
link.download = filename // 释放URL对象
link.click() URL.revokeObjectURL(link.href)
// 释放URL对象 }
URL.revokeObjectURL(link.href)
} /**
* 补全时间序列数据中缺失的条目
* @param rawData 原始数据,格式为 [["时间字符串", "数值", "单位", "类型"], ...]
* @returns 补全后的数据,缺失条目数值为 null
*/
export const completeTimeSeries = (rawData: string[][]): (string | null)[][] => {
// 步骤1校验原始数据并解析时间
if (rawData.length < 2) {
console.warn('数据量不足2条无法计算时间间隔直接返回原始数据')
return rawData.map(item => [...item])
}
// 解析所有时间为Date对象过滤无效时间并按时间排序
const validData = rawData
.map(item => {
// 确保至少有时间和数值字段
if (!item[0]) {
return { time: new Date(0), item, isValid: false }
}
const time = new Date(item[0])
return { time, item, isValid: !isNaN(time.getTime()) }
})
.filter(data => data.isValid)
.sort((a, b) => a.time.getTime() - b.time.getTime()) // 确保数据按时间排序
.map(data => data.item)
if (validData.length < 2) {
throw new Error('有效时间数据不足2条无法继续处理')
}
// 步骤2计算时间间隔分析前几条数据确定最可能的间隔
const intervals: number[] = []
// 分析前10条数据来确定间隔避免单一间隔出错
const analyzeCount = Math.min(10, validData.length - 1)
for (let i = 0; i < analyzeCount; i++) {
const currentTime = new Date(validData[i][0]!).getTime()
const nextTime = new Date(validData[i + 1][0]!).getTime()
const interval = nextTime - currentTime
if (interval > 0) {
intervals.push(interval)
}
}
// 取最常见的间隔作为标准间隔
const timeInterval = getMostFrequentValue(intervals)
if (timeInterval <= 0) {
throw new Error('无法确定有效的时间间隔')
}
// 步骤3生成完整的时间序列范围从第一条到最后一条
const startTime = new Date(validData[0][0]!).getTime()
const endTime = new Date(validData[validData.length - 1][0]!).getTime()
const completeTimes: Date[] = []
// 生成从 startTime 到 endTime 的所有间隔时间点
for (let time = startTime; time <= endTime; time += timeInterval) {
completeTimes.push(new Date(time))
}
// 步骤4将原始数据转为时间映射表使用精确的时间字符串匹配
const timeDataMap = new Map<string, (string | undefined)[]>()
validData.forEach(item => {
// 使用原始时间字符串作为键,避免格式转换导致的匹配问题
if (item[0]) {
timeDataMap.set(item[0], item)
}
})
// 提取模板数据(从第一条有效数据中提取单位和类型,处理可能的缺失)
const template = validData[0]
// 步骤5对比补全数据缺失条目数值为 null
const completedData = completeTimes.map(time => {
// 保持与原始数据相同的时间格式
const timeStr = formatTime(time)
const existingItem = timeDataMap.get(timeStr)
if (existingItem) {
// 存在该时间,返回原始数据
return [...existingItem]
} else {
// 缺失该时间,数值设为 null其他字段沿用第一个有效数据的格式
// 处理可能缺失的单位和类型字段
const result: (string | null | undefined)[] = [timeStr, '/']
// 仅在原始数据有单位字段时才添加
if (template.length > 2) {
result.push(template[2])
}
// 仅在原始数据有类型字段时才添加
if (template.length > 3) {
result.push(template[3])
}
return result
}
})
return completedData
}
/**
* 格式化时间为 "YYYY-MM-DD HH:mm:ss" 格式
* @param date 日期对象
* @returns 格式化后的时间字符串
*/
function formatTime(date: Date): string {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
const seconds = String(date.getSeconds()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}
/**
* 获取数组中出现频率最高的值
* @param arr 数字数组
* @returns 出现频率最高的值
*/
function getMostFrequentValue(arr: number[]): number {
if (arr.length === 0) return 0
const frequencyMap = new Map<number, number>()
arr.forEach(num => {
frequencyMap.set(num, (frequencyMap.get(num) || 0) + 1)
})
let maxFrequency = 0
let mostFrequent = arr[0]
frequencyMap.forEach((frequency, num) => {
if (frequency > maxFrequency) {
maxFrequency = frequency
mostFrequent = num
}
})
return mostFrequent
}

View File

@@ -94,7 +94,15 @@ const tableStore = new TableStore({
}, },
{ title: '设备名称', field: 'ndid', align: 'center' }, { title: '设备名称', field: 'ndid', align: 'center' },
{ title: '异常时间', field: 'evtTime', align: 'center', sortable: true }, { title: '异常时间', field: 'evtTime', align: 'center', sortable: true },
{ title: '告警代码', field: 'code', align: 'center', sortable: true } {
title: '告警代码',
field: 'code',
align: 'center',
sortable: true,
formatter: (row: any) => {
return row.cellValue ? '\u200B' + row.cellValue : '/'
}
}
] ]
}) })

View File

@@ -86,7 +86,7 @@ const tableStore = new TableStore({
{ title: '设备名称', field: 'equipmentName', align: 'center' }, { title: '设备名称', field: 'equipmentName', align: 'center' },
{ title: '工程名称', field: 'engineeringName', align: 'center' }, { title: '工程名称', field: 'engineeringName', align: 'center' },
{ title: '项目名称', field: 'projectName', align: 'center' }, { title: '项目名称', field: 'projectName', align: 'center' },
{ title: '发生时刻', field: 'startTime', align: 'center', minWidth: 110, sortable: true }, { title: '发生时刻', field: 'startTime', align: 'center', width: 180, sortable: true },
{ {
title: '模块信息', title: '模块信息',
field: 'moduleNo', field: 'moduleNo',
@@ -99,20 +99,21 @@ const tableStore = new TableStore({
title: '告警代码', title: '告警代码',
field: 'code', field: 'code',
align: 'center', align: 'center',
width: 100,
formatter: (row: any) => { formatter: (row: any) => {
return row.cellValue ? row.cellValue : '/' return row.cellValue ? '\u200B' + row.cellValue : '/'
}, },
sortable: true sortable: true
}, },
{ {
title: '事件描述', title: '事件描述',
minWidth: 220,
field: 'showName' field: 'showName'
}, },
{ {
title: '级别', title: '级别',
field: 'level', field: 'level',
width: 100,
render: 'tag', render: 'tag',
custom: { custom: {
1: 'danger', 1: 'danger',
@@ -133,7 +134,8 @@ const tableStore = new TableStore({
// } // }
// } // }
], ],
beforeSearchFun: () => {} beforeSearchFun: () => {},
}) })
provide('tableStore', tableStore) provide('tableStore', tableStore)

View File

@@ -51,7 +51,7 @@ const tableStore = new TableStore({
align: 'center', align: 'center',
formatter: (row: any) => { formatter: (row: any) => {
return row.cellValue ? row.cellValue : '/' return row.cellValue ? '\u200B' + row.cellValue : '/'
}, },
sortable: true sortable: true
}, },

View File

@@ -75,7 +75,7 @@ import TableHeader from '@/components/table/header/index.vue'
import shushiboxi from '@/components/echarts/shushiboxi.vue' import shushiboxi from '@/components/echarts/shushiboxi.vue'
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue' import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
import rmsboxi from '@/components/echarts/rmsboxi.vue' import rmsboxi from '@/components/echarts/rmsboxi.vue'
import { analyseWave } from '@/api/common' import { analyseWave, getFileByEventId } from '@/api/common'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { getFileZip } from '@/api/cs-harmonic-boot/datatrend' import { getFileZip } from '@/api/cs-harmonic-boot/datatrend'
@@ -153,7 +153,7 @@ const tableStore = new TableStore({
render: 'basicButton', render: 'basicButton',
loading: 'loading1', loading: 'loading1',
disabled: row => { disabled: row => {
return !row.wavePath && row.evtParamTm < 20 return !row.wavePath
}, },
click: async row => { click: async row => {
row.loading1 = true row.loading1 = true
@@ -212,7 +212,6 @@ const tableStore = new TableStore({
loading: 'loading2', loading: 'loading2',
render: 'basicButton', render: 'basicButton',
disabled: row => { disabled: row => {
// && row.evtParamTm < 20
return !row.wavePath return !row.wavePath
}, },
click: row => { click: row => {
@@ -235,8 +234,24 @@ const tableStore = new TableStore({
icon: 'el-icon-DataLine', icon: 'el-icon-DataLine',
render: 'basicButton', render: 'basicButton',
disabled: row => { disabled: row => {
return !(!row.wavePath && row.evtParamTm < 20) return row.showName != '未知';
} }
},
{
name: 'edit',
title: '波形补召',
type: 'primary',
icon: 'el-icon-Check',
render: 'basicButton',
disabled: row => {
return row.wavePath || row.showName === '未知';
},
click: row => {
getFileByEventId(row.id).then(res => {
ElMessage.success(res.message)
tableStore.index()
})
}
} }
] ]
} }

View File

@@ -1,448 +1,469 @@
<template> <template>
<div class="default-main analyze-apf" :style="{ height: pageHeight.height }" v-loading="loading"> <div class="default-main analyze-apf" :style="{ height: pageHeight.height }" v-loading="loading">
<DeviceTree @node-click="nodeClick" @init="nodeClick" @deviceTypeChange="deviceTypeChange"></DeviceTree> <DeviceTree @node-click="nodeClick" @init="nodeClick" @deviceTypeChange="deviceTypeChange"></DeviceTree>
<div class="analyze-apf-right" v-if="formInline.devId"> <div class="analyze-apf-right" v-if="formInline.devId">
<div ref="headerRef"> <div ref="headerRef">
<TableHeader :showSearch="false" ref="tableHeaderRef" @selectChange="selectChange"> <TableHeader :showSearch="false" ref="tableHeaderRef" @selectChange="selectChange">
<template v-slot:select> <template v-slot:select>
<el-form-item label="时间:"> <el-form-item label="时间:">
<DatePicker ref="datePickerRef"></DatePicker> <DatePicker ref="datePickerRef"></DatePicker>
</el-form-item> </el-form-item>
<el-form-item label="统计指标:"> <el-form-item label="统计指标:">
<el-select <el-select
style="width: 200px" style="width: 200px"
v-model.trim="formInline.statisticalId" v-model.trim="formInline.statisticalId"
filterable filterable
@change="frequencyFlag" @change="frequencyFlag"
placeholder="请选择" placeholder="请选择"
> >
<el-option <el-option
v-for="item in zblist" v-for="item in zblist"
:key="item.value" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="谐波次数:" v-show="frequencyShow"> <el-form-item label="谐波次数:" v-show="frequencyShow">
<el-select <el-select
v-model.trim="formInline.frequency" v-model.trim="formInline.frequency"
filterable filterable
placeholder="请选择" placeholder="请选择"
style="width: 100px" style="width: 100px"
> >
<el-option <el-option
v-for="item in 49" v-for="item in 49"
:key="item + 1" :key="item + 1"
:label="item + 1" :label="item + 1"
:value="item + 1" :value="item + 1"
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="值类型:"> <el-form-item label="值类型:">
<el-select v-model.trim="formInline.valueType" filterable placeholder="请选择"> <el-select v-model.trim="formInline.valueType" filterable placeholder="请选择">
<el-option <el-option
v-for="item in typelist" v-for="item in typelist"
:key="item.value" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</template> </template>
<template v-slot:operation> <template v-slot:operation>
<el-button type="primary" @click="search" icon="el-icon-Search">查询</el-button> <el-button type="primary" @click="search" icon="el-icon-Search">查询</el-button>
</template> <el-button :type="timeControl ? 'primary' : ''" icon="el-icon-Sort" @click="setTimeControl">
</TableHeader> 缺失数据
</div> </el-button>
</template>
<el-empty description="暂无数据" v-if="!echartsData" style="flex: 1"></el-empty> </TableHeader>
<template v-else> </div>
<div :style="echartHeight">
<MyEchart :options="echartsData" /> <el-empty description="暂无数据" v-if="!echartsData" style="flex: 1"></el-empty>
</div> <template v-else>
</template> <div :style="echartHeight">
</div> <MyEchart :options="echartsData" />
<el-empty v-else description="请选择设备" class="analyze-apf-right" /> </div>
</div> </template>
</template> </div>
<el-empty v-else description="请选择设备" class="analyze-apf-right" />
<script setup lang="ts"> </div>
import { ref, reactive } from 'vue' </template>
import { mainHeight } from '@/utils/layout'
import DeviceTree from '@/components/tree/govern/deviceTree.vue' <script setup lang="ts">
import { queryByCode, queryCsDictTree } from '@/api/system-boot/dictTree' import { ref, reactive } from 'vue'
import { getDevCapacity } from '@/api/cs-device-boot/capacity' import { mainHeight } from '@/utils/layout'
import { queryCommonStatisticalByTime } from '@/api/cs-harmonic-boot/stable' import DeviceTree from '@/components/tree/govern/deviceTree.vue'
import DatePicker from '@/components/form/datePicker/index.vue' import { queryByCode, queryCsDictTree } from '@/api/system-boot/dictTree'
import MyEchart from '@/components/echarts/MyEchart.vue' import { getDevCapacity } from '@/api/cs-device-boot/capacity'
import { yMethod } from '@/utils/echartMethod' import { queryCommonStatisticalByTime } from '@/api/cs-harmonic-boot/stable'
import TableHeader from '@/components/table/header/index.vue' import DatePicker from '@/components/form/datePicker/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
defineOptions({ import { yMethod, completeTimeSeries } from '@/utils/echartMethod'
name: 'govern/analyze/APF' import TableHeader from '@/components/table/header/index.vue'
}) const timeControl = ref(false)
defineOptions({
const tableHeaderRef = ref() name: 'govern/analyze/APF'
const headerRef = ref() })
const pageHeight = mainHeight(20)
const echartHeight = ref(mainHeight(80)) const tableHeaderRef = ref()
const loading = ref(false) const headerRef = ref()
const echartsData = ref<any>(null) const pageHeight = mainHeight(20)
const datePickerRef = ref() const echartHeight = ref(mainHeight(80))
const formInline = reactive({ const loading = ref(false)
statisticalId: '', const echartsData = ref<any>(null)
valueType: '', const datePickerRef = ref()
startTime: '', const formInline = reactive({
endTime: '', statisticalId: '',
devId: '', valueType: '',
frequency: '' startTime: '',
}) endTime: '',
const timeFlag = ref(true) devId: '',
const frequencyShow = ref(false) frequency: ''
const devCapacity = ref(0) })
const flag = ref(false) const dataLists = ref<any[]>([])
const typelist = [ const timeFlag = ref(true)
{ const frequencyShow = ref(false)
label: '平均值', const devCapacity = ref(0)
value: 'avg' const flag = ref(false)
}, const typelist = [
{ {
label: '最大值', label: '平均值',
value: 'max' value: 'avg'
}, },
{ {
label: '最值', label: '最值',
value: 'min' value: 'max'
}, },
{ {
label: 'CP95值', label: '最小值',
value: 'cp95' value: 'min'
} },
] {
const zblist = ref<any[]>([]) label: 'CP95值',
value: 'cp95'
const init = () => { }
return new Promise((resolve, reject) => { ]
queryByCode('Web_Apf').then(res => { const zblist = ref<any[]>([])
queryCsDictTree(res.data?.id).then(res => {
zblist.value = res.data.map((item: any) => { const init = () => {
return { return new Promise((resolve, reject) => {
value: item.id, queryByCode('Web_Apf').then(res => {
label: item.name, queryCsDictTree(res.data?.id).then(res => {
...item zblist.value = res.data.map((item: any) => {
} return {
}) value: item.id,
formInline.statisticalId = zblist.value[0]?.value label: item.name,
formInline.valueType = typelist[0].value ...item
resolve(null) }
}) })
}) formInline.statisticalId = zblist.value[0]?.value
}) formInline.valueType = typelist[0].value
} resolve(null)
const deviceTypeChange = (val: any, obj: any) => { })
flag.value = true })
nodeClick(obj) })
} }
const nodeClick = async (e: anyObj) => { const deviceTypeChange = (val: any, obj: any) => {
if (e.level == 2 && flag.value) { flag.value = true
formInline.devId = e.id nodeClick(obj)
loading.value = true }
if (zblist.value.length === 0) { const nodeClick = async (e: anyObj) => {
await init() if (e.level == 2 && flag.value) {
} formInline.devId = e.id
getDevCapacity(formInline.devId) loading.value = true
.then(res => { if (zblist.value.length === 0) {
devCapacity.value = res.data await init()
search() }
}) getDevCapacity(formInline.devId)
.catch(() => { .then(res => {
loading.value = false devCapacity.value = res.data
}) search()
} })
} .catch(() => {
const lineStyle = [ loading.value = false
{ type: 'solid', width: 3 }, })
{ type: 'dotted', width: 3 }, }
{ type: 'dashed', width: 3 } }
] const lineStyle = [
const search = () => { { type: 'solid', width: 3 },
if (timeFlag.value) { { type: 'dotted', width: 3 },
datePickerRef.value && datePickerRef.value.setInterval(5) { type: 'dashed', width: 3 }
timeFlag.value = false ]
} const search = () => {
loading.value = true if (timeFlag.value) {
formInline.startTime = datePickerRef.value.timeValue[0] datePickerRef.value && datePickerRef.value.setInterval(5)
formInline.endTime = datePickerRef.value.timeValue[1] timeFlag.value = false
if (!frequencyShow.value) { }
formInline.frequency = '' loading.value = true
} formInline.startTime = datePickerRef.value.timeValue[0]
formInline.endTime = datePickerRef.value.timeValue[1]
queryCommonStatisticalByTime(formInline) if (!frequencyShow.value) {
.then(({ data }: { data: any[] }) => { formInline.frequency = ''
if (data.length) { }
let list = processingOfData(data, 'unit')
queryCommonStatisticalByTime(formInline)
echartsData.value = {} .then(({ data }: { data: any[] }) => {
let legend: any[] = [] dataLists.value = data
let xAxis: any[] = [] setEchart()
let yAxis: any[] = [] loading.value = false
let series: any[] = [] })
let color: any[] = [] .catch(() => {
let title = '' loading.value = false
data.forEach(item => { })
if (!xAxis.includes(item.time)) { }
xAxis.push(item.time) const setEchart = () => {
} loading.value = true
// if (!legend.includes(item.anotherName)) { let data = JSON.parse(JSON.stringify(dataLists.value))
// legend.push(item.anotherName) if (data.length) {
// } let list = processingOfData(data, 'unit')
})
let units = Object.keys(list) echartsData.value = {}
// console.log('🚀 ~ .then ~ units:', units) let legend: any[] = []
for (let unit in list) { let xAxis: any[] = []
console.log('🚀 ~ .then ~ unit:', unit) let yAxis: any[] = []
let [min, max] = yMethod(list[unit].map((item: any) => item.statisticalData)) let series: any[] = []
yAxis.push({ let color: any[] = []
name: unit == 'null' ? '' : unit, let title = ''
type: 'value', data.forEach(item => {
// max: 10, if (!xAxis.includes(item.time)) {
min: min, xAxis.push(item.time)
max: max, }
// splitNumber: 5, // if (!legend.includes(item.anotherName)) {
// minInterval: 1, // legend.push(item.anotherName)
// }
axisLine: { })
show: true, let units = Object.keys(list)
//symbol: ["none", "arrow"], // console.log('🚀 ~ .then ~ units:', units)
lineStyle: { for (let unit in list) {
color: '#333' console.log('🚀 ~ .then ~ unit:', unit)
} let [min, max] = yMethod(list[unit].map((item: any) => item.statisticalData))
} yAxis.push({
}) name: unit == 'null' ? '' : unit,
// processingOfData(list[unit], 'anotherName') type: 'value',
let anotherList = processingOfData(list[unit], 'anotherName') // max: 10,
for (let k in anotherList) { min: min,
title = k max: max,
let lineName = lineStyle[Object.keys(anotherList).indexOf(k)] // splitNumber: 5,
let phaseList = processingOfData(anotherList[k], 'phase') // minInterval: 1,
for (let j in phaseList) {
color.push(j == 'A' ? '#DAA520' : j == 'B' ? '#2E8B57' : j == 'C' ? '#A52a2a' : '#0000CC') axisLine: {
legend.push( show: true,
j == 'M' ? k : j == 'A' ? `A相_${k}` : j == 'B' ? `B相_${k}` : j == 'C' ? `C相_${k}` : j //symbol: ["none", "arrow"],
) lineStyle: {
series.push({ color: '#333'
name: }
j == 'M' }
? k })
: j == 'A' // processingOfData(list[unit], 'anotherName')
? `A相_${k}` let anotherList = processingOfData(list[unit], 'anotherName')
: j == 'B' for (let k in anotherList) {
? `B相_${k}` title = k
: j == 'C' let lineName = lineStyle[Object.keys(anotherList).indexOf(k)]
? `C相_${k}` let phaseList = processingOfData(anotherList[k], 'phase')
: j, for (let j in phaseList) {
symbol: 'none', color.push(j == 'A' ? '#DAA520' : j == 'B' ? '#2E8B57' : j == 'C' ? '#A52a2a' : '#0000CC')
smooth: true, legend.push(
type: 'line', j == 'M' ? k : j == 'A' ? `A相_${k}` : j == 'B' ? `B相_${k}` : j == 'C' ? `C相_${k}` : j
)
data: phaseList[j].map(item => [ series.push({
item.time, name: j == 'M' ? k : j == 'A' ? `A相_${k}` : j == 'B' ? `B相_${k}` : j == 'C' ? `C相_${k}` : j,
Math.floor(item.statisticalData * 100) / 100, symbol: 'none',
unit, smooth: true,
lineName.type type: 'line',
]),
lineStyle: lineName, // data: phaseList[j].map(item => [
yAxisIndex: unit.indexOf(units) // item.time,
}) // Math.floor(item.statisticalData * 100) / 100,
} // unit,
} // lineName.type
} // ]),
data: timeControl.value
echartsData.value = { ? completeTimeSeries(
title: { phaseList[j].map(item => [
text: zblist.value.filter(item => item.id == formInline.statisticalId)[0].name item.time,
}, Math.floor(item.statisticalData * 100) / 100,
tooltip: { unit,
axisPointer: { lineName.type
type: 'cross', ])
label: { )
color: '#fff', : phaseList[j].map(item => [
fontSize: 16 item.time,
} Math.floor(item.statisticalData * 100) / 100,
}, unit,
textStyle: { lineName.type
color: '#fff', ]),
fontStyle: 'normal',
opacity: 0.35, lineStyle: lineName,
fontSize: 14 yAxisIndex: unit.indexOf(units)
}, })
backgroundColor: 'rgba(0,0,0,0.55)', }
borderWidth: 0, }
formatter(params: any) { }
const xname = params[0].value[0]
let str = `${xname}<br>` echartsData.value = {
params.forEach((el: any, index: any) => { title: {
let marker = '' text: zblist.value.filter(item => item.id == formInline.statisticalId)[0].name
if (el.value[3] == 'dashed') { },
for (let i = 0; i < 3; i++) { tooltip: {
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>` axisPointer: {
} type: 'cross',
} else { label: {
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>` color: '#fff',
} fontSize: 16
}
str += `${marker}${el.seriesName.split('(')[0]}${ },
el.value[1] != null textStyle: {
? el.value[1] + ' ' + (el.value[2] == 'null' ? '' : el.value[2]) color: '#fff',
: '-' fontStyle: 'normal',
}<br>` opacity: 0.35,
}) fontSize: 14
return str },
} backgroundColor: 'rgba(0,0,0,0.55)',
}, borderWidth: 0,
legend: { formatter(params: any) {
itemWidth: 20, const xname = params[0].value[0]
itemHeight: 20, let str = `${xname}<br>`
itemStyle: { opacity: 0 }, //去圆点 params.forEach((el: any, index: any) => {
type: 'scroll', // 开启滚动分页 let marker = ''
top: 25 if (el.value[3] == 'dashed') {
// data: legend 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>`
grid: { }
left: '20px', } else {
right: '40px', marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
bottom: '50px', }
top: '80px',
containLabel: true str += `${marker}${el.seriesName.split('(')[0]}${
}, el.value[1] != null ? el.value[1] + ' ' + (el.value[2] == 'null' ? '' : el.value[2]) : '-'
toolbox: { }<br>`
feature: { })
saveAsImage: {} return str
} }
}, },
color: color, legend: {
xAxis: { itemWidth: 20,
name: '', itemHeight: 20,
type: 'time', itemStyle: { opacity: 0 }, //去圆点
axisLabel: { type: 'scroll', // 开启滚动分页
formatter: { top: 25
day: '{MM}-{dd}', // data: legend
month: '{MM}', },
year: '{yyyy}' grid: {
} left: '20px',
} right: '40px',
bottom: '50px',
// boundaryGap: false, top: '80px',
// data: xAxis, containLabel: true
// axisLabel: { },
// formatter: function (value: string) { toolbox: {
// return value.split(' ').join('\n') feature: {
// } saveAsImage: {}
// }, }
// axisLine: { },
// show: true, color: color,
// // symbol: ["none", "arrow"], xAxis: {
// lineStyle: { name: '',
// color: '#333' type: 'time',
// } axisLabel: {
// } formatter: {
}, day: '{MM}-{dd}',
yAxis: yAxis, month: '{MM}',
// [ year: '{yyyy}'
// { }
// name: '畸变率:(%)', }
// type: 'value',
// // max: 10, // boundaryGap: false,
// min: min1, // data: xAxis,
// max: max1, // axisLabel: {
// splitNumber: 5, // formatter: function (value: string) {
// minInterval: 1, // return value.split(' ').join('\n')
// }
// axisLine: { // },
// show: true, // axisLine: {
// //symbol: ["none", "arrow"], // show: true,
// lineStyle: { // // symbol: ["none", "arrow"],
// color: '#333' // lineStyle: {
// } // color: '#333'
// } // }
// }, // }
// { },
// name: '电流:(A)', yAxis: yAxis,
// type: 'value', // [
// min: min, // {
// max: max, // name: '畸变率:(%)',
// splitNumber: 5, // type: 'value',
// minInterval: 1, // // max: 10,
// splitLine: { // min: min1,
// show: false // max: max1,
// }, // splitNumber: 5,
// axisLine: { // minInterval: 1,
// show: true,
// //symbol: ["none", "arrow"], // axisLine: {
// lineStyle: { // show: true,
// color: '#333' // //symbol: ["none", "arrow"],
// } // lineStyle: {
// } // color: '#333'
// } // }
// ], // }
options: { // },
series: series // {
} // name: '电流:(A)',
} // type: 'value',
} else { // min: min,
echartsData.value = null // max: max,
} // splitNumber: 5,
loading.value = false // minInterval: 1,
}) // splitLine: {
.catch(() => { // show: false
loading.value = false // },
}) // axisLine: {
} // show: true,
const processingOfData = (data: any, type: string) => { // //symbol: ["none", "arrow"],
let groupedData: any = {} // lineStyle: {
// color: '#333'
data.forEach(item => { // }
if (!groupedData[item[type]]) { // }
groupedData[item[type]] = [] // }
} // ],
groupedData[item[type]].push(item) options: {
}) series: series
return groupedData }
} }
const frequencyFlag = () => { } else {
let name = zblist.value.filter(item => item.id == formInline.statisticalId)[0].name echartsData.value = null
if (name.includes('含有率') || name.includes('幅值')) { }
frequencyShow.value = true loading.value = false
formInline.frequency = 2 }
} else { const setTimeControl = () => {
frequencyShow.value = false timeControl.value = !timeControl.value
} setEchart()
tableHeaderRef.value && tableHeaderRef.value?.computedSearchRow() }
}
const selectChange = (flag: boolean) => { const processingOfData = (data: any, type: string) => {
setTimeout(() => { let groupedData: any = {}
echartHeight.value = mainHeight(23 + headerRef.value.offsetHeight)
}, 100) data.forEach(item => {
} if (!groupedData[item[type]]) {
</script> groupedData[item[type]] = []
}
<style lang="scss"> groupedData[item[type]].push(item)
.analyze-apf { })
display: flex; return groupedData
}
&-right { const frequencyFlag = () => {
height: 100%; let name = zblist.value.filter(item => item.id == formInline.statisticalId)[0].name
overflow: hidden; if (name.includes('含有率') || name.includes('幅值')) {
flex: 1; frequencyShow.value = true
padding: 10px 10px 10px 0; formInline.frequency = 2
display: flex; } else {
flex-direction: column; frequencyShow.value = false
} }
} tableHeaderRef.value && tableHeaderRef.value?.computedSearchRow()
</style> }
<style lang="scss" scoped> const selectChange = (flag: boolean) => {
.el-select { setTimeout(() => {
min-width: 100px; echartHeight.value = mainHeight(23 + headerRef.value.offsetHeight)
} }, 100)
</style> }
</script>
<style lang="scss">
.analyze-apf {
display: flex;
&-right {
height: 100%;
overflow: hidden;
flex: 1;
padding: 10px 10px 10px 0;
display: flex;
flex-direction: column;
}
}
</style>
<style lang="scss" scoped>
.el-select {
min-width: 100px;
}
</style>

View File

@@ -314,7 +314,8 @@
label="装置mac地址:" label="装置mac地址:"
:rules="{ required: true, message: '请输入装置mac地址', trigger: 'blur' }" :rules="{ required: true, message: '请输入装置mac地址', trigger: 'blur' }"
> >
<MacAddressInput v-model="busItem.mac" :disabled="!((nodeLevel == 3 && pageStatus == 3) || ((nodeLevel == 2 || (nodeLevel == 1 && pageStatus == 2)) && pageStatus == 2))"/> <MacAddressInput v-model="busItem.mac"
:disabled="!(pageStatus == 2 && nodeLevel == 2)"/>
</el-form-item> </el-form-item>
<!-- <el-form-item <!-- <el-form-item
class="form-item" class="form-item"
@@ -346,7 +347,7 @@
filterable filterable
v-model="busItem.nodeId" v-model="busItem.nodeId"
placeholder="请选择所属前置机" placeholder="请选择所属前置机"
:disabled="!(pageStatus == 2 && nodeLevel >= 2)" :disabled="!(pageStatus == 2 && nodeLevel == 2)"
> >
<el-option <el-option
v-for="option in affiliatiedFrontArr" v-for="option in affiliatiedFrontArr"
@@ -479,17 +480,21 @@
:rules="{ required: true, message: '请输入pt', trigger: 'blur' }" :rules="{ required: true, message: '请输入pt', trigger: 'blur' }"
> >
<div style="width: 100%; display: flex; justify-content: space-between"> <div style="width: 100%; display: flex; justify-content: space-between">
<el-input <el-input-number
:controls="false"
:min="1"
style="width: 48%" style="width: 48%"
v-model="lineItem.ptRatio" v-model="lineItem.ptRatio"
:disabled="!((nodeLevel == 4 && pageStatus == 3) || ((nodeLevel == 3 || (nodeLevel == 2 && pageStatus == 2)) && pageStatus == 2))" :disabled="!((nodeLevel == 4 && pageStatus == 3) || ((nodeLevel == 3 || (nodeLevel == 2 && pageStatus == 2)) && pageStatus == 2))"
></el-input> ></el-input-number>
<span style="display: flex; align-items: center; justify-content: center;">:</span> <span style="display: flex; align-items: center; justify-content: center;">:</span>
<el-input <el-input-number
:controls="false"
:min="1"
style="width: 48%" style="width: 48%"
v-model="lineItem.pt2Ratio" v-model="lineItem.pt2Ratio"
:disabled="!((nodeLevel == 4 && pageStatus == 3) || ((nodeLevel == 3 || (nodeLevel == 2 && pageStatus == 2)) && pageStatus == 2))" :disabled="!((nodeLevel == 4 && pageStatus == 3) || ((nodeLevel == 3 || (nodeLevel == 2 && pageStatus == 2)) && pageStatus == 2))"
></el-input> ></el-input-number>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@@ -498,17 +503,21 @@
:rules="{ required: true, message: '请输入ct', trigger: 'blur' }" :rules="{ required: true, message: '请输入ct', trigger: 'blur' }"
> >
<div style="width: 100%; display: flex; justify-content: space-between"> <div style="width: 100%; display: flex; justify-content: space-between">
<el-input <el-input-number
:controls="false"
:min="1"
style="width: 48%" style="width: 48%"
v-model="lineItem.ctRatio" v-model="lineItem.ctRatio"
:disabled="!((nodeLevel == 4 && pageStatus == 3) || ((nodeLevel == 3 || (nodeLevel == 2 && pageStatus == 2)) && pageStatus == 2))" :disabled="!((nodeLevel == 4 && pageStatus == 3) || ((nodeLevel == 3 || (nodeLevel == 2 && pageStatus == 2)) && pageStatus == 2))"
></el-input> ></el-input-number>
<span style="display: flex; align-items: center; justify-content: center;">:</span> <span style="display: flex; align-items: center; justify-content: center;">:</span>
<el-input <el-input-number
:controls="false"
:min="1"
style="width: 48%" style="width: 48%"
v-model="lineItem.ct2Ratio" v-model="lineItem.ct2Ratio"
:disabled="!((nodeLevel == 4 && pageStatus == 3) || ((nodeLevel == 3 || (nodeLevel == 2 && pageStatus == 2)) && pageStatus == 2))" :disabled="!((nodeLevel == 4 && pageStatus == 3) || ((nodeLevel == 3 || (nodeLevel == 2 && pageStatus == 2)) && pageStatus == 2))"
></el-input> ></el-input-number>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@@ -818,6 +827,21 @@ const nodeClick = (e: anyObj, data: any) => {
cleanUnnecessaryData() cleanUnnecessaryData()
/**不是根节点请求数据 */ /**不是根节点请求数据 */
queryNodeContent() queryNodeContent()
// 关键修改确保tabs展开
setTimeout(() => {
// 设置默认选中的tab索引
if (nodeLevel.value >= 2 && projectInfoList.value.length > 0) {
deviceIndex.value = '0'
}
if (nodeLevel.value >= 3 && deviceInfoList.value.length > 0) {
busBarIndex.value = '0'
}
if (nodeLevel.value >= 4 && lineInfoList.value.length > 0) {
lineIndex.value = '0'
}
}, 100)
treeClickCount.value = 0 treeClickCount.value = 0
} }
@@ -1057,10 +1081,10 @@ const add = () => {
lineNo: 1, lineNo: 1,
conType: 0, conType: 0,
lineInterval: 1, lineInterval: 1,
ptRatio: 0, ptRatio: 1,
pt2Ratio: 0, pt2Ratio: 1,
ctRatio: 0, ctRatio: 1,
ct2Ratio: 0, ct2Ratio: 1,
volGrade: '', volGrade: '',
devMac:'', devMac:'',
}) })
@@ -1229,10 +1253,10 @@ const updateLineFunc = (id: any) => {
lineNo: currentLine.lineNo || 1, lineNo: currentLine.lineNo || 1,
conType: currentLine.conType || 0, conType: currentLine.conType || 0,
lineInterval: currentLine.lineInterval || 1, lineInterval: currentLine.lineInterval || 1,
ptRatio: currentLine.ptRatio || 0, ptRatio: currentLine.ptRatio || 1,
pt2Ratio: currentLine.pt2Ratio || 0, pt2Ratio: currentLine.pt2Ratio || 1,
ctRatio: currentLine.ctRatio || 0, ctRatio: currentLine.ctRatio || 1,
ct2Ratio: currentLine.ct2Ratio || 0, ct2Ratio: currentLine.ct2Ratio || 1,
volGrade: volGradeValue || 0, volGrade: volGradeValue || 0,
devMac: devMac, devMac: devMac,
devId: devId, devId: devId,
@@ -1414,10 +1438,10 @@ const next = async () => {
lineNo: 1, lineNo: 1,
conType: 0, conType: 0,
lineInterval: 1, lineInterval: 1,
ptRatio: 0, ptRatio: 1,
pt2Ratio: 0, pt2Ratio: 1,
ctRatio: 0, ctRatio: 1,
ct2Ratio: 0, ct2Ratio: 1,
volGrade: '', volGrade: '',
devMac: '', devMac: '',
}) })
@@ -1822,10 +1846,10 @@ const resetAllForms = () => {
line.lineNo = 1 line.lineNo = 1
line.conType = 0 line.conType = 0
line.lineInterval = 1 line.lineInterval = 1
line.ptRatio = 0 line.ptRatio = 1
line.pt2Ratio = 0 line.pt2Ratio = 1
line.ctRatio = 0 line.ctRatio = 1
line.ct2Ratio = 0 line.ct2Ratio = 1
line.volGrade = '' line.volGrade = ''
}) })
@@ -2155,10 +2179,10 @@ const handleLineTabsEdit = (targetName: any, action: any) => {
lineNo: 1, lineNo: 1,
conType: 0, conType: 0,
lineInterval: 1, lineInterval: 1,
ptRatio: 0, ptRatio: 1,
pt2Ratio: 0, pt2Ratio: 1,
ctRatio: 0, ctRatio: 1,
ct2Ratio: 0, ct2Ratio: 1,
volGrade: '', volGrade: '',
devMac: '', devMac: '',
}) })

View File

@@ -499,7 +499,7 @@
v-if="dataSet.indexOf('_event') != -1" v-if="dataSet.indexOf('_event') != -1"
v-loading="tableLoading" v-loading="tableLoading"
> >
<Event ref="eventRef"></Event> <Event ref="eventRef" :deviceType="deviceType"></Event>
</div> </div>
<!-- 测试项记录 --> <!-- 测试项记录 -->
<div <div

View File

@@ -134,7 +134,7 @@ const tableStore: any = new TableStore({
icon: 'el-icon-DataLine', icon: 'el-icon-DataLine',
render: 'basicButton', render: 'basicButton',
disabled: row => { disabled: row => {
return props.deviceType === '2' || row.wavePath; return row.showName != '未知';
} }
}, },
{ {
@@ -169,8 +169,8 @@ const tableStore: any = new TableStore({
icon: 'el-icon-Check', icon: 'el-icon-Check',
render: 'basicButton', render: 'basicButton',
disabled: row => { disabled: row => {
return props.deviceType != '2' || row.wavePath; return props.deviceType === '2' && row.wavePath || row.showName === '未知';
}, },
click: row => { click: row => {
getFileByEventId(row.id).then(res => { getFileByEventId(row.id).then(res => {
ElMessage.success(res.message) ElMessage.success(res.message)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="default-main"> <div class="default-main">
<TableHeader datePicker ref="refheader" > <TableHeader datePicker ref="refheader">
<template v-slot:select> <template v-slot:select>
<el-form-item label="关键字筛选"> <el-form-item label="关键字筛选">
<el-input <el-input
@@ -96,14 +96,14 @@ const tableStore = new TableStore({
fixed: 'right', fixed: 'right',
render: 'tag', render: 'tag',
custom: { custom: {
2: 'warning', 功能调试: 'warning',
3: 'warning', 出厂调试: 'warning',
4: 'success' 正式投运: 'success'
}, },
replaceValue: { replaceValue: {
2: '功能调试', 功能调试: '功能调试',
3: '出厂调试', 出厂调试: '出厂调试',
4: '正式投运' 正式投运: '正式投运'
}, },
minWidth: 80 minWidth: 80
}, },
@@ -138,21 +138,21 @@ const tableStore = new TableStore({
} }
}, },
{ title: '在线率(%)', fixed: 'right',width: 100, field: 'onlineRate', sortable: true }, { title: '在线率(%)', fixed: 'right', width: 100, field: 'onlineRate', sortable: true },
{ title: '完整性(%)', fixed: 'right',width: 100, field: 'integrity', sortable: true } { title: '完整性(%)', fixed: 'right', width: 100, field: 'integrity', sortable: true }
], ],
beforeSearchFun: () => {}, beforeSearchFun: () => {},
loadCallback: () => { loadCallback: () => {
tableStore.table.data.forEach(item => {
item.process = item.process == 2 ? '功能调试' : item.process == 3 ? '出厂调试' : '正式投运'
})
let name = tableStore.table.params.name let name = tableStore.table.params.name
let data = tableStore.table.copyData.filter(item => { let data = tableStore.table.copyData.filter(item => {
// 处理latestTime默认值 // 处理latestTime默认值
item.latestTime = item.latestTime || '/' item.latestTime = item.latestTime || '/'
// 需要检查的字段列表 // 需要检查的字段列表
const fieldsToCheck = ['projectName', 'engineeringName', 'mac', 'devName', 'lineName'] const fieldsToCheck = ['projectName', 'engineeringName', 'mac', 'devName', 'lineName']
console.log(
'🚀 ~ fieldsToCheck.some(field => item[field]?.includes(name)):',
fieldsToCheck.some(field => item[field]?.includes(name))
)
// 检查任何一个字段包含搜索名称 // 检查任何一个字段包含搜索名称
return fieldsToCheck.some(field => item[field]?.includes(name)) return fieldsToCheck.some(field => item[field]?.includes(name))

View File

@@ -14,7 +14,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, provide, nextTick, defineEmits, watch } from 'vue' import { ref, onMounted, provide, nextTick, defineEmits, watch } from 'vue'
import { getTabsDataByType } from '@/api/cs-device-boot/EquipmentDelivery'
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue' import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'

View File

@@ -108,7 +108,7 @@ const editd = (e: any) => {
// 设计 // 设计
const Aclick = (e: any) => { const Aclick = (e: any) => {
// window.open(window.location.origin + `/zutai/?id=${e.id}&&name=${e.name}&&preview=false&&graphicDisplay=zl`) // window.open(window.location.origin + `/zutai/?id=${e.id}&&name=${e.name}&&preview=false&&graphicDisplay=zl`)
window.open('http://192.168.1.179:4001' + `/zutai/?id=${e.id}&&name=${e.name}&&preview=false&&graphicDisplay=zl`) window.open(window.location.origin + `/zutai/?id=${e.id}&&name=${e.name}&&preview=false&&graphicDisplay=zl`)
} }
// 删除 // 删除
@@ -143,8 +143,8 @@ const deleted = (e: any) => {
} }
const imgData = (e: any) => { const imgData = (e: any) => {
// window.open(window.location.origin + `/zutai/?id=${e.id}&&name=${e.name}&&preview=true&&graphicDisplay=zl#/preview`) // window.open(window.location.origin + `/zutai/?id=${e.id}&&name=${e.name}&&preview=true&&graphicDisplay=zl#/preview_ZL`)
window.open('http://192.168.1.179:4001' + `/zutai/?id=${e.id}&&name=${e.name}&&preview=true&&graphicDisplay=zl#/preview`) window.open(window.location.origin + `/zutai/?id=${e.id}&&name=${e.name}&&preview=true&&graphicDisplay=zl#/preview_ZL`)
} }

View File

@@ -187,21 +187,37 @@
<!-- 绑定进程号 --> <!-- 绑定进程号 -->
<el-dialog draggable title="绑定进程号" v-model="popUps" :close-on-click-modal="false" width="400px"> <el-dialog draggable title="绑定进程号" v-model="popUps" :close-on-click-modal="false" width="400px">
<el-select v-model="processNo" placeholder="请选择进程号" style="width: 100%"> <el-form :model="bindProcessForm" ref="bindProcessFormRef" label-width="80px" :rules="rules2" >
<el-option <el-form-item label="前置机" prop="nodeId">
v-for="item in dataSource" <el-select v-model="bindProcessForm.nodeId" placeholder="请选择前置机" style="width: 100%" clearable @change="handleNodeChange">
:key="item.name" <el-option
:label="item.name" v-for="item in tableStore.table.data"
:value="item.name" :key="item.id"
></el-option> :label="item.name"
</el-select> :value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="进程号" prop="processNo">
<el-select v-model="bindProcessForm.processNo" placeholder="请选择进程号" style="width: 100%" clearable>
<el-option
v-for="item in processOptions"
:key="item.name"
:label="item.name"
:value="item.name"
></el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer> <template #footer>
<el-button @click="popUps = false"> </el-button> <el-button @click="popUps = false"> </el-button>
<el-button type="primary" @click="bindTheProcess"> </el-button> <el-button type="primary" @click="bindTheProcess"> </el-button>
</template> </template>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -231,13 +247,21 @@ const height = mainHeight(70)
const loading = ref(false) const loading = ref(false)
const popUps = ref(false) const popUps = ref(false)
const tableRef = ref() const tableRef = ref()
const processNo = ref('')
const ruleFormRef = ref() const ruleFormRef = ref()
const dataSource: any = ref([]) const dataSource: any = ref([])
const defaultProps = { const defaultProps = {
children: 'deviceInfoList', children: 'deviceInfoList',
label: 'name' label: 'name'
} }
const bindProcessFormRef = ref()
const bindProcessForm = ref({
nodeId: '',
processNo: ''
})
const processOptions = ref<Array<{ name: string; processNo: string }>>([])
const formData: any = ref({ const formData: any = ref({
name: '', name: '',
ip: '', ip: '',
@@ -256,6 +280,11 @@ const rules = reactive({
sort: [{ required: true, message: '排序不可为空', trigger: 'blur' }], sort: [{ required: true, message: '排序不可为空', trigger: 'blur' }],
remark: [{ required: true, message: '描述不可为空', trigger: 'blur' }] remark: [{ required: true, message: '描述不可为空', trigger: 'blur' }]
}) })
const rules2 = reactive({
nodeId: [{ required: true, message: '请选择前置机', trigger: 'change' }],
processNo: [{ required: true, message: '请选择进程号', trigger: 'change' }]
})
const dialogFormVisible = ref(false) const dialogFormVisible = ref(false)
const dialogTitle = ref('新增前置机') const dialogTitle = ref('新增前置机')
@@ -417,21 +446,66 @@ const treeRef = ref()
const change = (val: any) => { const change = (val: any) => {
treeRef.value!.filter(filterText.value) treeRef.value!.filter(filterText.value)
} }
// 修改 edit 方法
const edit = (data: any) => { const edit = (data: any) => {
processNo.value = data.nodeProcess bindProcessForm.value.processNo = data.nodeProcess
bindProcessForm.value.nodeId = nodeId.value // 默认选中当前节点
processId.value = data.id processId.value = data.id
popUps.value = true popUps.value = true
// 首次加载当前前置机的进程号选项
loadProcessOptionsForNode(nodeId.value)
} }
const loadProcessOptionsForNode = (nodeId: string) => {
// 请求该前置机下的进程列表
nodeDeviceTree({ id: nodeId }).then(res => {
if (res.data && res.data.processDeviceList) {
// 处理进程列表数据
processOptions.value = res.data.processDeviceList.map(item => ({
...item,
name: item.processNo + '' // 保持与原逻辑一致
}))
} else {
processOptions.value = []
}
})
}
// 前置机切换
const handleNodeChange = (nodeId: any) => {
if (!nodeId) {
processOptions.value = []
bindProcessForm.value.processNo = ''
return
}
// 清除之前选中的进程号
bindProcessForm.value.processNo = ''
// 加载新选中前置机的进程号选项
loadProcessOptionsForNode(nodeId)
}
// 更新进程号 // 更新进程号
const bindTheProcess = () => { const bindTheProcess = () => {
updateProcess({ bindProcessFormRef.value.validate((valid: any) => {
id: processId.value, if (valid) {
processNo: processNo.value updateProcess({
}).then((res: any) => { id: processId.value,
ElMessage.success('修改成功!') processNo: bindProcessForm.value.processNo,
popUps.value = false nodeId: bindProcessForm.value.nodeId
currentChangeEvent() }).then((res: any) => {
ElMessage.success('修改成功!')
popUps.value = false
currentChangeEvent()
})
}
}) })
} }
const filterNode = (value: string, data: any, node: any) => { const filterNode = (value: string, data: any, node: any) => {
if (!value) return true if (!value) return true