历史趋势添加缺失数据功能

This commit is contained in:
guanj
2025-10-31 13:41:48 +08:00
parent 13c0a28c95
commit dc44e16d4d
8 changed files with 2833 additions and 2530 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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