DashBoardComponent.vue 4.81 KB
<script lang="ts" setup>
  import type { ECharts, EChartsOption } from 'echarts';
  import { PropType, watch } from 'vue';
  import { nextTick, onMounted, onUnmounted, ref, unref, computed } from 'vue';
  import { init } from 'echarts';
  import {
    DashboardComponentLayout,
    DashBoardValue,
    instrumentComponent1,
    InstrumentComponentType,
    update_instrument_1_font,
    update_instrument_2_font,
    update_instrument_1_value,
    update_instrument_2_value,
  } from './dashBoardComponent.config';
  import { dateUtil } from '/@/utils/dateUtil';
  import {
    DEFAULT_RADIO_RECORD,
    RadioRecord,
    DEFAULT_DATE_FORMAT,
    fontSize,
  } from '../../detail/config/util';
  import { Tooltip } from 'ant-design-vue';
  import { useThrottleFn } from '@vueuse/shared';

  const props = defineProps({
    add: {
      type: Function,
    },
    layout: {
      type: Object as PropType<DashboardComponentLayout>,
      default: () => ({}),
    },
    value: {
      type: Object as PropType<DashBoardValue>,
      default: () => ({}),
    },
    radio: {
      type: Object as PropType<RadioRecord>,
      default: () => DEFAULT_RADIO_RECORD,
    },
    random: {
      type: Boolean,
      default: true,
    },
  });

  const getControlsWidgetId = () => `widget-chart-${props.value.id}`;

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

  function initChart() {
    const chartDom = document.getElementById(getControlsWidgetId())!;
    chartRef.value = init(chartDom);
    const option: EChartsOption = props.layout.chartOption || instrumentComponent1();

    nextTick(() => {
      option && unref(chartRef)?.setOption(option);
    });
  }

  const getRadio = computed(() => {
    const { radio } = props.radio;
    return radio;
  });

  const beforeUpdateFn = (componentType: InstrumentComponentType) => {
    if (componentType === 'instrument-component-1') return update_instrument_1_font;
    if (componentType === 'instrument-component-2') return update_instrument_2_font;
    return (_radio: number) => {};
  };

  function update() {
    const option = beforeUpdateFn(props.layout.componentType);
    unref(chartRef)?.setOption((option(unref(getRadio)) as unknown as EChartsOption) || {});
    unref(chartRef)?.resize();
  }

  const getUpdateValueFn = (componentType: InstrumentComponentType) => {
    if (componentType === 'instrument-component-1') return update_instrument_1_value;
    if (componentType === 'instrument-component-2') return update_instrument_2_value;
    return (_radio: number) => {};
  };

  const updateChartValue = useThrottleFn((newValue) => {
    const updateFn = getUpdateValueFn(props.layout.componentType);
    unref(chartRef)?.setOption((updateFn(newValue || 0) as unknown as EChartsOption) || {});
  }, 500);

  watch(() => props.value.value, updateChartValue);

  const updateChartFont = useThrottleFn(() => {
    const option = beforeUpdateFn(props.layout.componentType);
    setTimeout(() => {
      unref(chartRef)?.setOption((option(unref(getRadio)) as unknown as EChartsOption) || {});
    });
  }, 500);

  watch(() => props.radio, updateChartFont);

  const updateChartType = useThrottleFn(() => {
    unref(chartRef)?.clear();
    unref(chartRef)?.setOption(props?.layout?.chartOption || {});
  }, 500);

  watch(() => props.layout.chartOption, updateChartType);

  let timeout: Nullable<number> = null;

  function handleRandomValue() {
    const newValue = Math.floor(Math.random() * 100);
    const updateFn = getUpdateValueFn(props.layout.componentType);
    unref(chartRef)?.setOption((updateFn(newValue) as unknown as EChartsOption) || {});
  }

  onMounted(() => {
    initChart();
    props.add && props.add(props.value.id, update);
    if (props.random) timeout = setInterval(handleRandomValue, 2000) as unknown as number;
  });

  onUnmounted(() => {
    unref(chartRef)?.clear();
    clearInterval(timeout as number);
    timeout = null;
  });

  defineExpose({ update });
</script>

<template>
  <div class="flex flex-col w-full h-full min-w-3 min-h-3">
    <div :id="getControlsWidgetId()" class="widget-charts w-full h-full flex-auto"></div>
    <div>
      <div class="text-center" :style="{ fontSize: fontSize({ radio: getRadio, basic: 16 }) }">
        {{ props.value.name }}
      </div>
      <div
        class="text-xs text-center truncate p-5"
        :style="{ fontSize: fontSize({ radio: getRadio, basic: 12, max: 16 }), color: '#999' }"
      >
        <Tooltip
          placement="top"
          :title="dateUtil(props?.value?.updateTime || new Date()).format(DEFAULT_DATE_FORMAT)"
        >
          <span class="mr-2">更新时间:</span>
          <span>
            {{ dateUtil(props?.value?.updateTime || new Date()).format(DEFAULT_DATE_FORMAT) }}
          </span>
        </Tooltip>
      </div>
    </div>
  </div>
</template>

<style scoped>
  .widget-charts > div {
    width: 100%;
    height: 100%;
  }
</style>