index.vue 5.57 KB
<script lang="ts" setup>
import { computed, onMounted, onUnmounted, ref, toRaw, unref } from 'vue'
import type { 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 type { CommandSource } from '@/core/websocket/processor'
import { useLatestMultipleMessageValue } from '@/core/Library/hook/useLatestMessageValue'
import { useProductsStore } from '@/store/modules/products'
interface IList {
  time: string | number
}

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>>()

const maxLength = ref<number>(20)

const timeList = ref<number[] | string[] | any>([])// 存储XAxis的值
const seriesData = ref<any>([])// 存储series的值
const titleATTR = ref<string[] | any>([])

const productsStore = useProductsStore()

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

const handleHistoryData = (commandSource: CommandSource, message: SubscriptionData, attr: string[] | string) => {
  const { data } = commandSource || {}
  const { deviceName } = data as NodeDataDataSourceJsonType

  (attr as string[]).forEach((item) => {
    timeList.value.push(...message[item].map((item1) => {
      const [ts] = item1
      return ts
    }))
  })
  timeList.value = Array.from(new Set(timeList.value))?.sort((a: any, b: any) => a - b)// 去重获取到的时间
  seriesData.value.forEach((item: any) => {
    item.data = unref(timeList).map((time: any) => ({ name: time, value: null }))
  })

  seriesData.value.forEach((item: any) => {
    item.data.forEach((item1: any) => {
      message[item.attribute].forEach((messageItem) => {
        const [ts, value] = messageItem
        if (item1.name === ts) {
          item1.value = value || undefined
          item1.name = formatToDateTime(item1.name)
        }
      })
    })
  })
  unref(chartInstance)?.setOption({
    title: {
      text: `${deviceName || ''}`,
    },
    xAxis: {
      data: toRaw(unref(timeList.value.map((item: string | number) => formatToDateTime(item)))),
    },
    legend: {
      data: unref(titleATTR),
    } as any,
    series: toRaw(
      unref(seriesData).map((item: { type: string; name: string; data: any }) => {
        const { type, name, data } = item
        return {
          type,
          name,
          data,
        }
      }),
    ),
  } as EChartsOption)
}

// const contentDataStore = useContentDataStoreWithOut()

const handlerTimeSeriesData = (commandSource: CommandSource, message: SubscriptionData, attr: string[] | string) => {
  const { data } = commandSource
  const { deviceName } = data as NodeDataDataSourceJsonType
  const list: IList | any = {}// 记录时间
  useLatestMultipleMessageValue(message, attr as any, (attribute, timespan, value) => {
    list.time = timespan || list.time
    seriesData.value.forEach((item: any) => {
      if (item.attribute === attribute) {
        item.data.push({
          name: formatToDateTime(list.time),
          value: value || undefined,
        })
      }
      if (item.data.length > unref(maxLength))
        item.data.shift()
    })
  })
  list.time && timeList.value.push(formatToDateTime(list.time))
  if (unref(timeList).length > unref(maxLength))
    timeList.value.shift()

  unref(chartInstance)?.setOption({
    title: {
      text: `${deviceName || ''}`,
    },
    xAxis: {
      data: toRaw(unref(timeList)),
    },
    legend: {
      data: unref(titleATTR),
    } as any,
    series: toRaw(
      unref(seriesData).map((item: { type: string; name: string; data: any }) => {
        const { type, name, data } = item
        return {
          type,
          name,
          data,
        }
      }),
    ),
  } as EChartsOption)
}

const { onMessage } = useOnMessage({
  onReceiveDataSourceMessage(commandSource, message) {
    const { data } = commandSource
    const { chartOption, attr, deviceProfileId } = data as NodeDataDataSourceJsonType
    const { queryType } = chartOption || {}
    if (!seriesData.value.length) {
      (attr as string[]).forEach((item: string) => {
        titleATTR.value.push(productsStore.getObjectModelByIdWithIdentifier(deviceProfileId, item)?.functionName)

        seriesData.value.push({ attribute: item, data: [], type: 'line', name: productsStore.getObjectModelByIdWithIdentifier(deviceProfileId, item)?.functionName })
      })
    }

    if (queryType === SocketSubscriberEnum.TS_SUB_CMDS)
      handlerTimeSeriesData(commandSource, message.data, attr)
    else if (queryType === SocketSubscriberEnum.HISTORY_CMDS)
      handleHistoryData(commandSource, 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>