index.vue 5.21 KB
<script lang="ts" setup>
  import { EChartsOption, ECharts, init } from 'echarts';
  import { onMounted } from 'vue';
  import { unref } from 'vue';
  import { ref } from 'vue';
  import { useDataFetch } from '../../../hook/useSocket';
  import { ComponentPropsConfigType, DataFetchUpdateFn } from '../../../index.type';
  import { option } from './config';
  import { UpdateTime } from '/@/views/visual/commonComponents/UpdateTime';
  import { useIntervalFn } from '@vueuse/core';
  import { computed } from 'vue';
  import { useComponentScale } from '../../../hook/useComponentScale';
  import { nextTick } from 'vue';
  import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';

  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 getDesign = computed(() => {
    const { option, persetOption } = props.config;
    const { componentInfo, attribute, attributeRename } = option;
    const { fontColor: presetFontColor, unit: presetUnit } = persetOption || {};
    const { unit, fontColor } = componentInfo || {};
    return {
      unit: unit ?? presetUnit,
      fontColor: fontColor ?? presetFontColor,
      attribute: attributeRename || attribute,
    };
  });

  const options = (): EChartsOption => {
    const { unit, fontColor } = unref(getDesign);
    return {
      series: [
        {
          type: 'gauge',
          radius: '50%',
          center: ['50%', '60%'],
          startAngle: 200,
          endAngle: -20,
          min: 0,
          max: 100,
          splitNumber: 10,
          itemStyle: {
            color: fontColor,
          },
          progress: {
            show: true,
            width: 30,
          },
          pointer: {
            show: false,
          },
          axisLine: {
            lineStyle: {
              width: 30,
            },
          },
          axisTick: {
            distance: -35,
            splitNumber: 5,
            lineStyle: {
              width: 2,
              color: '#999',
            },
          },
          splitLine: {
            distance: -40,
            length: 10,
            lineStyle: {
              width: 3,
              color: '#999',
            },
          },
          axisLabel: {
            distance: 0,
            color: '#999',
          },
          anchor: {
            show: false,
          },
          title: {
            show: false,
          },
          detail: {
            valueAnimation: true,
            width: '60%',
            lineHeight: 10,
            borderRadius: 8,
            offsetCenter: [0, '30%'],
            fontSize: 14,
            fontWeight: 'bolder',
            formatter: `{value} ${unit ?? ''}`,
            color: fontColor || 'inherit',
          },
          data: [
            {
              value: 20,
            },
          ],
        },
        {
          type: 'gauge',
          radius: '50%',
          center: ['50%', '60%'],
          startAngle: 200,
          endAngle: -20,
          min: 0,
          max: 100,
          itemStyle: {
            color: fontColor,
          },
          progress: {
            show: true,
            width: 8,
          },
          pointer: {
            show: false,
          },
          axisLine: {
            show: false,
          },
          axisTick: {
            show: false,
          },
          splitLine: {
            show: false,
          },
          axisLabel: {
            show: false,
          },
          detail: {
            show: false,
          },
          data: [
            {
              value: 20,
            },
          ],
        },
      ],
    };
  };

  const updateChart = (value: number) => {
    unref(chartInstance)?.setOption({
      series: [{ data: [{ value: value.toFixed(2) }] }, { data: [{ value: value.toFixed(2) }] }],
    } as EChartsOption);
  };

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

  const randomFn = () => {
    useIntervalFn(() => {
      const value = (Math.random() * 100).toFixed(0);
      unref(chartInstance)?.setOption({
        series: [{ data: [{ value }] }, { data: [{ value }] }],
      } as EChartsOption);
    }, 3000);
  };

  const updateFn: DataFetchUpdateFn = (message, attribute) => {
    const { data = {} } = message;
    const [latest] = data[attribute] || [];
    const [timespan, value] = latest;
    time.value = timespan;
    updateChart(isNaN(value as unknown as number) ? 0 : Number(value));
  };

  useDataFetch(props, updateFn);

  onMounted(() => {
    initial();
    !props.config.option.uuid && randomFn();
  });

  const resize = async () => {
    await nextTick();
    unref(chartInstance)?.resize();
  };

  useComponentScale(props, resize);
</script>

<template>
  <main class="w-full h-full flex flex-col justify-center items-center">
    <DeviceName :config="config" />
    <div ref="chartRefEl" class="flex-1 w-full h-full"> </div>
    <div class="text-gray-500 text-xs text-center truncate">{{
      getDesign.attribute || '温度'
    }}</div>
    <UpdateTime :time="time" />
  </main>
</template>