useSaveAndRedo.ts 4.63 KB
import type { VueFlowStore, Elements } from '@vue-flow/core';
import { computed, ref, unref } from 'vue';
import { BasicNodeBindData, NodeData } from '../types/node';
import { useBasicDataTransform } from './useBasicDataTransform';
import {
  getRuleChainData,
  getRuleChainDetail,
  saveRuleChainData,
  saveRuleChainDetail,
} from '/@/api/ruleDesigner';
import { ConnectionItemType, RuleChainDetail, RuleChainType } from '../types/ruleNode';
import { useNewNode } from './useNewNode';
import { buildUUID } from '/@/utils/uuid';
import { useRoute, useRouter } from 'vue-router';
import { RuleChainEntityType } from '../enum/entity';
import { PageEnum } from '/@/enums/pageEnum';
import { clearRuleChainImportCache, getRuleChainImportCache } from './useRuleChainCache';

export function useSaveAndRedo() {
  const changeMarker = ref(false);

  const loading = ref(false);

  const redoDataRef = ref<Elements>([]);

  const ROUTE = useRoute();

  const ROUTER = useRouter();

  const debugMarker = ref(false);

  const getRuleChainId = computed(() => (ROUTE.params as Record<'id', string>).id);

  const getIsImportFlag = computed(() => ROUTE.fullPath === PageEnum.RULE_CHAIN_DETAIL_IMPORT);

  const ruleChainDetail = ref<RuleChainDetail>();

  const { combineData, deconstructionData } = useBasicDataTransform();

  const triggerChange = () => {
    changeMarker.value = true;
  };

  const resetChange = () => {
    changeMarker.value = false;
  };

  const handleApplyChange = (flowActionType: VueFlowStore) => {
    if (!unref(changeMarker)) return;

    const { connections, nodes, firstNodeIndex } = combineData(
      flowActionType.getNodes,
      flowActionType.getEdges
    );

    handleSaveRuleChain(connections, nodes, firstNodeIndex, flowActionType);
  };

  const handleRedoChange = (flowActionType: VueFlowStore) => {
    if (!unref(changeMarker)) return;
    flowActionType.setElements(unref(redoDataRef));
    resetChange();
  };

  async function getCurrentRuleChainDetail() {
    ruleChainDetail.value = unref(getIsImportFlag)
      ? (getImportChainDetail() as RuleChainDetail)
      : await getRuleChainDetail(unref(getRuleChainId));
  }

  async function handleSaveRuleChain(
    connections: ConnectionItemType[],
    nodes: BasicNodeBindData[],
    firstNodeIndex: number | undefined = undefined,
    flowActionType: VueFlowStore
  ) {
    try {
      loading.value = true;

      let ruleChainId = unref(getRuleChainId);
      if (unref(getIsImportFlag)) {
        const detail = await saveRuleChainDetail(unref(ruleChainDetail)!);
        ruleChainDetail.value = detail;
        ruleChainId = detail.id.id;
      }
      const data = await saveRuleChainData({
        connections,
        nodes,
        firstNodeIndex,
        ruleChainId: {
          entityType: RuleChainEntityType.RULE_CHAIN,
          id: ruleChainId,
        },
      });

      const elements = parseRuleChain(data);
      flowActionType.setElements(elements);

      resetChange();

      if (unref(getIsImportFlag)) {
        clearRuleChainImportCache();

        ROUTER.replace({
          path: `/rule/chain/${ruleChainId}`,
          replace: true,
        });
      }
    } finally {
      loading.value = false;
    }
  }

  async function getCurrentPageMetaData(flowActionType: VueFlowStore) {
    try {
      loading.value = true;

      const data = unref(getIsImportFlag)
        ? await getImportMetadata()
        : await getRuleChainData(unref(getRuleChainId));
      if (!data) return;
      const elements = parseRuleChain(data);

      flowActionType.setElements(elements);

      unref(getIsImportFlag) ? triggerChange() : resetChange();
    } finally {
      loading.value = false;
    }
  }

  function parseRuleChain(ruleChain: RuleChainType) {
    const inputId = buildUUID();

    const { getInputNodeConfig } = useNewNode();

    const value = deconstructionData(ruleChain, inputId);

    const { nodes = [], edges = [] } = value || {};

    const inputNode = getInputNodeConfig(inputId);

    const elements = [inputNode, ...nodes, ...edges];

    redoDataRef.value = elements;

    return elements;
  }

  const handleRemoveDebug = (flowActionType: VueFlowStore) => {
    for (const item of unref(flowActionType.getNodes)) {
      (item.data as NodeData)!.data!.debugMode = false;
    }
    triggerChange();
  };

  const getImportMetadata = () => {
    return getRuleChainImportCache().metadata;
  };

  const getImportChainDetail = () => getRuleChainImportCache().ruleChain;

  return {
    loading,
    debugMarker,
    changeMarker,
    ruleChainDetail,
    triggerChange,
    handleApplyChange,
    handleRedoChange,
    handleRemoveDebug,
    getCurrentPageMetaData,
    getCurrentRuleChainDetail,
  };
}