index.vue 6.85 KB
<script lang="ts" setup>
  import { EChartsOption, ECharts, init } from 'echarts';
  import { unref, ref, onMounted, nextTick, toRaw, computed } from 'vue';
  import { ComponentPropsConfigType } from '../../../index.type';
  import { option } from './config';
  // import { UpdateTime } from '/@/views/visual/commonComponents/UpdateTime';
  import { useComponentScale } from '../../../hook/useComponentScale';
  import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
  import { useIntervalFn } from '@vueuse/core';
  import { useMultipleDataFetch } from '../../../hook/socket/useSocket';
  import { MultipleDataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
  import { useReceiveMessage } from '../../../hook/useReceiveMessage';
  import { formatToDateTime } from '/@/utils/dateUtil';
  import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
  import { useI18n } from '/@/hooks/web/useI18n';
  interface IList {
    [key: string]: string | number;
  }

  const { t } = useI18n();

  const props = defineProps<{
    config: ComponentPropsConfigType<typeof option>;
  }>();
  const chartRefEl = ref<Nullable<HTMLDivElement>>(null);

  const chartInstance = ref<Nullable<ECharts>>(null);
  // const time = ref<Nullable<number>>(null);

  const updateInterval = ref<number>(1000); //默认每秒更新一次
  const maxDataPoints = ref<number>(30); //默认每秒显示10个数据点

  const chartData = ref<{ time: string | number; value: number }[]>([]);
  const legendData = ref<string[]>([t('visual.board.temperatureText')]);
  const timeList = ref<string[]>([]);

  const generateRandomData = () => {
    const minValue = 0;
    const maxValue = 100;
    const time = new Date().toLocaleTimeString();
    const value = Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue;
    return { time, value, name: t('visual.board.temperatureText') };
  };

  const options = (): EChartsOption => {
    return {
      tooltip: {
        // trigger: 'axis',
      },
      legend: {
        top: '10%',
        left: 'center',
        data: [t('visual.board.temperatureText')],
      },
      grid: {
        top: '30%',
        left: '6%',
        right: '10%',
        bottom: '8%',
        containLabel: true,
      },
      xAxis: {
        type: 'category',
        // boundaryGap: false,
      },
      yAxis: {
        type: 'value',
        boundaryGap: [0, '100%'],
      },
      series: [{ type: 'line', name: t('visual.board.temperatureText'), data: [] }],
    };
  };

  const random = () => {
    useIntervalFn(() => {
      const newData = generateRandomData();
      chartData.value.push(newData);
      if (unref(chartData).length > maxDataPoints.value) {
        chartData.value.shift();
      }
      unref(chartInstance)?.setOption({
        xAxis: {
          data: toRaw(unref(chartData).map((data) => data.time)),
        },
        series: [{ data: toRaw(unref(chartData).map((item) => item.value)) }],
      });
    }, updateInterval);
  };

  const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();

  const getDesign = computed(() => {
    const { persetOption, option } = props.config;
    const { dataSource = [] } = option || {};
    const {
      unit: presetUnit,
      fontColor: presetFontColor,
      // lineColor: persetLineColor,
    } = persetOption || {};

    return {
      dataSource: dataSource?.map((item) => {
        const { unit, showDeviceName, fontColor } = item.componentInfo || {};
        const { attribute, attributeRename, deviceId, deviceName, deviceRename, deviceProfileId } =
          item;

        const { functionName } =
          getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute) || {};

        return {
          unit: unit ?? presetUnit,
          fontColor: fontColor ?? presetFontColor,
          attribute,
          attributeName: attributeRename || functionName,
          showDeviceName,
          deviceName: deviceRename || deviceName,
          id: deviceId,
          // lineColor: lineColor || persetLineColor,
        };
      }),
    };
  });

  const initial = () => {
    chartInstance.value = init(unref(chartRefEl)! as HTMLElement);
    chartInstance.value.setOption(options());
  };

  const series = ref(
    unref(getDesign).dataSource.map((item) => {
      return {
        type: 'line',
        name: `${item.deviceName} - ${item.attributeName}`,
        data: [] as { name: string; value: number }[],
        id: item.id,
        attribute: item.attribute,
        // itemStyle: {
        //   color: item.lineColor,
        // },
        // lineStyle: {
        //   color: item.lineColor,
        // },
      };
    })
  );

  const { forEachGroupMessage } = useReceiveMessage();

  const updateFn: MultipleDataFetchUpdateFn = async (message, deviceId, attribute) => {
    legendData.value = unref(getDesign).dataSource.map((item) => {
      return `${item.deviceName} - ${item.attributeName}`;
    });
    const list: IList | any = {};
    forEachGroupMessage(message, deviceId, attribute, (attribute, value, timespan) => {
      list.time = timespan || list.time;
      series.value.forEach((item) => {
        if (item.id === deviceId && item.attribute === attribute) {
          item.data.push({
            name: formatToDateTime(list.time, 'YYYY-MM-DD HH:mm:ss'),
            value: value,
          });
          if (item.data.length > unref(maxDataPoints)) {
            item.data.shift();
          }
        }
      });
    });
    list.time && timeList.value.push(formatToDateTime(list.time, 'YYYY-MM-DD HH:mm:ss'));
    if (unref(timeList).length > unref(maxDataPoints)) {
      timeList.value.shift();
    }
    await nextTick();
    unref(chartInstance)?.setOption({
      xAxis: {
        data: toRaw(unref(timeList)),
      },
      legend: {
        data: toRaw(unref(legendData)),
      },
      series: toRaw(
        unref(series).map((item) => {
          const { type, name, data } = item;
          return {
            type,
            name,
            data,
            // itemStyle,
            // lineStyle,
          };
        })
      ),
    });
  };

  useMultipleDataFetch(props, updateFn);
  onMounted(() => {
    initial();
    !props.config.option.dataSource?.length && random();
  });

  const resize = async () => {
    await nextTick();

    // 修改echarts大小
    // unref(chartInstance)?.setOption({
    //   legend: {
    //     textStyle: {
    //       fontSize: 14 * unref(getRatio),
    //     },
    //   },
    // } as EChartsOption);
    unref(chartInstance)?.resize();
  };

  useComponentScale(props, resize);
</script>

<template>
  <main class="w-full h-full flex flex-col justify-center items-center flex-1">
    <DeviceName :config="config" />
    <div
      ref="chartRefEl"
      class="flex-1 w-full h-7/8 flex-col justify-center items-center flex mb-3"
    >
    </div>
    <!-- <UpdateTime :time="time" /> -->
  </main>
</template>