index.vue 5.19 KB
<script lang="ts" setup>
  import { EChartsOption, SeriesOption, ECharts, init } from 'echarts';
  import { unref, ref, onMounted, computed, nextTick } from 'vue';
  import { useMultipleDataFetch } from '../../../hook/useSocket';
  import { ComponentPropsConfigType, MultipleDataFetchUpdateFn } 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 { useReceiveMessage } from '../../../hook/useReceiveMessage';
  import { useReceiveValue } from '../../../hook/useReceiveValue';
  import { toRaw } from 'vue';

  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 { persetOption, option } = props.config;
    const { dataSource = [] } = option || {};
    const {
      unit: presetUnit,
      fontColor: presetFontColor,
      showDeviceName: presetShowDeviceName,
    } = persetOption || {};
    return {
      dataSource: dataSource?.map((item) => {
        const { unit, fontColor, showDeviceName } = item.componentInfo || {};
        const { attribute, attributeName, attributeRename, deviceName, deviceRename, deviceId } =
          item;
        return {
          unit: unit ?? presetUnit,
          fontColor: fontColor ?? presetFontColor,
          attribute,
          attributeRename,
          showDeviceName: showDeviceName ?? presetShowDeviceName,
          deviceName,
          deviceRename,
          attributeName,
          id: deviceId,
        };
      }),
    };
  });

  const options = (): EChartsOption => {
    return {
      tooltip: {
        trigger: 'item',
        confine: true,
      },
      legend: {
        top: '5%',
        left: 'center',
        selectedMode: false,
        textStyle: {
          fontSize: unref(getRatio) ? 14 * unref(getRatio) : 14,
        },
      },
      series: [
        {
          type: 'pie',
          radius: ['40%', '70%'],
          center: ['50%', '70%'],
          // adjust the start angle
          startAngle: 180,
          label: {
            show: false,
          },
          itemStyle: {
            borderRadius: 4,
            borderColor: '#fff',
            borderWidth: 2,
          },
          data: [
            { value: 1048, name: '数据1' },
            { value: 735, name: '数据2' },
            {
              value: 1048 + 735,
              itemStyle: {
                color: 'none',
                decal: {
                  symbol: 'none',
                },
              },
              label: {
                show: false,
              },
            },
          ],
        },
      ],
    };
  };

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

  const updateChart = (data: SeriesOption['data']) => {
    unref(chartInstance)?.setOption({
      series: [{ data }],
    } as EChartsOption);
  };
  const { forEachGroupMessage } = useReceiveMessage();
  const { getNumberValue } = useReceiveValue();

  const series = ref(
    unref(getDesign).dataSource.map((item) => ({
      value: 0,
      name: `${item.showDeviceName ? `${item.deviceRename || item.deviceName}-` : ''}${
        item.attributeRename || item.attributeName || item.attribute
      }`,
      itemStyle: { color: item.fontColor },
      attribute: item.attribute,
      id: item.id,
      tooltip: {
        valueFormatter(value) {
          return `${value} ${item.unit ?? ''}`;
        },
      },
    }))
  );

  const updateFn: MultipleDataFetchUpdateFn = (message, deviceId, attribute) => {
    forEachGroupMessage(message, deviceId, attribute, (attribute, value, timespan) => {
      series.value.forEach((item) => {
        if (item.id === deviceId && item.attribute === attribute) {
          item.value = getNumberValue(value);
          time.value = timespan;
        }
      });
    });

    const option = {
      value: series.value.reduce((total: number, current: any) => total + Number(current.value), 0),
      itemStyle: {
        color: 'none',
        decal: {
          symbol: 'none',
        },
      } as any,
      label: {
        show: false,
      },
    };
    updateChart([...toRaw(unref(series)), option]);
  };

  useMultipleDataFetch(props, updateFn);

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

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

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

  const { getRatio } = 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>
    <UpdateTime :time="time" />
  </main>
</template>