map/ui/dasadmin/src/views/backend/equipment/airBlower/realDataChart.vue
2024-12-03 14:25:13 +08:00

474 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="realDataChart">
<el-row>
<el-col :span="8" class="leftPart">
<div class="leftHeader">
<el-button type="primary" @click="addPoint">添加测点</el-button>
<span>显示区间</span>
<el-select v-model="showTimeInterval">
<el-option label="5分钟" :value="300"></el-option>
<el-option label="10分钟" :value="600"></el-option>
<el-option label="15分钟" :value="900"></el-option>
</el-select>
</div>
<div class="leftMain">
<el-scrollbar>
<el-checkbox-group v-model="selectList" @change="changeCheck">
<el-checkbox
v-for="item in realDataList"
:key="item.prop"
:label="item.name"
:value="item.prop"
class="checkboxStyle"
></el-checkbox>
</el-checkbox-group>
</el-scrollbar>
</div>
</el-col>
<el-col :span="16" class="rightPart">
<div class="chartPart">
<div class="chartRef" ref="chartRef"></div>
</div>
</el-col>
</el-row>
</div>
<el-dialog v-model="selectPointVisible" title="选择测点" width="1000">
<SelectPoint ref="selectPointRef" :visible="selectPointVisible" :default-attr="selectPointAttr"></SelectPoint>
<template #footer>
<div class="selectPointDialogFooter">
<el-button type="primary" @click="saveSelectPoint">保存</el-button>
<el-button @click="selectPointVisible = false">取消</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
import SelectPoint from '/@/views/backend/equipment/airBlower/selectPoint.vue'
import { getRealValueListReq } from '/@/api/backend/deviceModel/request'
import { dayjs, ElMessage } from 'element-plus'
import { getCutDecimalsValue } from './utils'
const emits = defineEmits(['clearChart'])
const props = withDefaults(defineProps<{ id: string; visible: boolean }>(), {
id: '',
visible: false,
})
const showTimeInterval = ref(300)
//#region
const defaultList = [
{
prop: 'iturbineoperationmode',
name: '运行模式',
unit: '',
},
{
prop: 'iwindspeed',
name: '风速',
unit: '(m/s)',
},
{
prop: 'iwinddirection',
name: '风向',
unit: '(°)',
},
{
prop: 'igenspeed',
name: '发电机转速',
unit: '(rpm)',
},
{
prop: 'igenpower',
name: '有功功率',
unit: '(kW)',
},
{
prop: 'iactivepowersetpointvalue',
name: '有功给定',
unit: '(kW)',
},
{
prop: 'ireactivepower',
name: '无功功率',
unit: '(kVar)',
},
{
prop: 'ireactivepowersetpointvalue',
name: '无功给定',
unit: '(kVar)',
},
{
prop: 'ipitchangle1',
name: '桨叶1角度',
unit: '(°)',
},
{
prop: 'ipitchangle2',
name: '桨叶2角度',
unit: '(°)',
},
{
prop: 'ipitchangle3',
name: '桨叶3角度',
unit: '(°)',
},
]
//#endregion
const selectList = ref([])
const changeCheck = () => {
if (!timer && selectList.value[0]) {
createTimer()
}
if (selectList.value.length === 0) {
clearTimer()
chartInstance && chartInstance.clear()
}
}
const realDataList = ref<any[]>(JSON.parse(JSON.stringify(defaultList)))
const chartRef = ref()
let chartInstance: any = null
const getRealData = () => {
const params = selectList.value.map((item: string) => item.toLowerCase())
const time = dayjs().format('YYYY-MM-DD HH:mm:ss')
getRealValueListReq([
{
deviceId: props.id,
attributes: params,
},
]).then((res) => {
if (res.code === 200) {
createChartData(res.data[props.id], time)
}
})
return []
}
let realDataXAxis: any = []
let realDataSeries: any = []
const getRandomDarkColor = () => {
let r = Math.floor(Math.random() * 200) // 限制在0到127之间以生成较深的颜色
let g = Math.floor(Math.random() * 200)
let b = Math.floor(Math.random() * 200)
let color = `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`
return color
}
const createChartData = (data: { [k: string]: number }, time: string) => {
if (realDataXAxis.length > showTimeInterval.value) {
realDataXAxis.shift()
realDataSeries.forEach((item: any) => {
item.data.shift()
})
}
const attrCode = Object.keys(data)
realDataXAxis.push(time)
const lastSeriesId = realDataSeries.map((item: any) => item.id)
const color = getRandomDarkColor()
let clearState = null
lastSeriesId.forEach((item: any) => {
if (!attrCode.includes(item)) {
const cur = realDataSeries.find((val: any) => val.id === item)
delete cur.id
clearState = true
}
})
if (clearState) {
chartInstance.setOption(
{
series: realDataSeries,
},
{
replaceMerge: ['series'],
}
)
}
const seriesData = attrCode.map((item) => {
const curVal = getCutDecimalsValue(data[item], 2)
if (lastSeriesId.includes(item)) {
const cur = realDataSeries.find((val: any) => val.id === item)
cur.data.push(curVal)
return cur
} else {
const info = realDataList.value.find((val) => val.prop === item)
const list = realDataSeries?.[0]?.data ?? []
const len = list.length
const fillData = new Array(len).fill('')
fillData.push(curVal)
return {
id: item,
name: info.name + info.unit,
type: 'line',
barWidth: 20,
itemStyle: {
color: color,
barBorderRadius: 2,
},
smooth: true,
symbol: 'none',
data: fillData,
}
}
})
realDataSeries = seriesData
createChart()
}
const createChart = () => {
const chart = chartInstance ?? echarts.init(chartRef.value)
let option = null
if (chartInstance && realDataXAxis.length > 1) {
option = {
xAxis: {
data: realDataXAxis,
},
series: realDataSeries,
}
} else {
option = {
grid: {
top: 50,
right: 23,
bottom: 50,
left: 18,
containLabel: true,
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
},
xAxis: {
type: 'category',
axisLine: {
show: true,
lineStyle: {
color: '#dadada',
width: 1,
type: 'solid',
},
},
axisLabel: {
//x轴文字的配置
show: true,
color: '#4E5969',
interval: 'auto',
formatter: function (value: any) {
return value.slice(11)
},
//rotate: 45
},
splitLine: {
//分割线配置
show: false,
lineStyle: {
color: '#999999',
},
},
data: realDataXAxis,
},
yAxis: [
{
type: 'value',
name: '',
nameTextStyle: {
color: '#4E5969',
},
axisLine: {
show: false,
lineStyle: {
color: '#dadada',
width: 0,
type: 'solid',
},
},
axisLabel: {
//x轴文字的配置
show: true,
color: '#4E5969',
},
axisTick: { show: false },
splitLine: {
interval: 50,
lineStyle: {
type: 'dashed',
color: '#dadada',
},
},
},
],
dataZoom: [
{
type: 'inside',
start: 0,
end: 100,
},
{
start: 0,
end: 100,
},
],
legend: {
data: [],
textStyle: {
color: '#73767a',
},
},
series: realDataSeries,
}
}
chart.setOption(option, { replaceMerge: 'series' })
chartInstance = chart
}
const selectPointRef = ref()
const selectPointVisible = ref(false)
const selectPointAttr = computed(() => {
return realDataList.value.map((item) => {
return {
attributeName: item.name,
attributeCode: item.prop,
}
})
})
const addPoint = () => {
selectPointVisible.value = true
}
const saveSelectPoint = () => {
const data = selectPointRef.value?.getSelectList()
if (data) {
const selectList = data.map((item: any) => {
return {
prop: item.attributeCode,
name: item.attributeName,
unit: item.unit,
}
})
realDataList.value = selectList
selectPointVisible.value = false
ElMessage.success('添加成功')
}
}
let timer: any = null
const createTimer = () => {
timer = setInterval(() => {
getRealData()
}, 1000)
}
const clearTimer = () => {
timer && clearInterval(timer)
timer = null
realDataSeries = []
realDataXAxis = []
pauseState.value = false
emits('clearChart')
}
const pauseState = ref(false)
const saveChart = () => {
timer && clearInterval(timer)
pauseState.value = true
return {
time: realDataXAxis,
chartData: realDataSeries,
}
}
const continueChart = () => {
pauseState.value = false
const fillVal = new Array(5).fill('')
realDataXAxis.push(...fillVal)
realDataSeries.forEach((item: any) => {
item.data.push(...fillVal)
})
createTimer()
}
defineExpose({
saveChart,
continueChart,
})
onMounted(() => {
if (selectList.value.length > 0) {
createTimer()
}
})
onUnmounted(() => {
clearTimer()
chartInstance && chartInstance.dispose()
selectList.value = []
})
watch(
() => props.visible,
(v) => {
if (!v) {
clearTimer()
chartInstance && chartInstance.clear()
selectList.value = []
}
}
)
</script>
<style scoped lang="scss">
.realDataChart {
width: 100%;
height: 100%;
.leftPart {
width: 100%;
height: 100%;
border-right: 1px solid #edf2fa;
.leftHeader {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
span {
margin-left: auto;
}
.el-select {
width: 100px;
}
:deep(.el-select__wrapper) {
width: 100px;
}
}
.leftMain {
width: 100%;
height: 400px;
.checkboxStyle {
display: flex;
width: 100%;
height: 40px;
}
}
}
.rightPart {
width: 100%;
height: 100%;
min-height: 452px;
.chartPart {
width: 100%;
height: 100%;
min-height: 452px;
.chartRef {
width: 100%;
height: 100%;
min-height: 452px;
}
}
}
}
.selectPointDialogFooter {
text-align: center;
.el-button {
width: 120px;
height: 40px;
}
}
</style>