index.vue 6.18 KB
<script setup lang="ts">
  import { Spin } 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 { Icon } from '/@/components/Icon';
  import { UpdateNodeDrawer } from './src/components/UpdateNodeDrawer';
  import { UpdateEdgeDrawer } from './src/components/UpdateEdgeDrawer';

  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 flowElRef = ref<Nullable<FlowElRef>>(null);

  const elements = ref([]);

  const {
    loading,
    changeMarker,
    getCurrentPageMetaData,
    triggerChange,
    handleApplyChange,
    handleRedoChange,
  } = useSaveAndRedo();

  const { flowActionType } = useRuleFlow({
    id: getId,
    createNodeModalActionType,
    createEdgeModalActionType,
    updateEdgeDrawerActionType,
    updateNodeDrawerActionType,
    triggerChange,
  });

  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 handleDeleteSelectionElements = () => {
    flowActionType.removeEdges(unref(flowActionType.getSelectedEdges));
    flowActionType.removeNodes(unref(flowActionType.getSelectedNodes));
  };

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

  createFlowContext({
    createEdgeModalActionType,
    createNodeModalActionType,
    updateEdgeDrawerActionType,
    updateNodeDrawerActionType,
    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="button-box-shadow w-14 h-14 flex justify-center items-center bg-gray-400 rounded-full opacity-50"
            >
              <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">
          <button
            class="w-10 h-10 bg-gray-300 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>
      </VueFlow>
    </Spin>

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

    <UpdateEdgeDrawer ref="updateEdgeDrawerActionType" />
    <UpdateNodeDrawer ref="updateNodeDrawerActionType" />
  </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;
    }
  }
</style>