index.vue 7.32 KB
<script lang="ts" setup>
  import { onMounted, unref } from 'vue';
  import { ref } from 'vue';
  import { Empty, Spin, Button } from 'ant-design-vue';
  import { getBoundingClientRect } from '/@/utils/domUtils';
  import { GridItem, GridLayout } from 'vue3-grid-layout';
  import {
    DEFAULT_MAX_COL,
    DEFAULT_MIN_HEIGHT,
    DEFAULT_MIN_WIDTH,
    DEFAULT_ITEM_MARIGN,
    VisualComponentPermission,
  } from './index';
  import { useDragGridLayout } from './hooks/useDragGridLayout';
  import { WidgetHeader, WidgetWrapper } from './components/WidgetWrapper';
  import { computed } from 'vue';
  import { WidgetDataType, useDataSource } from './hooks/useDataSource';
  import { WidgetDistribute } from './components/WidgetDistribute';
  import { DataSourceBindPanel } from '../dataSourceBindPanel';
  import { PageHeader } from './components/PagerHeader';
  import { useShare } from './hooks/useShare';
  import { useRole } from '/@/hooks/business/useRole';
  import { Authority } from '/@/components/Authority';
  import { useModal } from '/@/components/Modal';
  import { ModalParamsType } from '/#/utils';
  import { DataActionModeEnum } from '/@/enums/toolEnum';
  import { HistoryTrendModal } from './components/HistoryTrendModal';
  import { AlarmTimeModal } from './components/AlarmTimeModal';
  import { watch } from 'vue';
  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
  import { ThemeEnum } from '/@/enums/appEnum';
  import { createDataBoardContext } from './hooks/useDataBoardContext';
  import { useSocket } from '/@/views/visual/packages/hook/socket/useSocket';
  import { createAlarmContext } from './hooks/useAlarmTime';
  import { createHistoryContext } from './hooks/useHistoryForm';

  const props = defineProps<{
    value?: Recordable;
  }>();

  const getProps = computed(() => props);

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

  const containerRectRef = ref<DOMRect>({} as unknown as DOMRect);

  const { loading, draggable, resizable, dataSource, rawDataSource, setLayoutInfo, getDataSource } =
    useDataSource(getProps);

  const { resize, resized, moved, containerResized } = useDragGridLayout(dataSource, setLayoutInfo);

  const [register, { openModal }] = useModal();

  const [registerTrendModal, { openModal: openTrendModal }] = useModal();

  /**
   * @description 获取画板宽高
   */
  onMounted(() => {
    const rect = getBoundingClientRect(unref(containerRefEl)!);
    if (rect) {
      containerRectRef.value = rect as DOMRect;
    }
  });
  const { getIsSharePage } = useShare();
  const { isCustomerUser } = useRole();
  const handleOpenCreatePanel = () => {
    openModal(true, { mode: DataActionModeEnum.CREATE } as ModalParamsType);
  };

  const handleUpdateWidget = (data: WidgetDataType) => {
    openModal(true, { mode: DataActionModeEnum.UPDATE, record: data } as ModalParamsType);
  };

  const handleOpenTrend = (data: WidgetDataType) => {
    openTrendModal(true, { mode: DataActionModeEnum.READ, record: data } as ModalParamsType);
  };

  // 设备告警时间选择
  const [registerAlarmModal, { openModal: openAlarmModal }] = useModal();
  const handleOpenAlarm = (data: WidgetDataType) => {
    openAlarmModal(true, { mode: DataActionModeEnum.READ, record: data } as ModalParamsType);
  };

  const alarmForm = ref<{
    time?: number | string;
    pageSize: number;
    startTs?: number | string;
    endTs?: string | number;
  }>({
    time: 2592000000,
    pageSize: 20,
    startTs: undefined,
    endTs: undefined,
  });

  //告警发送数据
  const getAlarmForm = (values) => {
    const { way, pageSize, startTs, endTs } = values;
    if (way == 'timePeriod') {
      alarmForm.value = {
        time: undefined,
        startTs,
        endTs,
        pageSize,
      };
    } else
      alarmForm.value = {
        time: startTs,
        pageSize,
        startTs: undefined,
        endTs: undefined,
      };
  };
  createAlarmContext({ alarmForm: alarmForm });

  // 历史数据发送
  const historyForm = ref({
    startTs: Date.now() - 30 * 24 * 60 * 60 * 1000,
    endTs: Date.now(),
    agg: 'NONE',
    limit: 30,
    interval: undefined,
    way: 'latest',
  });

  const getHistoryForm = (values) => {
    const { startTs, endTs, agg, limit, interval, way } = values;
    historyForm.value = {
      startTs,
      endTs,
      agg,
      limit,
      interval,
      way,
    };
    if (way === 'latest') {
      historyForm.value.startTs = Date.now() - startTs;
      historyForm.value.endTs = Date.now();
    }
  };
  createHistoryContext({ historyForm: historyForm, getHistoryForm });

  const { send, close } = useSocket(dataSource);

  createDataBoardContext({ send, close });

  const { getDarkMode } = useRootSetting();
  watch(
    getIsSharePage,
    (value) => {
      if (value) {
        const root = document.querySelector('#app');
        (root as HTMLDivElement).style.backgroundColor =
          unref(getDarkMode) === ThemeEnum.LIGHT ? '#F5F5F5' : '#1b1b1b';
      }
    },
    { immediate: true }
  );
</script>

<template>
  <section
    ref="containerRefEl"
    class="palette w-full h-full flex-col bg-neutral-100 flex dark:bg-dark-700 dark:text-light-50"
  >
    <PageHeader :widget-number="dataSource.length">
      <Authority :value="VisualComponentPermission.CREATE">
        <Button
          v-if="!getIsSharePage && !isCustomerUser"
          type="primary"
          @click="handleOpenCreatePanel"
        >
          创建组件
        </Button>
      </Authority>
    </PageHeader>

    <Spin :spinning="loading">
      <GridLayout
        v-model:layout="dataSource"
        :col-num="DEFAULT_MAX_COL"
        :row-height="30"
        :margin="[DEFAULT_ITEM_MARIGN, DEFAULT_ITEM_MARIGN]"
        :is-draggable="draggable"
        :is-resizable="resizable"
        :vertical-compact="true"
        :use-css-transforms="true"
        style="width: 100%"
      >
        <GridItem
          v-for="item in dataSource"
          :key="item.i"
          :static="item.static"
          :x="item.x"
          :y="item.y"
          :w="item.w"
          :h="item.h"
          :i="item.i"
          :min-h="DEFAULT_MIN_HEIGHT"
          :min-w="DEFAULT_MIN_WIDTH"
          :style="{ display: 'flex', flexWrap: 'wrap' }"
          class="grid-item-layout"
          @resized="resized"
          @resize="resize"
          @moved="moved"
          @container-resized="containerResized"
          drag-ignore-from=".no-drag"
        >
          <WidgetWrapper>
            <template #header>
              <WidgetHeader
                :raw-data-source="rawDataSource"
                :source-info="item"
                @update="handleUpdateWidget"
                @open-trend="handleOpenTrend"
                @open-alarm="handleOpenAlarm"
                @ok="getDataSource"
              />
            </template>
            <WidgetDistribute :source-info="item" />
          </WidgetWrapper>
        </GridItem>
      </GridLayout>
      <Empty
        v-if="!dataSource.length"
        class="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
      />
    </Spin>

    <DataSourceBindPanel @register="register" :layout="dataSource" @ok="getDataSource" />

    <!-- 趋势 -->
    <HistoryTrendModal @register="registerTrendModal" />

    <!-- 选择时间 -->
    <AlarmTimeModal @register="registerAlarmModal" @getAlarmForm="getAlarmForm" />
  </section>
</template>

<style lang="less" scoped></style>