WidgetHeader.vue 7.56 KB
<script lang="ts" setup>
  import { ref } from 'vue';
  import { useShare } from '../../hooks/useShare';
  import AuthDropDown, { AuthDropMenuList } from '/@/components/Widget/AuthDropDown.vue';
  import { useRole } from '/@/hooks/business/useRole';
  import { DataActionModeEnum } from '/@/enums/toolEnum';
  import { VisualComponentPermission } from '../..';
  import { Tooltip } from 'ant-design-vue';
  import { MoreOutlined, AreaChartOutlined, FieldTimeOutlined } from '@ant-design/icons-vue';
  import { WidgetDataType } from '../../hooks/useDataSource';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { addDataComponent, deleteDataComponent } from '/@/api/dataBoard';
  import { useBoardId } from '../../hooks/useBoardId';
  import { unref, toRaw } from 'vue';
  import { ApiDataBoardDataType, ComponentLayoutType } from '../../types';
  import { useCalcNewWidgetPosition } from '../../hooks/useCalcNewWidgetPosition';
  import { Layout } from 'vue3-grid-layout';
  import { DataComponentRecord } from '/@/api/dataBoard/model';
  import { computed } from 'vue';
  import { useGetComponentConfig } from '../../../packages/hook/useGetComponetConfig';
  import { isBoolean } from '/@/utils/is';
  import { useApp } from '../../hooks/useApp';
  import { useI18n } from '/@/hooks/web/useI18n';
  import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue';
  import { deleteFilePath } from '/@/api/oss/ossFileUploader';

  const props = defineProps<{
    sourceInfo: WidgetDataType;
    rawDataSource: ApiDataBoardDataType;
  }>();

  const emit = defineEmits<{
    (event: 'ok'): void;
    (event: 'update', data: WidgetDataType): void;
    (event: 'openTrend', data: WidgetDataType): void;
    (event: 'openAlarm', data: WidgetDataType): void;
  }>();

  const { isCustomerUser } = useRole();

  const { t } = useI18n();

  const { getIsSharePage } = useShare();

  const { createMessage } = useMessage();

  const { getIsAppPage } = useApp();

  const { boardId } = useBoardId();

  const dropMenuList = ref<AuthDropMenuList[]>([
    {
      text: t('visual.board.editComponent'),
      event: DataActionModeEnum.UPDATE,
      icon: 'ant-design:edit-outlined',
      auth: VisualComponentPermission.UPDATE,
      onClick: handleUpdate,
    },
    {
      text: t('visual.board.copyComponent'),
      event: DataActionModeEnum.COPY,
      icon: 'ant-design:copy-outlined',
      auth: VisualComponentPermission.COPY,
      onClick: handleCopy,
    },
    {
      text: t('visual.board.delComponent'),
      event: DataActionModeEnum.DELETE,
      icon: 'ant-design:delete-outlined',
      auth: VisualComponentPermission.DELETE,
      popconfirm: {
        title: t('common.isDelete'),
        onConfirm: handleDelete.bind(null),
      },
    },
  ]);

  function handleUpdate() {
    emit('update', toRaw(props.sourceInfo));
  }

  const countElementOccurrences = (arr) => {
    const countMap = {};

    arr.forEach((element) => {
      if (countMap[element]) {
        countMap[element]++;
      } else {
        countMap[element] = 1;
      }
    });

    return countMap;
  };

  async function handleDelete() {
    try {
      const { componentData: oldDataSource } = props.rawDataSource;
      const customIconUrls = ref<any>([]);
      oldDataSource?.forEach((item: any) => {
        item.dataSource?.forEach((dataSource) => {
          if (dataSource.componentInfo?.customIcon) {
            dataSource.componentInfo?.customIcon.forEach((icon: FileItem) => {
              customIconUrls.value.push(icon.url);
            });
          }
        });
      });

      const { dataSource: deleteDataSource } = props.sourceInfo;
      const dataSourceDeleteUrl = deleteDataSource.map(
        (item) => item.componentInfo.customIcon?.[0].url
      );

      if (dataSourceDeleteUrl?.length) {
        // 判断外部所有组件是否有dataSourceDeleteUrl使用中的url
        const deletePromise = unref(customIconUrls)?.filter((item) =>
          dataSourceDeleteUrl?.includes(item)
        );

        const deleteUrlInfo = countElementOccurrences(deletePromise);
        const deleteUrl = deletePromise?.filter((item) => deleteUrlInfo?.[item] == 1);
        Promise.all(
          deleteUrl.map((item) => {
            deleteFilePath(item);
          })
        );
      }
    } catch (err) {}

    try {
      await deleteDataComponent({ dataBoardId: unref(boardId), ids: [props.sourceInfo.id] });
      createMessage.success(t('common.deleteSuccessText'));
      emit('ok');
    } catch (error) {}
  }

  const getLayout = computed(() => {
    const { sourceInfo } = props;
    const { id, w, h, x, y } = sourceInfo;
    return { id, w, h, x, y } as ComponentLayoutType;
  });

  const hasTrendQueryIcon = computed(() => {
    const frontId = props.sourceInfo.frontId;
    const config = useGetComponentConfig(frontId);
    const flag = config.persetOption?.trendQuery;
    return isBoolean(flag) ? flag : true;
  });

  const isAlarmHistory = computed(() => {
    const frontId = props.sourceInfo.frontId;
    if (
      // frontId == 'DeviceAlarm' ||
      frontId == 'DeviceAlarmHistory' ||
      frontId == 'StatisticsComponent7'
    ) {
      return true;
    } else {
      return false;
    }
  });
  const isAlarm = computed(() => {
    const frontId = props.sourceInfo.frontId;
    if (frontId == 'DeviceAlarm') {
      return false;
    } else {
      return true;
    }
  });

  async function handleCopy() {
    const id = props.sourceInfo.id;
    const copyRecord = props.rawDataSource.componentData.find((item) => item.id === id);
    const copyLayout = unref(getLayout);
    const raw = toRaw(copyRecord) as unknown as DataComponentRecord;

    const layout = useCalcNewWidgetPosition(
      props.rawDataSource.componentLayout as unknown as Layout[],
      { width: copyLayout!.w, height: copyLayout!.h }
    );

    try {
      await addDataComponent({
        boardId: unref(boardId),
        record: {
          frontId: raw.frontId,
          dataSource: raw.dataSource,
          name: raw.name,
          remark: raw.remark,
          layout: layout as Layout,
        },
      });
      createMessage.success(t('common.copyOk'));
      emit('ok');
    } catch (error) {
      throw error;
    }
  }

  const handleOpenTrendModal = () => {
    emit('openTrend', toRaw(props.sourceInfo));
  };

  const handleAlarmModal = () => {
    emit('openAlarm', toRaw(props.sourceInfo));
  };
</script>

<template>
  <section class="p-2.5 flex flex-col w-full">
    <main class="flex w-full h-full h-7">
      <Tooltip :title="sourceInfo.name">
        <div class="flex-1 w-full h-full flex text-lg justify-center font-semibold truncate">
          <div class="w-full truncate text-center">
            {{ sourceInfo.name }}
          </div>
        </div>
      </Tooltip>

      <div v-if="!getIsSharePage" class="flex items-center w-16 justify-evenly">
        <Tooltip
          v-if="!isCustomerUser && hasTrendQueryIcon && isAlarm"
          :title="
            isAlarmHistory ? t('component.fieldTime.timeText') : t('component.areaChart.trendText')
          "
        >
          <FieldTimeOutlined v-if="isAlarmHistory" class="text-lg" @click="handleAlarmModal" />
          <AreaChartOutlined v-else class="text-lg" @click="handleOpenTrendModal" />
        </Tooltip>
        <AuthDropDown
          v-if="!isCustomerUser && dropMenuList.length && !getIsAppPage"
          :drop-menu-list="dropMenuList"
          :trigger="['click']"
        >
          <Tooltip :title="t('common.moreText')">
            <MoreOutlined class="transform rotate-90 cursor-pointer text-lg" />
          </Tooltip>
        </AuthDropDown>
      </div>
    </main>
  </section>
</template>