index.vue 9.4 KB
<script setup lang="ts">
  import { Spin, Tooltip } from 'ant-design-vue';
  import { Background, BackgroundVariant } from '@vue-flow/background';
  import { Controls } from '@vue-flow/controls';
  import { Panel, PanelPosition, VueFlow } from '@vue-flow/core';
  import { computed, onMounted, Ref, ref, unref } from 'vue';
  import './style';
  import {
    BasicConnectionArrow,
    BasicConnectionLine,
    BasicEdge,
    MenuSidebar,
  } from './src/components';
  import type { FlowElRef } from './types/flow';
  import { useDragCreate } from './hook/useDragCreate';
  import { createFlowContext } from './hook/useFlowContext';
  import { CreateNodeModal } from './src/components/CreateNodeModal';
  import { useRuleFlow } from './hook/useRuleFlow';
  import { CreateEdgeModal } from './src/components/CreateEdgeModal';
  import { useFullScreen } from './hook/useFullScreen';
  import { useSaveAndRedo } from './hook/useSaveAndRedo';
  import { NodeData } from './types/node';
  import { Icon } from '/@/components/Icon';
  import { UpdateNodeDrawer } from './src/components/UpdateNodeDrawer';
  import { UpdateEdgeDrawer } from './src/components/UpdateEdgeDrawer';
  import { CreateRuleChainModal } from './src/components/CreateRuleChainModal';
  import { useRouter } from 'vue-router';

  // import { getRuleChinsList } from '/@/api/ruleengine/ruleengineApi';
  // import { ApiSelect } from '/@/components/Form';
  // import DownImage from '/@/assets/svg/down-svg.svg';

  const getId = Number(Math.random().toString().substring(2)).toString(16);

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

  const createNodeModalActionType = ref<Nullable<InstanceType<typeof CreateNodeModal>>>(null);

  const createEdgeModalActionType = ref<Nullable<InstanceType<typeof CreateEdgeModal>>>(null);

  const updateNodeDrawerActionType = ref<Nullable<InstanceType<typeof UpdateNodeDrawer>>>(null);

  const updateEdgeDrawerActionType = ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>(null);

  const createRuleChainModalActionType =
    ref<Nullable<InstanceType<typeof CreateRuleChainModal>>>(null);

  const flowElRef = ref<Nullable<FlowElRef>>(null);

  const elements = ref([]);

  const useSaveAndRedoActionType = useSaveAndRedo();

  const {
    loading,
    changeMarker,
    ruleChainDetail,
    getCurrentPageMetaData,
    triggerChange,
    handleApplyChange,
    handleRedoChange,
    handleRemoveDebug,
    getCurrentRuleChainDetail,
  } = useSaveAndRedoActionType;

  const { flowActionType } = useRuleFlow({
    id: getId,
    ruleChainDetail,
    useSaveAndRedoActionType,
    modalActionType: {
      createNodeModalActionType,
      createEdgeModalActionType,
      updateEdgeDrawerActionType,
      updateNodeDrawerActionType,
      createRuleChainModalActionType,
    },
  });

  const { handleOnDragOver, handleOnDrop } = useDragCreate({
    el: flowElRef,
    createNodeModalActionType,
    flowActionType,
    triggerChange,
  });

  const { handleFullScreen, getFullScreenIcon } = useFullScreen(
    rootElRef as unknown as Ref<Nullable<HTMLDivElement>>
  );

  const handleGetContainer = () => unref(rootElRef)!;

  const getDeleteDisplayState = computed(() => unref(flowActionType.getSelectedElements).length);

  const getDebugMarker = computed(() =>
    flowActionType.getNodes.value.some((item) => (item.data as NodeData).data?.debugMode)
  );

  const handleDeleteSelectionElements = () => {
    flowActionType.removeNodes(unref(flowActionType.getSelectedNodes));
    flowActionType.removeEdges(unref(flowActionType.getSelectedEdges));
    useSaveAndRedoActionType.triggerChange?.();
  };

  const ROUTER = useRouter();
  // const isShowSelect = ref<boolean>(false);
  const handleBack = () => {
    ROUTER.go(-1);
  };

  // const handleDown = () => {
  //   isShowSelect.value = !unref(isShowSelect);
  // };

  // const handleSelectChange = (e) => {
  //   ROUTER.replace(`${e}`);
  // };

  onMounted(() => {
    getCurrentPageMetaData(flowActionType);
    getCurrentRuleChainDetail();
  });

  createFlowContext({
    createEdgeModalActionType,
    createNodeModalActionType,
    updateEdgeDrawerActionType,
    updateNodeDrawerActionType,
    createRuleChainModalActionType,
    flowActionType,
    triggerChange,
  });
</script>

<template>
  <main ref="rootElRef" class="w-full h-full flex relative" @drop="handleOnDrop">
    <!-- <Sidebar /> -->
    <MenuSidebar />

    <Spin :spinning="loading" wrapperClassName="w-full h-ful rule-chain-designer-loading-container">
      <VueFlow
        :id="getId"
        ref="flowElRef"
        v-model="elements"
        class="w-full h-full"
        @dragover="handleOnDragOver"
      >
        <template #connection-line="props">
          <BasicConnectionLine v-bind="props" />
        </template>
        <template #edge-custom="props">
          <BasicEdge v-bind="props" />
        </template>
        <BasicConnectionArrow />
        <Background :variant="BackgroundVariant.Lines" :gap="25" pattern-color="#cfcfcf" />

        <Controls :position="PanelPosition.BottomLeft" />

        <Panel position="bottom-right" class="controls">
          <section class="flex gap-4">
            <button
              :style="{ transform: `translateY(${getDeleteDisplayState ? 0 : '72px'})` }"
              class="button-box-shadow w-14 h-14 flex justify-center items-center bg-orange-600 rounded-full transition-transform transform"
              @click="handleDeleteSelectionElements"
            >
              <Icon class="!text-3xl !text-light-50" icon="mdi:delete" />
            </button>
            <button
              :class="getDebugMarker ? '!bg-orange-600 !opacity-100' : 'opacity-50'"
              class="button-box-shadow w-14 h-14 flex justify-center items-center bg-gray-400 rounded-full opacity-50"
              @click="handleRemoveDebug(flowActionType)"
            >
              <Icon class="!text-3xl !text-light-50" icon="carbon:debug" />
            </button>
            <button
              :class="changeMarker ? '!bg-orange-600 !opacity-100' : 'opacity-50'"
              class="button-box-shadow w-14 h-14 flex justify-center items-center bg-gray-400 rounded-full"
              @click="handleApplyChange(flowActionType)"
            >
              <Icon class="!text-3xl !text-light-50" icon="mdi:tick" />
            </button>
            <button
              :class="changeMarker ? '!bg-orange-600 !opacity-100' : 'opacity-50'"
              class="button-box-shadow w-14 h-14 flex justify-center items-center bg-gray-400 rounded-full"
              @click="handleRedoChange(flowActionType)"
            >
              <Icon class="!text-3xl !text-light-50" icon="ic:baseline-close" />
            </button>
          </section>
        </Panel>

        <Panel position="top-right" class="flex">
          <Tooltip title="返回">
            <button
              class="w-10 h-10 bg-gray-300 flex justify-center items-center rounded-full dark:bg-dark-50"
              @click="handleBack"
              ><Icon icon="ant-design:rollback-outlined" class="cursor-pointer svg:text-xl" />
            </button>
          </Tooltip>
          <button
            class="w-10 h-10 bg-gray-300 mx-1 flex justify-center items-center rounded-full dark:bg-dark-50"
            @click="handleFullScreen"
          >
            <Icon class="!text-2xl dark:text-light-50" :icon="getFullScreenIcon" />
          </button>
        </Panel>
        <!-- <Panel position="top-left">
          <h1 class="ml-10">{{ ruleChainDetail?.name }}</h1>
        </Panel> -->
        <!-- <Panel position="top-center" class="flex flex-col items-center">
          <button
            class="w-10 h-10 bg-gray-300 mx-1 flex justify-center items-center rounded-full dark:bg-dark-50"
            @click="handleDown"
          >
            <img :src="DownImage" alt="avatar" />
          </button>
          <div v-if="isShowSelect" class="mt-1">
            <ApiSelect
              class="!mx-2 flex-auto w-40"
              :api="
                async (params) => {
                  const options = await getRuleChinsList(params);
                  return options?.data
                    .map((item) => ({ label: item.name, value: item.id.id }))
                    .filter((item) => item.label !== ruleChainDetail?.name);
                }
              "
              :showSearch="true"
              :filterOption="(inputValue: string, option: Record<'label' | 'value', string>) =>
          option.label.includes(inputValue)"
              placeholder="请选择规则链"
              :params="{
                page: 0,
                pageSize: 100,
                sortProperty: 'createdTime',
                sortOrder: 'DESC',
              }"
              @change="handleSelectChange"
            />
          </div>
        </Panel> -->
      </VueFlow>
    </Spin>

    <CreateNodeModal ref="createNodeModalActionType" :get-container="handleGetContainer" />
    <CreateEdgeModal ref="createEdgeModalActionType" :get-container="handleGetContainer" />

    <UpdateEdgeDrawer ref="updateEdgeDrawerActionType" />
    <UpdateNodeDrawer ref="updateNodeDrawerActionType" />

    <CreateRuleChainModal ref="createRuleChainModalActionType" />
  </main>
</template>

<style scoped>
  .button-box-shadow {
    box-shadow: 0 3px 5px -1px #0003, 0 6px 10px 0 #00000024, 0 1px 18px 0 #0000001f;
  }
</style>

<style lang="less">
  .rule-chain-designer-loading-container {
    .ant-spin-container {
      @apply w-full h-full;
    }

    // :deep(.top .center) {
    //   margin: 0 !important;
    // }
  }
</style>