index.vue 3.38 KB
<script lang="ts" setup>
import { computed, onMounted, onUnmounted, ref, unref } from 'vue'
import type { DatasetComponentOption, ECharts, EChartsOption } from 'echarts'
import { init } from 'echarts'
import { getDefaultOption } from './index.config'
import type { CreateComponentType, RenderComponentExposeType } from '@/core/Library/types'
import { useOnMessage } from '@/core/Library/hook/useOnMessage'
import type { NodeDataDataSourceJsonType } from '@/api/node/model'
import type { SubscriptionData } from '@/core/websocket/type/message'
import { SocketSubscriberEnum } from '@/enums/datasource'
import { formatToDateTime } from '@/utils/dateUtil'
import { useLatestMessageValue } from '@/core/Library/hook/useLatestMessageValue'
import type { CommandSource } from '@/core/websocket/processor'

const props = defineProps<{
  config: CreateComponentType
}>()

const getCellBounds = computed(() => props.config.cellBounds || { width: 300, height: 300, x: 0, y: 0 })

const chartElRef = ref<Nullable<HTMLDivElement>>()

const chartInstance = ref<Nullable<ECharts>>()

function initChartInstance() {
  chartInstance.value = init(unref(chartElRef))
  chartInstance.value.setOption(getDefaultOption())
}

const handleHistoryData = (message: SubscriptionData, attr: string) => {
  const data = message[attr]
  const xAxisData: string[] = []
  const seriesData: number[] = []

  for (const item of data) {
    const [ts, value] = item
    xAxisData.push(formatToDateTime(ts))
    seriesData.push(value)
  }

  unref(chartInstance)?.setOption({
    xAxis: { data: xAxisData },
    series: { data: seriesData },
  } as EChartsOption)
}

function sliceData(data: any[], maxLength = 20) {
  if (data.length > maxLength)
    return data.slice(1)
  return data
}

const handlerTimeSeriesData = (commandSource: CommandSource, message: SubscriptionData, attr: string) => {
  const { data } = commandSource
  const { attrInfo, deviceInfo } = data as NodeDataDataSourceJsonType
  const { deviceName } = deviceInfo || {}
  const { ts, latestValue } = useLatestMessageValue(message, attr)
  const option = unref(chartInstance)?.getOption() as EChartsOption
  const oldDataset = (option.dataset as DatasetComponentOption[])?.[0].source as Recordable[]
  oldDataset.push({
    ts: formatToDateTime(ts),
    [attr]: latestValue,
  })

  unref(chartInstance)?.setOption({
    title: {
      text: `${deviceName || ''}-${attrInfo.name || ''}`,
    },
    dataset: {
      dimensions: ['ts', attr],
      source: sliceData(oldDataset),
    },
  } as EChartsOption)
}

const { onMessage } = useOnMessage({
  onReceiveDataSourceMessage(commandSource, message) {
    const { data } = commandSource
    const { chartOption, attr } = data as NodeDataDataSourceJsonType
    const { queryType } = chartOption || {}

    if (queryType === SocketSubscriberEnum.TS_SUB_CMDS)
      handlerTimeSeriesData(commandSource, message.data, attr)
    else if (queryType === SocketSubscriberEnum.HISTORY_CMDS)
      handleHistoryData(message.data, attr)
  },
})

onMounted(() => {
  initChartInstance()
})

onUnmounted(() => {
  chartInstance.value?.dispose()
  chartInstance.value = null
})

defineExpose<RenderComponentExposeType>({ onMessage })
</script>

<template>
  <div class="w-full h-full justify-center flex items-center">
    <div
      ref="chartElRef" :style="{ width: `${getCellBounds.width}px`, height: `${getCellBounds.height}px` }"
      class="w-full h-full"
    />
  </div>
</template>