11 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
stt
8f8f2aad6e Merge branch 'main' of http://192.168.1.22:3000/Web/admin-govern 2025-10-24 16:26:20 +08:00
stt
a9dcb54286 iframe弹框样式修改 2025-10-24 16:26:17 +08:00
33 changed files with 3963 additions and 2672 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
}) })
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

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

@@ -4,12 +4,12 @@ const dataProcessing = (arr: any[]) => {
.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
@@ -55,9 +55,9 @@ export const yMethod = (arr: any) => {
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) {
@@ -128,20 +128,18 @@ export const yMethod = (arr: any) => {
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) => {
console.log('🚀 ~ convertToCSV ~ data:', data)
let csv = '' let csv = ''
// 添加列头 // 添加列头
csv += ',' + title.join(',') + '\n' csv += ',' + title.join(',') + '\n'
// 遍历数据并添加到CSV字符串中 // 遍历数据并添加到CSV字符串中
data?.map(item => { data?.map(item => {
csv += item.join(',') + '\n' csv += '\u200B' + item.join(',') + '\n'
}) })
return csv return csv
} }
@@ -155,3 +153,144 @@ export const exportCSV = (title: object, data: any, filename: string) => {
// 释放URL对象 // 释放URL对象
URL.revokeObjectURL(link.href) 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

@@ -52,6 +52,9 @@
</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>
<el-button :type="timeControl ? 'primary' : ''" icon="el-icon-Sort" @click="setTimeControl">
缺失数据
</el-button>
</template> </template>
</TableHeader> </TableHeader>
</div> </div>
@@ -76,9 +79,9 @@ import { getDevCapacity } from '@/api/cs-device-boot/capacity'
import { queryCommonStatisticalByTime } from '@/api/cs-harmonic-boot/stable' import { queryCommonStatisticalByTime } from '@/api/cs-harmonic-boot/stable'
import DatePicker from '@/components/form/datePicker/index.vue' import DatePicker from '@/components/form/datePicker/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue' import MyEchart from '@/components/echarts/MyEchart.vue'
import { yMethod } from '@/utils/echartMethod' import { yMethod, completeTimeSeries } from '@/utils/echartMethod'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
const timeControl = ref(false)
defineOptions({ defineOptions({
name: 'govern/analyze/APF' name: 'govern/analyze/APF'
}) })
@@ -98,6 +101,7 @@ const formInline = reactive({
devId: '', devId: '',
frequency: '' frequency: ''
}) })
const dataLists = ref<any[]>([])
const timeFlag = ref(true) const timeFlag = ref(true)
const frequencyShow = ref(false) const frequencyShow = ref(false)
const devCapacity = ref(0) const devCapacity = ref(0)
@@ -180,225 +184,242 @@ const search = () => {
queryCommonStatisticalByTime(formInline) queryCommonStatisticalByTime(formInline)
.then(({ data }: { data: any[] }) => { .then(({ data }: { data: any[] }) => {
if (data.length) { dataLists.value = data
let list = processingOfData(data, 'unit') setEchart()
echartsData.value = {}
let legend: any[] = []
let xAxis: any[] = []
let yAxis: any[] = []
let series: any[] = []
let color: any[] = []
let title = ''
data.forEach(item => {
if (!xAxis.includes(item.time)) {
xAxis.push(item.time)
}
// if (!legend.includes(item.anotherName)) {
// legend.push(item.anotherName)
// }
})
let units = Object.keys(list)
// console.log('🚀 ~ .then ~ units:', units)
for (let unit in list) {
console.log('🚀 ~ .then ~ unit:', unit)
let [min, max] = yMethod(list[unit].map((item: any) => item.statisticalData))
yAxis.push({
name: unit == 'null' ? '' : unit,
type: 'value',
// max: 10,
min: min,
max: max,
// splitNumber: 5,
// minInterval: 1,
axisLine: {
show: true,
//symbol: ["none", "arrow"],
lineStyle: {
color: '#333'
}
}
})
// processingOfData(list[unit], 'anotherName')
let anotherList = processingOfData(list[unit], 'anotherName')
for (let k in anotherList) {
title = k
let lineName = lineStyle[Object.keys(anotherList).indexOf(k)]
let phaseList = processingOfData(anotherList[k], 'phase')
for (let j in phaseList) {
color.push(j == 'A' ? '#DAA520' : j == 'B' ? '#2E8B57' : j == 'C' ? '#A52a2a' : '#0000CC')
legend.push(
j == 'M' ? k : j == 'A' ? `A相_${k}` : j == 'B' ? `B相_${k}` : j == 'C' ? `C相_${k}` : j
)
series.push({
name:
j == 'M'
? k
: j == 'A'
? `A相_${k}`
: j == 'B'
? `B相_${k}`
: j == 'C'
? `C相_${k}`
: j,
symbol: 'none',
smooth: true,
type: 'line',
data: phaseList[j].map(item => [
item.time,
Math.floor(item.statisticalData * 100) / 100,
unit,
lineName.type
]),
lineStyle: lineName,
yAxisIndex: unit.indexOf(units)
})
}
}
}
echartsData.value = {
title: {
text: zblist.value.filter(item => item.id == formInline.statisticalId)[0].name
},
tooltip: {
axisPointer: {
type: 'cross',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
formatter(params: any) {
const xname = params[0].value[0]
let str = `${xname}<br>`
params.forEach((el: any, index: any) => {
let marker = ''
if (el.value[3] == 'dashed') {
for (let i = 0; i < 3; i++) {
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
}
} else {
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
}
str += `${marker}${el.seriesName.split('(')[0]}${
el.value[1] != null
? el.value[1] + ' ' + (el.value[2] == 'null' ? '' : el.value[2])
: '-'
}<br>`
})
return str
}
},
legend: {
itemWidth: 20,
itemHeight: 20,
itemStyle: { opacity: 0 }, //去圆点
type: 'scroll', // 开启滚动分页
top: 25
// data: legend
},
grid: {
left: '20px',
right: '40px',
bottom: '50px',
top: '80px',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
color: color,
xAxis: {
name: '',
type: 'time',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
// boundaryGap: false,
// data: xAxis,
// axisLabel: {
// formatter: function (value: string) {
// return value.split(' ').join('\n')
// }
// },
// axisLine: {
// show: true,
// // symbol: ["none", "arrow"],
// lineStyle: {
// color: '#333'
// }
// }
},
yAxis: yAxis,
// [
// {
// name: '畸变率:(%)',
// type: 'value',
// // max: 10,
// min: min1,
// max: max1,
// splitNumber: 5,
// minInterval: 1,
// axisLine: {
// show: true,
// //symbol: ["none", "arrow"],
// lineStyle: {
// color: '#333'
// }
// }
// },
// {
// name: '电流:(A)',
// type: 'value',
// min: min,
// max: max,
// splitNumber: 5,
// minInterval: 1,
// splitLine: {
// show: false
// },
// axisLine: {
// show: true,
// //symbol: ["none", "arrow"],
// lineStyle: {
// color: '#333'
// }
// }
// }
// ],
options: {
series: series
}
}
} else {
echartsData.value = null
}
loading.value = false loading.value = false
}) })
.catch(() => { .catch(() => {
loading.value = false loading.value = false
}) })
} }
const setEchart = () => {
loading.value = true
let data = JSON.parse(JSON.stringify(dataLists.value))
if (data.length) {
let list = processingOfData(data, 'unit')
echartsData.value = {}
let legend: any[] = []
let xAxis: any[] = []
let yAxis: any[] = []
let series: any[] = []
let color: any[] = []
let title = ''
data.forEach(item => {
if (!xAxis.includes(item.time)) {
xAxis.push(item.time)
}
// if (!legend.includes(item.anotherName)) {
// legend.push(item.anotherName)
// }
})
let units = Object.keys(list)
// console.log('🚀 ~ .then ~ units:', units)
for (let unit in list) {
console.log('🚀 ~ .then ~ unit:', unit)
let [min, max] = yMethod(list[unit].map((item: any) => item.statisticalData))
yAxis.push({
name: unit == 'null' ? '' : unit,
type: 'value',
// max: 10,
min: min,
max: max,
// splitNumber: 5,
// minInterval: 1,
axisLine: {
show: true,
//symbol: ["none", "arrow"],
lineStyle: {
color: '#333'
}
}
})
// processingOfData(list[unit], 'anotherName')
let anotherList = processingOfData(list[unit], 'anotherName')
for (let k in anotherList) {
title = k
let lineName = lineStyle[Object.keys(anotherList).indexOf(k)]
let phaseList = processingOfData(anotherList[k], 'phase')
for (let j in phaseList) {
color.push(j == 'A' ? '#DAA520' : j == 'B' ? '#2E8B57' : j == 'C' ? '#A52a2a' : '#0000CC')
legend.push(
j == 'M' ? k : j == 'A' ? `A相_${k}` : j == 'B' ? `B相_${k}` : j == 'C' ? `C相_${k}` : j
)
series.push({
name: j == 'M' ? k : j == 'A' ? `A相_${k}` : j == 'B' ? `B相_${k}` : j == 'C' ? `C相_${k}` : j,
symbol: 'none',
smooth: true,
type: 'line',
// data: phaseList[j].map(item => [
// item.time,
// Math.floor(item.statisticalData * 100) / 100,
// unit,
// lineName.type
// ]),
data: timeControl.value
? completeTimeSeries(
phaseList[j].map(item => [
item.time,
Math.floor(item.statisticalData * 100) / 100,
unit,
lineName.type
])
)
: phaseList[j].map(item => [
item.time,
Math.floor(item.statisticalData * 100) / 100,
unit,
lineName.type
]),
lineStyle: lineName,
yAxisIndex: unit.indexOf(units)
})
}
}
}
echartsData.value = {
title: {
text: zblist.value.filter(item => item.id == formInline.statisticalId)[0].name
},
tooltip: {
axisPointer: {
type: 'cross',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
formatter(params: any) {
const xname = params[0].value[0]
let str = `${xname}<br>`
params.forEach((el: any, index: any) => {
let marker = ''
if (el.value[3] == 'dashed') {
for (let i = 0; i < 3; i++) {
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
}
} else {
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
}
str += `${marker}${el.seriesName.split('(')[0]}${
el.value[1] != null ? el.value[1] + ' ' + (el.value[2] == 'null' ? '' : el.value[2]) : '-'
}<br>`
})
return str
}
},
legend: {
itemWidth: 20,
itemHeight: 20,
itemStyle: { opacity: 0 }, //去圆点
type: 'scroll', // 开启滚动分页
top: 25
// data: legend
},
grid: {
left: '20px',
right: '40px',
bottom: '50px',
top: '80px',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
color: color,
xAxis: {
name: '',
type: 'time',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
// boundaryGap: false,
// data: xAxis,
// axisLabel: {
// formatter: function (value: string) {
// return value.split(' ').join('\n')
// }
// },
// axisLine: {
// show: true,
// // symbol: ["none", "arrow"],
// lineStyle: {
// color: '#333'
// }
// }
},
yAxis: yAxis,
// [
// {
// name: '畸变率:(%)',
// type: 'value',
// // max: 10,
// min: min1,
// max: max1,
// splitNumber: 5,
// minInterval: 1,
// axisLine: {
// show: true,
// //symbol: ["none", "arrow"],
// lineStyle: {
// color: '#333'
// }
// }
// },
// {
// name: '电流:(A)',
// type: 'value',
// min: min,
// max: max,
// splitNumber: 5,
// minInterval: 1,
// splitLine: {
// show: false
// },
// axisLine: {
// show: true,
// //symbol: ["none", "arrow"],
// lineStyle: {
// color: '#333'
// }
// }
// }
// ],
options: {
series: series
}
}
} else {
echartsData.value = null
}
loading.value = false
}
const setTimeControl = () => {
timeControl.value = !timeControl.value
setEchart()
}
const processingOfData = (data: any, type: string) => { const processingOfData = (data: any, type: string) => {
let groupedData: any = {} let groupedData: any = {}

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)

View File

@@ -8,21 +8,39 @@
<DatePicker ref="datePickerRef"></DatePicker> <DatePicker ref="datePickerRef"></DatePicker>
</el-form-item> </el-form-item>
<el-form-item label="统计指标" label-width="80px"> <el-form-item label="统计指标" label-width="80px">
<el-select multiple :multiple-limit="3" collapse-tags collapse-tags-tooltip <el-select
v-model="searchForm.index" placeholder="请选择统计指标" @change="onIndexChange($event)"> multiple
<el-option v-for="item in indexOptions" :key="item.id" :label="item.name" :multiple-limit="3"
:value="item.id"></el-option> collapse-tags
collapse-tags-tooltip
v-model="searchForm.index"
placeholder="请选择统计指标"
@change="onIndexChange($event)"
>
<el-option
v-for="item in indexOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio-group v-model="searchForm.dataLevel" :disabled="props?.TrendList?.lineType != 1" @change="init()"> <el-radio-group
v-model="searchForm.dataLevel"
:disabled="props?.TrendList?.lineType != 1"
@change="init()"
>
<el-radio-button label="一次值" value="Primary" /> <el-radio-button label="一次值" value="Primary" />
<el-radio-button label="二次值" value="Secondary" /> <el-radio-button label="二次值" value="Secondary" />
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="统计类型"> <el-form-item label="统计类型">
<el-select style="min-width: 120px !important" placeholder="请选择" v-model="searchForm.valueType"> <el-select
style="min-width: 120px !important"
placeholder="请选择"
v-model="searchForm.valueType"
>
<el-option value="max" label="最大值"></el-option> <el-option value="max" label="最大值"></el-option>
<el-option value="min" label="最小值"></el-option> <el-option value="min" label="最小值"></el-option>
<el-option value="avg" label="平均值"></el-option> <el-option value="avg" label="平均值"></el-option>
@@ -30,19 +48,37 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<div class="history_count" v-for="(item, index) in countData" :key="index" <div
v-show="item.countOptions.length != 0"> class="history_count"
<span class="mr12">{{item.name.includes('次数') ? item.name : item.name + '谐波次数'}}</span> v-for="(item, index) in countData"
<el-select v-model="item.count" @change="onCountChange($event, index)" placeholder="请选择谐波次数" :key="index"
style="width: 100px" class="mr20"> v-show="item.countOptions.length != 0"
<el-option v-for="vv in item.countOptions" :key="vv" :label="vv" >
:value="vv"></el-option> <span class="mr12">
{{ item.name.includes('次数') ? item.name : item.name + '谐波次数' }}
</span>
<el-select
v-model="item.count"
@change="onCountChange($event, index)"
placeholder="请选择谐波次数"
style="width: 100px"
class="mr20"
>
<el-option
v-for="vv in item.countOptions"
:key="vv"
:label="vv"
:value="vv"
></el-option>
</el-select> </el-select>
</div> </div>
</el-form-item> </el-form-item>
</template> </template>
<template #operation> <template #operation>
<el-button type="primary" icon="el-icon-Search" @click="init()">查询</el-button> <el-button type="primary" icon="el-icon-Search" @click="init()">查询</el-button>
<el-button :type="timeControl ? 'primary' : ''" icon="el-icon-Sort" @click="setTimeControl">
缺失数据
</el-button>
</template> </template>
</TableHeader> </TableHeader>
</div> </div>
@@ -59,7 +95,7 @@ import { ref, onMounted, watch } from 'vue'
import MyEchart from '@/components/echarts/MyEchart.vue' import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { queryStatistical } from '@/api/system-boot/csstatisticalset' import { queryStatistical } from '@/api/system-boot/csstatisticalset'
import { yMethod, exportCSV } from '@/utils/echartMethod' import { yMethod, exportCSV, completeTimeSeries } from '@/utils/echartMethod'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import { getTabsDataByType } from '@/api/cs-device-boot/EquipmentDelivery' import { getTabsDataByType } from '@/api/cs-device-boot/EquipmentDelivery'
import DatePicker from '@/components/form/datePicker/index.vue' import DatePicker from '@/components/form/datePicker/index.vue'
@@ -71,7 +107,7 @@ defineOptions({
}) })
const props = defineProps({ const props = defineProps({
TrendList: { TrendList: {
type: Array, type: Array
} }
}) })
// console.log("🚀 ~ props:", props.TrendList) // console.log("🚀 ~ props:", props.TrendList)
@@ -81,7 +117,7 @@ const voltageLevelList = dictData.getBasicData('Dev_Voltage_Stand')
//接线方式 //接线方式
const volConTypeList = dictData.getBasicData('Dev_Connect') const volConTypeList = dictData.getBasicData('Dev_Connect')
const num = ref(0) const num = ref(0)
const timeControl = ref(false)
//值类型 //值类型
const pageHeight = ref(mainHeight(290)) const pageHeight = ref(mainHeight(290))
const loading = ref(true) const loading = ref(true)
@@ -168,8 +204,8 @@ queryByCode(props?.TrendList?.lineType == 0 ? 'apf-harmonic' : 'portable-harmoni
}) })
init() init()
}) })
}) })
const chartsList = ref<any>([])
const activeName: any = ref() const activeName: any = ref()
const deviceData: any = ref([]) const deviceData: any = ref([])
//历史趋势devId //历史趋势devId
@@ -191,7 +227,7 @@ const getTrendRequest = (val: any) => {
//初始化趋势图 //初始化趋势图
const headerRef = ref() const headerRef = ref()
const datePickerRef = ref() const datePickerRef = ref()
const lineStyle = [{ type: 'solid', }, { type: 'dashed', }, { type: 'dotted', }] const lineStyle = [{ type: 'solid' }, { type: 'dashed' }, { type: 'dotted' }]
const init = async () => { const init = async () => {
loading.value = true loading.value = true
// 选择指标的时候切换legend内容和data数据 // 选择指标的时候切换legend内容和data数据
@@ -258,228 +294,9 @@ const init = async () => {
return return
} }
historyDataList.value = res.data historyDataList.value = res.data
let chartsList = JSON.parse(JSON.stringify(res.data)) chartsList.value = JSON.parse(JSON.stringify(res.data))
echartsData.value = {}
//icon图标替换legend图例
// y轴单位数组
let unitList: any = []
let groupedData = chartsList.reduce((acc: any, item: any) => {
let key = ''
if (item.phase == null) {
key = item.unit
} else {
key = item.anotherName
}
if (!acc[key]) {
acc[key] = []
}
acc[key].push(item)
return acc
}, {})
let result = Object.values(groupedData)
// console.log("🚀 ~ .then ~ result:", result)
// console.log("🚀 ~ .then ~ result:", result)
if (chartsList.length > 0) {
unitList = result.map((item: any) => {
return item[0].unit
})
}
echartsData.value = {
legend: {
itemWidth: 20,
itemHeight: 20,
itemStyle: { opacity: 0 },//去圆点
type: 'scroll', // 开启滚动分页
// orient: 'vertical', // 垂直排列
top: 5,
right: 70,
// width: 550,
// height: 50
},
grid: {
top: '80px',
},
tooltip: {
axisPointer: {
type: 'cross',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
formatter(params: any) {
const xname = params[0].value[0]
let str = `${xname}<br>`
params.forEach((el: any, index: any) => {
let marker = ''
if (el.value[3] == 'dashed') {
for (let i = 0; i < 3; i++) {
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
}
} else {
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
}
let unit = el.value[2] ? el.value[2] : ''
str += `${marker}${el.seriesName.split('(')[0]}${el.value[1]}${unit}
<br>`
})
return str
}
},
color: ['#DAA520', '#2E8B57', '#A52a2a', ...color],
xAxis: {
type: 'time',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
},
yAxis: [{}],
toolbox: {
featureProps: {
myTool1: {
show: true,
title: '下载csv',
icon: 'path://M588.8 551.253333V512H352v39.253333h236.373333z m0 78.933334v-39.253334H352v39.253334h236.373333z m136.533333 78.933333V334.933333l-157.866666-157.866666H273.066667A59.306667 59.306667 0 0 0 213.333333 236.373333v551.253334a59.306667 59.306667 0 0 0 59.306667 59.306666h274.773333v42.666667H853.333333v-180.48zM568.746667 234.666667l100.266666 100.693333h-81.066666a20.053333 20.053333 0 0 1-19.626667-20.053333z m-20.48 573.013333H273.066667a19.2 19.2 0 0 1-17.493334-19.626667V236.373333a19.2 19.2 0 0 1 19.626667-19.626666h256v98.133333a58.88 58.88 0 0 0 58.88 59.306667h96.426667v334.933333h-98.133334v-39.68H352v39.68h196.266667z m100.266666 23.04a37.973333 37.973333 0 0 1-32 15.786667 38.826667 38.826667 0 0 1-32.426666-15.786667 53.76 53.76 0 0 1-10.24-32.853333 42.666667 42.666667 0 0 1 42.666666-47.786667 35.84 35.84 0 0 1 37.546667 29.866667h-12.8a23.893333 23.893333 0 0 0-24.746667-19.2c-17.066667 0-29.013333 14.08-29.013333 35.84s11.52 37.546667 28.586667 37.546666a26.453333 26.453333 0 0 0 26.453333-25.6h12.8a39.253333 39.253333 0 0 1-7.253333 22.186667z m59.733334 15.786667a35.84 35.84 0 0 1-40.106667-34.56H682.666667a23.893333 23.893333 0 0 0 26.88 23.04c12.8 0 22.613333-6.4 22.613333-15.786667s-4.266667-11.52-14.506667-13.653333l-21.333333-5.12c-17.066667-4.266667-24.32-11.52-24.32-23.893334s12.8-26.453333 34.133333-26.453333a31.573333 31.573333 0 0 1 35.413334 30.293333h-13.653334a19.626667 19.626667 0 0 0-22.613333-18.773333c-12.8 0-20.48 5.12-20.48 12.8s5.12 11.093333 17.066667 13.653333l14.933333 2.986667a42.666667 42.666667 0 0 1 20.906667 8.96 23.893333 23.893333 0 0 1 7.68 17.92c-0.426667 17.066667-14.506667 28.16-37.12 28.16z m88.746666 0h-14.506666l-32.426667-92.16h14.08l19.626667 59.733333 6.4 20.053333c0-9.386667 3.413333-12.8 5.546666-20.053333l19.2-59.733333h14.08z',
onclick: e => {
// console.log("🚀 ~ init ~ echartsData.value:", echartsData.value.options.series.map(item => item.data))
let list = echartsData.value.options.series?.map((item: any) => item.data)
let dataList = list[0]?.map((item: any, index: any) => {
let value = [item[0], item[1]]
list.forEach((item1: any, index1: any) => {
if (index1 > 0) {
value.push(item1 && item1[index] ? item1[index][1] : null)
}
})
return value
})
exportCSV(
echartsData.value.options.series.map((item: any) => item.name),
dataList,
'历史趋势.csv'
)
}
}
}
},
options: {
series: []
}
}
// console.log("🚀 ~ unitList.forEach ~ unitList:", unitList)
if (chartsList.length > 0) {
let yData: any = []
echartsData.value.yAxis = []
let setList = [...new Set(unitList)];
setList.forEach((item: any, index: any) => {
if (index > 2) {
echartsData.value.grid.right = (index - 1) * 80
}
yData.push([])
let right = {
position: 'right',
offset: (index - 1) * 80
}
// console.log("🚀 ~ unitList.forEach ~ right.index:", index)
echartsData.value.yAxis.push({
name: item,
yAxisIndex: index,
splitNumber: 5,
minInterval: 1,
splitLine: {
show: false
},
...(index > 0 ? right : null)
})
})
// console.log("🚀 ~ result.forEach ~ result:", result)
// '电压负序分量', '电压正序分量', '电压零序分量'
let ABCName = [...new Set(chartsList.map((item: any) => { return item.anotherName == '电压负序分量' ? '电压不平衡' : item.anotherName == '电压正序分量' ? '电压不平衡' : item.anotherName == '电压零序分量' ? '电压不平衡' : item.anotherName }))];
// console.log("🚀 ~ .then ~ ABCName:", ABCName)
result.forEach((item: any, index: any) => {
let yMethodList: any = []
let ABCList = Object.values(
item.reduce((acc, item) => {
let key = ''
if (item.phase == null) {
key = item.anotherName
} else {
key = item.phase
}
if (!acc[key]) {
acc[key] = []
}
acc[key].push(item)
return acc
}, {})
)
// console.log("🚀 ~ ABCList.forEach ~ ABCList:", ABCList)
ABCList.forEach((kk: any) => {
let colorName = kk[0].phase?.charAt(0).toUpperCase()
let lineS = ABCName.findIndex(item => item === (kk[0].anotherName == '电压负序分量' ? '电压不平衡' : kk[0].anotherName == '电压正序分量' ? '电压不平衡' : kk[0].anotherName == '电压零序分量' ? '电压不平衡' : kk[0].anotherName));
let seriesList: any = []
kk.forEach((cc: any) => {
if (cc.statisticalData !== null) {
yData[setList.indexOf(kk[0].unit)].push(cc.statisticalData?.toFixed(2))
}
seriesList.push([cc.time, cc.statisticalData?.toFixed(2), cc.unit, lineStyle[lineS].type])
})
// console.log(kk);
echartsData.value.options.series.push({
name: kk[0].phase
? kk[0].phase + '相' + kk[0].anotherName
: kk[0].anotherName,
type: 'line',
smooth: true,
color: colorName == 'A' ? '#DAA520' : colorName == 'B' ? '#2E8B57' : colorName == 'C' ? '#A52a2a' : '',
symbol: 'none',
data: seriesList,
lineStyle: lineStyle[lineS],
yAxisIndex: setList.indexOf(kk[0].unit)
})
})
// let [min, max] = yMethod(yMethodList)
// echartsData.value.yAxis[index].min = min
// echartsData.value.yAxis[index].max = max
})
yData.forEach((item: any, index: any) => {
let [min, max] = yMethod(item)
echartsData.value.yAxis[index].min = min
echartsData.value.yAxis[index].max = max
})
// console.log("🚀 ~ result.forEach ~ echartsData.value:", echartsData.value)
}
loading.value = false loading.value = false
setEchart()
} }
}) })
.catch(error => { .catch(error => {
@@ -490,6 +307,253 @@ const init = async () => {
} }
} }
} }
const setEchart = () => {
loading.value = true
echartsData.value = {}
//icon图标替换legend图例
// y轴单位数组
let unitList: any = []
let groupedData = chartsList.value.reduce((acc: any, item: any) => {
let key = ''
if (item.phase == null) {
key = item.unit
} else {
key = item.anotherName
}
if (!acc[key]) {
acc[key] = []
}
acc[key].push(item)
return acc
}, {})
let result = Object.values(groupedData)
// console.log("🚀 ~ .then ~ result:", result)
// console.log("🚀 ~ .then ~ result:", result)
if (chartsList.value.length > 0) {
unitList = result.map((item: any) => {
return item[0].unit
})
}
echartsData.value = {
legend: {
itemWidth: 20,
itemHeight: 20,
itemStyle: { opacity: 0 }, //去圆点
type: 'scroll', // 开启滚动分页
// orient: 'vertical', // 垂直排列
top: 5,
right: 70
// width: 550,
// height: 50
},
grid: {
top: '80px'
},
tooltip: {
axisPointer: {
type: 'cross',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
formatter(params: any) {
const xname = params[0].value[0]
let str = `${xname}<br>`
params.forEach((el: any, index: any) => {
let marker = ''
if (el.value[3] == 'dashed') {
for (let i = 0; i < 3; i++) {
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
}
} else {
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
}
let unit = el.value[2] ? el.value[2] : ''
str += `${marker}${el.seriesName.split('(')[0]}${el.value[1]}${unit}
<br>`
})
return str
}
},
color: ['#DAA520', '#2E8B57', '#A52a2a', ...color],
xAxis: {
type: 'time',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
},
yAxis: [{}],
toolbox: {
featureProps: {
myTool1: {
show: true,
title: '下载csv',
icon: 'path://M588.8 551.253333V512H352v39.253333h236.373333z m0 78.933334v-39.253334H352v39.253334h236.373333z m136.533333 78.933333V334.933333l-157.866666-157.866666H273.066667A59.306667 59.306667 0 0 0 213.333333 236.373333v551.253334a59.306667 59.306667 0 0 0 59.306667 59.306666h274.773333v42.666667H853.333333v-180.48zM568.746667 234.666667l100.266666 100.693333h-81.066666a20.053333 20.053333 0 0 1-19.626667-20.053333z m-20.48 573.013333H273.066667a19.2 19.2 0 0 1-17.493334-19.626667V236.373333a19.2 19.2 0 0 1 19.626667-19.626666h256v98.133333a58.88 58.88 0 0 0 58.88 59.306667h96.426667v334.933333h-98.133334v-39.68H352v39.68h196.266667z m100.266666 23.04a37.973333 37.973333 0 0 1-32 15.786667 38.826667 38.826667 0 0 1-32.426666-15.786667 53.76 53.76 0 0 1-10.24-32.853333 42.666667 42.666667 0 0 1 42.666666-47.786667 35.84 35.84 0 0 1 37.546667 29.866667h-12.8a23.893333 23.893333 0 0 0-24.746667-19.2c-17.066667 0-29.013333 14.08-29.013333 35.84s11.52 37.546667 28.586667 37.546666a26.453333 26.453333 0 0 0 26.453333-25.6h12.8a39.253333 39.253333 0 0 1-7.253333 22.186667z m59.733334 15.786667a35.84 35.84 0 0 1-40.106667-34.56H682.666667a23.893333 23.893333 0 0 0 26.88 23.04c12.8 0 22.613333-6.4 22.613333-15.786667s-4.266667-11.52-14.506667-13.653333l-21.333333-5.12c-17.066667-4.266667-24.32-11.52-24.32-23.893334s12.8-26.453333 34.133333-26.453333a31.573333 31.573333 0 0 1 35.413334 30.293333h-13.653334a19.626667 19.626667 0 0 0-22.613333-18.773333c-12.8 0-20.48 5.12-20.48 12.8s5.12 11.093333 17.066667 13.653333l14.933333 2.986667a42.666667 42.666667 0 0 1 20.906667 8.96 23.893333 23.893333 0 0 1 7.68 17.92c-0.426667 17.066667-14.506667 28.16-37.12 28.16z m88.746666 0h-14.506666l-32.426667-92.16h14.08l19.626667 59.733333 6.4 20.053333c0-9.386667 3.413333-12.8 5.546666-20.053333l19.2-59.733333h14.08z',
onclick: e => {
// console.log("🚀 ~ init ~ echartsData.value:", echartsData.value.options.series.map(item => item.data))
let list = echartsData.value.options.series?.map((item: any) => item.data)
let dataList = list[0]?.map((item: any, index: any) => {
let value = [item[0], item[1]]
list.forEach((item1: any, index1: any) => {
if (index1 > 0) {
value.push(item1 && item1[index] ? item1[index][1] : null)
}
})
return value
})
exportCSV(
echartsData.value.options.series.map((item: any) => item.name),
dataList,
'历史趋势.csv'
)
}
}
}
},
options: {
series: []
}
}
// console.log("🚀 ~ unitList.forEach ~ unitList:", unitList)
if (chartsList.value.length > 0) {
let yData: any = []
echartsData.value.yAxis = []
let setList = [...new Set(unitList)]
setList.forEach((item: any, index: any) => {
if (index > 2) {
echartsData.value.grid.right = (index - 1) * 80
}
yData.push([])
let right = {
position: 'right',
offset: (index - 1) * 80
}
// console.log("🚀 ~ unitList.forEach ~ right.index:", index)
echartsData.value.yAxis.push({
name: item,
yAxisIndex: index,
splitNumber: 5,
minInterval: 1,
splitLine: {
show: false
},
...(index > 0 ? right : null)
})
})
// console.log("🚀 ~ result.forEach ~ result:", result)
// '电压负序分量', '电压正序分量', '电压零序分量'
let ABCName = [
...new Set(
chartsList.value.map((item: any) => {
return item.anotherName == '电压负序分量'
? '电压不平衡'
: item.anotherName == '电压正序分量'
? '电压不平衡'
: item.anotherName == '电压零序分量'
? '电压不平衡'
: item.anotherName
})
)
]
// console.log("🚀 ~ .then ~ ABCName:", ABCName)
result.forEach((item: any, index: any) => {
let yMethodList: any = []
let ABCList = Object.values(
item.reduce((acc, item) => {
let key = ''
if (item.phase == null) {
key = item.anotherName
} else {
key = item.phase
}
if (!acc[key]) {
acc[key] = []
}
acc[key].push(item)
return acc
}, {})
)
// console.log("🚀 ~ ABCList.forEach ~ ABCList:", ABCList)
ABCList.forEach((kk: any) => {
let colorName = kk[0].phase?.charAt(0).toUpperCase()
let lineS = ABCName.findIndex(
item =>
item ===
(kk[0].anotherName == '电压负序分量'
? '电压不平衡'
: kk[0].anotherName == '电压正序分量'
? '电压不平衡'
: kk[0].anotherName == '电压零序分量'
? '电压不平衡'
: kk[0].anotherName)
)
let seriesList: any = []
kk.forEach((cc: any) => {
if (cc.statisticalData !== null) {
yData[setList.indexOf(kk[0].unit)].push(cc.statisticalData?.toFixed(2))
}
seriesList.push([cc.time, cc.statisticalData?.toFixed(2), cc.unit, lineStyle[lineS].type])
})
// console.log(kk);
echartsData.value.options.series.push({
name: kk[0].phase ? kk[0].phase + '相' + kk[0].anotherName : kk[0].anotherName,
type: 'line',
smooth: true,
color:
colorName == 'A' ? '#DAA520' : colorName == 'B' ? '#2E8B57' : colorName == 'C' ? '#A52a2a' : '',
symbol: 'none',
// data: seriesList,
data: timeControl.value ? completeTimeSeries(seriesList) : seriesList,
lineStyle: lineStyle[lineS],
yAxisIndex: setList.indexOf(kk[0].unit)
})
})
// let [min, max] = yMethod(yMethodList)
// echartsData.value.yAxis[index].min = min
// echartsData.value.yAxis[index].max = max
})
yData.forEach((item: any, index: any) => {
let [min, max] = yMethod(item)
echartsData.value.yAxis[index].min = min
echartsData.value.yAxis[index].max = max
})
// console.log("🚀 ~ result.forEach ~ echartsData.value:", echartsData.value)
}
loading.value = false
}
const setTimeControl = () => {
timeControl.value = !timeControl.value
setEchart()
}
const selectChange = (flag: boolean) => { const selectChange = (flag: boolean) => {
if (flag) { if (flag) {
pageHeight.value = mainHeight(332) pageHeight.value = mainHeight(332)
@@ -600,7 +664,7 @@ const handleExport = async () => {
: (strs += list[index].data[indexs] + ',') : (strs += list[index].data[indexs] + ',')
}) })
if (count == 0 && xAxis[indexs]) { if (count == 0 && xAxis[indexs]) {
csv += `${xAxis[indexs]},` + strs + '\n' csv += '\u200B' + `${xAxis[indexs]},` + strs + '\n'
} }
}) })
return csv return csv
@@ -639,7 +703,6 @@ const formatCountOptions = () => {
countData.value.push(vv) countData.value.push(vv)
} }
}) })
}) })
// list.map((item: any, index: any) => { // list.map((item: any, index: any) => {
// if (!countData.value[index]) { // if (!countData.value[index]) {
@@ -702,9 +765,9 @@ const onIndexChange = (val: any) => {
num.value += 1 num.value += 1
let pp: any = [] let pp: any = []
indexOptions.value.forEach((item: any) => { indexOptions.value.forEach((item: any) => {
const filteredResult = val.filter(vv => item.id == vv); const filteredResult = val.filter(vv => item.id == vv)
if (filteredResult.length > 0) { if (filteredResult.length > 0) {
pp.push(filteredResult[0]); pp.push(filteredResult[0])
} }
}) })
searchForm.value.index = pp searchForm.value.index = pp

View File

@@ -1,9 +1,14 @@
<template> <template>
<div class="default-main device-manage" :style="{ height: pageHeight.height }"> <div class="default-main device-manage" :style="{ height: pageHeight.height }">
<!-- @node-change="nodeClick" --> <!-- @node-change="nodeClick" -->
<schemeTree @node-change="nodeClick" @node-click="nodeClick" @init="nodeClick" @onAdd="onAdd" @bind="bind" <schemeTree
ref="schemeTreeRef"></schemeTree> @node-change="nodeClick"
@node-click="nodeClick"
@init="nodeClick"
@onAdd="onAdd"
@bind="bind"
ref="schemeTreeRef"
></schemeTree>
<div class="device-manage-right" v-if="deviceData"> <div class="device-manage-right" v-if="deviceData">
<el-descriptions title="方案信息" :column="2" border> <el-descriptions title="方案信息" :column="2" border>
<!-- <template #extra> <!-- <template #extra>
@@ -23,8 +28,12 @@
<p>测试项信息</p> <p>测试项信息</p>
</div> --> </div> -->
<el-tabs v-model.trim="activeName" type="border-card" @tab-change="handleClickTabs"> <el-tabs v-model.trim="activeName" type="border-card" @tab-change="handleClickTabs">
<el-tab-pane v-for="(item, index) in deviceData?.records" :label="item.itemName" <el-tab-pane
:name="item.id" :key="index"> v-for="(item, index) in deviceData?.records"
:label="item.itemName"
:name="item.id"
:key="index"
>
<template #label> <template #label>
<span class="custom-tabs-label"> <span class="custom-tabs-label">
<el-icon> <el-icon>
@@ -110,11 +119,22 @@
<TableHeader :showSearch="false" ref="tableHeaderRef" @selectChange="selectChange"> <TableHeader :showSearch="false" ref="tableHeaderRef" @selectChange="selectChange">
<template v-slot:select :key="num"> <template v-slot:select :key="num">
<el-form-item for="-" label="统计指标"> <el-form-item for="-" label="统计指标">
<el-select style="min-width: 200px" collapse-tags collapse-tags-tooltip <el-select
v-model.trim="searchForm.index" placeholder="请选择统计指标" style="min-width: 200px"
@change="onIndexChange($event)" multiple :multiple-limit="3"> collapse-tags
<el-option v-for="item in indexOptions" :key="item.id" collapse-tags-tooltip
:label="item.name" :value="item.id"></el-option> v-model.trim="searchForm.index"
placeholder="请选择统计指标"
@change="onIndexChange($event)"
multiple
:multiple-limit="3"
>
<el-option
v-for="item in indexOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
@@ -125,26 +145,53 @@
<el-radio-group v-model.trim="searchForm.dataLevel" @change="init(true)"> <el-radio-group v-model.trim="searchForm.dataLevel" @change="init(true)">
<el-radio-button label="一次值" value="Primary" /> <el-radio-button label="一次值" value="Primary" />
<el-radio-button label="二次值" value="Secondary" /> <el-radio-button label="二次值" value="Secondary" />
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item for="-" label="统计类型" label-width="80px"> <el-form-item for="-" label="统计类型" label-width="80px">
<el-select style="width: 120px" v-model.trim="searchForm.type" <el-select
placeholder="请选择值类型"> style="width: 120px"
<el-option v-for="item in typeOptions" :key="item.id" :label="item.name" v-model.trim="searchForm.type"
:value="item.id"></el-option> placeholder="请选择值类型"
>
<el-option
v-for="item in typeOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<div for="-" v-for="(item, index) in countData" :key="index" <div
for="-"
v-show="item.countOptions.length != 0"> v-for="(item, index) in countData"
<span class="mr12">{{item.name.includes('次数') ? item.name : item.name.includes('幅值') ? item.name.slice(0, -2) + '次数' : item.name + '谐波次数'}}</span> :key="index"
<el-select v-model.trim="item.count" class="mr20" collapse-tags collapse-tags-tooltip v-show="item.countOptions.length != 0"
placeholder="请选择谐波次数" style="width: 120px"> >
<el-option v-for="vv in item.countOptions" :key="vv" :label="vv" <span class="mr12">
:value="vv"></el-option> {{
item.name.includes('次数')
? item.name
: item.name.includes('幅值')
? item.name.slice(0, -2) + '次数'
: item.name + '谐波次数'
}}
</span>
<el-select
v-model.trim="item.count"
class="mr20"
collapse-tags
collapse-tags-tooltip
placeholder="请选择谐波次数"
style="width: 120px"
>
<el-option
v-for="vv in item.countOptions"
:key="vv"
:label="vv"
:value="vv"
></el-option>
</el-select> </el-select>
</div> </div>
</el-form-item> </el-form-item>
@@ -153,28 +200,43 @@
<!-- <el-button type="primary" icon="el-icon-Download" @click="handleExport"> <!-- <el-button type="primary" icon="el-icon-Download" @click="handleExport">
数据导出 数据导出
</el-button> --> </el-button> -->
<el-button type="primary" icon="el-icon-Search" <el-button type="primary" icon="el-icon-Search" @click="init(true)">
@click="init(true)">查询</el-button> 查询
</el-button>
<!-- <el-button
:type="timeControl ? 'primary' : ''"
icon="el-icon-Sort"
@click="setTimeControl"
>
缺失数据
</el-button> -->
</template> </template>
</TableHeader> </TableHeader>
</div> </div>
<!-- <div class="history_title"> <!-- <div class="history_title">
<p>{{ chartTitle }}</p> <p>{{ chartTitle }}</p>
</div> --> </div> -->
<div class="history_chart mt5" v-loading="loading" :style="EcharHeight" <div
:key="EcharHeight.height" ref="chartRef"> class="history_chart mt5"
<MyEchart ref="historyChart" v-if="echartsData" :isExport="true" v-loading="loading"
:options="echartsData" /> :style="EcharHeight"
:key="EcharHeight.height"
ref="chartRef"
>
<MyEchart
ref="historyChart"
v-if="echartsData"
:isExport="true"
:options="echartsData"
/>
</div> </div>
</div> </div>
<el-empty :style="EcharHeight" v-else description="未绑定数据" /> <el-empty :style="EcharHeight" v-else description="未绑定数据" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="暂态数据" name="1"> <el-tab-pane label="暂态数据" name="1">
<transient :activeName='activeName' ref="transientRef" :activeColName="activeColName" /> <transient :activeName="activeName" ref="transientRef" :activeColName="activeColName" />
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
</div> </div>
<el-empty v-else description="请选择设备" class="device-manage-right" /> <el-empty v-else description="请选择设备" class="device-manage-right" />
@@ -193,8 +255,8 @@ import MyEchart from '@/components/echarts/MyEchart.vue'
import { getTestRecordInfo, getHistoryTrend } from '@/api/cs-device-boot/planData' import { getTestRecordInfo, getHistoryTrend } from '@/api/cs-device-boot/planData'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { queryStatistical } from '@/api/system-boot/csstatisticalset' import { queryStatistical } from '@/api/system-boot/csstatisticalset'
import { TrendCharts, Plus, Platform, } from '@element-plus/icons-vue' import { TrendCharts, Plus, Platform } from '@element-plus/icons-vue'
import { yMethod } from '@/utils/echartMethod' import { yMethod, completeTimeSeries } from '@/utils/echartMethod'
import { color, gradeColor3 } from '@/components/echarts/color' import { color, gradeColor3 } from '@/components/echarts/color'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
@@ -208,6 +270,8 @@ const childTab = ref('0')
const num = ref(0) const num = ref(0)
const config = useConfig() const config = useConfig()
const transientRef = ref() const transientRef = ref()
const timeControl = ref(false)
const chartsList = ref([])
color[0] = config.layout.elementUiPrimary[0] color[0] = config.layout.elementUiPrimary[0]
//电压等级 //电压等级
const voltageLevelList = dictData.getBasicData('Dev_Voltage_Stand') const voltageLevelList = dictData.getBasicData('Dev_Voltage_Stand')
@@ -330,16 +394,16 @@ const nodeClick = async (e: anyObj) => {
if (res.data.records.length == 1) { if (res.data.records.length == 1) {
activeName.value = res.data.records[0].id activeName.value = res.data.records[0].id
} else { } else {
for (const item of res.data.records) { for (const item of res.data.records) {
if (item.id == e.id) { if (item.id == e.id) {
activeName.value = item.id; activeName.value = item.id
break; // 找到匹配项后停止遍历 break // 找到匹配项后停止遍历
} }
} }
// 如果没有找到匹配项默认设置为第一个元素的id // 如果没有找到匹配项默认设置为第一个元素的id
if (activeName.value !== e.id) { // 假设e.id是一个用于比较的初始值表示未找到匹配项 if (activeName.value !== e.id) {
activeName.value = res.data.records[0].id; // 假设e.id是一个用于比较的初始值表示未找到匹配项
activeName.value = res.data.records[0].id
} }
} }
@@ -369,9 +433,9 @@ const onIndexChange = (val: any) => {
num.value += 1 num.value += 1
let pp: any = [] let pp: any = []
indexOptions.value.forEach((item: any) => { indexOptions.value.forEach((item: any) => {
const filteredResult = val.filter(vv => item.id == vv); const filteredResult = val.filter(vv => item.id == vv)
if (filteredResult.length > 0) { if (filteredResult.length > 0) {
pp.push(filteredResult[0]); pp.push(filteredResult[0])
} }
}) })
searchForm.value.index = pp searchForm.value.index = pp
@@ -432,7 +496,7 @@ const range = (start: any, end: any, step: any) => {
return Array.from({ length: (end - start) / step + 1 }, (_, i) => start + i * step) return Array.from({ length: (end - start) / step + 1 }, (_, i) => start + i * step)
} }
const colors = ['#DAA520', '#2E8B57', '#A52a2a'] const colors = ['#DAA520', '#2E8B57', '#A52a2a']
const lineStyle = [{ type: 'solid', }, { type: 'dashed', }, { type: 'dotted', }] const lineStyle = [{ type: 'solid' }, { type: 'dashed' }, { type: 'dotted' }]
const titleList: any = ref('') const titleList: any = ref('')
const init = (flag: boolean) => { const init = (flag: boolean) => {
@@ -451,7 +515,6 @@ const init = (flag: boolean) => {
}) })
}) })
//选择的指标使用方法处理 //选择的指标使用方法处理
formatCountOptions() formatCountOptions()
//查询历史趋势 //查询历史趋势
@@ -471,7 +534,7 @@ const init = (flag: boolean) => {
middleTitle = '' middleTitle = ''
} }
let indexList = searchForm.value.index let indexList = searchForm.value.index
chartTitle.value = ''//deviceData.value.itemName + '_' + middleTitle + '_' chartTitle.value = '' //deviceData.value.itemName + '_' + middleTitle + '_'
indexList.map((item: any, indexs: any) => { indexList.map((item: any, indexs: any) => {
indexOptions.value.map((vv: any) => { indexOptions.value.map((vv: any) => {
if (vv.id == item) { if (vv.id == item) {
@@ -494,9 +557,6 @@ const init = (flag: boolean) => {
} }
}) })
let obj = { let obj = {
devId: historyDevId.value, devId: historyDevId.value,
list: lists, list: lists,
@@ -508,7 +568,6 @@ const init = (flag: boolean) => {
return return
} }
if (flag) { if (flag) {
getDeviceList({ getDeviceList({
id: historyDevId.value, id: historyDevId.value,
isTrueFlag: 1 isTrueFlag: 1
@@ -524,222 +583,11 @@ const init = (flag: boolean) => {
.then((res: any) => { .then((res: any) => {
if (res.code === 'A0000') { if (res.code === 'A0000') {
historyDataList.value = res.data historyDataList.value = res.data
let chartsList = JSON.parse(JSON.stringify(res.data))
echartsData.value = {}
//icon图标替换legend图例
// y轴单位数组
let unitList: any = []
let groupedData = chartsList.reduce((acc: any, item: any) => {
let key = ''
if (item.phase == null) {
key = item.unit
} else {
key = item.anotherName
}
if (!acc[key]) {
acc[key] = []
}
acc[key].push(item)
return acc
}, {})
let result = Object.values(groupedData)
if (chartsList.length > 0) {
unitList = result.map((item: any) => {
return item[0].unit
})
}
echartsData.value = {
// title: {
// text: chartTitle.value,
// left: '0',
// textStyle: {
// color: '#000',
// fontSize: '16'
// },
// },
toolbox: {
featureProps: {
myTool1: {
show: true,
title: '下载csv',
icon: 'path://M588.8 551.253333V512H352v39.253333h236.373333z m0 78.933334v-39.253334H352v39.253334h236.373333z m136.533333 78.933333V334.933333l-157.866666-157.866666H273.066667A59.306667 59.306667 0 0 0 213.333333 236.373333v551.253334a59.306667 59.306667 0 0 0 59.306667 59.306666h274.773333v42.666667H853.333333v-180.48zM568.746667 234.666667l100.266666 100.693333h-81.066666a20.053333 20.053333 0 0 1-19.626667-20.053333z m-20.48 573.013333H273.066667a19.2 19.2 0 0 1-17.493334-19.626667V236.373333a19.2 19.2 0 0 1 19.626667-19.626666h256v98.133333a58.88 58.88 0 0 0 58.88 59.306667h96.426667v334.933333h-98.133334v-39.68H352v39.68h196.266667z m100.266666 23.04a37.973333 37.973333 0 0 1-32 15.786667 38.826667 38.826667 0 0 1-32.426666-15.786667 53.76 53.76 0 0 1-10.24-32.853333 42.666667 42.666667 0 0 1 42.666666-47.786667 35.84 35.84 0 0 1 37.546667 29.866667h-12.8a23.893333 23.893333 0 0 0-24.746667-19.2c-17.066667 0-29.013333 14.08-29.013333 35.84s11.52 37.546667 28.586667 37.546666a26.453333 26.453333 0 0 0 26.453333-25.6h12.8a39.253333 39.253333 0 0 1-7.253333 22.186667z m59.733334 15.786667a35.84 35.84 0 0 1-40.106667-34.56H682.666667a23.893333 23.893333 0 0 0 26.88 23.04c12.8 0 22.613333-6.4 22.613333-15.786667s-4.266667-11.52-14.506667-13.653333l-21.333333-5.12c-17.066667-4.266667-24.32-11.52-24.32-23.893334s12.8-26.453333 34.133333-26.453333a31.573333 31.573333 0 0 1 35.413334 30.293333h-13.653334a19.626667 19.626667 0 0 0-22.613333-18.773333c-12.8 0-20.48 5.12-20.48 12.8s5.12 11.093333 17.066667 13.653333l14.933333 2.986667a42.666667 42.666667 0 0 1 20.906667 8.96 23.893333 23.893333 0 0 1 7.68 17.92c-0.426667 17.066667-14.506667 28.16-37.12 28.16z m88.746666 0h-14.506666l-32.426667-92.16h14.08l19.626667 59.733333 6.4 20.053333c0-9.386667 3.413333-12.8 5.546666-20.053333l19.2-59.733333h14.08z',
onclick: e => {
handleExport()
}
}
}
},
legend: {
itemWidth: 20,
itemHeight: 20,
itemStyle: { opacity: 0 },//去圆点
type: 'scroll', // 开启滚动分页
right: 70,
// width: 550,
// height: 50
},
grid: {
top: '80px',
},
tooltip: {
axisPointer: {
type: 'cross',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
formatter(params: any) {
const xname = params[0].value[0]
let str = `${xname}<br>`
params.forEach((el: any, index: any) => {
let marker = ''
if (el.value[3] == 'dashed') {
for (let i = 0; i < 3; i++) {
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
}
} else {
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
}
str += `${marker}${el.seriesName.split('(')[0]}${el.value[1] ? el.value[1] + ' ' + (el.value[2] || '') : '-'
}<br>`
})
return str
}
},
// color: ['#DAA520', '#2E8B57', '#A52a2a', ...color],
xAxis: {
type: 'time',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
},
yAxis: [{}],
options: {
series: []
}
}
if (chartsList.length > 0) {
let yData: any = []
echartsData.value.yAxis = []
let setList = [...new Set(unitList)];
setList.forEach((item: any, index: any) => {
if (index > 2) {
echartsData.value.grid.right = (index - 1) * 80
}
yData.push([])
let right = {
position: 'right',
offset: (index - 1) * 80
}
echartsData.value.yAxis.push({
name: item,
yAxisIndex: index,
splitNumber: 5,
minInterval: 1,
splitLine: {
show: false
},
...(index > 0 ? right : null)
})
})
// console.log("🚀 ~ result.forEach ~ result:", result)
let ABCName = [...new Set(chartsList.map((item: any) => { return item.anotherName == '电压负序分量' ? '电压不平衡' : item.anotherName == '电压正序分量' ? '电压不平衡' : item.anotherName == '电压零序分量' ? '电压不平衡' : item.anotherName }))];
result.forEach((item: any, index: any) => {
let yMethodList: any = []
let ABCList = Object.values(
item.reduce((acc, item) => {
let key = ''
if (item.phase == null) {
key = item.anotherName
} else {
key = item.phase
}
if (!acc[key]) {
acc[key] = []
}
acc[key].push(item)
return acc
}, {})
)
ABCList.forEach((kk: any) => {
let colorName = kk[0].phase?.charAt(0).toUpperCase()
let lineS = ABCName.findIndex(item => item === (kk[0].anotherName == '电压负序分量' ? '电压不平衡' : kk[0].anotherName == '电压正序分量' ? '电压不平衡' : kk[0].anotherName == '电压零序分量' ? '电压不平衡' : kk[0].anotherName));
let seriesList: any = []
kk.forEach((cc: any) => {
if (cc.statisticalData !== null) {
yData[setList.indexOf(kk[0].unit)].push(cc.statisticalData?.toFixed(2))
}
seriesList.push([cc.time, cc.statisticalData?.toFixed(2), cc.unit, lineStyle[lineS].type])
})
echartsData.value.options.series.push({
name: kk[0].phase
? kk[0].phase + '相' + kk[0].anotherName
: kk[0].anotherName,
type: 'line',
color: colorName == 'A' ? '#DAA520' : colorName == 'B' ? '#2E8B57' : colorName == 'C' ? '#A52a2a' : '',
smooth: true,
symbol: 'none',
lineStyle: lineStyle[lineS],
data: seriesList,
yAxisIndex: setList.indexOf(kk[0].unit)
})
})
// let [min, max] = yMethod(yMethodList)
// echartsData.value.yAxis[index].min = min
// echartsData.value.yAxis[index].max = max
})
yData.forEach((item: any, index: any) => {
let [min, max] = yMethod(item)
echartsData.value.yAxis[index].min = min
echartsData.value.yAxis[index].max = max
})
}
chartsList.value = JSON.parse(JSON.stringify(res.data))
loading.value = false loading.value = false
setEchart()
} }
}) })
.catch(error => { .catch(error => {
@@ -750,6 +598,236 @@ const init = (flag: boolean) => {
} }
} }
} }
const setEchart = () => {
loading.value = true
echartsData.value = {}
//icon图标替换legend图例
// y轴单位数组
let unitList: any = []
let groupedData = chartsList.value.reduce((acc: any, item: any) => {
let key = ''
if (item.phase == null) {
key = item.unit
} else {
key = item.anotherName
}
if (!acc[key]) {
acc[key] = []
}
acc[key].push(item)
return acc
}, {})
let result = Object.values(groupedData)
if (chartsList.value.length > 0) {
unitList = result.map((item: any) => {
return item[0].unit
})
}
echartsData.value = {
// title: {
// text: chartTitle.value,
// left: '0',
// textStyle: {
// color: '#000',
// fontSize: '16'
// },
// },
toolbox: {
featureProps: {
myTool1: {
show: true,
title: '下载csv',
icon: 'path://M588.8 551.253333V512H352v39.253333h236.373333z m0 78.933334v-39.253334H352v39.253334h236.373333z m136.533333 78.933333V334.933333l-157.866666-157.866666H273.066667A59.306667 59.306667 0 0 0 213.333333 236.373333v551.253334a59.306667 59.306667 0 0 0 59.306667 59.306666h274.773333v42.666667H853.333333v-180.48zM568.746667 234.666667l100.266666 100.693333h-81.066666a20.053333 20.053333 0 0 1-19.626667-20.053333z m-20.48 573.013333H273.066667a19.2 19.2 0 0 1-17.493334-19.626667V236.373333a19.2 19.2 0 0 1 19.626667-19.626666h256v98.133333a58.88 58.88 0 0 0 58.88 59.306667h96.426667v334.933333h-98.133334v-39.68H352v39.68h196.266667z m100.266666 23.04a37.973333 37.973333 0 0 1-32 15.786667 38.826667 38.826667 0 0 1-32.426666-15.786667 53.76 53.76 0 0 1-10.24-32.853333 42.666667 42.666667 0 0 1 42.666666-47.786667 35.84 35.84 0 0 1 37.546667 29.866667h-12.8a23.893333 23.893333 0 0 0-24.746667-19.2c-17.066667 0-29.013333 14.08-29.013333 35.84s11.52 37.546667 28.586667 37.546666a26.453333 26.453333 0 0 0 26.453333-25.6h12.8a39.253333 39.253333 0 0 1-7.253333 22.186667z m59.733334 15.786667a35.84 35.84 0 0 1-40.106667-34.56H682.666667a23.893333 23.893333 0 0 0 26.88 23.04c12.8 0 22.613333-6.4 22.613333-15.786667s-4.266667-11.52-14.506667-13.653333l-21.333333-5.12c-17.066667-4.266667-24.32-11.52-24.32-23.893334s12.8-26.453333 34.133333-26.453333a31.573333 31.573333 0 0 1 35.413334 30.293333h-13.653334a19.626667 19.626667 0 0 0-22.613333-18.773333c-12.8 0-20.48 5.12-20.48 12.8s5.12 11.093333 17.066667 13.653333l14.933333 2.986667a42.666667 42.666667 0 0 1 20.906667 8.96 23.893333 23.893333 0 0 1 7.68 17.92c-0.426667 17.066667-14.506667 28.16-37.12 28.16z m88.746666 0h-14.506666l-32.426667-92.16h14.08l19.626667 59.733333 6.4 20.053333c0-9.386667 3.413333-12.8 5.546666-20.053333l19.2-59.733333h14.08z',
onclick: e => {
handleExport()
}
}
}
},
legend: {
itemWidth: 20,
itemHeight: 20,
itemStyle: { opacity: 0 }, //去圆点
type: 'scroll', // 开启滚动分页
right: 70
// width: 550,
// height: 50
},
grid: {
top: '80px'
},
tooltip: {
axisPointer: {
type: 'cross',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
formatter(params: any) {
const xname = params[0].value[0]
let str = `${xname}<br>`
params.forEach((el: any, index: any) => {
let marker = ''
if (el.value[3] == 'dashed') {
for (let i = 0; i < 3; i++) {
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
}
} else {
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
}
str += `${marker}${el.seriesName.split('(')[0]}${
el.value[1] ? el.value[1] + ' ' + (el.value[2] || '') : '-'
}<br>`
})
return str
}
},
// color: ['#DAA520', '#2E8B57', '#A52a2a', ...color],
xAxis: {
type: 'time',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
},
yAxis: [{}],
options: {
series: []
}
}
if (chartsList.value.length > 0) {
let yData: any = []
echartsData.value.yAxis = []
let setList = [...new Set(unitList)]
setList.forEach((item: any, index: any) => {
if (index > 2) {
echartsData.value.grid.right = (index - 1) * 80
}
yData.push([])
let right = {
position: 'right',
offset: (index - 1) * 80
}
echartsData.value.yAxis.push({
name: item,
yAxisIndex: index,
splitNumber: 5,
minInterval: 1,
splitLine: {
show: false
},
...(index > 0 ? right : null)
})
})
// console.log("🚀 ~ result.forEach ~ result:", result)
let ABCName = [
...new Set(
chartsList.value.map((item: any) => {
return item.anotherName == '电压负序分量'
? '电压不平衡'
: item.anotherName == '电压正序分量'
? '电压不平衡'
: item.anotherName == '电压零序分量'
? '电压不平衡'
: item.anotherName
})
)
]
result.forEach((item: any, index: any) => {
let yMethodList: any = []
let ABCList = Object.values(
item.reduce((acc, item) => {
let key = ''
if (item.phase == null) {
key = item.anotherName
} else {
key = item.phase
}
if (!acc[key]) {
acc[key] = []
}
acc[key].push(item)
return acc
}, {})
)
ABCList.forEach((kk: any) => {
let colorName = kk[0].phase?.charAt(0).toUpperCase()
let lineS = ABCName.findIndex(
item =>
item ===
(kk[0].anotherName == '电压负序分量'
? '电压不平衡'
: kk[0].anotherName == '电压正序分量'
? '电压不平衡'
: kk[0].anotherName == '电压零序分量'
? '电压不平衡'
: kk[0].anotherName)
)
let seriesList: any = []
kk.forEach((cc: any) => {
if (cc.statisticalData !== null) {
yData[setList.indexOf(kk[0].unit)].push(cc.statisticalData?.toFixed(2))
}
seriesList.push([cc.time, cc.statisticalData?.toFixed(2), cc.unit, lineStyle[lineS].type])
})
echartsData.value.options.series.push({
name: kk[0].phase ? kk[0].phase + '相' + kk[0].anotherName : kk[0].anotherName,
type: 'line',
color:
colorName == 'A' ? '#DAA520' : colorName == 'B' ? '#2E8B57' : colorName == 'C' ? '#A52a2a' : '',
smooth: true,
symbol: 'none',
lineStyle: lineStyle[lineS],
// data: seriesList,
data: timeControl.value ? completeTimeSeries(seriesList) : seriesList,
yAxisIndex: setList.indexOf(kk[0].unit)
})
})
// let [min, max] = yMethod(yMethodList)
// echartsData.value.yAxis[index].min = min
// echartsData.value.yAxis[index].max = max
})
yData.forEach((item: any, index: any) => {
let [min, max] = yMethod(item)
echartsData.value.yAxis[index].min = min
echartsData.value.yAxis[index].max = max
})
}
loading.value = false
}
const setTimeControl = () => {
timeControl.value = !timeControl.value
setEchart()
}
//导出 //导出
const historyChart = ref() const historyChart = ref()
const handleExport = async () => { const handleExport = async () => {
@@ -828,6 +906,7 @@ const handleExport = async () => {
let csv = '' let csv = ''
csv = title csv = title
// 遍历数据并添加到CSV字符串中 // 遍历数据并添加到CSV字符串中
list[0]?.data.map((vv: any, indexs: any) => { list[0]?.data.map((vv: any, indexs: any) => {
let strs = '', let strs = '',
count = null count = null
@@ -843,11 +922,11 @@ const handleExport = async () => {
index == list.length - 1 ? (strs += '/') : (strs += '/,') index == list.length - 1 ? (strs += '/') : (strs += '/,')
} }
}) })
if (count == 0 && xAxis[indexs]) { // if (count == 0 && xAxis[indexs]) {
csv += `${xAxis[indexs]},` + strs + '\n' csv += '\u200B' + `${vv[0]},` + strs + '\n'
} else { // } else {
strs += '/,' // strs += '/,'
} // }
}) })
return csv return csv
} }
@@ -878,7 +957,6 @@ const tableHeaderRef = ref()
//根据选择的指标处理谐波次数 //根据选择的指标处理谐波次数
const formatCountOptions = () => { const formatCountOptions = () => {
countData.value = [] countData.value = []
// console.log(123, indexOptions.value); // console.log(123, indexOptions.value);
@@ -889,7 +967,6 @@ const formatCountOptions = () => {
countData.value.push(vv) countData.value.push(vv)
} }
}) })
}) })
// indexOptions.value.map((item: any, index: any) => { // indexOptions.value.map((item: any, index: any) => {
// if (!countDataCopy.value[index]) { // if (!countDataCopy.value[index]) {
@@ -944,7 +1021,6 @@ const formatCountOptions = () => {
} }
setTimeout(() => { setTimeout(() => {
tableHeaderRef.value && tableHeaderRef.value?.computedSearchRow() tableHeaderRef.value && tableHeaderRef.value?.computedSearchRow()
}, 100) }, 100)
} }
@@ -969,7 +1045,6 @@ const selectChange = (e: boolean) => {
} }
const handleChange = () => { const handleChange = () => {
if (activeColName.value == '0') { if (activeColName.value == '0') {
if (flag.value) { if (flag.value) {
EcharHeight.value = mainHeight(480) EcharHeight.value = mainHeight(480)
@@ -985,15 +1060,13 @@ const handleChange = () => {
} }
setTimeout(() => { setTimeout(() => {
transientRef.value && transientRef.value.setHeight() transientRef.value && transientRef.value.setHeight()
}, 100); }, 100)
} }
watch( watch(
() => searchForm.value.index, () => searchForm.value.index,
(val: any, oldval: any) => { (val: any, oldval: any) => {
// if (val) { // if (val) {
// let list = val // let list = val
// setTimeout(() => { // setTimeout(() => {
// formatCountOptions(list) // formatCountOptions(list)
@@ -1007,7 +1080,6 @@ watch(
// countData.value.splice(key, 1) // countData.value.splice(key, 1)
// } // }
// }) // })
// init(false) // init(false)
// } // }
}, },
@@ -1017,7 +1089,6 @@ watch(
} }
) )
onMounted(() => { onMounted(() => {
setTimeout(() => { setTimeout(() => {
init(true) init(true)
}, 1500) }, 1500)

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

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="container"> <div class="container">
<!-- 使用 v-for 遍历四个角落 --> <!-- 使用 v-for 遍历四个角落 -->
<div v-for="corner in corners" :key="corner.id" :class="['corner', corner.className]"> <div v-for="corner in corners" v-show="corner.show" :key="corner.id" :class="['corner', corner.className]">
<div class="content"> <div class="content">
<div class="title" style="display: flex"> <div class="title" style="display: flex">
<img src="@/assets/img/lightning.png" class="title_img" /> <img src="@/assets/img/lightning.png" class="title_img" />
@@ -15,8 +15,9 @@
:header-cell-style="{ textAlign: 'center' }" :header-cell-style="{ textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }" :cell-style="{ textAlign: 'center' }"
height="200" height="200"
style="padding: 5px;"
> >
<vxe-column field="name" title="名称" width="70"></vxe-column> <vxe-column field="name" title="名称"></vxe-column>
<vxe-column field="a" title="A" width="40"></vxe-column> <vxe-column field="a" title="A" width="40"></vxe-column>
<vxe-column field="b" title="B" width="40"></vxe-column> <vxe-column field="b" title="B" width="40"></vxe-column>
<vxe-column field="c" title="C" width="40"></vxe-column> <vxe-column field="c" title="C" width="40"></vxe-column>
@@ -345,7 +346,7 @@ onBeforeUnmount(() => {
} }
.corner { .corner {
width: 200px; width: 240px;
/* height: 135px; */ /* height: 135px; */
background-color: #fff; background-color: #fff;
position: absolute; position: absolute;
@@ -397,7 +398,7 @@ onBeforeUnmount(() => {
font-size: 16px; font-size: 16px;
// text-align: center; // text-align: center;
padding: 5px; padding: 5px;
/* color: #409eff; */ color: #fff;
border-bottom: 1px solid #444; border-bottom: 1px solid #444;
background-color: var(--el-color-primary); background-color: var(--el-color-primary);
border-radius: 8px 8px 0 0; border-radius: 8px 8px 0 0;