index.vue 7.35 KB
<script lang="ts" setup>
  import { EChartsOption, ECharts, init } from 'echarts';
  import { unref, ref, onMounted, computed, nextTick } from 'vue';
  import { ComponentPropsConfigType } from '../../../index.type';
  import { option } from './config';
  import { UpdateTime } from '/@/views/visual/commonComponents/UpdateTime';
  import { useIntervalFn } from '@vueuse/core';
  import { useComponentScale } from '../../../hook/useComponentScale';
  import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
  import { useDataFetch } from '../../../hook/socket/useSocket';
  import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
  import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
  import { useI18n } from '/@/hooks/web/useI18n';
  const props = defineProps<{
    config: ComponentPropsConfigType<typeof option>;
  }>();
  const { t } = useI18n();

  const chartRefEl = ref<Nullable<HTMLDivElement>>(null);

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

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

  const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();

  const getDesign = computed(() => {
    const { option, persetOption } = props.config;
    const { componentInfo, attribute, attributeRename, deviceProfileId } = option;
    const { functionName } =
      getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute) || {};
    const {
      fontColor: presetFontColor,
      unit: presetUnit,
      pointerColor: presetPointerColor,
      instrumentPanelColor: presetInstrumentPanelColor,
      gradientInfo: presetGradientInfo,
      showTime: persetShowTime,
      maxNumber: persetMaxNumber,
      fontSize: persetFontSize,
      valueSize: persetValueSize,
    } = persetOption || {};
    const {
      unit,
      fontColor,
      pointerColor,
      instrumentPanelColor,
      gradientInfo,
      showTime,
      maxNumber,
      fontSize,
      valueSize,
    } = componentInfo || {};
    return {
      unit: unit ?? presetUnit,
      fontColor: fontColor ?? presetFontColor,
      attribute: attributeRename || functionName,
      pointerColor: pointerColor ?? presetPointerColor,
      instrumentPanelColor: instrumentPanelColor ?? presetInstrumentPanelColor,
      gradientInfo: gradientInfo ?? presetGradientInfo,
      showTime: showTime ?? persetShowTime,
      maxNumber: maxNumber || persetMaxNumber,
      fontSize: fontSize || persetFontSize || 14,
      valueSize: valueSize || persetValueSize || 14,
    };
  });

  const options = (): EChartsOption => {
    const { unit, fontColor, pointerColor, maxNumber, valueSize } = unref(getDesign);

    return {
      series: [
        {
          type: 'gauge',
          min: 0,
          max: maxNumber,
          progress: {
            show: true,
            width: unref(getRatio) ? 6 * unref(getRatio) : 6,
          },
          axisLine: {
            lineStyle: {
              width: unref(getRatio) ? 6 * unref(getRatio) : 6,
            },
          },
          axisTick: {
            show: false,
          },
          splitLine: {
            length: unref(getRatio) ? 3 * unref(getRatio) : 3,
            lineStyle: {
              width: unref(getRatio) ? 1 * unref(getRatio) : 1,
              color: '#999',
            },
          },
          axisLabel: {
            distance: unref(getRatio) ? 10 * unref(getRatio) : 10,
            color: '#999',
            fontSize: unref(getRatio) ? 6 * unref(getRatio) : 6,
          },
          pointer: {
            //指针
            show: true,
            icon: 'path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999 2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929 C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078 C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014 L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423 2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314 2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028 2089.24407,615.30999 2090.36389,615.30999 Z',
            width: 4 * unref(getRatio) ? 4 * unref(getRatio) : 4,
            length: '100%',
            itemStyle: {
              color: pointerColor,
            },
          },
          title: {
            show: false,
          },
          detail: {
            valueAnimation: true,
            fontSize: unref(getRatio) ? valueSize * unref(getRatio) : valueSize,
            offsetCenter: [0, '70%'],
            formatter: `{value} ${unit ?? ''}`,
            color: fontColor || 'inherit',
          },
          data: [
            {
              value: 70,
            },
          ],
        },
      ],
    };
  };

  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)! as HTMLElement);
    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] || [];
    if (!latest.length) return;
    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();

    // 修改echarts大小
    unref(chartInstance)?.setOption({
      series: [
        {
          progress: {
            width: 6 * unref(getRatio),
          },
          axisLine: {
            // 仪表盘
            lineStyle: {
              width: 6 * unref(getRatio),
            },
          },
          axisLabel: {
            distance: 10 * unref(getRatio),
            fontSize: 6 * unref(getRatio),
          },
          pointer: {
            width: 4 * unref(getRatio),
          },
          splitLine: {
            length: 3 * unref(getRatio),
            lineStyle: {
              width: 1 * unref(getRatio),
            },
          },
          detail: {
            fontSize: unref(getDesign).valueSize * 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"
    :class="!getDesign.showTime && 'p-5'"
  >
    <DeviceName :config="config" />
    <div class="flex flex-1 flex-col justify-center items-center w-full h-full">
      <div ref="chartRefEl" class="flex-1 w-full h-6/7 flex flex-col justify-center items-center">
      </div>
      <div
        class="text-gray-500 text-center"
        :style="{
          fontSize: (getRatio ? getRatio * getDesign.fontSize : getDesign.fontSize) + 'px',
        }"
        >{{ getDesign.attribute || t('visual.board.speedText') }}</div
      >
    </div>
    <UpdateTime v-if="getDesign.showTime" :time="time" />
  </main>
</template>