382 lines
8.8 KiB
Vue
382 lines
8.8 KiB
Vue
<template>
|
||
<div style="width: 100%; height: 100%; overflow: auto; padding-top: 76px">
|
||
<!-- 图例 -->
|
||
<div class="legend">
|
||
<div
|
||
class="legend-item"
|
||
:class="{ active: legend.isShow }"
|
||
v-for="(legend, index) in legendList"
|
||
:key="index"
|
||
@click="handleLegendChange(legend)"
|
||
>
|
||
<span class="legend-item-color" :style="{ backgroundColor: legend.color }"></span>
|
||
<span>{{ legend.title }}</span>
|
||
</div>
|
||
</div>
|
||
<!-- 图例结束 -->
|
||
<custom-chart
|
||
ref="customChartRef"
|
||
:option="option"
|
||
:opts="{ notMerge: true }"
|
||
:height="list.length * 295"
|
||
@dataZoom="handleZoomChange"
|
||
></custom-chart>
|
||
<a-spin style="z-index: 11; position: absolute; top: 45%; left: 48%" :spinning="spinning" />
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import CustomChart from '@/components/CustomChart/index.vue'
|
||
import * as echarts from 'echarts'
|
||
import dayjs from 'dayjs'
|
||
import utc from 'dayjs/plugin/utc'
|
||
import { cloneDeep } from 'lodash'
|
||
|
||
dayjs.extend(utc)
|
||
const typeList = ['MET', 'SOH', 'QC', 'PHD'] //
|
||
|
||
// 自定义图例列表
|
||
const legendList = [
|
||
{
|
||
title: 'SPHDPREL',
|
||
color: '#17a840',
|
||
isShow: true,
|
||
},
|
||
{
|
||
title: 'SPHDF',
|
||
color: '#0cbfb0',
|
||
isShow: true,
|
||
},
|
||
{
|
||
title: 'QC',
|
||
color: '#1c82eb',
|
||
isShow: true,
|
||
},
|
||
{
|
||
title: 'GASBKPHDPREL',
|
||
color: '#d3ad16',
|
||
isShow: true,
|
||
},
|
||
{
|
||
title: 'GASBKPHDF',
|
||
color: '#db6423',
|
||
isShow: true,
|
||
},
|
||
{
|
||
title: 'SOH/MET',
|
||
color: '#8852da',
|
||
isShow: true,
|
||
},
|
||
]
|
||
|
||
// 图表配置
|
||
const initialOption = {
|
||
tooltip: {
|
||
formatter: (params) => {
|
||
// return `
|
||
// <div>${params.marker}${params.name}</div>
|
||
// <div>START:${dayjs(new Date(params.value[4])).format('YYYY-MM-DD HH:mm:ss')}</div>
|
||
// <div style="white-space: pre"> END:${dayjs(new Date(params.value[2])).format('YYYY-MM-DD HH:mm:ss')}</div>
|
||
// `
|
||
return `
|
||
<div>${params.marker}${params.name}</div>
|
||
<div>START:${dayjs.utc(params.value[4]).format('YYYY-MM-DD HH:mm:ss')}</div>
|
||
<div style="white-space: pre"> END:${dayjs.utc(params.value[2]).format('YYYY-MM-DD HH:mm:ss')}</div>
|
||
`
|
||
},
|
||
},
|
||
grid: [],
|
||
xAxis: [],
|
||
yAxis: [],
|
||
series: [],
|
||
dataZoom: [],
|
||
}
|
||
|
||
export default {
|
||
props: {
|
||
title: {
|
||
type: String,
|
||
},
|
||
spinning: {
|
||
type: Boolean,
|
||
},
|
||
list: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
scaleSettings: {
|
||
type: Object,
|
||
required: true,
|
||
},
|
||
},
|
||
components: {
|
||
CustomChart,
|
||
},
|
||
data() {
|
||
return {
|
||
legendList: cloneDeep(legendList),
|
||
option: {},
|
||
zoomDataAll: [],
|
||
}
|
||
},
|
||
methods: {
|
||
handleZoomChange(params) {
|
||
this.zoomDataAll = this.option.dataZoom.map((item) => {
|
||
if (item.id == params.batch[0].dataZoomId) {
|
||
return {
|
||
id: params.batch[0].dataZoomId,
|
||
start: params.batch[0].start,
|
||
end: params.batch[0].end,
|
||
}
|
||
} else {
|
||
return item
|
||
}
|
||
})
|
||
},
|
||
renderItem(params, api) {
|
||
let categoryIndex = api.value(0)
|
||
let start = api.coord([api.value(1), categoryIndex])
|
||
let end = api.coord([api.value(2), categoryIndex])
|
||
let height = 20
|
||
|
||
let rectShape = echarts.graphic.clipRectByRect(
|
||
{
|
||
x: start[0],
|
||
y: start[1] - height / 2,
|
||
width: end[0] - start[0],
|
||
height: height,
|
||
},
|
||
{
|
||
x: params.coordSys.x,
|
||
y: params.coordSys.y,
|
||
width: params.coordSys.width,
|
||
height: params.coordSys.height,
|
||
}
|
||
)
|
||
return (
|
||
rectShape && {
|
||
type: 'rect',
|
||
shape: rectShape,
|
||
style: api.style(),
|
||
}
|
||
)
|
||
},
|
||
|
||
convertStatus(item) {
|
||
switch (item.status) {
|
||
case 'SFULL':
|
||
item.status = 'SPHDF'
|
||
break
|
||
case 'SPREL':
|
||
item.status = 'SPHDPREL'
|
||
break
|
||
case 'GPREL':
|
||
item.status = 'GASBKPHDPREL'
|
||
break
|
||
case 'GFULL':
|
||
item.status = 'GASBKPHDF'
|
||
break
|
||
case 'QC':
|
||
item.status = 'QC'
|
||
break
|
||
case 'SOH':
|
||
case 'MET':
|
||
item.status = 'SOH/MET'
|
||
break
|
||
}
|
||
},
|
||
|
||
initChartOption(val) {
|
||
let now = dayjs(new Date())
|
||
now = now.add(1, 'hour').set('minute', 0).set('second', 0).set('millisecond', 0)
|
||
|
||
const max = now.valueOf()
|
||
const min = max - this.scaleSettings.cacheTime * 24 * 60 * 60 * 1000
|
||
const option = cloneDeep(initialOption)
|
||
const { grid, xAxis, yAxis, series, dataZoom } = option
|
||
this.list.forEach((item, index) => {
|
||
grid.push({
|
||
left: 70,
|
||
right: 20,
|
||
top: 70 * index + 225 * index,
|
||
height: 225,
|
||
})
|
||
|
||
xAxis.push({
|
||
gridIndex: index,
|
||
min,
|
||
max,
|
||
interval: this.scaleSettings.scaleInterval * 60 * 1000,
|
||
axisLabel: {
|
||
show: true,
|
||
formatter: (val) => {
|
||
// let dateTime = new Date(val)
|
||
// return dayjs.utc(dateTime).format('HH:mm\nMM/DD')
|
||
return dayjs.utc(val).format('HH:mm\nMM/DD')
|
||
},
|
||
color: '#ade6ee',
|
||
},
|
||
splitLine: {
|
||
lineStyle: {
|
||
color: '#214751',
|
||
},
|
||
},
|
||
})
|
||
|
||
yAxis.push({
|
||
gridIndex: index,
|
||
name: item.title,
|
||
nameLocation: 'middle', // 设置标题位置为中间
|
||
nameTextStyle: {
|
||
// 设置标题样式
|
||
fontSize: 14,
|
||
color: '#5b9cba',
|
||
},
|
||
nameGap: 46,
|
||
data: typeList,
|
||
splitLine: {
|
||
show: true,
|
||
lineStyle: {
|
||
color: '#214751',
|
||
},
|
||
},
|
||
axisLine: {
|
||
lineStyle: {
|
||
color: '#214751',
|
||
},
|
||
},
|
||
axisTick: {
|
||
show: false,
|
||
},
|
||
axisLabel: {
|
||
color: '#ade6ee',
|
||
},
|
||
})
|
||
|
||
const data = []
|
||
item.dataList.forEach((item) => {
|
||
this.convertStatus(item)
|
||
|
||
let originalTime = new Date(item.beginTime * 1000).getTime()
|
||
let startTime = new Date(item.beginTime * 1000).getTime()
|
||
if (item.type == 'PHD') {
|
||
startTime = item.endTime * 1000 - 60 * 1000 * 30
|
||
}
|
||
|
||
const endTime = new Date(item.endTime * 1000).getTime()
|
||
const duration = endTime - startTime
|
||
const index = typeList.findIndex((type) => item.type == type)
|
||
const find = this.legendList.find((legendItem) => legendItem.title == item.status)
|
||
if (find.isShow) {
|
||
data.push({
|
||
name: item.status,
|
||
value: [index, startTime, endTime, duration, originalTime],
|
||
itemStyle: {
|
||
normal: {
|
||
color: find.color,
|
||
},
|
||
},
|
||
})
|
||
}
|
||
})
|
||
|
||
series.push({
|
||
type: 'custom',
|
||
renderItem: this.renderItem,
|
||
encode: {
|
||
x: [1, 2],
|
||
y: 0,
|
||
},
|
||
data: data,
|
||
xAxisIndex: index,
|
||
yAxisIndex: index,
|
||
})
|
||
if (!val) {
|
||
dataZoom.push({
|
||
type: 'inside',
|
||
id: index,
|
||
xAxisIndex: index,
|
||
start: 100 - (this.scaleSettings.timelineLength / (this.scaleSettings.cacheTime * 24 * 60)) * 100,
|
||
end: 100,
|
||
zoomLock: true,
|
||
})
|
||
}
|
||
})
|
||
|
||
this.option = option
|
||
},
|
||
|
||
// 图例控制图表
|
||
handleLegendChange(legend) {
|
||
legend.isShow = !legend.isShow
|
||
this.initChartOption()
|
||
this.option.dataZoom = this.zoomDataAll.map((item, index) => {
|
||
return {
|
||
type: 'inside',
|
||
id: item.id,
|
||
xAxisIndex: index,
|
||
start: item.start,
|
||
end: item.end,
|
||
zoomLock: true,
|
||
}
|
||
})
|
||
},
|
||
|
||
resize() {
|
||
this.$refs.customChartRef.resize()
|
||
},
|
||
},
|
||
watch: {
|
||
list: {
|
||
handler() {
|
||
this.initChartOption()
|
||
},
|
||
immediate: true,
|
||
},
|
||
},
|
||
}
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.legend {
|
||
width: 100%;
|
||
padding: 25px 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
background: #022024;
|
||
z-index: 11;
|
||
|
||
&-item {
|
||
color: #ade6ee;
|
||
line-height: 12px;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
display: flex;
|
||
|
||
&:not(:last-child) {
|
||
margin-right: 30px;
|
||
}
|
||
|
||
&-color {
|
||
display: inline-block;
|
||
width: 12px;
|
||
height: 12px;
|
||
border-radius: 4px;
|
||
margin-right: 6px;
|
||
vertical-align: baseline;
|
||
filter: grayscale(1);
|
||
}
|
||
|
||
&.active {
|
||
.legend-item-color {
|
||
filter: grayscale(0);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|