AnalysisSystemForRadionucli.../src/views/stationOperation/components/RealTimeDataChart.vue

369 lines
8.1 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 { cloneDeep } from 'lodash'
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 `${params.marker}${params.name}: ${(params.value[3] / 1000 / 60).toFixed()}min`
},
},
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(dateTime).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 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],
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>