TimeLineChart.vue 3.45 KB
<script setup lang="ts">
  import { ref, Ref, onMounted, computed, watch } from 'vue';
  import { useECharts } from '/@/hooks/web/useECharts';
  import { useAppStore } from '/@/store/modules/app';
  import { useI18n } from '/@/hooks/web/useI18n';
  import { Empty } from 'ant-design-vue';
  import { EChartsOption, SeriesOption } from 'echarts';

  const { t } = useI18n();

  const props = withDefaults(
    defineProps<{
      timeType: string;
      chartsData?: Partial<EChartsOption>;
    }>(),
    {
      timeType: 'week',
      chartsData: () => ({}),
    }
  );

  const emits = defineEmits(['emitTimeRange']);

  const appStore = useAppStore();

  const timeRange = ref('week');

  const timeRangeList = ref([
    { label: `1${t('home.index.timeUnit.hour')}`, value: 'hour', interval: 1000 * 60 * 5 },
    { label: `1${t('home.index.timeUnit.day')}`, value: 'day', interval: 1000 * 60 * 60 * 1 },
    {
      label: `7${t('home.index.timeUnit.day')}`,
      value: 'week',
      interval: 1000 * 60 * 60 * 1,
    },
    {
      label: `30${t('home.index.timeUnit.day')}`,
      value: 'month',
      interval: 1000 * 60 * 60 * 24,
    },
  ]);

  const skinName = computed(() => {
    return appStore.getDarkMode === 'light' ? '#ffffff' : '#151515';
  });

  const chartRef = ref<HTMLDivElement | null>(null);

  const { setOptions, resize } = useECharts(chartRef as Ref<HTMLDivElement>);

  const getOptions = (): EChartsOption => {
    const { xAxis, series } = props.chartsData || {};
    return {
      backgroundColor: skinName.value,
      tooltip: {
        trigger: 'axis',
      },
      grid: {
        left: '1%',
        right: '2%',
        bottom: '1%',
        containLabel: true,
      },
      xAxis,
      yAxis: {
        type: 'value',
        axisLabel: { formatter: '{value}' },
      },
      series,
    };
  };

  watch(
    () => appStore.getDarkMode,
    (target) => {
      const backgroundColor = target === 'light' ? '#ffffff' : '#151515';
      setOptions &&
        setOptions({
          ...getOptions(),
          backgroundColor,
        });
    }
  );

  watch(
    () => props.chartsData,
    () => {
      setOptions(getOptions());
    },
    {
      deep: true,
      immediate: true,
    }
  );

  onMounted(() => {
    setOptions(getOptions());
    //自适应
    window.addEventListener('resize', () => {
      resize();
      setOptions(getOptions());
    });
  });

  const handleTimeRangeChange = (e: any) => {
    const startTs = Date.now() - e.target.value;
    const endTs = Date.now();
    emits('emitTimeRange', e.target.value, startTs, endTs);
  };
</script>
<template>
  <a-card :title="t('application.record.text.timeLineTitle')" class="w-full h-120">
    <template #extra>
      <a-radio-group @change="handleTimeRangeChange" v-model:value="timeRange" button-style="solid">
        <template v-for="(timeItem, index) in timeRangeList" :key="timeItem.value">
          <div style="display: none">{{ index }}</div>
          <a-radio-button :value="timeItem.value">
            {{ timeItem.label }}
          </a-radio-button>
        </template>
      </a-radio-group>
    </template>
    <div
      v-show="(chartsData?.series as SeriesOption[])?.length"
      ref="chartRef"
      class="w-full h-80"
    ></div>
    <div
      v-show="!(chartsData?.series as SeriesOption[])?.length"
      class="w-full h-72 flex justify-center items-center"
    >
      <Empty :image="Empty.PRESENTED_IMAGE_SIMPLE" />
    </div>
  </a-card>
</template>

<style scoped></style>