Compare commits

...

19 Commits

Author SHA1 Message Date
stt
078488a842 监测点详情 趋势图数据 2025-11-13 08:49:44 +08:00
stt
384ea90acd 监测点列表详情 2025-11-12 09:51:28 +08:00
stt
25971e5239 Merge branch 'main' of http://192.168.1.22:3000/Web/admin-govern 2025-11-10 14:47:21 +08:00
stt
c3d7e91f4e 页面修改 2025-11-10 14:47:18 +08:00
sjl
72c37c2759 微调 2025-11-10 13:58:23 +08:00
sjl
d1eb7f2dad 设备录入微调 2025-11-10 13:10:15 +08:00
stt
308ceb1a03 暂态电能质量分析添加时间组件 2025-11-07 11:28:24 +08:00
stt
ad7b77ff92 稳态治理效果分析添加时间组件 2025-11-07 10:32:55 +08:00
stt
0e76ab66f3 添加查询条件 2025-11-06 16:21:39 +08:00
stt
24afa84f29 稳态电能质量分析页面同步时间组件 2025-11-06 16:11:12 +08:00
stt
a5f3571906 时间组件缓存提取出来 2025-11-06 14:55:56 +08:00
stt
d16d262d1a Merge branch 'main' of http://192.168.1.22:3000/Web/admin-govern 2025-11-06 14:24:20 +08:00
stt
593f2e2c66 内部时间组件设置默认值 2025-11-06 14:24:15 +08:00
sjl
d1e7aab876 微调 2025-11-05 15:12:06 +08:00
sjl
8a3e0263d2 Merge branch 'main' of http://192.168.1.22:3000/Web/admin-govern 2025-11-05 15:10:50 +08:00
sjl
35ce7314b0 微调 2025-11-05 15:10:44 +08:00
guanj
5538d18127 Merge branch 'main' of http://192.168.1.22:3000/Web/admin-govern 2025-11-05 15:09:09 +08:00
guanj
00dd79e000 修改echart y轴计算方式 2025-11-05 15:09:00 +08:00
stt
b5aff1a837 样式修改 2025-11-05 14:45:56 +08:00
37 changed files with 3556 additions and 464 deletions

View File

@@ -0,0 +1,57 @@
import request from '@/utils/request'
// 主要监测点列表查询>>分页
export function mainLineList(data: any) {
return request({
url: '/harmonic-boot/mainLine/list',
method: 'post',
data: data
})
}
// 主要监测点指标越限详情
export function statLimitRateDetails(data: any) {
return request({
url: '/harmonic-boot/mainLine/statLimitRateDetails',
method: 'post',
data: data
})
}
// 查询监测点列表=全部>>不分页
export function cslineList(data: any) {
return request({
url: '/cs-device-boot/csline/list',
method: 'post',
data: data
})
}
// 监测点详情 趋势图数据
export function trendData(data: any) {
return request({
url: '/cs-device-boot/csGroup/trendData',
method: 'post',
data: data
})
}
// 每日越限占比统计
export function totalLimitStatisticsDetails(data: any) {
return request({
url: '/harmonic-boot/totalLimitStatistics/details',
method: 'post',
data: data
})
}
// 总体指标越限统计列表
export function totalLimitStatisticsList(data: any) {
return request({
url: '/harmonic-boot/totalLimitStatistics/list',
method: 'post',
data: data
})
}

View File

@@ -1,6 +1,7 @@
<template>
<div>
<!--F47曲线 -->
<TableHeader :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen"></TableHeader>
<el-descriptions class="mt2" direction="vertical" :column="4" border>
<el-descriptions-item align="center" label="名称">{{ data.name }}</el-descriptions-item>
<el-descriptions-item align="center" label="事件总数">{{ data.gs }}</el-descriptions-item>
@@ -11,7 +12,7 @@
ref="chartRef"
class="tall"
:options="echartList"
:style="{ width: prop.width, height: `calc(${prop.height} - 80px)` }"
:style="{ width: prop.width, height: `calc(${prop.height} - 80px - ${headerHeight}px + ${fullscreen ? 0 : 56}px)` }"
@chart-click="handleChartClick"
/>
<el-dialog v-model="isWaveCharts" draggable title="瞬时/RMS波形" append-to-body width="70%">
@@ -23,19 +24,51 @@
<script setup lang="ts">
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue';
import TableHeader from '@/components/table/header/index.vue'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const headerHeight = ref(57)
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
const echartList = ref({})
const chartRef = ref()
@@ -61,8 +94,21 @@ const tableStore: any = new TableStore({
column: [],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {
let res = {

View File

@@ -1,6 +1,7 @@
<template>
<div>
<!--暂降方向统计 -->
<TableHeader :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen"></TableHeader>
<my-echart class="tall" :options="echartList" :style="{ width: prop.width, height: `calc(${prop.height} )` }" />
</div>
</template>
@@ -12,12 +13,47 @@ import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import TableHeader from '@/components/table/header/index.vue'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const headerHeight = ref(57)
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
const data = [
{
name: '来自电网',
@@ -93,8 +129,21 @@ const tableStore: any = new TableStore({
column: [],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {}
})

View File

@@ -11,9 +11,6 @@
<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({
@@ -30,103 +27,50 @@ const config = useConfig()
const echartList = ref({
title: {
text: '35kV进线谐波含有率',
text: '指标日趋势图',
},
xAxis: {
type: 'time',
type: 'category',
data: [
'00:00', '01:00', '02:00', '03:00', '04:00', '05:00',
'06:00', '07:00', '08:00', '09:00', '10:00', '11:00',
'12:00', '13:00', '14:00', '15:00', '16:00', '17:00',
'18:00', '19:00', '20:00', '21:00', '22:00', '23:00'
],
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
interval: 1
}
},
yAxis: [{}, {}],
yAxis: {
type: 'value',
name: '数值'
},
grid: {
left: '10px',
right: '20px'
right: '20px',
containLabel: true
},
options: {
series: [
{
// name: '暂降次数',
type: 'bar',
name: '有功功率',
name: '指标值',
type: 'line',
showSymbol: true,
smooth: true,
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]
10, 12, 15, 18, 22, 28,
35, 45, 60, 75, 88, 95,
100, 98, 90, 80, 70, 60,
50, 40, 30, 25, 20, 15
],
itemStyle: {
normal: {
//这里是颜色
color: function (params: any) {
if (params.value[1] == 0 || params.value[1] == 3.14159) {
return '#ccc'
} else {
return config.layout.elementUiPrimary[0]
}
}
color: 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
areaStyle: {
opacity: 0.3
}
}
]
}

View File

@@ -1,12 +1,13 @@
<template>
<div>
<!--指标越限程度 -->
<TableHeader :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen"></TableHeader>
<my-echart
class="tall"
:options="echartList"
:style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }"
/>
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} / 2 )`" isGroup></Table>
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} / 2 - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`" isGroup></Table>
<!-- 指标日趋势图 -->
<DailyTrendChart ref="dailyTrendChartRef" />
</div>
@@ -15,17 +16,49 @@
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import DailyTrendChart from '@/components/cockpit/exceedanceLevel/components/dailyTrendChart.vue'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const headerHeight = ref(57)
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
const echartList = ref({
title: {
text: '指标越限严重度'
@@ -119,8 +152,21 @@ const tableStore: any = new TableStore({
}
],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {
tableStore.table.data = [

View File

@@ -1,7 +1,7 @@
<template>
<div>
<!--治理效果报表 -->
<TableHeader :showReset="false" v-if="fullscreen">
<TableHeader :showReset="false" datePicker @selectChange="selectChange" v-if="fullscreen">
<template v-slot:select>
<el-form-item label="治理对象">
<el-select
@@ -39,12 +39,11 @@ import { ref, onMounted, provide, reactive, watch, h, computed } from 'vue'
import TableStore from '@/utils/tableStore'
import { exportExcel } from '@/views/govern/reportForms/export.js'
import TableHeader from '@/components/table/header/index.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useConfig } from '@/stores/config'
import Json from './index.json'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
@@ -66,6 +65,9 @@ const powerList: any = ref([
}
])
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const tableStore: any = new TableStore({
url: '/user-boot/role/selectRoleDetail?id=0',
method: 'POST',
@@ -74,8 +76,20 @@ const tableStore: any = new TableStore({
exportName: '主要监测点列表',
column: [],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {}
})
@@ -103,6 +117,16 @@ onMounted(() => {
tableStore.index()
})
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)

View File

@@ -1,13 +1,21 @@
<template>
<div>
<!--电网侧指标越限统计 -->
<TableHeader :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen"></TableHeader>
<my-echart
class="tall"
:options="echartList"
:style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }"
:style="{
width: prop.width,
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
}"
/>
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} / 2 )`" isGroup></Table>
<Table
ref="tableRef"
@cell-click="cellClickEvent"
:height="`calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`"
isGroup
></Table>
<!-- 指标越限详情 -->
<OverLimitDetails ref="OverLimitDetailsRef" />
</div>
@@ -17,16 +25,48 @@ import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import OverLimitDetails from '@/components/cockpit/listOfMainMonitoringPoints/components/overLimitDetails.vue'
import TableHeader from '@/components/table/header/index.vue'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const headerHeight = ref(57)
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
const echartList = ref({
title: {
text: '指标越限占比'
@@ -52,7 +92,7 @@ const echartList = ref({
type: 'bar',
name: '越限占比',
data: [0, 45, 22, 0, 70],
barMaxWidth: 30,
barMaxWidth: 30
// label: {
// show: true,
@@ -140,8 +180,21 @@ const tableStore: any = new TableStore({
}
],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {
tableStore.table.data = [

View File

@@ -1,8 +1,8 @@
<template>
<div>
<!--指标越限明细 -->
<el-calendar v-model="value" :style="{ height: prop.height, overflow: 'auto' }">
<TableHeader :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen"></TableHeader>
<el-calendar v-model="value" :style="{ height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`, overflow: 'auto' }">
<template #date-cell="{ data }">
<div style="height: 100%; padding: 8px" :style="{ background: setBackground(data.day) }">
<p :class="data.isSelected ? 'is-selected' : ''">
@@ -30,24 +30,56 @@
<script setup lang="ts">
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import TableHeader from '@/components/table/header/index.vue'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import { overflow } from 'html2canvas/dist/types/css/property-descriptors/overflow'
import { dayjs } from 'element-plus'
dayjs.en.weekStart = 1 //设置日历的周起始日为星期一
const value = ref(new Date())
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const headerHeight = ref(57)
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
dayjs.en.weekStart = 1 //设置日历的周起始日为星期一
const value = ref(new Date())
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
const list = ref([
{
time: '2025-10-01',
time: '2025-11-01',
key: 81,
text: '3次谐波越限<br/>5次谐波越限<br/>三相不平衡越限'
},
@@ -57,22 +89,22 @@ const list = ref([
text: '3次谐波越限<br/>5次谐波越限<br/>三相不平衡越限'
},
{
time: '2025-10-08',
time: '2025-11-08',
key: 20,
text: '3次谐波越限<br/>5次谐波越限<br/>三相不平衡越限'
},
{
time: '2025-10-16',
time: '2025-11-16',
key: 20,
text: '3次谐波越限<br/>5次谐波越限<br/>三相不平衡越限'
},
{
time: '2025-10-23',
time: '2025-11-23',
key: 20,
text: '3次谐波越限<br/>5次谐波越限<br/>三相不平衡越限'
},
{
time: '2025-10-04',
time: '2025-11-04',
key: 0,
text: ''
},
@@ -90,9 +122,21 @@ const tableStore: any = new TableStore({
column: [],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// value.value = new Date(prop.timeValue?.[0])
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {
tableStore.table.data = []

View File

@@ -1,40 +1,226 @@
<template>
<div>
<!--指标越限概率分布 -->
<TableHeader :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen">
<template v-slot:select>
<el-form-item>
<el-select size="small" v-model="tableStore.table.params.searchValue">
<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: prop.width, height: `calc(${prop.height} / 2 )` }"
:style="{
width: prop.width,
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
}"
/>
<my-echart
class="mt10"
:options="echartList1"
:style="{ width: prop.width, height: `calc(${prop.height} / 2 - 10px)` }"
:style="{
width: prop.width,
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
}"
/>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const options = [
{
value: '1',
label: '35V进线'
}
]
const headerHeight = ref(57)
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
// const echartList = ref({
// options: {
// xAxis: null,
// yAxis: null,
// dataZoom: null,
// backgroundColor: '#fff',
// tooltip: {
// // trigger: 'axis'
// textStyle: {
// color: '#fff',
// fontStyle: 'normal',
// opacity: 0.35,
// fontSize: 14
// },
// backgroundColor: 'rgba(0,0,0,0.55)',
// borderWidth: 0,
// formatter: function (params: any) {
// console.log(params)
// var tips = ''
// for (var i = 0; i < params.length; i++) {
// tips += params[i].name + '</br/>'
// tips += '监测点数' + ':' + '&nbsp' + '&nbsp' + params[i].value + '</br/>'
// }
// return tips
// }
// },
// title: {
// text: '指标越限概率分布',
// x: 'center'
// },
// visualMap: {
// max: 20,
// show: false,
// inRange: {
// color: ['#313695', '#00BB00', '#ff8000', '#a50026']
// }
// },
// xAxis3D: {
// type: 'category',
// name: '指标越限',
// data: ['0-10', '10-20', '20-30', '30-40', '40-50'],
// axisLine: {
// lineStyle: {
// color: '#111'
// }
// },
// axisLabel: {
// color: '#111'
// }
// },
// yAxis3D: {
// type: 'category',
// name: '指标类型',
// data: ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡'],
// nameTextStyle: {
// color: '#111'
// },
// axisLine: {
// show: true,
// lineStyle: {
// color: '#111'
// }
// },
// axisLabel: {
// color: '#111'
// },
// splitLine: {
// lineStyle: {
// // 使用深浅的间隔色
// color: ['#111'],
// type: 'dashed',
// opacity: 0.5
// }
// }
// },
// zAxis3D: {
// type: 'value',
// splitNumber: 10,
// minInterval: 10,
// name: '越限占比'
// },
// grid3D: {
// viewControl: {
// projection: 'perspective',
// distance: 250
// },
// boxWidth: 200,
// boxDepth: 80,
// light: {
// main: {
// intensity: 1.2
// },
// ambient: {
// intensity: 0.3
// }
// }
// },
// series: [
// {
// type: 'bar3D',
// data: [
// [0, 0, 1],
// [0, 1, 1],
// [0.2, 1]
// ],
// shading: 'realistic',
// label: {
// show: false,
// textStyle: {
// fontSize: 16,
// borderWidth: 1
// }
// },
// itemStyle: {
// opacity: 1
// },
// emphasis: {
// label: {
// textStyle: {
// fontSize: 20,
// color: '#900'
// }
// },
// itemStyle: {
// color: '#900'
// }
// }
// }
// ]
// }
// })
var yAxisData=['闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡']
const echartList = ref({
options: {
xAxis: null,
yAxis: null,
dataZoom: null,
backgroundColor: '#fff',
tooltip: {
// trigger: 'axis'
textStyle: {
color: '#fff',
fontStyle: 'normal',
@@ -44,44 +230,74 @@ const echartList = ref({
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
formatter: function (params: any) {
console.log(params)
console.log(params, '33344')
var yIndex = params.value[1]; //获取y轴索引
var tips = ''
for (var i = 0; i < params.length; i++) {
tips += params[i].name + '</br/>'
tips += '监测点数' + ':' + '&nbsp' + '&nbsp' + params[i].value + '</br/>'
}
// tips += '指标类型: ' + params.name + '</br>'
tips += '指标类型: ' + yAxisData[yIndex] + '</br>'
tips += '越限程度: ' + params.seriesName + '</br>'
// tips += '越限占比: ' + params.value + '%</br>'
tips += '越限占比: ' + params.value[2] + '%</br>'
return tips
}
},
title: {
text: '指标越限概率分布',
x: 'center'
},
visualMap: {
max: 20,
show: false,
inRange: {
color: ['#313695', '#00BB00', '#ff8000', '#a50026']
x: 'center',
textStyle: {
fontSize: 16,
fontWeight: 'normal'
}
},
visualMap: {
max: 100,
show: true,
inRange: {
color: [
'#313695',
'#4575b4',
'#74add1',
'#abd9e9',
'#e0f3f8',
'#ffffbf',
'#fee090',
'#fdae61',
'#f46d43',
'#d73027',
'#a50026'
]
}
// calculable: true,
// orient: 'horizontal',
// left: 'center',
// bottom: '5%'
},
xAxis3D: {
type: 'category',
name: '指标越限',
data: ['0-10', '10-20', '20-30', '30-40', '40-50'],
name: '越限程度',
nameLocation: 'middle',
nameGap: 30,
data: ['0-20%', '20-40%', '40-60%', '60-80%', '80-100%'],
axisLine: {
lineStyle: {
color: '#111'
}
},
axisLabel: {
color: '#111',
margin: 15
},
nameTextStyle: {
color: '#111'
}
},
yAxis3D: {
type: 'category',
name: '指标类型',
data: ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡'],
nameLocation: 'middle',
nameGap: 30,
// data: ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡'],
data:yAxisData,
nameTextStyle: {
color: '#111'
},
@@ -92,11 +308,11 @@ const echartList = ref({
}
},
axisLabel: {
color: '#111'
color: '#111',
margin: 15
},
splitLine: {
lineStyle: {
// 使用深浅的间隔色
color: ['#111'],
type: 'dashed',
opacity: 0.5
@@ -105,61 +321,203 @@ const echartList = ref({
},
zAxis3D: {
type: 'value',
splitNumber: 10,
minInterval: 10,
name: '越限占比'
name: '越限占比(%)',
nameLocation: 'middle',
nameGap: 30,
nameTextStyle: {
color: '#111'
},
axisLine: {
lineStyle: {
color: '#111'
}
},
axisLabel: {
color: '#111'
},
min: 0,
max: 100
},
grid3D: {
viewControl: {
projection: 'perspective',
distance: 250
distance: 250,
rotateSensitivity: 10,
zoomSensitivity: 2
},
boxWidth: 200,
boxDepth: 80,
boxWidth: 150,
boxDepth: 100,
boxHeight: 100,
light: {
main: {
intensity: 1.2
},
ambient: {
intensity: 0.3
intensity: 0.4
}
}
},
series: [
{
type: 'bar3D',
name: '0-20%',
data: [
[0, 0, 1],
[0, 1, 1],
[0.2, 1]
// [xIndex, yIndex, value]
[0, 0, 5], // 闪变 - 0-20%
[0, 1, 10], // 谐波电压 - 0-20%
[0, 2, 8], // 谐波电流 - 0-20%
[0, 3, 15], // 电压偏差 - 0-20%
[0, 4, 12] // 三相不平衡 - 0-20%
],
shading: 'realistic',
label: {
show: false,
textStyle: {
fontSize: 16,
borderWidth: 1
}
show: false
},
itemStyle: {
opacity: 1
opacity: 0.9
},
emphasis: {
label: {
show: true,
textStyle: {
fontSize: 20,
color: '#900'
fontSize: 14,
color: '#000'
}
},
itemStyle: {
color: '#900'
color: '#ff8000'
}
}
},
{
type: 'bar3D',
name: '20-40%',
// data: chartData.map(function (item) {
// return {
// value: [item[1], item[0], item[2]]
// };
// }),
data: [
[1, 0, 10], // 闪变 - 20-40%
[1, 1, 20], // 谐波电压 - 20-40%
[1, 2, 15], // 谐波电流 - 20-40%
[1, 3, 25], // 电压偏差 - 20-40%
[1, 4, 18] // 三相不平衡 - 20-40%
],
shading: 'realistic',
label: {
show: false
},
itemStyle: {
opacity: 0.9
},
emphasis: {
label: {
show: true,
textStyle: {
fontSize: 14,
color: '#000'
}
},
itemStyle: {
color: '#ff8000'
}
}
},
{
type: 'bar3D',
name: '40-60%',
data: [
[2, 0, 15], // 闪变 - 40-60%
[2, 1, 25], // 谐波电压 - 40-60%
[2, 2, 30], // 谐波电流 - 40-60%
[2, 3, 35], // 电压偏差 - 40-60%
[2, 4, 28] // 三相不平衡 - 40-60%
],
shading: 'realistic',
label: {
show: false
},
itemStyle: {
opacity: 0.9
},
emphasis: {
label: {
show: true,
textStyle: {
fontSize: 14,
color: '#000'
}
},
itemStyle: {
color: '#ff8000'
}
}
},
{
type: 'bar3D',
name: '60-80%',
data: [
[3, 0, 20], // 闪变 - 60-80%
[3, 1, 30], // 谐波电压 - 60-80%
[3, 2, 35], // 谐波电流 - 60-80%
[3, 3, 40], // 电压偏差 - 60-80%
[3, 4, 35] // 三相不平衡 - 60-80%
],
shading: 'realistic',
label: {
show: false
},
itemStyle: {
opacity: 0.9
},
emphasis: {
label: {
show: true,
textStyle: {
fontSize: 14,
color: '#000'
}
},
itemStyle: {
color: '#ff8000'
}
}
},
{
type: 'bar3D',
name: '80-100%',
data: [
[4, 0, 25], // 闪变 - 80-100%
[4, 1, 35], // 谐波电压 - 80-100%
[4, 2, 40], // 谐波电流 - 80-100%
[4, 3, 45], // 电压偏差 - 80-100%
[4, 4, 42] // 三相不平衡 - 80-100%
],
shading: 'realistic',
label: {
show: false
},
itemStyle: {
opacity: 0.9
},
emphasis: {
label: {
show: true,
textStyle: {
fontSize: 14,
color: '#000'
}
},
itemStyle: {
color: '#ff8000'
}
}
}
]
}
})
const echartList1 = ref({
title: {
text: '越限时间概率分布'
@@ -356,8 +714,21 @@ const tableStore: any = new TableStore({
showPage: false,
column: [],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {
tableStore.table.data = []
@@ -365,6 +736,7 @@ const tableStore: any = new TableStore({
})
const tableRef = ref()
tableStore.table.params.searchValue = '1'
provide('tableRef', tableRef)
provide('tableStore', tableStore)

View File

@@ -0,0 +1,709 @@
<template>
<el-dialog draggable title="谐波电压/电流含有率" v-model="dialogVisible" append-to-body width="70%">
<!-- 总体指标占比详情谐波含有率 -->
<div>
<TableHeader ref="tableHeaderRef" :showSearch="false" @selectChange="selectChange">
<template v-slot:select>
<el-form-item>
<DatePicker ref="datePickerRef"></DatePicker>
</el-form-item>
<el-form-item label="统计指标" label-width="80px">
<el-select
multiple
:multiple-limit="2"
collapse-tags
collapse-tags-tooltip
v-model="searchForm.index"
placeholder="请选择统计指标"
@change="onIndexChange($event)"
>
<el-option
v-for="item in indexOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-radio-group v-model="searchForm.dataLevel" @change="init()">
<el-radio-button label="一次值" value="Primary" />
<el-radio-button label="二次值" value="Secondary" />
</el-radio-group>
</el-form-item>
<el-form-item label="统计类型">
<el-select
style="min-width: 120px !important"
placeholder="请选择"
v-model="searchForm.valueType"
>
<el-option value="max" label="最大值"></el-option>
<el-option value="min" label="最小值"></el-option>
<el-option value="avg" label="平均值"></el-option>
<el-option value="cp95" label="cp95"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<div
class="history_count"
v-for="(item, index) in countData"
:key="index"
v-show="item.countOptions.length != 0"
>
<span class="mr12">
{{ item.name.includes('次数') ? item.name : item.name + '谐波次数' }}
</span>
<el-select
v-model="item.count"
@change="onCountChange($event, index)"
placeholder="请选择谐波次数"
style="width: 100px"
class="mr20"
>
<el-option
v-for="vv in item.countOptions"
:key="vv"
:label="vv"
:value="vv"
></el-option>
</el-select>
</div>
</el-form-item>
</template>
<template #operation>
<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>
</TableHeader>
</div>
<div class="history_chart" :style="pageHeight" v-loading="loading">
<MyEchart
ref="historyChart"
:options="echartsData"
v-if="showEchart"
/>
<el-empty :style="pageHeight" v-else description="暂无数据" />
</div>
</el-dialog>
</template>
<script lang="ts" setup>
import { mainHeight } from '@/utils/layout'
import { queryByCode, queryCsDictTree } from '@/api/system-boot/dictTree'
import { ref, onMounted, watch } from 'vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData'
import { queryStatistical } from '@/api/system-boot/csstatisticalset'
import { yMethod, exportCSV, completeTimeSeries } from '@/utils/echartMethod'
import TableHeader from '@/components/table/header/index.vue'
import { trendData } from '@/api/harmonic-boot/cockpit/cockpit'
import DatePicker from '@/components/form/datePicker/index.vue'
import { color } from '@/components/echarts/color'
import { ElMessage } from 'element-plus'
const dictData = useDictData()
defineOptions({
// name: 'govern/device/control'
})
const props = defineProps({
TrendList: {
type: Array
}
})
const dialogVisible: any = ref(false)
// console.log("🚀 ~ props:", props.TrendList)
const showEchart = ref(true)
const num = ref(0)
const timeControl = ref(false)
//值类型
const pageHeight = ref(mainHeight(332))
const loading = ref(true)
const searchForm: any = ref({})
const tableHeaderRef = ref()
const typeOptions = [
{
name: '平均值',
id: 'avg'
},
{
name: '最大值',
id: 'max'
},
{
name: '最小值',
id: 'min'
},
{
name: 'CP95值',
id: 'cp95'
}
]
searchForm.value = {
index: [],
type: typeOptions[0].id,
count: '',
searchBeginTime: '',
searchEndTime: '',
dataLevel: 'Primary',
valueType: 'avg'
}
//统计指标
const indexOptions: any = ref([])
//谐波次数
const countOptions: any = ref([])
// Harmonic_Type
// portable-harmonic
const legendDictList: any = ref([])
const initCode = (field: string, title: string) => {
queryByCode('steady_state_power_quality').then(res => {
queryCsDictTree(res.data.id).then(item => {
//排序
indexOptions.value = item.data.sort((a: any, b: any) => {
return a.sort - b.sort
})
const titleMap: Record<string, number> = {
flickerOvertime: 0,
uaberranceOvertime: 3,
ubalanceOvertime: 4,
freqDevOvertime: 5
}
let defaultIndex = 0 // 默认值
if (field in titleMap) {
defaultIndex = titleMap[field]
} else if (field.includes('uharm')) {
defaultIndex = 1
} else if (field.includes('iharm')) {
defaultIndex = 2
}
searchForm.value.index[0] = indexOptions.value[defaultIndex].id
})
queryStatistical(res.data.id).then(vv => {
legendDictList.value = vv.data
indexOptions.value.map((item: any, index: any) => {
if (!countDataCopy.value[index]) {
countDataCopy.value[index] = {
index: item.id,
countOptions: [],
count: [],
name: indexOptions.value.find((vv: any) => {
return vv.id == item.id
})?.name
}
}
legendDictList.value?.selectedList?.map((vv: any, vvs: any) => {
//查找相等的指标
if (item.id == vv.dataType) {
vv.eleEpdPqdVOS.map((kk: any, kks: any) => {
if (kk.harmStart && kk.harmEnd) {
range(0, 0, 0)
if (kk.showName == '间谐波电压含有率') {
countDataCopy.value[index].countOptions = range(kk.harmStart, kk.harmEnd, 1).map(
(item: any) => {
return item - 0.5
}
)
} else {
countDataCopy.value[index].countOptions = range(kk.harmStart, kk.harmEnd, 1)
}
if (title && countDataCopy.value[index].countOptions.includes(Number(title))) {
countDataCopy.value[index].count = Number(title)
} else if (title && countDataCopy.value[index].countOptions.includes(title)) {
countDataCopy.value[index].count = title
} else if (
!countDataCopy.value[index].count ||
countDataCopy.value[index].count.length == 0
) {
// 只有当count为空时才设置默认值
countDataCopy.value[index].count = countDataCopy.value[index].countOptions[0]
}
}
})
}
})
})
nextTick(() => {
formatCountOptions()
})
init()
})
})
}
const chartsList = ref<any>([])
const chartTitle: any = ref('')
const echartsData = ref<any>(null)
//加载echarts图表
//历史趋势数据
const historyDataList: any = ref([])
const range = (start: any, end: any, step: any) => {
return Array.from({ length: (end - start) / step + 1 }, (_, i) => start + i * step)
}
//获取请求趋势数据参数
const trendRequestData = ref()
const getTrendRequest = (val: any) => {
trendRequestData.value = val
// init()
}
//初始化趋势图
const headerRef = ref()
const datePickerRef = ref()
const lineStyle = [{ type: 'solid' }, { type: 'dashed' }, { type: 'dotted' }]
const init = async () => {
loading.value = true
// 选择指标的时候切换legend内容和data数据
let list: any = []
legendDictList.value?.selectedList?.map((item: any) => {
searchForm.value.index.map((vv: any) => {
if (item.dataType == vv) {
list.push(item.eleEpdPqdVOS)
}
})
})
//颜色数组
const colorList = color
//选择的指标使用方法处理
formatCountOptions()
//查询历史趋势
historyDataList.value = []
chartTitle.value = ''
searchForm.value.index.map((item: any, indexs: any) => {
indexOptions.value.map((vv: any) => {
if (vv.id == item) {
chartTitle.value += indexs == searchForm.value.index.length - 1 ? vv.name : vv.name + '/'
}
})
})
let lists: any = []
let frequencys: any = null
countData.value.map((item: any, index: any) => {
if (item.name.includes('谐波含有率')) {
frequencys = item.count
} else {
frequencys = ''
}
lists[index] = {
statisticalId: item.index,
frequency: frequencys !== null && frequencys !== undefined ? String(frequencys) : ''
}
})
let obj = {
//...trendRequestData.value,
lineId: trendRequestData.value.lineId,
list: lists,
dataLevel: searchForm.value.dataLevel,
valueType: searchForm.value.valueType,
searchBeginTime: datePickerRef.value && datePickerRef.value.timeValue[0],
searchEndTime: datePickerRef.value && datePickerRef.value.timeValue[1]
}
if (searchForm.value.index.length == 0) {
ElMessage.warning('请选择统计指标')
loading.value = false
return
}
if (obj.list.length != 0) {
try {
showEchart.value = true
await trendData(obj)
.then((res: any) => {
if (res.code == 'A0000') {
if (res.data.length == 0) {
loading.value = false
showEchart.value = false
return
}
historyDataList.value = res.data
chartsList.value = JSON.parse(JSON.stringify(res.data))
loading.value = false
setEchart()
}
})
.catch(error => {
loading.value = false
})
} catch (error) {
loading.value = false
}
}
}
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 = {
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)
})
})
})
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) => {
if (flag) {
pageHeight.value = mainHeight(372)
} else {
pageHeight.value = mainHeight(332)
}
}
//导出
const historyChart = ref()
const countData: any = ref([])
const countDataCopy: any = ref([])
//根据选择的指标处理谐波次数
const formatCountOptions = () => {
countData.value = []
if (searchForm.value.index.length != 0) {
searchForm.value.index.forEach((item: any, index: any) => {
countDataCopy.value.forEach((vv: any, vvs: any) => {
if (vv.index == item) {
countData.value.push(vv)
}
})
})
countData.value.map((item: any, key: any) => {
if (item.name == '谐波电流有效值') {
item.name = '谐波电流次数'
} else if (item.name == '谐波电压含有率') {
item.name = '谐波电压次数'
} else if (item.name == '间谐波电压含有率') {
item.name = '间谐波电压次数'
}
})
}
// setTimeout(() => {
// tableHeaderRef.value.computedSearchRow()
// }, 500)
}
// 判断下拉框是否存在
const onCountChange = (val: any, index: any) => {
if (val.length == 0) {
countData.value[index].count = countData.value[index].countOptions[0]
}
}
const flag = ref(true)
const onIndexChange = (val: any) => {
num.value += 1
let pp: any = []
indexOptions.value.forEach((item: any) => {
const filteredResult = val.filter(vv => item.id == vv)
if (filteredResult.length > 0) {
pp.push(filteredResult[0])
}
})
searchForm.value.index = pp
flag.value = true
formatCountOptions()
}
watch(
() => searchForm.value.index,
(val: any, oldval: any) => {},
{
deep: true,
immediate: true
}
)
const openDialog = async (row: any, field: any, title: any) => {
dialogVisible.value = true
trendRequestData.value = row
nextTick(() => {
// 默认当天
datePickerRef.value.setInterval(5)
datePickerRef.value.timeValue = [row.time, row.time]
initCode(field, title)
})
}
defineExpose({ getTrendRequest, openDialog })
</script>
<style lang="scss" scoped>
.history_header {
display: flex;
// flex-wrap: wrap;
#history_select {
width: 100%;
display: flex;
// justify-content: flex-start;
// overflow-x: auto;
height: auto;
flex-wrap: wrap;
.el-form-item {
flex: none !important;
// max-width: 380px;
}
.el-select {
margin-right: 10px;
}
}
// #history_select::-webkit-scrollbar {
// width: 0 !important;
// display: none !important;
// }
.history_searchBtn {
flex: 1;
display: flex;
justify-content: flex-end;
margin-top: 3px;
}
}
.history_chart {
width: 100%;
// flex: 1;
margin-top: 10px;
}
.history_count {
.el-select {
min-width: 100px;
}
}
</style>

View File

@@ -0,0 +1,184 @@
<template>
<div>
<!-- 指标越限详情 -->
<el-dialog draggable title="指标越限详情" v-model="dialogVisible" append-to-body width="70%">
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef">
<template v-slot:select>
<el-form-item label="监测点">
<el-select
v-model="tableStore.table.params.lineId"
placeholder="请选择监测点"
style="width: 150px"
>
<el-option
v-for="item in options"
:key="item.lineId"
:label="item.name"
:value="item.lineId"
/>
</el-select>
</el-form-item>
</template>
</TableHeader>
<Table ref="tableRef" @cell-click="cellClickEvent" isGroup :height="height"></Table>
</el-dialog>
<!-- 谐波电流谐波电压占有率 -->
<HarmonicRatio ref="harmonicRatioRef" @close="onHarmonicRatioClose" :TrendList="TrendList" />
</div>
</template>
<script setup lang="ts">
import { ref, provide,nextTick } from 'vue'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import TableStore from '@/utils/tableStore'
import { mainHeight } from '@/utils/layout'
import HarmonicRatio from '@/components/cockpit/indicatorFittingChart/components/harmonicRatio.vue'
import { cslineList } from '@/api/harmonic-boot/cockpit/cockpit'
const dialogVisible: any = ref(false)
const harmonicRatioRef: any = ref(null)
const options = ref()
const height = mainHeight(0, 2).height as any
const tableHeaderRef = ref()
const TrendList = ref([{lineType:1}])
const loop50 = (key: string) => {
let list: any[] = []
for (let i = 2; i < 26; i++) {
list.push({
title: i + '次',
field: key + i + 'Overtime',
width: '80',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row[key + i + 'Overtime']}</span>`
}
})
}
return list
}
const tableStore: any = new TableStore({
url: '/harmonic-boot/mainLine/statLimitRateDetails',
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',
width: '150',
sortable: true
},
{
title: '名称',
field: 'lineName',
width: '150'
},
{
title: '闪变越限(分钟)',
field: 'flickerOvertime',
width: '80',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>`
}
},
{
title: '谐波电压越限(分钟)',
children: loop50('uharm')
},
{
title: '谐波电流越限(分钟)',
children: loop50('iharm')
},
{
title: '三相不平衡度越限(分钟)',
field: 'ubalanceOvertime',
width: '100',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>`
}
},
{
title: '电压偏差越限(分钟)',
field: 'uaberranceOvertime',
width: '100',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.uaberranceOvertime}</span>`
}
},
{
title: '频率偏差越限(分钟)',
field: 'freqDevOvertime',
width: '100',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.freqDevOvertime}</span>`
}
}
],
beforeSearchFun: () => {
},
loadCallback: () => {
}
})
provide('tableStore', tableStore)
tableStore.table.params.sortBy = ''
tableStore.table.params.orderBy = ''
const open = async (row: any,searchBeginTime:any,searchEndTime:any) => {
dialogVisible.value = true
initCSlineList()
tableStore.table.params.lineId = row.lineId
nextTick(() => {
tableHeaderRef.value.setTimeInterval([searchBeginTime, searchEndTime])
tableStore.table.params.searchBeginTime =searchBeginTime
tableStore.table.params.searchEndTime = searchEndTime
tableStore.index()
})
}
// 点击行
const cellClickEvent = ({ row, column }: any) => {
if (column.field != 'name' && column.field != 'time') {
dialogVisible.value = false
// if(column.title && column.title=='闪变越限(分钟)'){
// column.title = '1次'
// }
// harmonicRatioRef.value.openDialog(row,column.title.replace(/次/g, ""))
harmonicRatioRef.value.openDialog(row,column.field,column.title.replace(/次/g, ""))
}
}
// 谐波弹窗关闭时的回调
const onHarmonicRatioClose = () => {
// 重新打开指标越限详情弹窗
nextTick(() => {
dialogVisible.value = true
})
}
const initCSlineList = async () => {
const res = await cslineList({})
options.value = res.data
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@@ -1,41 +1,75 @@
<template>
<div>
<!--主要监测点列表 -->
<TableHeader :showReset="false" >
<TableHeader :showReset="false" @selectChange="selectChange" v-if="fullscreen" datePicker ref="tableHeaderRef">
<template v-slot:select>
<el-form-item label="关键词">
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="请输关键字" />
<el-input v-model="tableStore.table.params.keywords" clearable placeholder="请输关键字" />
</el-form-item>
</template>
</TableHeader>
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} - 58px)`"></Table>
<Table
ref="tableRef"
@cell-click="cellClickEvent"
:height="`calc(${prop.height} - ${headerHeight}px + ${fullscreen ? -50 : 56}px )`"
></Table>
<!-- 指标越限详情 -->
<OverLimitDetails ref="OverLimitDetailsRef" />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import { ref, onMounted, provide, reactive, watch, nextTick } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import { ElTag } from 'element-plus'
import OverLimitDetails from '@/components/cockpit/listOfMainMonitoringPoints/components/overLimitDetails.vue'
import OverLimitDetails from '@/components/cockpit/indicatorFittingChart/components/overLimitDetails.vue'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const dictData = useDictData()
const OverLimitDetailsRef = ref()
const tableStore: any = new TableStore({
url: '/user-boot/role/selectRoleDetail?id=0',
method: 'POST',
const headerHeight = ref(57)
showPage: false,
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const tableHeaderRef = ref()
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
const tableStore: any = new TableStore({
url: '/harmonic-boot/mainLine/list',
method: 'POST',
showPage: fullscreen.value ? true : false,
exportName: '主要监测点列表',
column: [
{
@@ -48,79 +82,86 @@ const tableStore: any = new TableStore({
},
{
title: '监测点名称',
field: 'name',
field: 'lineName',
minWidth: '90',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.name}</span>`
return `<span style='cursor: pointer;text-decoration: underline;'>${row.lineName}</span>`
}
},
{
title: '监测对象类型',
field: 'type',
field: 'objType',
minWidth: '90'
},
{
title: '是否治理',
field: 'whetherToGovern',
field: 'govern',
minWidth: '70'
},
{ title: '主要存在的电能质量问题', field: 'question', minWidth: '150' }
{ title: '主要存在的电能质量问题', field: 'problems', minWidth: '150', showOverflow: true }
],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1]
},
loadCallback: () => {
tableStore.table.data = [
{
name: '10kV1#电动机',
type: '电动机',
whetherToGovern: '否',
question: '3次谐波电压、5次谐波电流、电压不平衡度超标'
},
{
name: '10kV2#(治理后)',
type: '电焊机',
whetherToGovern: '100A APF',
question: '所有指标均合格'
},
{
name: '380V电焊机(治理前)',
type: '电焊机',
whetherToGovern: '100A APF',
question: '5次谐波电流、电压不平衡度超标'
},
{
name: '380V水泵机',
type: '电动机',
whetherToGovern: '否',
question: '所有指标均合格'
}
]
tableStore.table.height = `calc(${prop.height} - 80px)`
}
})
const tableRef = ref()
provide('tableRef', tableRef)
tableStore.table.params.type = ''
tableStore.table.params.searchValue = ''
tableStore.table.params.keywords = ''
provide('tableStore', tableStore)
// 点击行
const cellClickEvent = ({ row, column }: any) => {
if (column.field == 'name') {
console.log(row)
OverLimitDetailsRef.value.open(row)
if (column.field == 'lineName') {
OverLimitDetailsRef.value.open(
row,
tableStore.table.params.searchBeginTime || prop.timeValue?.[0],
tableStore.table.params.searchEndTime || prop.timeValue?.[1]
)
}
}
// 获取缓存的初始值
const getInitialInterval = (): 3 => {
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.interval !== undefined) {
return cached.interval as 3 // 强制断言为 3 或根据实际类型调整
}
}
return 3 // 明确返回字面量类型 3
}
// 外部总的时间值
const getInitialTimeValue = () => {
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
return cached.timeValue
}
}
return prop.timeValue // 使用传入的默认值
}
// 在组件挂载时设置缓存值到 DatePicker
onMounted(() => {
tableStore.index()
})

View File

@@ -7,27 +7,70 @@
<el-select
v-model="tableStore.table.params.searchValue"
placeholder="请选择谐波次数"
style="width: 240px"
style="width: 150px"
>
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
<el-option
v-for="item in harmonicOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="指标类型">
<el-form-item label="指标类型" v-show="!tableStore.table.params.checked">
<el-select
v-model="tableStore.table.params.searchValue"
v-model="tableStore.table.params.indicatorType"
placeholder="请选择指标类型"
style="width: 240px"
style="width: 150px"
>
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
<el-option
v-for="item in indicatorList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="指标类型1" v-show="tableStore.table.params.checked == true">
<el-select
v-model="tableStore.table.params.indicatorType1"
placeholder="请选择指标类型1"
style="width: 150px"
>
<el-option
v-for="item in indicatorList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="指标类型2" v-show="tableStore.table.params.checked == true">
<el-select
v-model="tableStore.table.params.indicatorType2"
placeholder="请选择指标类型2"
style="width: 150px"
>
<el-option
v-for="item in indicatorList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-checkbox v-model="tableStore.table.params.checked">指标对比分析</el-checkbox>
</el-form-item>
</template>
</TableHeader>
<my-echart
class="tall"
v-if="!tableStore.table.params.checked"
:options="echartList"
style="width: 98%; height: 320px"
/>
<my-echart class="tall" v-else :options="echartContrastList" style="width: 98%; height: 320px" />
</el-dialog>
</template>
@@ -55,16 +98,12 @@ const options = [
]
const config = useConfig()
const powerList: any = ref([
{
label: '三相总有功功率',
value: '1'
},
{
label: '三相总无功功率',
value: '2'
}
])
const harmonicOptions = Array.from({ length: 50 }, (_, i) => ({
value: String(i + 1),
label: `${i + 1}次谐波`
}))
const exceedingTheLimitList: any = ref([
{
label: '越限',
@@ -95,9 +134,8 @@ const indicatorList: any = ref([
])
const echartList = ref({
title: {
text: '35kV进线谐波含有率',
text: '谐波电压含有率'
},
xAxis: {
type: 'time',
axisLabel: {
@@ -108,7 +146,6 @@ const echartList = ref({
}
}
},
yAxis: [{}, {}],
grid: {
left: '10px',
@@ -117,51 +154,171 @@ const echartList = ref({
options: {
series: [
{
// name: '暂降次数',
type: 'bar',
name: '有功功率',
name: 'A相',
type: 'line',
showSymbol: false,
smooth: true,
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]
['2025-10-16 07:00:00', 0.5],
['2025-10-16 07:15:00', 0.6],
['2025-10-16 07:30:00', 0.4],
['2025-10-16 07:45:00', 0.7],
['2025-10-16 08:00:00', 1.2],
['2025-10-16 08:15:00', 1.5],
['2025-10-16 08:30:00', 1.8],
['2025-10-16 08:45:00', 2.1],
['2025-10-16 09:00:00', 2.5],
['2025-10-16 09:15:00', 2.8],
['2025-10-16 09:30:00', 3.0],
['2025-10-16 09:45:00', 2.7],
['2025-10-16 10:00:00', 2.2],
['2025-10-16 10:15:00', 1.9],
['2025-10-16 10:30:00', 1.6],
['2025-10-16 10:45:00', 1.3],
['2025-10-16 11:00:00', 1.1],
['2025-10-16 11:15:00', 0.8],
['2025-10-16 11:30:00', 0.6],
['2025-10-16 11:45:00', 0.4],
['2025-10-16 12:00:00', 0.3],
['2025-10-16 12:15:00', 0.2],
['2025-10-16 12:30:00', 0.3],
['2025-10-16 12:45:00', 0.4]
],
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: '谐波总畸变率',
name: 'B相',
type: 'line',
showSymbol: false,
smooth: true,
data: [
['2025-10-16 07:00:00', 0.4],
['2025-10-16 07:15:00', 0.5],
['2025-10-16 07:30:00', 0.3],
['2025-10-16 07:45:00', 0.6],
['2025-10-16 08:00:00', 1.0],
['2025-10-16 08:15:00', 1.3],
['2025-10-16 08:30:00', 1.6],
['2025-10-16 08:45:00', 1.9],
['2025-10-16 09:00:00', 2.2],
['2025-10-16 09:15:00', 2.5],
['2025-10-16 09:30:00', 2.7],
['2025-10-16 09:45:00', 2.4],
['2025-10-16 10:00:00', 2.0],
['2025-10-16 10:15:00', 1.7],
['2025-10-16 10:30:00', 1.4],
['2025-10-16 10:45:00', 1.1],
['2025-10-16 11:00:00', 0.9],
['2025-10-16 11:15:00', 0.7],
['2025-10-16 11:30:00', 0.5],
['2025-10-16 11:45:00', 0.3],
['2025-10-16 12:00:00', 0.2],
['2025-10-16 12:15:00', 0.1],
['2025-10-16 12:30:00', 0.2],
['2025-10-16 12:45:00', 0.3]
],
yAxisIndex: 0
},
{
name: 'C相',
type: 'line',
showSymbol: false,
smooth: true,
data: [
['2025-10-16 07:00:00', 0.6],
['2025-10-16 07:15:00', 0.7],
['2025-10-16 07:30:00', 0.5],
['2025-10-16 07:45:00', 0.8],
['2025-10-16 08:00:00', 1.4],
['2025-10-16 08:15:00', 1.7],
['2025-10-16 08:30:00', 2.0],
['2025-10-16 08:45:00', 2.3],
['2025-10-16 09:00:00', 2.8],
['2025-10-16 09:15:00', 3.1],
['2025-10-16 09:30:00', 3.3],
['2025-10-16 09:45:00', 3.0],
['2025-10-16 10:00:00', 2.5],
['2025-10-16 10:15:00', 2.1],
['2025-10-16 10:30:00', 1.8],
['2025-10-16 10:45:00', 1.5],
['2025-10-16 11:00:00', 1.3],
['2025-10-16 11:15:00', 1.0],
['2025-10-16 11:30:00', 0.8],
['2025-10-16 11:45:00', 0.6],
['2025-10-16 12:00:00', 0.5],
['2025-10-16 12:15:00', 0.4],
['2025-10-16 12:30:00', 0.5],
['2025-10-16 12:45:00', 0.6]
],
yAxisIndex: 0
},
{
name: '暂降触发点',
type: 'line',
showSymbol: false,
smooth: true,
data: [
['2025-10-16 07:00:00', 3.14159],
['2025-10-16 07:15:00', 3.14159],
['2025-10-16 07:30:00', 3.14159],
['2025-10-16 07:45:00', 3.14159],
['2025-10-16 08:00:00', 3.14159],
['2025-10-16 08:15:00', 3.14159],
['2025-10-16 08:30:00', 3.14159],
['2025-10-16 08:45:00', 3.14159],
['2025-10-16 09:00:00', 3.14159],
['2025-10-16 09:15:00', 3.14159],
['2025-10-16 09:30:00', 3.14159],
['2025-10-16 09:45:00', 3.14159],
['2025-10-16 10:00:00', 3.14159],
['2025-10-16 10:15:00', 3.14159],
['2025-10-16 10:30:00', 3.14159],
['2025-10-16 10:45:00', 3.14159],
['2025-10-16 11:00:00', 3.14159],
['2025-10-16 11:15:00', 3.14159],
['2025-10-16 11:30:00', 3.14159],
['2025-10-16 11:45:00', 3.14159],
['2025-10-16 12:00:00', 3.14159],
['2025-10-16 12:15:00', 3.14159],
['2025-10-16 12:30:00', 3.14159],
['2025-10-16 12:45:00', 3.14159]
],
lineStyle: {
type: 'dashed',
color: '#ff0000' // 红色
},
itemStyle: {
color: '#ff0000' // 红色
},
yAxisIndex: 0
}
]
}
})
const echartContrastList = ref({
title: {
text: 'A相谐波电压和A相谐波电流对比趋势图'
},
xAxis: {
type: 'time',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
},
yAxis: [{}, {}],
grid: {
left: '10px',
right: '20px'
},
options: {
series: [
{
name: 'A相谐波电压',
type: 'line',
showSymbol: false,
smooth: true,
@@ -191,11 +348,45 @@ const echartList = ref({
['2025-10-16 12:30:00', 0],
['2025-10-16 12:45:00', 0]
],
yAxisIndex: 0
},
{
name: 'A相谐波电流',
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.05],
['2025-10-16 08:30:00', 0.05],
['2025-10-16 08:45:00', 0.05],
['2025-10-16 09:00:00', 0.5],
['2025-10-16 09:15:00', 0.5],
['2025-10-16 09:30:00', 0.5],
['2025-10-16 09:45:00', 0.5],
['2025-10-16 10:00:00', 0.4],
['2025-10-16 10:15:00', 0.4],
['2025-10-16 10:30:00', 0.4],
['2025-10-16 10:45:00', 0.4],
['2025-10-16 11:00:00', 0.4],
['2025-10-16 11:15:00', 0.05],
['2025-10-16 11:30:00', 0.05],
['2025-10-16 11:45:00', 0.05],
['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
@@ -219,6 +410,10 @@ tableStore.table.params.power = '1'
tableStore.table.params.indicator = '1'
tableStore.table.params.exceedingTheLimit = '1'
tableStore.table.params.searchValue = ''
tableStore.table.params.checked = false
tableStore.table.params.indicatorType = '' // 指标类型
tableStore.table.params.indicatorType1 = '' // 指标类型1
tableStore.table.params.indicatorType2 = '' // 指标类型2
provide('tableStore', tableStore)
onMounted(() => {

View File

@@ -0,0 +1,134 @@
<template>
<!-- 综合评估详情 -->
<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>
</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 options = [
{
value: '35kV进线',
label: '35kV进线'
}
]
const height = mainHeight(0, 2).height as any
const loop50 = (key: string) => {
let list: any[] = []
for (let i = 2; i < 51; i++) {
list.push({
title: i + '次',
// field: key + i,
field: 'flicker',
width: '80'
})
}
return list
}
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',
width: '150'
},
{
title: '名称',
field: 'name',
width: '150'
},
{
title: '闪变越限(分钟)',
field: 'flicker',
width: '80'
},
{
title: '谐波电压越限(分钟)',
children: loop50('voltage')
},
{
title: '谐波电流越限(分钟)',
children: loop50('harmonicCurrent')
},
{
title: '三相不平衡度越限(分钟)',
field: 'flicker',
width: '100'
},
{
title: '电压偏差越限(分钟)',
field: 'flicker',
width: '100'
},
{
title: '频率偏差越限(分钟)',
field: 'flicker',
width: '100'
}
],
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()
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@@ -8,7 +8,7 @@
<el-select
v-model="tableStore.table.params.searchValue"
placeholder="请选择监测点名称"
style="width: 240px"
style="width: 150px"
>
<el-option
v-for="item in options"
@@ -147,6 +147,7 @@ const open = async (row: any) => {
// 点击行
const cellClickEvent = ({ row, column }: any) => {
console.log(row, '1111')
if (column.field != 'name' && column.field != 'time') {
harmonicRatioRef.value.openDialog(row)
}

View File

@@ -70,6 +70,9 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useConfig } from '@/stores/config'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
@@ -78,6 +81,10 @@ const prop = defineProps({
timeKey: { type: String },
timeValue: { type: Object }
})
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const config = useConfig()
const powerList: any = ref([
{
@@ -243,8 +250,21 @@ const tableStore: any = new TableStore({
exportName: '主要监测点列表',
column: [],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {
tableStore.table.height = `calc(${prop.height} - 80px)`

View File

@@ -1,8 +1,8 @@
<template>
<div>
<!--监测点列表 -->
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} )`"></Table>
<TableHeader :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen"></TableHeader>
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`"></Table>
<!-- 指标越限详情 -->
<OverLimitDetails ref="OverLimitDetailsRef" />
</div>
@@ -11,19 +11,51 @@
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import { ElTag } from 'element-plus'
import OverLimitDetails from '@/components/cockpit/listOfMainMonitoringPoints/components/overLimitDetails.vue'
import TableHeader from '@/components/table/header/index.vue'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const dictData = useDictData()
const headerHeight = ref(57)
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
const OverLimitDetailsRef = ref()
const tableStore: any = new TableStore({
url: '/user-boot/role/selectRoleDetail?id=0',
@@ -64,7 +96,7 @@ const tableStore: any = new TableStore({
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;' onclick="handleReportClick('${row.name}')">${row.type2}</span>`
},
}
},
{ title: '监测点名称', field: 'type3', minWidth: '70' },
{ title: '监测类型', field: 'type4', minWidth: '60' },
@@ -80,8 +112,21 @@ const tableStore: any = new TableStore({
{ title: '最新数据时间', field: 'type6', minWidth: '140' }
],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {
tableStore.table.data = [

View File

@@ -0,0 +1,449 @@
<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: 150px"
>
<el-option
v-for="item in harmonicOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="指标类型" v-show="!tableStore.table.params.checked">
<el-select
v-model="tableStore.table.params.indicatorType"
placeholder="请选择指标类型"
style="width: 150px"
>
<el-option
v-for="item in indicatorList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="指标类型1" v-show="tableStore.table.params.checked == true">
<el-select
v-model="tableStore.table.params.indicatorType1"
placeholder="请选择指标类型1"
style="width: 150px"
>
<el-option
v-for="item in indicatorList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="指标类型2" v-show="tableStore.table.params.checked == true">
<el-select
v-model="tableStore.table.params.indicatorType2"
placeholder="请选择指标类型2"
style="width: 150px"
>
<el-option
v-for="item in indicatorList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-checkbox v-model="tableStore.table.params.checked">指标对比分析</el-checkbox>
</el-form-item>
</template>
</TableHeader>
<my-echart
class="tall"
v-if="!tableStore.table.params.checked"
:options="echartList"
style="width: 98%; height: 320px"
/>
<my-echart class="tall" v-else :options="echartContrastList" 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 harmonicOptions = Array.from({ length: 50 }, (_, i) => ({
value: String(i + 1),
label: `${i + 1}次谐波`
}))
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: '谐波电压含有率'
},
xAxis: {
type: 'time',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
},
yAxis: [{}, {}],
grid: {
left: '10px',
right: '20px'
},
options: {
series: [
{
name: 'A相',
type: 'line',
showSymbol: false,
smooth: true,
data: [
['2025-10-16 07:00:00', 0.5],
['2025-10-16 07:15:00', 0.6],
['2025-10-16 07:30:00', 0.4],
['2025-10-16 07:45:00', 0.7],
['2025-10-16 08:00:00', 1.2],
['2025-10-16 08:15:00', 1.5],
['2025-10-16 08:30:00', 1.8],
['2025-10-16 08:45:00', 2.1],
['2025-10-16 09:00:00', 2.5],
['2025-10-16 09:15:00', 2.8],
['2025-10-16 09:30:00', 3.0],
['2025-10-16 09:45:00', 2.7],
['2025-10-16 10:00:00', 2.2],
['2025-10-16 10:15:00', 1.9],
['2025-10-16 10:30:00', 1.6],
['2025-10-16 10:45:00', 1.3],
['2025-10-16 11:00:00', 1.1],
['2025-10-16 11:15:00', 0.8],
['2025-10-16 11:30:00', 0.6],
['2025-10-16 11:45:00', 0.4],
['2025-10-16 12:00:00', 0.3],
['2025-10-16 12:15:00', 0.2],
['2025-10-16 12:30:00', 0.3],
['2025-10-16 12:45:00', 0.4]
],
yAxisIndex: 0
},
{
name: 'B相',
type: 'line',
showSymbol: false,
smooth: true,
data: [
['2025-10-16 07:00:00', 0.4],
['2025-10-16 07:15:00', 0.5],
['2025-10-16 07:30:00', 0.3],
['2025-10-16 07:45:00', 0.6],
['2025-10-16 08:00:00', 1.0],
['2025-10-16 08:15:00', 1.3],
['2025-10-16 08:30:00', 1.6],
['2025-10-16 08:45:00', 1.9],
['2025-10-16 09:00:00', 2.2],
['2025-10-16 09:15:00', 2.5],
['2025-10-16 09:30:00', 2.7],
['2025-10-16 09:45:00', 2.4],
['2025-10-16 10:00:00', 2.0],
['2025-10-16 10:15:00', 1.7],
['2025-10-16 10:30:00', 1.4],
['2025-10-16 10:45:00', 1.1],
['2025-10-16 11:00:00', 0.9],
['2025-10-16 11:15:00', 0.7],
['2025-10-16 11:30:00', 0.5],
['2025-10-16 11:45:00', 0.3],
['2025-10-16 12:00:00', 0.2],
['2025-10-16 12:15:00', 0.1],
['2025-10-16 12:30:00', 0.2],
['2025-10-16 12:45:00', 0.3]
],
yAxisIndex: 0
},
{
name: 'C相',
type: 'line',
showSymbol: false,
smooth: true,
data: [
['2025-10-16 07:00:00', 0.6],
['2025-10-16 07:15:00', 0.7],
['2025-10-16 07:30:00', 0.5],
['2025-10-16 07:45:00', 0.8],
['2025-10-16 08:00:00', 1.4],
['2025-10-16 08:15:00', 1.7],
['2025-10-16 08:30:00', 2.0],
['2025-10-16 08:45:00', 2.3],
['2025-10-16 09:00:00', 2.8],
['2025-10-16 09:15:00', 3.1],
['2025-10-16 09:30:00', 3.3],
['2025-10-16 09:45:00', 3.0],
['2025-10-16 10:00:00', 2.5],
['2025-10-16 10:15:00', 2.1],
['2025-10-16 10:30:00', 1.8],
['2025-10-16 10:45:00', 1.5],
['2025-10-16 11:00:00', 1.3],
['2025-10-16 11:15:00', 1.0],
['2025-10-16 11:30:00', 0.8],
['2025-10-16 11:45:00', 0.6],
['2025-10-16 12:00:00', 0.5],
['2025-10-16 12:15:00', 0.4],
['2025-10-16 12:30:00', 0.5],
['2025-10-16 12:45:00', 0.6]
],
yAxisIndex: 0
},
{
name: '暂降触发点',
type: 'line',
showSymbol: false,
smooth: true,
data: [
['2025-10-16 07:00:00', 3.14159],
['2025-10-16 07:15:00', 3.14159],
['2025-10-16 07:30:00', 3.14159],
['2025-10-16 07:45:00', 3.14159],
['2025-10-16 08:00:00', 3.14159],
['2025-10-16 08:15:00', 3.14159],
['2025-10-16 08:30:00', 3.14159],
['2025-10-16 08:45:00', 3.14159],
['2025-10-16 09:00:00', 3.14159],
['2025-10-16 09:15:00', 3.14159],
['2025-10-16 09:30:00', 3.14159],
['2025-10-16 09:45:00', 3.14159],
['2025-10-16 10:00:00', 3.14159],
['2025-10-16 10:15:00', 3.14159],
['2025-10-16 10:30:00', 3.14159],
['2025-10-16 10:45:00', 3.14159],
['2025-10-16 11:00:00', 3.14159],
['2025-10-16 11:15:00', 3.14159],
['2025-10-16 11:30:00', 3.14159],
['2025-10-16 11:45:00', 3.14159],
['2025-10-16 12:00:00', 3.14159],
['2025-10-16 12:15:00', 3.14159],
['2025-10-16 12:30:00', 3.14159],
['2025-10-16 12:45:00', 3.14159]
],
lineStyle: {
type: 'dashed',
color: '#ff0000' // 红色
},
itemStyle: {
color: '#ff0000' // 红色
},
yAxisIndex: 0
}
]
}
})
const echartContrastList = ref({
title: {
text: 'A相谐波电压和A相谐波电流对比趋势图'
},
xAxis: {
type: 'time',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
},
yAxis: [{}, {}],
grid: {
left: '10px',
right: '20px'
},
options: {
series: [
{
name: 'A相谐波电压',
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: 0
},
{
name: 'A相谐波电流',
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.05],
['2025-10-16 08:30:00', 0.05],
['2025-10-16 08:45:00', 0.05],
['2025-10-16 09:00:00', 0.5],
['2025-10-16 09:15:00', 0.5],
['2025-10-16 09:30:00', 0.5],
['2025-10-16 09:45:00', 0.5],
['2025-10-16 10:00:00', 0.4],
['2025-10-16 10:15:00', 0.4],
['2025-10-16 10:30:00', 0.4],
['2025-10-16 10:45:00', 0.4],
['2025-10-16 11:00:00', 0.4],
['2025-10-16 11:15:00', 0.05],
['2025-10-16 11:30:00', 0.05],
['2025-10-16 11:45:00', 0.05],
['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 = ''
tableStore.table.params.checked = false
tableStore.table.params.indicatorType = '' // 指标类型
tableStore.table.params.indicatorType1 = '' // 指标类型1
tableStore.table.params.indicatorType2 = '' // 指标类型2
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

@@ -0,0 +1,185 @@
<template>
<div>
<!-- 指标越限详情 -->
<el-dialog draggable title="指标越限详情" v-model="dialogVisible" append-to-body width="70%">
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef">
<template v-slot:select>
<el-form-item label="监测点">
<el-select
v-model="tableStore.table.params.lineId"
placeholder="请选择监测点"
style="width: 150px"
>
<el-option
v-for="item in options"
:key="item.lineId"
:label="item.name"
:value="item.lineId"
/>
</el-select>
</el-form-item>
</template>
</TableHeader>
<Table ref="tableRef" @cell-click="cellClickEvent" isGroup :height="height"></Table>
</el-dialog>
<!-- 谐波电流谐波电压占有率 -->
<HarmonicRatio ref="harmonicRatioRef" @close="onHarmonicRatioClose" :TrendList="TrendList" />
</div>
</template>
<script setup lang="ts">
import { ref, provide,nextTick } from 'vue'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import TableStore from '@/utils/tableStore'
import { mainHeight } from '@/utils/layout'
import HarmonicRatio from '@/components/cockpit/overLimitStatistics/components/harmonicRatio.vue'
import { cslineList } from '@/api/harmonic-boot/cockpit/cockpit'
const dialogVisible: any = ref(false)
const harmonicRatioRef: any = ref(null)
const options = ref()
const height = mainHeight(0, 2).height as any
const tableHeaderRef = ref()
const TrendList = ref([{lineType:1}])
const loop50 = (key: string) => {
let list: any[] = []
for (let i = 2; i < 26; i++) {
list.push({
title: i + '次',
field: key + i + 'Overtime',
width: '80',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row[key + i + 'Overtime']}</span>`
}
})
}
return list
}
const tableStore: any = new TableStore({
url: '/harmonic-boot/totalLimitStatistics/details',
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',
width: '150',
sortable: true
},
{
title: '名称',
field: 'lineName',
width: '150'
},
{
title: '闪变越限(%)',
field: 'flickerOvertime',
width: '80',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>`
}
},
{
title: '谐波电压越限(%)',
children: loop50('uharm')
},
{
title: '谐波电流越限(%)',
children: loop50('iharm')
},
{
title: '三相不平衡度越限(%)',
field: 'ubalanceOvertime',
width: '100',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>`
}
},
{
title: '电压偏差越限(%)',
field: 'uaberranceOvertime',
width: '100',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.uaberranceOvertime}</span>`
}
},
{
title: '频率偏差越限(%)',
field: 'freqDevOvertime',
width: '100',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.freqDevOvertime}</span>`
}
}
],
beforeSearchFun: () => {
},
loadCallback: () => {
}
})
provide('tableStore', tableStore)
tableStore.table.params.sortBy = ''
tableStore.table.params.orderBy = ''
const open = async (row: any,searchBeginTime:any,searchEndTime:any) => {
dialogVisible.value = true
initCSlineList()
tableStore.table.params.lineId = row.lineId
nextTick(() => {
tableHeaderRef.value.setTimeInterval([searchBeginTime, searchEndTime])
tableStore.table.params.searchBeginTime =searchBeginTime
tableStore.table.params.searchEndTime = searchEndTime
tableStore.index()
})
}
// 点击行
const cellClickEvent = ({ row, column }: any) => {
if (column.field != 'name' && column.field != 'time') {
dialogVisible.value = false
// if(column.title && column.title=='闪变越限(分钟)'){
// column.title = '1次'
// }
// harmonicRatioRef.value.openDialog(row,column.title.replace(/次/g, ""))
harmonicRatioRef.value.openDialog(row,column.title)
harmonicRatioRef.value.getTrendRequest(row)
}
}
// 谐波弹窗关闭时的回调
const onHarmonicRatioClose = () => {
// 重新打开指标越限详情弹窗
nextTick(() => {
dialogVisible.value = true
})
}
const initCSlineList = async () => {
const res = await cslineList({})
options.value = res.data
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@@ -1,13 +1,21 @@
<template>
<div>
<!--总体指标越限统计 -->
<TableHeader :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen"></TableHeader>
<my-echart
class="tall"
:options="echartList"
: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 - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`"
isGroup
></Table>
<!-- 指标越限详情 -->
<OverLimitDetails ref="OverLimitDetailsRef" />
</div>
@@ -16,17 +24,49 @@
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import OverLimitDetails from '@/components/cockpit/listOfMainMonitoringPoints/components/overLimitDetails.vue'
import OverLimitDetails from '@/components/cockpit/overLimitStatistics/components/overLimitDetails.vue'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const headerHeight = ref(57)
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
const echartList = ref({
title: {
text: '指标越限占比'
@@ -52,7 +92,7 @@ const echartList = ref({
type: 'bar',
name: '越限占比',
data: [0, 45, 22, 0, 70],
barMaxWidth: 30,
barMaxWidth: 30
// label: {
// show: true,
@@ -69,7 +109,7 @@ const echartList = ref({
})
const OverLimitDetailsRef = ref()
const tableStore: any = new TableStore({
url: '/user-boot/dept/deptTree',
url: '/harmonic-boot/totalLimitStatistics/list',
method: 'POST',
showPage: false,
@@ -85,7 +125,7 @@ const tableStore: any = new TableStore({
},
{
title: '名称',
field: 'name',
field: 'lineName',
minWidth: '90'
},
{
@@ -93,68 +133,70 @@ const tableStore: any = new TableStore({
children: [
{
title: '闪变',
field: 'type',
field: 'flicker',
minWidth: '70',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type}</span>`
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flicker}</span>`
}
},
{
title: '谐波电压',
field: 'type1',
field: 'uharm',
minWidth: '80',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type1}</span>`
return `<span style='cursor: pointer;text-decoration: underline;'>${row.uharm}</span>`
}
},
{
title: '谐波电流',
field: 'type2',
field: 'iharm',
minWidth: '80',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type2}</span>`
return `<span style='cursor: pointer;text-decoration: underline;'>${row.iharm}</span>`
}
},
{
title: '电压偏差',
field: 'type3',
field: 'voltageDev',
minWidth: '80',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type3}</span>`
return `<span style='cursor: pointer;text-decoration: underline;'>${row.voltageDev}</span>`
}
},
{
title: '三相不平衡',
field: 'type4',
field: 'ubalance',
minWidth: '90',
render: 'customTemplate',
customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type4}</span>`
return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalance}</span>`
}
}
]
}
],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {
tableStore.table.data = [
{
name: '10kV1#电动机',
type: '0',
type1: '45',
type2: '22',
type3: '0',
type4: '70'
}
]
tableStore.table.height = `calc(${prop.height} - 80px)`
}
})
@@ -167,8 +209,11 @@ provide('tableStore', tableStore)
// 点击行
const cellClickEvent = ({ row, column }: any) => {
if (column.field != 'name') {
console.log(row)
OverLimitDetailsRef.value.open(row)
OverLimitDetailsRef.value.open(
row,
tableStore.table.params.searchBeginTime || prop.timeValue?.[0],
tableStore.table.params.searchEndTime || prop.timeValue?.[1]
)
}
}

View File

@@ -1,25 +1,57 @@
<template>
<div>
<!--敏感负荷列表 -->
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height})`" isGroup></Table>
<TableHeader :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen"></TableHeader>
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`" isGroup></Table>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import TableHeader from '@/components/table/header/index.vue'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const headerHeight = ref(57)
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
const OverLimitDetailsRef = ref()
const tableStore: any = new TableStore({
url: '/user-boot/dept/deptTree',
@@ -59,8 +91,21 @@ const tableStore: any = new TableStore({
}
],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {
tableStore.table.data = [

View File

@@ -1,8 +1,8 @@
<template>
<div>
<!--暂态事件明细 -->
<el-calendar v-model="value" :style="{ height: prop.height, overflow: 'auto' }">
<TableHeader :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen"></TableHeader>
<el-calendar v-model="value" :style="{ height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`, overflow: 'auto' }">
<template #date-cell="{ data }">
<div style="height: 100%; padding: 8px" :style="{ background: setBackground(data.day) }">
<p :class="data.isSelected ? 'is-selected' : ''">
@@ -42,23 +42,53 @@
<script setup lang="ts">
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import { overflow } from 'html2canvas/dist/types/css/property-descriptors/overflow'
import { dayjs } from 'element-plus'
import TransientList from './components/transientList.vue'
import TableHeader from '@/components/table/header/index.vue'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
dayjs.en.weekStart = 1 //设置日历的周起始日为星期一
const value = ref(new Date())
const prop = defineProps({
w: { type: String },
h: { type: String },
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const headerHeight = ref(57)
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
dayjs.en.weekStart = 1 //设置日历的周起始日为星期一
const value = ref(new Date())
const transientListRef = ref()
const list = ref([
{
@@ -113,9 +143,21 @@ const tableStore: any = new TableStore({
column: [],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// value.value = new Date(prop.timeValue?.[0])
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {
tableStore.table.data = []

View File

@@ -1,34 +1,68 @@
<template>
<div>
<!--暂态事件概率分布 -->
<TableHeader :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen"></TableHeader>
<my-echart
class="tall"
:options="echartList"
:style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }"
:style="{ width: prop.width, height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )` }"
/>
<my-echart
class="mt10"
:options="echartList1"
:style="{ width: prop.width, height: `calc(${prop.height} / 2 - 10px)` }"
:style="{ width: prop.width, height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )` }"
/>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import { ref, onMounted, provide, reactive, watch } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import { useConfig } from '@/stores/config'
const config = useConfig()
import TableHeader from '@/components/table/header/index.vue'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const headerHeight = ref(57)
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
const config = useConfig()
const echartList = ref({
options: {
xAxis: null,
@@ -308,8 +342,21 @@ const tableStore: any = new TableStore({
showPage: false,
column: [],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {
tableStore.table.data = []

View File

@@ -1,12 +1,21 @@
<template>
<div>
<!--暂态事件统计 -->
<TableHeader :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen"></TableHeader>
<my-echart
class="tall"
:options="echartList"
:style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }"
:style="{
width: prop.width,
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
}"
/>
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} / 2 )`" isGroup></Table>
<Table
ref="tableRef"
@cell-click="cellClickEvent"
:height="`calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`"
isGroup
></Table>
<TransientStatisticsDetail ref="transientStatisticsDetailRef"></TransientStatisticsDetail>
</div>
</template>
@@ -15,18 +24,51 @@ import { ref, onMounted, provide, reactive, watch, h } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import { useConfig } from '@/stores/config'
import TransientStatisticsDetail from './components/transientStatisticsDetail.vue'
const config = useConfig()
import TableHeader from '@/components/table/header/index.vue'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
width: { type: String },
height: { type: String },
timeKey: { type: String },
timeValue: { type: Object }
})
const headerHeight = ref(57)
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
// 计算是否全屏展示
const fullscreen = computed(() => {
const w = Number(prop.w)
const h = Number(prop.h)
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
// 执行相应逻辑
return true
} else {
return false
}
})
const config = useConfig()
const data = [
{
name: '电压中断',
@@ -148,8 +190,20 @@ const tableStore: any = new TableStore({
}
],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {
tableStore.table.data = [

View File

@@ -1,7 +1,7 @@
<template>
<div>
<!--趋势对比 -->
<TableHeader :showReset="false" @selectChange="selectChange" v-if="fullscreen">
<TableHeader :showReset="false" datePicker @selectChange="selectChange" v-if="fullscreen">
<template v-slot:select>
<el-form-item label="监测点名称">
<el-select
@@ -67,6 +67,8 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import { getTimeOfTheMonth } from '@/utils/formatTime'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useConfig } from '@/stores/config'
import { useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const prop = defineProps({
w: { type: String },
h: { type: String },
@@ -75,6 +77,9 @@ const prop = defineProps({
timeKey: { type: String },
timeValue: { type: Object }
})
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
const config = useConfig()
const powerList: any = ref([
{
@@ -238,8 +243,15 @@ const echartList = ref({
}
})
const headerHeight = ref(57)
const selectChange = (showSelect: any, height: any) => {
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
// 如果有传入 datePicker 的值
if (datePickerValue) {
// 更新表格参数
tableStore.table.params.searchBeginTime = datePickerValue.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue?.[1]
}
}
const tableStore: any = new TableStore({
url: '/user-boot/role/selectRoleDetail?id=0',
@@ -249,8 +261,21 @@ const tableStore: any = new TableStore({
exportName: '主要监测点列表',
column: [],
beforeSearchFun: () => {
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
// 尝试从缓存获取时间值
let beginTime, endTime
if (fullscreen.value) {
const cached = timeCacheStore.getCache(route.path)
if (cached && cached.timeValue) {
beginTime = cached.timeValue[0]
endTime = cached.timeValue[1]
}
}
// 如果缓存中没有则使用默认值
tableStore.table.params.searchBeginTime = beginTime || prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
tableStore.table.params.searchEndTime = endTime || prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
},
loadCallback: () => {
tableStore.table.height = `calc(${prop.height} - 80px)`

View File

@@ -1,13 +1,26 @@
<template>
<div style="width: 540px">
<el-select v-model.trim="interval" style="min-width: 90px; width: 90px; margin-right: 10px"
@change="timeChange">
<el-select
v-model.trim="interval"
style="min-width: 90px; width: 90px; margin-right: 10px"
@change="timeChange"
>
<el-option v-for="item in timeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-date-picker v-model.trim="timeValue" type="daterange" :disabled="disabledPicker"
style="width: 220px; margin-right: 10px" unlink-panels :clearable="false" range-separator=""
start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD" :shortcuts="shortcuts" />
<el-date-picker
v-model.trim="timeValue"
type="daterange"
:disabled="disabledPicker"
style="width: 220px; margin-right: 10px"
unlink-panels
:clearable="false"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
:shortcuts="shortcuts"
/>
<el-button :disabled="backDisabled" type="primary" :icon="DArrowLeft" @click="preClick"></el-button>
<el-button type="primary" :icon="VideoPause" @click="nowTime">当前</el-button>
<el-button :disabled="preDisabled" type="primary" :icon="DArrowRight" @click="next"></el-button>
@@ -21,13 +34,19 @@ import { ref, onMounted, nextTick, watch } from 'vue'
interface Props {
nextFlag?: boolean
theCurrentTime?: boolean
initialInterval?: number
initialTimeValue?: any
}
const props = withDefaults(defineProps<Props>(), {
nextFlag: false,
theCurrentTime: true
theCurrentTime: true,
initialInterval: 3,
initialTimeValue: undefined
})
const emit = defineEmits(['change'])
const interval = ref(3)
const timeFlag = ref(1)
const count = ref(0)
@@ -72,8 +91,27 @@ const shortcuts = [
}
]
onMounted(() => {
// 使用传入的初始值
if (props.initialInterval !== undefined) {
interval.value = props.initialInterval
}
if (props.initialTimeValue) {
timeValue.value = props.initialTimeValue
}
timeChange(3)
})
// 添加统一的事件触发方法
const emitChange = () => {
nextTick(() => {
emit('change', {
interval: interval.value,
timeValue: timeValue.value,
timeFlag: timeFlag.value
})
})
}
// 选择时间范围
const timeChange = (e: number) => {
backDisabled.value = false
@@ -110,6 +148,8 @@ const timeChange = (e: number) => {
} else {
timeFlag.value = 1
}
// 触发 change 事件
emitChange()
}
// 当前
@@ -178,6 +218,9 @@ const preClick = () => {
// 判断向后键的状态
// var temp = NowgetEndTime()
// timeStatus(temp, endTime)
// 触发 change 事件
emitChange()
}
//下一个
const next = () => {
@@ -383,7 +426,6 @@ const next = () => {
if (year >= presentY && !props.nextFlag) {
startTime = presentY + '-01-01'
if (presentM < 10) {
if (presentD < 10) {
endTime = presentY + '-0' + presentM + '-0' + presentD
} else {
@@ -400,18 +442,31 @@ const next = () => {
startTime = year + '-01-01'
endTime = year + '-12-31'
}
}
if (!props.nextFlag) {
if (new Date(endTime + ' 00:00:00').getTime() >= new Date(window.XEUtils.toDateString(new Date(), 'yyyy-MM-dd ') + ' 00:00:00').getTime()) {
if (
new Date(endTime + ' 00:00:00').getTime() >=
new Date(window.XEUtils.toDateString(new Date(), 'yyyy-MM-dd ') + ' 00:00:00').getTime()
) {
preDisabled.value = true
}
}
timeValue.value = [startTime, endTime]
// 触发 change 事件
emitChange()
}
// 监听值变化并触发事件
watch(
[interval, timeValue],
() => {
emitChange()
},
{ deep: true }
)
const setTime = (flag = 0, e = 0) => {
let dd = window.XEUtils.toDateString(new Date().getTime() - e * 3600 * 1000 * 24, 'dd')

View File

@@ -10,7 +10,12 @@
:inline="true"
>
<el-form-item label="日期" v-if="datePicker" style="grid-column: span 2; max-width: 570px">
<DatePicker ref="datePickerRef" :nextFlag="nextFlag" :theCurrentTime="theCurrentTime"></DatePicker>
<DatePicker
ref="datePickerRef"
:nextFlag="nextFlag"
:theCurrentTime="theCurrentTime"
@change="handleDatePickerChange"
></DatePicker>
</el-form-item>
<el-form-item label="区域" v-if="area">
@@ -57,6 +62,9 @@ import { mainHeight } from '@/utils/layout'
import { useDictData } from '@/stores/dictData'
import { Search, RefreshLeft } from '@element-plus/icons-vue'
import { defineProps } from 'vue'
import { useTimeCacheStore } from '@/stores/timeCache'
import { useRoute } from 'vue-router'
const emit = defineEmits(['selectChange'])
const tableStore = inject('tableStore') as TableStore
@@ -67,6 +75,11 @@ const areaRef = ref()
const headerForm = ref()
const headerFormSecond = ref()
const num = ref(0)
// 获取路由和缓存 store
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
interface Props {
datePicker?: boolean
area?: boolean
@@ -86,6 +99,18 @@ const props = withDefaults(defineProps<Props>(), {
showReset: true,
showExport: false
})
// 处理 DatePicker 值变化事件
const handleDatePickerChange = (value: any) => {
// 将值缓存到 timeCache
if (value) {
timeCacheStore.setCache(route.path, value.interval, value.timeValue)
}
// 将 datePicker 的变化传递给父组件
emit('selectChange', true, tableHeader.value.offsetHeight, value)
}
// 动态计算table高度
let resizeObserver = new ResizeObserver(entries => {
for (const entry of entries) {
@@ -105,16 +130,31 @@ const headerFormSecondStyleClose = {
padding: '0'
}
onMounted(() => {
if (props.datePicker && tableStore) {
tableStore.table.params.searchBeginTime = datePickerRef.value?.timeValue[0]
tableStore.table.params.searchEndTime = datePickerRef.value?.timeValue[1]
tableStore.table.params.startTime = datePickerRef.value?.timeValue[0]
tableStore.table.params.endTime = datePickerRef.value?.timeValue[1]
// 设置初始值到 DatePicker
if (props.datePicker && datePickerRef.value) {
// 从缓存中获取值并设置
const cached = timeCacheStore.getCache(route.path)
if (cached) {
if (cached.interval !== undefined) {
datePickerRef.value.setInterval(cached.interval)
}
if (cached.timeValue) {
datePickerRef.value.timeValue = cached.timeValue
}
}
// 更新 tableStore 参数
tableStore.table.params.searchBeginTime = datePickerRef.value?.timeValue?.[0]
tableStore.table.params.searchEndTime = datePickerRef.value?.timeValue?.[1]
tableStore.table.params.startTime = datePickerRef.value?.timeValue?.[0]
tableStore.table.params.endTime = datePickerRef.value?.timeValue?.[1]
tableStore.table.params.timeFlag = datePickerRef.value?.timeFlag
}
if (props.area) {
tableStore.table.params.deptIndex = dictData.state.area[0].id
}
nextTick(() => {
resizeObserver.observe(tableHeader.value)
computedSearchRow()
@@ -189,12 +229,29 @@ const onResetForm = () => {
const setInterval = (val: any) => {
datePickerRef.value.setInterval(val)
}
const setTimeInterval = (val: any) => {
datePickerRef.value.timeValue = val
tableStore.table.params.searchBeginTime = val[0]
tableStore.table.params.searchEndTime = val[1]
tableStore.table.params.startTime = val[0]
tableStore.table.params.endTime = val[1]
}
// 导出
const onExport = () => {
tableStore.onTableAction('export', { showAllFlag: true })
}
defineExpose({ onComSearch, areaRef, setDatePicker, setInterval, datePickerRef, showSelectChange, computedSearchRow })
defineExpose({
onComSearch,
areaRef,
setDatePicker,
setInterval,
setTimeInterval,
datePickerRef,
showSelectChange,
computedSearchRow
})
</script>
<style scoped lang="scss">

View File

@@ -15,7 +15,7 @@
style='cursor: pointer' v-if='props.canExpand' /> -->
</div>
<el-tree :style="{ height: 'calc(100vh - 200px)' }"
style=' overflow: auto;' ref='treeRef' :props='defaultProps' highlight-current
style=' overflow: auto;' ref='treeRef' :props='defaultProps' highlight-current :default-expand-all="false"
@check-change="checkTreeNodeChange" :filter-node-method='filterNode' node-key='id' v-bind='$attrs'>
<template #default='{ node, data }'>
<span class='custom-tree-node'>
@@ -75,7 +75,6 @@ const filterNode = (value: string, data: any, node: any) => {
// 过滤父节点 / 子节点 (如果输入的参数是父节点且能匹配则返回该节点以及其下的所有子节点如果参数是子节点则返回该节点的父节点。name是中文字符enName是英文字符.
const chooseNode = (value: string, data: any, node: any) => {
if (data.name.indexOf(value) !== -1) {
return true
}

View File

@@ -29,7 +29,7 @@
</div>
<el-tree :style="{ height: 'calc(100vh - 200px)' }"
style=' overflow: auto;' ref='treeRef' :props='defaultProps' highlight-current
style=' overflow: auto;' ref='treeRef' :props='defaultProps' highlight-current :default-expand-all="false"
@check-change="checkTreeNodeChange" :filter-node-method='filterNode' node-key='id' v-bind='$attrs'>
<template #default='{ node, data }'>
<span class='custom-tree-node'>

View File

@@ -24,6 +24,7 @@
@node-click="handleNodeClick"
:default-checked-keys="defaultCheckedKeys"
v-bind='$attrs'
:default-expand-all="false"
>
<template #default='{ node, data }'>
<span class='custom-tree-node'>
@@ -119,8 +120,69 @@ const handleNodeClick = (data: any, node: any, event: any) => {
// 存储所有勾选的节点
const checkedNodes = ref<any[]>([])
const defaultCheckedKeys = ref<string[]>([])
// 处理节点勾选变化
const handleCheckChange = (data: any, checkInfo: any) => {
const { checkedNodes: nodes } = checkInfo
// 过滤出监测点层级(level=3)的节点
const monitoringPointNodes = nodes.filter((node: any) => {
return node.level === 3
})
// 限制最多只能勾选5个监测点
if (monitoringPointNodes.length > 5) {
// 获取之前选中的节点
const previousCheckedNodes = checkedNodes.value || []
// 计算新增的节点
const newNodes = monitoringPointNodes.filter(
(node: any) => !previousCheckedNodes.some((prev: any) => prev.id === node.id)
)
// 如果是从父级勾选导致超过限制,保留前几个直到达到限制数量
if (newNodes.length > 0) {
const allowedNewCount = 5 - previousCheckedNodes.length
if (allowedNewCount > 0) {
// 允许添加allowedNewCount个新节点
const allowedNewNodes = newNodes.slice(0, allowedNewCount)
const finalNodes = [...previousCheckedNodes, ...allowedNewNodes]
checkedNodes.value = finalNodes
// 设置树的勾选状态为正确的节点
treeRef.value?.setCheckedNodes(finalNodes)
// 将勾选的监测点节点暴露出去
emit('checkedNodesChange', finalNodes)
// 更新节点的可勾选状态
updateNodeCheckStatus(finalNodes.length)
// 只有在真正超过5个时才提示警告
if (monitoringPointNodes.length > 5) {
ElMessage.warning('最多只能选择5个监测点')
}
return
}
}
// 其他情况回滚到之前的状态
ElMessage.warning('最多只能选择5个监测点')
treeRef.value?.setCheckedNodes(checkedNodes.value)
return
}
checkedNodes.value = monitoringPointNodes
// 将勾选的监测点节点暴露出去
emit('checkedNodesChange', monitoringPointNodes)
// 更新节点的可勾选状态
updateNodeCheckStatus(monitoringPointNodes.length)
}
// 处理节点勾选变化
const handleCheckChange2 = (data: any, checkInfo: any) => {
const { checkedNodes: nodes } = checkInfo
// 过滤出监测点层级(level=3)的节点
const monitoringPointNodes = nodes.filter((node: any) => {

34
src/stores/timeCache.ts Normal file
View File

@@ -0,0 +1,34 @@
// src/stores/timeCache.ts
import { defineStore } from 'pinia'
import { RouteLocationNormalizedLoaded } from 'vue-router'
// 时间组件的缓存值 用于驾驶舱放大的时候和内部的时间组件同步
interface TimeCacheState {
cache: Map<string, {
interval: number | undefined // 时间组件的月份、年份、时间、时间格式的缓存值
timeValue: any // 时间组件的值
}>
}
export const useTimeCacheStore = defineStore('timeCache', {
state: (): TimeCacheState => ({
cache: new Map()
}),
actions: {
setCache(routePath: string, interval: number | undefined, timeValue: any) {
this.cache.set(routePath, {
interval,
timeValue
})
},
getCache(routePath: string) {
return this.cache.get(routePath)
},
hasCache(routePath: string) {
return this.cache.has(routePath)
}
}
})

View File

@@ -1,3 +1,5 @@
import { number } from "vue-types"
const dataProcessing = (arr: any[]) => {
return arr
.filter(item => typeof item === 'number' || (typeof item === 'string' && !isNaN(parseFloat(item))))
@@ -12,6 +14,7 @@ const calculateValue = (o: number, value: number, num: number, isMin: boolean) =
} else if (value > -1 && value < 0 && isMin == false) {
return 0
}
let base
if (Math.abs(o) >= 100) {
base = 100
@@ -20,7 +23,9 @@ const calculateValue = (o: number, value: number, num: number, isMin: boolean) =
} else if (Math.abs(o) >= 1) {
base = 1
} else {
base = 0.1
const multiple = 1 / 0.1
// 先放大→向上取整→再缩小
return Math.ceil(Math.abs(o) * multiple) / multiple
}
let calculatedValue
if (isMin) {
@@ -34,8 +39,10 @@ const calculateValue = (o: number, value: number, num: number, isMin: boolean) =
calculatedValue = value - num * value
} else {
calculatedValue = value + num * value
}
}
if (base === 0.1) {
return parseFloat(calculatedValue.toFixed(1))
} else if (isMin) {
@@ -57,6 +64,7 @@ export const yMethod = (arr: any) => {
minValue = Math.min(...numList)
const o = maxValue - minValue
min = calculateValue(o, minValue, num, true)
max = calculateValue(o, maxValue, num, false)
// if (-100 >= minValue) {
// min = Math.floor((minValue + num * minValue) / 100) * 100

View File

@@ -313,6 +313,7 @@ const sourceChange = (e: any) => {
tableStore.table.params.engineeringid = e[1] || ''
tableStore.table.params.projectId = e[2] || ''
}
}
// tableStore.table.params.engineeringid = e[1] || ''

View File

@@ -1068,7 +1068,7 @@ const add = () => {
nodeId: '',
cntractNo: '',
sort: 0,
nodeProcess: '自动分配',
nodeProcess: '',
})
busBarIndex.value = (deviceInfoList.value.length - 1).toString()
// 清理监测点数据
@@ -1325,7 +1325,7 @@ const remove = () => {
message: res.message
})
reaseStatus()
console.log('engineeringId',engineeringId)
if (engineeringId) {
setTimeout(() => {
treedata(engineeringId)
@@ -1359,7 +1359,7 @@ const remove = () => {
case 4: // 监测点层级
const deviceId = nodeData.value.pids ? nodeData.value.pids.split(',')[3] : null
console.log(deviceId)
deleteLine(nodeData.value.id).then((res: any) => {
ElMessage({
type: 'success',
@@ -1421,7 +1421,7 @@ const next = async () => {
nodeId: '',
cntractNo: '',
sort: 0,
nodeProcess: '自动分配',
nodeProcess: '',
})
busBarIndex.value = (deviceInfoList.value.length - 1).toString()
nextfalg.value = false
@@ -1536,9 +1536,8 @@ const submitAllLevelData = () => {
// 项目信息
const projectData = tempAllLevelData.value.projects.length > 0
? tempAllLevelData.value.projects[0]
? tempAllLevelData.value.projects.find(project => project !== undefined) || {}
: (projectInfoList.value[0] || {})
// 如果是从根节点开始新增工程和项目
if (nodeData.value.level === 0) {
submitData = {
@@ -1557,10 +1556,9 @@ const submitAllLevelData = () => {
case 2: // 工程 + 项目 + 设备
// 工程信息
const engineeringData2 = tempAllLevelData.value.engineering || { ...engineeringParam.value }
// 项目信息
const projectData2 = tempAllLevelData.value.projects.length > 0
? tempAllLevelData.value.projects[0]
? tempAllLevelData.value.projects.find(project => project !== undefined) || {}
: (projectInfoList.value[0] || {})
// 设备信息
@@ -1616,7 +1614,7 @@ const submitAllLevelData = () => {
// 项目信息
const projectData3 = tempAllLevelData.value.projects.length > 0
? tempAllLevelData.value.projects[0]
? tempAllLevelData.value.projects.find(project => project !== undefined) || {}
: (projectInfoList.value[0] || {})
// 设备信息
@@ -1771,9 +1769,8 @@ const submitAllLevelData = () => {
pageStatus.value = 1
// 清空所有表单
resetAllForms()
// 刷新树并选中合适的节点
TerminalRef.value.info().then(() => {
TerminalRef.value.info()
// 等待树更新完成后,根据之前点击的节点层级选中合适的节点
setTimeout(() => {
let nodeIdToSelect: string|null|undefined = null;
@@ -1808,7 +1805,7 @@ const submitAllLevelData = () => {
treedata(); // 选中根节点
}
}, 100);
})
})
}
/**
@@ -2120,7 +2117,7 @@ const handleBusBarTabsEdit = (targetName: any, action: any) => {
nodeId: '',
cntractNo: '',
sort: 0,
nodeProcess: '自动分配',
nodeProcess: '',
})
busBarIndex.value = (deviceInfoList.value.length - 1).toString()
} else if (action === 'remove') {
@@ -2240,6 +2237,7 @@ const tabChange = (type: string) => {
}
const treedata = (selectedNodeId?: string) => {
if (selectedNodeId) {
TerminalRef.value.info(selectedNodeId);
} else {
@@ -2296,10 +2294,15 @@ const area = () => {
onMounted(() => {
nodeData.value.level = 0
nextTick(() => {
const dom = document.getElementById('navigation-splitpanes')
if (dom) {
if (dom && dom.offsetHeight > 0) {
size.value = Math.round((180 / dom.offsetHeight) * 100)
} else {
// 设置默认值
size.value = 20
}
})
})
area()
</script>

View File

@@ -99,11 +99,15 @@ tableStore.table.params.resourceType = 1
tableStore.table.params.customType = 1
const flag = ref(true)
onMounted(() => {
nextTick(() => {
const dom = document.getElementById('navigation-splitpanes')
if (dom) {
if (dom && dom.offsetHeight > 0) {
size.value = ((280 / (dom.offsetWidth - 7)) * 100)
} else {
// 设置默认值
size.value = 20
}
})
})
// getTemplateByDept({ id: dictData.state.area[0].id }).then((res: any) => {

View File

@@ -31,6 +31,7 @@
</template>
<template v-slot:operation>
<el-button type="primary" class="ml10" @click="add" icon="el-icon-Plus">新增</el-button>
</template>
</TableHeader>
<Table
@@ -81,17 +82,7 @@
</el-tooltip>
</template>
<template v-else>
<el-popconfirm
class="box-item"
title="确定重启吗?"
placement="bottom"
@confirm="restart(data)"
>
<template #actions="{ confirm, cancel }">
<el-button size="small" @click="cancel">取消</el-button>
<el-button type="warning" size="small" @click="confirm">确认</el-button>
</template>
<el-popconfirm title="确定重启吗?" placement="bottom" @confirm="restart(data)">
<template #reference>
<el-tooltip content="重启" placement="top">
<el-button
@@ -99,10 +90,13 @@
icon="el-icon-Refresh"
type="warning"
link
@click.stop
></el-button>
/>
</el-tooltip>
</template>
<template #actions="{ confirm, cancel }">
<el-button size="small" @click="cancel">取消</el-button>
<el-button type="warning" size="small" @click="confirm">确认</el-button>
</template>
</el-popconfirm>
</template>
</div>
@@ -433,6 +427,7 @@ const currentChangeEvent = () => {
// 重启进程
const restart = (data: any) => {
restartProcess({
nodeId: nodeId.value,
processNo: data.processNo

View File

@@ -1,9 +1,9 @@
<template>
<div class="default-main">
<TableHeader :showSearch="false" v-if="flag">
<TableHeader :showSearch="false" v-show="flag">
<template v-slot:select>
<el-form-item label="日期">
<DatePicker ref="datePickerRef" :nextFlag="false" :theCurrentTime="true"></DatePicker>
<DatePicker ref="datePickerRef" :nextFlag="false" :theCurrentTime="true" @change="handleDatePickerChange"></DatePicker>
</el-form-item>
</template>
<template v-slot:operation>
@@ -42,6 +42,7 @@
:height="rowHeight * item.h - seRowHeight(item.h) + 'px'"
:width="rowWidth * item.w - 30 + 'px'"
:timeKey="(item as LayoutItem).timeKey"
:interval="datePickerRef?.interval"
:w="item.w"
:h="item.h"
/>
@@ -63,10 +64,13 @@ import DatePicker from '@/components/form/datePicker/index.vue'
import { useDebounceFn } from '@vueuse/core'
import { queryActivatePage, queryByPagePath } from '@/api/system-boot/csstatisticalset'
import RoutingConfig from '@/views/pqs/cockpit/homePage/components/routingConfig.vue'
import { useRouter } from 'vue-router'
import { useRouter,useRoute } from 'vue-router'
import { useTimeCacheStore } from '@/stores/timeCache'
const { push } = useRouter()
const datePickerRef = ref()
const router = useRouter()
const route = useRoute()
const timeCacheStore = useTimeCacheStore()
defineOptions({
// name: 'dashboard/index'
@@ -225,6 +229,20 @@ const editd = (e: any) => {
const settings = () => {
RoutingConfigRef.value.open()
}
// 处理 DatePicker 值变化事件
const handleDatePickerChange = (value: any) => {
// 将值缓存到 timeCache
if (value) {
timeCacheStore.setCache(
route.path,
value.interval,
value.timeValue
)
}
}
// 生命周期钩子
onMounted(() => {
// initRowHeight()