HistoryTrendModal.vue 6.69 KB
<script lang="ts" setup>
  import moment from 'moment';
  import { nextTick, Ref, ref, unref } from 'vue';
  import { getDeviceHistoryInfo } from '/@/api/alarm/position';
  import { Empty } from 'ant-design-vue';
  import { useECharts } from '/@/hooks/web/useECharts';
  import { dateUtil } from '/@/utils/dateUtil';
  import { AggregateDataEnum, eChartOptions } from '/@/views/device/localtion/config.data';
  import { useGridLayout } from '/@/hooks/component/useGridLayout';
  import { ColEx } from '/@/components/Form/src/types';
  import { DataSource } from '/@/api/dataBoard/model';
  import { useForm, BasicForm } from '/@/components/Form';
  import { formSchema, QueryWay, SchemaFiled } from '../config/historyTrend.config';
  import { DEFAULT_DATE_FORMAT } from '../config/util';
  import { Loading } from '/@/components/Loading';
  import BasicModal from '/@/components/Modal/src/BasicModal.vue';
  import { useModalInner } from '/@/components/Modal';
  import { getDeviceAttributes } from '/@/api/dataBoard';

  defineEmits(['register']);

  const chartRef = ref();

  const deviceAttrs = ref<string[]>([]);

  const loading = ref(false);

  const isNull = ref(false);

  function getSearchParams(value: Recordable) {
    const { startTs, endTs, interval, agg, limit, keys, way, deviceId } = value;
    if (way === QueryWay.LATEST) {
      return {
        entityId: deviceId,
        keys: keys ? keys : unref(deviceAttrs).join(),
        startTs: moment().subtract(startTs, 'ms').valueOf(),
        endTs: Date.now(),
        interval,
        agg,
        limit,
      };
    } else {
      return {
        entityId: deviceId,
        keys: keys ? keys : unref(deviceAttrs).join(),
        startTs: moment(startTs).valueOf(),
        endTs: moment(endTs).valueOf(),
        interval,
        agg,
        limit,
      };
    }
  }

  function hasDeviceAttr() {
    if (!unref(deviceAttrs).length) {
      return false;
    } else {
      return true;
    }
  }

  function setChartOptions(data, keys?) {
    const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);

    const dataArray: any[] = [];
    for (const key in data) {
      for (const item1 of data[key]) {
        let { ts, value } = item1;
        const time = dateUtil(ts).format(DEFAULT_DATE_FORMAT);
        value = Number(value).toFixed(2);
        dataArray.push([time, value, key]);
      }
    }
    keys = keys ? [keys] : unref(deviceAttrs);
    const series: any = keys.map((item) => {
      return {
        name: item,
        type: 'line',
        data: dataArray.filter((item1) => item1[2] === item),
      };
    });
    // 设置数据
    setOptions(eChartOptions(series, keys));
  }

  const [register, method] = useForm({
    schemas: formSchema,
    baseColProps: useGridLayout(2, 3, 4) as unknown as ColEx,
    rowProps: {
      gutter: 10,
    },
    labelWidth: 120,
    fieldMapToTime: [
      [SchemaFiled.DATE_RANGE, [SchemaFiled.START_TS, SchemaFiled.END_TS], 'YYYY-MM-DD HH:ss'],
    ],
    submitButtonOptions: {
      loading: loading as unknown as boolean,
    },
    async submitFunc() {
      // 表单验证
      await method.validate();
      const value = method.getFieldsValue();
      const searchParams = getSearchParams(value);
      if (!hasDeviceAttr()) return;
      // 发送请求
      loading.value = true;
      const res = await getDeviceHistoryInfo(searchParams);
      loading.value = false;
      // 判断数据对象是否为空
      if (!Object.keys(res).length) {
        isNull.value = false;
        return;
      } else {
        isNull.value = true;
      }
      setChartOptions(res, value.keys);
    },
  });

  const getDeviceDataKey = async (deviceId: string) => {
    if (!deviceId) return;
    try {
      deviceAttrs.value = (await getDeviceAttributes({ deviceId })) || [];
      await nextTick();
      method.updateSchema({
        field: SchemaFiled.KEYS,
        componentProps: {
          options: unref(deviceAttrs).map((item) => ({ label: item, value: item })),
        },
      });
    } catch (error) {}
  };

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

    method.setFieldsValue({
      [SchemaFiled.START_TS]: 1 * 24 * 60 * 60 * 1000,
      [SchemaFiled.LIMIT]: 7,
      [SchemaFiled.AGG]: AggregateDataEnum.NONE,
    });

    if (!hasDeviceAttr()) return;

    const { deviceId } = method.getFieldsValue();

    const res = await getDeviceHistoryInfo({
      entityId: deviceId,
      keys: unref(deviceAttrs).join(),
      startTs: Date.now() - 1 * 24 * 60 * 60 * 1000,
      endTs: Date.now(),
      agg: AggregateDataEnum.NONE,
      limit: 7,
    });

    // 判断对象是否为空
    if (!Object.keys(res).length) {
      isNull.value = false;
      return;
    } else {
      isNull.value = true;
    }
    setChartOptions(res);
  };

  const generateDeviceOptions = (dataSource: DataSource[]) => {
    const record: { [key: string]: boolean } = {};
    const options: Record<'label' | 'value', string>[] = [];
    for (const item of dataSource) {
      const { deviceName, gatewayDevice, slaveDeviceId } = item;
      let { deviceId } = item;
      if (gatewayDevice) {
        deviceId = slaveDeviceId;
      }
      if (record[deviceId]) continue;
      options.push({
        label: deviceName,
        value: deviceId,
      });
      record[deviceId] = true;
    }

    return options;
  };

  const [registerModal] = useModalInner(async (dataSource: DataSource[]) => {
    deviceAttrs.value = [];
    loading.value = false;
    const options = generateDeviceOptions(dataSource);
    await nextTick();
    method.updateSchema({
      field: SchemaFiled.DEVICE_ID,
      componentProps({ formActionType }) {
        const { setFieldsValue } = formActionType;
        return {
          options,
          onChange(value: string) {
            getDeviceDataKey(value);
            setFieldsValue({ [SchemaFiled.KEYS]: null });
          },
        };
      },
    });

    await handleModalOpen();
  });
</script>

<template>
  <BasicModal @register="registerModal" :destroy-on-close="true" width="70%" title="历史趋势">
    <section
      class="flex flex-col p-4 h-full w-full min-w-7/10"
      style="color: #f0f2f5; background-color: #f0f2f5"
    >
      <section class="bg-white my-3 p-2">
        <BasicForm @register="register" />
      </section>
      <section class="bg-white p-3" style="min-hight: 350px">
        <div v-show="isNull" ref="chartRef" :style="{ height: '350px', width: '100%' }">
          <Loading :loading="loading" :absolute="true" />
        </div>
        <Empty
          class="h-350px flex flex-col justify-center items-center"
          description="暂无数据,请选择设备查询"
          v-show="!isNull"
        />
      </section>
    </section>
  </BasicModal>
</template>

<style scoped></style>