166 lines
5.6 KiB
Vue
166 lines
5.6 KiB
Vue
|
|
<template>
|
|||
|
|
<div :style="height">
|
|||
|
|
<MyEchart v-if="list.length != 0" :options="options1" style="height: 100%; width: 100%" class="pt10" />
|
|||
|
|
<el-empty description="暂无数据" style="width: 100%; height: 100%" v-else></el-empty>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup lang="ts">
|
|||
|
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
|||
|
|
import { ref, reactive } from 'vue'
|
|||
|
|
import { mainHeight } from '@/utils/layout'
|
|||
|
|
import { max } from 'lodash'
|
|||
|
|
const height = ref(mainHeight(290))
|
|||
|
|
const list = ref([])
|
|||
|
|
const options1 = ref({})
|
|||
|
|
const setData = (data: any) => {
|
|||
|
|
// list.value = [...fillDataFromFirstTime(data),...data]
|
|||
|
|
list.value = data
|
|||
|
|
init()
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* 补全离散数据(严格从数组第一个time开始,最后一个time结束)
|
|||
|
|
* @param {Array} data 原始离散数据数组
|
|||
|
|
* @param {number} interval 补全时间间隔(秒,默认10秒)
|
|||
|
|
* @returns {Array} 补全后的连续数据
|
|||
|
|
*/
|
|||
|
|
function fillDataFromFirstTime(data, interval = 10) {
|
|||
|
|
// 1. 基础校验
|
|||
|
|
if (!Array.isArray(data) || data.length === 0) {
|
|||
|
|
console.error('原始数据必须是非空数组')
|
|||
|
|
return []
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 锁定起始时间:直接取数组第一个元素的time(不做任何偏移)
|
|||
|
|
const firstItem = data[0]
|
|||
|
|
const startTime = new Date(firstItem.time)
|
|||
|
|
const startTimestamp = startTime.getTime()
|
|||
|
|
|
|||
|
|
// 3. 锁定结束时间:取数组最后一个元素的time
|
|||
|
|
const lastItem = data[data.length - 1]
|
|||
|
|
const endTime = new Date(lastItem.time)
|
|||
|
|
const endTimestamp = endTime.getTime()
|
|||
|
|
|
|||
|
|
// 4. 预处理:按时间排序(防止原始数据乱序)
|
|||
|
|
const sortedData = [...data].sort((a, b) => new Date(a.time) - new Date(b.time))
|
|||
|
|
|
|||
|
|
// 5. 初始化状态(继承第一个数据的type)
|
|||
|
|
let currentType = firstItem.type
|
|||
|
|
let currentDesc = firstItem.description
|
|||
|
|
let nextStatusIndex = 1 // 指向待切换的下一个状态点
|
|||
|
|
|
|||
|
|
const filledData = []
|
|||
|
|
|
|||
|
|
// 6. 核心循环:从第一个time开始,按间隔补全到最后一个time
|
|||
|
|
for (let ts = startTimestamp; ts <= endTimestamp; ts += interval * 1000) {
|
|||
|
|
const currentDate = new Date(ts)
|
|||
|
|
// 格式化时间为和原始数据一致的 "YYYY-MM-DD HH:mm:ss" 格式
|
|||
|
|
const formattedTime = `${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(
|
|||
|
|
2,
|
|||
|
|
'0'
|
|||
|
|
)}-${String(currentDate.getDate()).padStart(2, '0')} ${String(currentDate.getHours()).padStart(
|
|||
|
|
2,
|
|||
|
|
'0'
|
|||
|
|
)}:${String(currentDate.getMinutes()).padStart(2, '0')}:${String(currentDate.getSeconds()).padStart(2, '0')}`
|
|||
|
|
|
|||
|
|
// 7. 检查是否到达下一个状态切换点
|
|||
|
|
if (nextStatusIndex < sortedData.length) {
|
|||
|
|
const nextStatusTime = new Date(sortedData[nextStatusIndex].time).getTime()
|
|||
|
|
if (ts >= nextStatusTime) {
|
|||
|
|
currentType = sortedData[nextStatusIndex].type
|
|||
|
|
currentDesc = sortedData[nextStatusIndex].description
|
|||
|
|
nextStatusIndex++
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 8. 生成补全数据项(结构与原始数据完全一致)
|
|||
|
|
filledData.push({
|
|||
|
|
time: formattedTime,
|
|||
|
|
devId: firstItem.devId,
|
|||
|
|
description: currentDesc,
|
|||
|
|
type: currentType
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return filledData
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const init = () => {
|
|||
|
|
options1.value = {
|
|||
|
|
title: {
|
|||
|
|
text: '运行状态'
|
|||
|
|
},
|
|||
|
|
legend: {
|
|||
|
|
show: false
|
|||
|
|
},
|
|||
|
|
tooltip: {
|
|||
|
|
formatter: function (params: any) {
|
|||
|
|
var res = params[0].data[0] + '<br/>运行状态:'
|
|||
|
|
var texts = ''
|
|||
|
|
if (params[0].data[1] === 1 || params[0].data[1] === '1') {
|
|||
|
|
texts = '中断'
|
|||
|
|
} else if (params[0].data[1] === 10 || params[0].data[1] === '10') {
|
|||
|
|
texts = '正常'
|
|||
|
|
}
|
|||
|
|
res = res + texts
|
|||
|
|
return res
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
xAxis: {
|
|||
|
|
// type: 'category',
|
|||
|
|
// data: data.updateTime
|
|||
|
|
type: 'time',
|
|||
|
|
name: '时间',
|
|||
|
|
//
|
|||
|
|
axisLabel: {
|
|||
|
|
formatter: {
|
|||
|
|
day: '{MM}-{dd}',
|
|||
|
|
month: '{MM}',
|
|||
|
|
year: '{yyyy}'
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
yAxis: {
|
|||
|
|
name: '',
|
|||
|
|
type: 'value',
|
|||
|
|
max: 11,
|
|||
|
|
interval: 1,
|
|||
|
|
splitLine: {
|
|||
|
|
lineStyle: {
|
|||
|
|
// 使用深浅的间隔色
|
|||
|
|
color: ['#ccc'],
|
|||
|
|
type: 'dashed',
|
|||
|
|
opacity: 0
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
axisLabel: {
|
|||
|
|
// 这里重新定义就可以
|
|||
|
|
formatter: function (value: number) {
|
|||
|
|
var texts = []
|
|||
|
|
if (value === 1) {
|
|||
|
|
texts.push('中断')
|
|||
|
|
} else if (value === 10) {
|
|||
|
|
texts.push('正常')
|
|||
|
|
}
|
|||
|
|
return texts
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
series: [
|
|||
|
|
{
|
|||
|
|
name: '运行状态',
|
|||
|
|
data: list.value.map((item: any, index: number) => [item.time, item.type == 0 ? 1 : 10]),
|
|||
|
|
type: 'line',
|
|||
|
|
showSymbol: false,
|
|||
|
|
|
|||
|
|
step: 'end'
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
defineExpose({
|
|||
|
|
setData
|
|||
|
|
})
|
|||
|
|
</script>
|
|||
|
|
<style lang="scss" scoped></style>
|