Commit a0634f38362a7ea0358f3c3492147983389efbdc

Authored by xp.Huang
2 parents 795a7084 a26ce2a9

Merge branch 'feat/rule-chain' into 'main_dev'

feat: 选择创建规则链

See merge request yunteng/thingskit-front!855
1 1 import { Ref, toRaw, unref } from 'vue';
2   -import { BasicNodeBindData, NodeData } from '../types/node';
3   -import { Elements, GraphNode } from '@vue-flow/core';
4   -import { RuleChainType } from '../types/ruleNode';
  2 +import { BasicNodeBindData, EdgeData, NodeData } from '../types/node';
  3 +import { Elements, GraphEdge, GraphNode } from '@vue-flow/core';
  4 +import { ConnectionItemType, RuleChainType } from '../types/ruleNode';
5 5 import { allComponents } from '../packages';
6 6 import { RuleNodeTypeEnum } from '../packages/index.type';
7 7 import { buildUUID } from '/@/utils/uuid';
... ... @@ -9,6 +9,9 @@ import { isNullOrUnDef } from '/@/utils/is';
9 9 import { useAddNodes } from './useAddNodes';
10 10 import { useAddEdges } from './useAddEdges';
11 11 import { RuleChainEntityType } from '../enum/entity';
  12 +import { EntryCategoryComponentEnum } from '../enum/category';
  13 +
  14 +const ignoreNodeKeys: string[] = [EntryCategoryComponentEnum.INPUT];
12 15
13 16 export function useBasicDataTransform() {
14 17 const nodeConfigMap = new Map<string, NodeData>();
... ... @@ -24,7 +27,7 @@ export function useBasicDataTransform() {
24 27 }
25 28
26 29 function mergeData(data: NodeData['data'], nodeData: NodeData, node: GraphNode) {
27   - const { x: layoutX, y: layoutY } = node.computedPosition;
  30 + const { x: layoutX, y: layoutY } = node.position;
28 31
29 32 return {
30 33 debugMode: !!data?.debugMode,
... ... @@ -172,8 +175,126 @@ export function useBasicDataTransform() {
172 175
173 176 initNodeConfigMap();
174 177
  178 + /**
  179 + * @description 保存连接信息
  180 + */
  181 + function getConnections(
  182 + nodesRef: Ref<GraphNode[]> | GraphNode[],
  183 + edges: Ref<GraphEdge[]> | GraphEdge[]
  184 + ) {
  185 + const nodeIndexMap = new Map();
  186 +
  187 + const connections: ConnectionItemType[] = [];
  188 +
  189 + unref(nodesRef).forEach((item, index) => {
  190 + nodeIndexMap.set(item.id, index);
  191 + });
  192 +
  193 + for (const item of unref(edges)) {
  194 + const { data, target, source } = item;
  195 + const { data: bindData } = data as EdgeData;
  196 + const { type } = bindData || {};
  197 + const fromIndex = nodeIndexMap.get(source);
  198 + const toIndex = nodeIndexMap.get(target);
  199 + type?.forEach((key) => {
  200 + connections.push({ fromIndex, toIndex, type: key });
  201 + });
  202 + }
  203 +
  204 + return connections;
  205 + }
  206 +
  207 + function getNodes(nodesRef: Ref<GraphNode[]> | GraphNode[], removeId: boolean) {
  208 + const nodes: BasicNodeBindData[] = [];
  209 +
  210 + for (const node of unref(nodesRef)) {
  211 + const nodeData = node.data as NodeData;
  212 +
  213 + if (ignoreNodeKeys.includes(nodeData.config?.key as string)) continue;
  214 +
  215 + const data = nodeData.data;
  216 +
  217 + nodes.push(
  218 + Object.assign(
  219 + mergeData(data, nodeData, node),
  220 + nodeData.created && !removeId
  221 + ? ({
  222 + id: { id: node.id, entityType: RuleChainEntityType.RULE_NODE },
  223 + } as BasicNodeBindData)
  224 + : {}
  225 + )
  226 + );
  227 + }
  228 +
  229 + return nodes;
  230 + }
  231 +
  232 + function getFirsetNodeIndex(
  233 + nodesRef: Ref<GraphNode[]> | GraphNode[],
  234 + edges: Ref<GraphEdge[]> | GraphEdge[]
  235 + ) {
  236 + const inputNode = unref(edges).find(
  237 + (item) => (item.sourceNode.data as NodeData).config?.key === EntryCategoryComponentEnum.INPUT
  238 + );
  239 +
  240 + if (inputNode) {
  241 + const targetId = inputNode.target;
  242 + const index = unref(nodesRef).findIndex((item) => item.id === targetId);
  243 + return index;
  244 + }
  245 + }
  246 +
  247 + function combineData(
  248 + nodesRef: Ref<GraphNode[]> | GraphNode[] = [],
  249 + edgesRef: Ref<GraphEdge[]> | GraphEdge[] = [],
  250 + removeId = false
  251 + ) {
  252 + const extraIgnoreNodeRef = unref(nodesRef).filter(
  253 + (item) => !ignoreNodeKeys.includes((item.data as NodeData).config?.key as string)
  254 + );
  255 +
  256 + const connections = getConnections(extraIgnoreNodeRef, edgesRef);
  257 +
  258 + const nodes = getNodes(extraIgnoreNodeRef, removeId);
  259 +
  260 + const firstNodeIndex = getFirsetNodeIndex(extraIgnoreNodeRef, edgesRef);
  261 +
  262 + return { connections, nodes, firstNodeIndex };
  263 + }
  264 +
  265 + function validateCanCreateRuleChain(
  266 + nodes: Ref<GraphNode[]> | GraphNode[] = [],
  267 + edges: Ref<GraphEdge[]> | GraphEdge[] = []
  268 + ) {
  269 + const rootNode: GraphNode[] = [];
  270 +
  271 + let flag = true;
  272 + for (const node of unref(nodes)) {
  273 + const list = unref(edges).filter(
  274 + (edge) => edge.source === node.id || edge.target === node.id
  275 + );
  276 +
  277 + if (!list.length) {
  278 + flag = false;
  279 + break;
  280 + }
  281 +
  282 + if (!list.filter((edge) => edge.target === node.id).length) {
  283 + if (!rootNode.length) rootNode.push(node);
  284 + else {
  285 + flag = false;
  286 + break;
  287 + }
  288 + }
  289 + }
  290 +
  291 + return { flag, firstNode: rootNode[0] || null };
  292 + }
  293 +
175 294 return {
176 295 mergeData,
  296 + combineData,
177 297 deconstructionData,
  298 + validateCanCreateRuleChain,
178 299 };
179 300 }
... ...
... ... @@ -3,11 +3,19 @@ import { getRuleNodeCache, setRuleNodeCache } from './useRuleChainCache';
3 3 import { RuleContextMenuEnum } from './useRuleChainContextMenu';
4 4 import { useAddNodes } from './useAddNodes';
5 5 import { buildUUID } from '/@/utils/uuid';
6   -import { toRaw, unref } from 'vue';
  6 +import { Ref, toRaw, unref } from 'vue';
7 7 import { useSaveAndRedo } from './useSaveAndRedo';
8 8 import { isUnDef } from '/@/utils/is';
9 9 import { useAddEdges } from './useAddEdges';
10 10 import { EdgeData } from '../types/node';
  11 +import { CreateNodeModal } from '../src/components/CreateNodeModal';
  12 +import { CreateEdgeModal } from '../src/components/CreateEdgeModal';
  13 +import { UpdateNodeDrawer } from '../src/components/UpdateNodeDrawer';
  14 +import { UpdateEdgeDrawer } from '../src/components/UpdateEdgeDrawer';
  15 +import { CreateRuleChainModal } from '../src/components/CreateRuleChainModal';
  16 +import { useBasicDataTransform } from './useBasicDataTransform';
  17 +import { cloneDeep } from 'lodash-es';
  18 +import { useNewNode } from './useNewNode';
11 19
12 20 interface HandleContextMenuActionParamsType {
13 21 menuType: RuleContextMenuEnum;
... ... @@ -16,18 +24,58 @@ interface HandleContextMenuActionParamsType {
16 24 node?: GraphNode;
17 25 edge?: GraphEdge;
18 26 useSaveAndRedoActionType?: ReturnType<typeof useSaveAndRedo>;
  27 + modalActionType: {
  28 + createNodeModalActionType: Ref<Nullable<InstanceType<typeof CreateNodeModal>>>;
  29 + createEdgeModalActionType: Ref<Nullable<InstanceType<typeof CreateEdgeModal>>>;
  30 + updateNodeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateNodeDrawer>>>;
  31 + updateEdgeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>;
  32 + createRuleChainModalActionType: Ref<Nullable<InstanceType<typeof CreateRuleChainModal>>>;
  33 + };
  34 +}
  35 +
  36 +export function transformToRuleChain(
  37 + nodesRef: Ref<GraphNode[]> | GraphNode[] = [],
  38 + edgesRef: Ref<GraphEdge[]> | GraphEdge[] = []
  39 +) {
  40 + const nodeMap = new Map<string, GraphNode>();
  41 + const { combineData, validateCanCreateRuleChain } = useBasicDataTransform();
  42 +
  43 + nodesRef = cloneDeep(unref(nodesRef));
  44 + edgesRef = cloneDeep(unref(edgesRef));
  45 +
  46 + unref(nodesRef).forEach((node) => nodeMap.set(node.id, node));
  47 + const outputEdges = unref(edgesRef).filter((edge) => !nodeMap.has(edge.target));
  48 + const outputEdgesId = outputEdges.map((edge) => edge.id);
  49 +
  50 + const { getOutputNodeConfig } = useNewNode();
  51 + const outputNode = outputEdges.map((edge) => {
  52 + const id = buildUUID();
  53 + const name = (edge.data as EdgeData).data?.type?.join(' / ') || '';
  54 + edge.target = id;
  55 + return getOutputNodeConfig(name, edge.targetNode.position, id);
  56 + });
  57 +
  58 + nodesRef = [...nodesRef, ...(outputNode as GraphNode[])];
  59 +
  60 + const { connections, nodes } = combineData(nodesRef, edgesRef, true);
  61 +
  62 + const { firstNode } = validateCanCreateRuleChain(nodesRef, edgesRef);
  63 +
  64 + const firstNodeIndex = nodesRef.findIndex((node) => node.id === firstNode.id);
  65 +
  66 + return { connections, nodes, firstNodeIndex, outputEdgesId };
19 67 }
20 68
21 69 export const NODE_WIDTH = 176;
22 70 export const NODE_HEIGHT = 48;
23 71
24   -function getElementsCenter(nodes: GraphNode[]) {
  72 +function getElementsCenter(nodes: Ref<GraphNode[]> | GraphNode[] = []) {
25 73 let leftTopX: number | undefined;
26 74 let leftTopY: number | undefined;
27 75 let rightBottomX: number | undefined;
28 76 let rightBottomY: number | undefined;
29 77
30   - for (const node of nodes) {
  78 + for (const node of unref(nodes)) {
31 79 const { position } = node;
32 80 const { x, y } = position;
33 81 if (isUnDef(leftTopX)) {
... ... @@ -200,6 +248,37 @@ export function useContextMenuAction() {
200 248 useSaveAndRedoActionType?.handleRedoChange(flowActionType!);
201 249 };
202 250
  251 + const createRuleChain = async (_params: HandleContextMenuActionParamsType) => {
  252 + // const { useSaveAndRedoActionType, modalActionType, flowActionType } = params;
  253 + // const { createRuleChainModalActionType } = modalActionType;
  254 + // const result = (await unref(createRuleChainModalActionType)?.openCreateRuleChainModal()) as {
  255 + // name: string;
  256 + // additionalInfo: { description: string };
  257 + // };
  258 + // const ruleChainDetail = await saveRuleChainDetail(
  259 + // Object.assign(result, { debugger: false, type: 'CORE' }) as Partial<RuleChainDetail>
  260 + // );
  261 + // const selectedNodes = unref(flowActionType?.getSelectedNodes);
  262 + // const selectedEdges = unref(flowActionType?.getSelectedEdges);
  263 + // const { firstNodeIndex, connections, nodes, outputEdgesId } = transformToRuleChain(
  264 + // selectedNodes,
  265 + // selectedEdges
  266 + // );
  267 + // await saveRuleChainData({
  268 + // firstNodeIndex,
  269 + // connections,
  270 + // nodes,
  271 + // ruleChainId: ruleChainDetail.id,
  272 + // });
  273 + // const outputEdges = outputEdgesId.map((id) => flowActionType?.findEdge(id));
  274 + // console.log(getElementsCenter(unref(selectedNodes)));
  275 + // const { originX, originY } = getElementsCenter(unref(selectedNodes));
  276 + // const {} = useNewNode();
  277 + // flowActionType?.removeNodes(selectedNodes || []);
  278 + // flowActionType?.removeEdges(selectedEdges || []);
  279 + // useSaveAndRedoActionType?.triggerChange();
  280 + };
  281 +
203 282 const handleContextMenuAction = (params: HandleContextMenuActionParamsType) => {
204 283 const { menuType } = params;
205 284
... ... @@ -213,6 +292,7 @@ export function useContextMenuAction() {
213 292 [RuleContextMenuEnum.SELECT_COPY]: selectCopy,
214 293 [RuleContextMenuEnum.APPLY_CHANGE]: applyChange,
215 294 [RuleContextMenuEnum.UNDO_CHANGE]: undoChange,
  295 + [RuleContextMenuEnum.CREATE_RULE_CHAIN]: createRuleChain,
216 296 };
217 297
218 298 if (handlerMapping[menuType]) {
... ...
... ... @@ -5,6 +5,7 @@ import type { CreateNodeModal } from '../src/components/CreateNodeModal';
5 5 import type { CreateEdgeModal } from '../src/components/CreateEdgeModal';
6 6 import { UpdateNodeDrawer } from '../src/components/UpdateNodeDrawer';
7 7 import { UpdateEdgeDrawer } from '../src/components/UpdateEdgeDrawer';
  8 +import { CreateRuleChainModal } from '../src/components/CreateRuleChainModal';
8 9
9 10 const SYMBOL = Symbol('flow-context');
10 11
... ... @@ -30,6 +31,11 @@ interface FlowContextOptionsType {
30 31 updateEdgeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>;
31 32
32 33 /**
  34 + * @description 创建规则链 actions
  35 + */
  36 + createRuleChainModalActionType: Ref<Nullable<InstanceType<typeof CreateRuleChainModal>>>;
  37 +
  38 + /**
33 39 * @description vue flow store
34 40 */
35 41 flowActionType: VueFlowStore;
... ...
src/views/rule/designer/hook/useNewNode.ts renamed from src/views/rule/designer/hook/useInputNode.ts
  1 +import { XYPosition } from '@vue-flow/core';
1 2 import { Config as InputConfig } from '../packages/Entry/Input/config';
  3 +import { Config as OutputConfig } from '../packages/Flow/Output/config';
  4 +import { Config as RuleChainConfig } from '../packages/Flow/RuleChain/config';
2 5 import { useAddNodes } from './useAddNodes';
3 6
4   -export function useInputNode() {
  7 +export function useNewNode() {
5 8 const getInputNodeConfig = (id?: string) => {
6 9 const { getAddNodesParams } = useAddNodes();
7 10
... ... @@ -20,5 +23,38 @@ export function useInputNode() {
20 23 return newNode;
21 24 };
22 25
23   - return { getInputNodeConfig };
  26 + const getOutputNodeConfig = (name: string, position: XYPosition, id?: string) => {
  27 + const { getAddNodesParams } = useAddNodes();
  28 +
  29 + const newNode = getAddNodesParams(
  30 + position,
  31 + {
  32 + ...new OutputConfig(),
  33 + data: {
  34 + name,
  35 + },
  36 + },
  37 + { id, draggable: false, selectable: false }
  38 + );
  39 +
  40 + return newNode;
  41 + };
  42 +
  43 + const getRuleChainNodeConfig = (name: string, position: XYPosition, id?: string) => {
  44 + const { getAddNodesParams } = useAddNodes();
  45 + const newNode = getAddNodesParams(
  46 + position,
  47 + {
  48 + ...new RuleChainConfig(),
  49 + data: { name },
  50 + },
  51 + {
  52 + id,
  53 + }
  54 + );
  55 +
  56 + return newNode;
  57 + };
  58 +
  59 + return { getInputNodeConfig, getOutputNodeConfig, getRuleChainNodeConfig };
24 60 }
... ...
... ... @@ -27,14 +27,19 @@ import { RuleChainDetail } from '../types/ruleNode';
27 27 import { useContextMenuAction } from './useContextMenuAction';
28 28 import { useSaveAndRedo } from './useSaveAndRedo';
29 29 import { EntryCategoryComponentEnum } from '../enum/category';
  30 +import { CreateRuleChainModal } from '../src/components/CreateRuleChainModal';
  31 +import { useBasicDataTransform } from './useBasicDataTransform';
30 32
31 33 interface UseRuleFlowOptionsType {
32 34 id: string;
33 35 ruleChainDetail: Ref<RuleChainDetail | undefined>;
34   - createNodeModalActionType: Ref<Nullable<InstanceType<typeof CreateNodeModal>>>;
35   - createEdgeModalActionType: Ref<Nullable<InstanceType<typeof CreateEdgeModal>>>;
36   - updateNodeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateNodeDrawer>>>;
37   - updateEdgeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>;
  36 + modalActionType: {
  37 + createNodeModalActionType: Ref<Nullable<InstanceType<typeof CreateNodeModal>>>;
  38 + createEdgeModalActionType: Ref<Nullable<InstanceType<typeof CreateEdgeModal>>>;
  39 + updateNodeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateNodeDrawer>>>;
  40 + updateEdgeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>;
  41 + createRuleChainModalActionType: Ref<Nullable<InstanceType<typeof CreateRuleChainModal>>>;
  42 + };
38 43 useSaveAndRedoActionType: ReturnType<typeof useSaveAndRedo>;
39 44 }
40 45
... ... @@ -47,14 +52,10 @@ const validateInputAndOutput: ValidConnectionFunc = (connection: Connection) =>
47 52 };
48 53
49 54 export function useRuleFlow(options: UseRuleFlowOptionsType) {
50   - const {
51   - id,
52   - ruleChainDetail,
53   - createEdgeModalActionType,
54   - updateEdgeDrawerActionType,
55   - updateNodeDrawerActionType,
56   - useSaveAndRedoActionType,
57   - } = options;
  55 + const { id, ruleChainDetail, modalActionType, useSaveAndRedoActionType } = options;
  56 +
  57 + const { createEdgeModalActionType, updateEdgeDrawerActionType, updateNodeDrawerActionType } =
  58 + modalActionType;
58 59
59 60 const { triggerChange } = useSaveAndRedoActionType;
60 61
... ... @@ -162,29 +163,35 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) {
162 163
163 164 const { handleContextMenuAction } = useContextMenuAction();
164 165
  166 + const { validateCanCreateRuleChain } = useBasicDataTransform();
  167 +
165 168 onNodeContextMenu(async (params) => {
166 169 const menuType = params.node.selected
167 170 ? await createElementsSelectedContextMenu(
168 171 params,
169 172 unref(useSaveAndRedoActionType.changeMarker),
170   - validateSelectionElementsCanCreateRuleChain()
  173 + validateCanCreateRuleChain(
  174 + flowActionType.getSelectedNodes,
  175 + flowActionType.getSelectedEdges
  176 + ).flag
171 177 )
172 178 : await createNodeContextMenu(params);
173 179
174   - if (menuType) {
175   - if (menuType === RuleContextMenuEnum.DETAIL) {
176   - handleUpdateNode(params.node);
177   - return;
178   - }
  180 + if (!menuType) return;
179 181
180   - handleContextMenuAction({
181   - menuType,
182   - flowActionType,
183   - event: params.event,
184   - node: params.node,
185   - useSaveAndRedoActionType,
186   - });
  182 + if (menuType === RuleContextMenuEnum.DETAIL) {
  183 + handleUpdateNode(params.node);
  184 + return;
187 185 }
  186 +
  187 + handleContextMenuAction({
  188 + menuType,
  189 + flowActionType,
  190 + event: params.event,
  191 + node: params.node,
  192 + useSaveAndRedoActionType,
  193 + modalActionType,
  194 + });
188 195 });
189 196
190 197 onEdgeContextMenu(async (params) => {
... ... @@ -207,6 +214,7 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) {
207 214 event: params.event,
208 215 useSaveAndRedoActionType,
209 216 edge: params.edge,
  217 + modalActionType,
210 218 });
211 219 }
212 220 });
... ... @@ -216,21 +224,25 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) {
216 224 ? await createElementsSelectedContextMenu(
217 225 getCreatePanelContextMenuParams(params),
218 226 unref(useSaveAndRedoActionType.changeMarker),
219   - validateSelectionElementsCanCreateRuleChain()
  227 + validateCanCreateRuleChain(
  228 + flowActionType.getSelectedNodes,
  229 + flowActionType.getSelectedEdges
  230 + ).flag
220 231 )
221 232 : await createPanelContextMenu(
222 233 getCreatePanelContextMenuParams(params),
223 234 unref(useSaveAndRedoActionType.changeMarker)
224 235 );
225 236
226   - if (menuType) {
227   - handleContextMenuAction({
228   - menuType,
229   - flowActionType,
230   - event: params,
231   - useSaveAndRedoActionType,
232   - });
233   - }
  237 + if (!menuType) return;
  238 +
  239 + handleContextMenuAction({
  240 + menuType,
  241 + flowActionType,
  242 + event: params,
  243 + useSaveAndRedoActionType,
  244 + modalActionType,
  245 + });
234 246 });
235 247
236 248 /**
... ... @@ -382,17 +394,5 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) {
382 394 } as NodeMouseEvent;
383 395 }
384 396
385   - function validateSelectionElementsCanCreateRuleChain() {
386   - const nodes = unref(flowActionType.getSelectedNodes);
387   - const edges = unref(flowActionType.getSelectedEdges);
388   -
389   - for (const node of nodes) {
390   - const index = edges.findIndex((edge) => edge.target === node.id || edge.source === node.id);
391   - if (!~index) return false;
392   - }
393   -
394   - return true;
395   - }
396   -
397 397 return { flowActionType };
398 398 }
... ...
1   -import type { VueFlowStore, Getters, Elements } from '@vue-flow/core';
2   -import { ComputedRef, computed, ref, unref } from 'vue';
3   -import { BasicNodeBindData, EdgeData, NodeData } from '../types/node';
4   -import { EntryCategoryComponentEnum } from '../enum/category';
  1 +import type { VueFlowStore, Elements } from '@vue-flow/core';
  2 +import { computed, ref, unref } from 'vue';
  3 +import { BasicNodeBindData, NodeData } from '../types/node';
5 4 import { useBasicDataTransform } from './useBasicDataTransform';
6 5 import {
7 6 getRuleChainData,
... ... @@ -10,15 +9,13 @@ import {
10 9 saveRuleChainDetail,
11 10 } from '/@/api/ruleDesigner';
12 11 import { ConnectionItemType, RuleChainDetail, RuleChainType } from '../types/ruleNode';
13   -import { useInputNode } from './useInputNode';
  12 +import { useNewNode } from './useNewNode';
14 13 import { buildUUID } from '/@/utils/uuid';
15 14 import { useRoute, useRouter } from 'vue-router';
16 15 import { RuleChainEntityType } from '../enum/entity';
17 16 import { PageEnum } from '/@/enums/pageEnum';
18 17 import { clearRuleChainImportCache, getRuleChainImportCache } from './useRuleChainCache';
19 18
20   -const ignoreNodeKeys: string[] = [EntryCategoryComponentEnum.INPUT];
21   -
22 19 export function useSaveAndRedo() {
23 20 const changeMarker = ref(false);
24 21
... ... @@ -38,7 +35,7 @@ export function useSaveAndRedo() {
38 35
39 36 const ruleChainDetail = ref<RuleChainDetail>();
40 37
41   - const { mergeData, deconstructionData } = useBasicDataTransform();
  38 + const { combineData, deconstructionData } = useBasicDataTransform();
42 39
43 40 const triggerChange = () => {
44 41 changeMarker.value = true;
... ... @@ -48,90 +45,14 @@ export function useSaveAndRedo() {
48 45 changeMarker.value = false;
49 46 };
50 47
51   - /**
52   - * @description 保存连接信息
53   - */
54   - function getConnections(
55   - nodesRef: ComputedRef<Getters['getNodes']> | Getters['getNodes'],
56   - edges: ComputedRef<Getters['getEdges']>
57   - ) {
58   - const nodeIndexMap = new Map();
59   -
60   - const connections: ConnectionItemType[] = [];
61   -
62   - unref(nodesRef).forEach((item, index) => {
63   - nodeIndexMap.set(item.id, index);
64   - });
65   -
66   - for (const item of unref(edges)) {
67   - const { data, target, source } = item;
68   - const { data: bindData } = data as EdgeData;
69   - const { type } = bindData || {};
70   - const fromIndex = nodeIndexMap.get(source);
71   - const toIndex = nodeIndexMap.get(target);
72   - type?.forEach((key) => {
73   - connections.push({ fromIndex, toIndex, type: key });
74   - });
75   - }
76   -
77   - return connections;
78   - }
79   -
80   - function getNodes(nodesRef: ComputedRef<Getters['getNodes']> | Getters['getNodes']) {
81   - const nodes: BasicNodeBindData[] = [];
82   -
83   - for (const node of unref(nodesRef)) {
84   - const nodeData = node.data as NodeData;
85   -
86   - if (ignoreNodeKeys.includes(nodeData.config?.key as string)) continue;
87   -
88   - const data = nodeData.data;
89   -
90   - nodes.push(
91   - Object.assign(
92   - mergeData(data, nodeData, node),
93   - nodeData.created
94   - ? ({
95   - id: { id: node.id, entityType: RuleChainEntityType.RULE_NODE },
96   - } as BasicNodeBindData)
97   - : {}
98   - )
99   - );
100   - }
101   -
102   - return nodes;
103   - }
104   -
105   - function getFirsetNodeIndex(
106   - nodesRef: ComputedRef<Getters['getNodes']> | Getters['getNodes'],
107   - edges: ComputedRef<Getters['getEdges']>
108   - ) {
109   - const inputNode = unref(edges).find(
110   - (item) => (item.sourceNode.data as NodeData).config?.key === EntryCategoryComponentEnum.INPUT
111   - );
112   -
113   - if (inputNode) {
114   - const targetId = inputNode.target;
115   - const index = unref(nodesRef).findIndex((item) => item.id === targetId);
116   - return index;
117   - }
118   - }
119   -
120 48 const handleApplyChange = (flowActionType: VueFlowStore) => {
121 49 if (!unref(changeMarker)) return;
122 50
123   - const edgesRef = flowActionType.getEdges;
124   -
125   - const extraIgnoreNodeRef = unref(flowActionType.getNodes).filter(
126   - (item) => !ignoreNodeKeys.includes((item.data as NodeData).config?.key as string)
  51 + const { connections, nodes, firstNodeIndex } = combineData(
  52 + flowActionType.getNodes,
  53 + flowActionType.getEdges
127 54 );
128 55
129   - const connections = getConnections(extraIgnoreNodeRef, edgesRef);
130   -
131   - const nodes = getNodes(extraIgnoreNodeRef);
132   -
133   - const firstNodeIndex = getFirsetNodeIndex(extraIgnoreNodeRef, edgesRef);
134   -
135 56 handleSaveRuleChain(connections, nodes, firstNodeIndex);
136 57 };
137 58
... ... @@ -211,7 +132,7 @@ export function useSaveAndRedo() {
211 132 function parseRuleChain(ruleChain: RuleChainType) {
212 133 const inputId = buildUUID();
213 134
214   - const { getInputNodeConfig } = useInputNode();
  135 + const { getInputNodeConfig } = useNewNode();
215 136
216 137 const value = deconstructionData(ruleChain, inputId);
217 138
... ...
... ... @@ -19,10 +19,11 @@
19 19 import { CreateEdgeModal } from './src/components/CreateEdgeModal';
20 20 import { useFullScreen } from './hook/useFullScreen';
21 21 import { useSaveAndRedo } from './hook/useSaveAndRedo';
  22 + import { NodeData } from './types/node';
22 23 import { Icon } from '/@/components/Icon';
23 24 import { UpdateNodeDrawer } from './src/components/UpdateNodeDrawer';
24 25 import { UpdateEdgeDrawer } from './src/components/UpdateEdgeDrawer';
25   - import { NodeData } from './types/node';
  26 + import { CreateRuleChainModal } from './src/components/CreateRuleChainModal';
26 27
27 28 const getId = Number(Math.random().toString().substring(2)).toString(16);
28 29
... ... @@ -36,6 +37,9 @@
36 37
37 38 const updateEdgeDrawerActionType = ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>(null);
38 39
  40 + const createRuleChainModalActionType =
  41 + ref<Nullable<InstanceType<typeof CreateRuleChainModal>>>(null);
  42 +
39 43 const flowElRef = ref<Nullable<FlowElRef>>(null);
40 44
41 45 const elements = ref([]);
... ... @@ -57,11 +61,14 @@
57 61 const { flowActionType } = useRuleFlow({
58 62 id: getId,
59 63 ruleChainDetail,
60   - createNodeModalActionType,
61   - createEdgeModalActionType,
62   - updateEdgeDrawerActionType,
63   - updateNodeDrawerActionType,
64 64 useSaveAndRedoActionType,
  65 + modalActionType: {
  66 + createNodeModalActionType,
  67 + createEdgeModalActionType,
  68 + updateEdgeDrawerActionType,
  69 + updateNodeDrawerActionType,
  70 + createRuleChainModalActionType,
  71 + },
65 72 });
66 73
67 74 const { handleOnDragOver, handleOnDrop } = useDragCreate({
... ... @@ -85,6 +92,8 @@
85 92
86 93 const handleDeleteSelectionElements = () => {
87 94 flowActionType.removeNodes(unref(flowActionType.getSelectedNodes));
  95 + flowActionType.removeEdges(unref(flowActionType.getSelectedEdges));
  96 + useSaveAndRedoActionType.triggerChange?.();
88 97 };
89 98
90 99 onMounted(() => {
... ... @@ -97,6 +106,7 @@
97 106 createNodeModalActionType,
98 107 updateEdgeDrawerActionType,
99 108 updateNodeDrawerActionType,
  109 + createRuleChainModalActionType,
100 110 flowActionType,
101 111 triggerChange,
102 112 });
... ... @@ -177,6 +187,8 @@
177 187
178 188 <UpdateEdgeDrawer ref="updateEdgeDrawerActionType" />
179 189 <UpdateNodeDrawer ref="updateNodeDrawerActionType" />
  190 +
  191 + <CreateRuleChainModal ref="createRuleChainModalActionType" />
180 192 </main>
181 193 </template>
182 194
... ...
  1 +import { FormSchema } from '/@/components/Form';
  2 +
  3 +export enum FormFieldsEnum {
  4 + NAME = 'name',
  5 + DESCRIPTION = 'description',
  6 + ADDITIONAL_INFO = 'additionalInfo',
  7 +}
  8 +
  9 +export enum FormFieldsNameEnum {
  10 + NAME = '名称',
  11 + DESCRIPTION = '说明',
  12 +}
  13 +
  14 +export const formSchemas: FormSchema[] = [
  15 + {
  16 + field: FormFieldsEnum.NAME,
  17 + label: FormFieldsNameEnum.NAME,
  18 + component: 'Input',
  19 + required: true,
  20 + componentProps: {
  21 + placeholder: `请输入${FormFieldsNameEnum.NAME}`,
  22 + },
  23 + },
  24 + {
  25 + field: FormFieldsEnum.DESCRIPTION,
  26 + label: FormFieldsNameEnum.DESCRIPTION,
  27 + component: 'InputTextArea',
  28 + componentProps: {
  29 + placeholder: `请输入${FormFieldsNameEnum.DESCRIPTION}`,
  30 + },
  31 + },
  32 +];
... ...
  1 +export { default as CreateRuleChainModal } from './index.vue';
... ...
  1 +<script setup lang="ts">
  2 + import { BasicModal, useModalInner } from '/@/components/Modal';
  3 + import { BasicForm, useForm } from '/@/components/Form';
  4 + import { formSchemas, FormFieldsEnum } from './config';
  5 + import { ref } from 'vue';
  6 +
  7 + interface SaveParamsType {
  8 + name: string;
  9 + additional: { description: string };
  10 + }
  11 +
  12 + const visible = ref(false);
  13 +
  14 + const [register, { closeModal }] = useModalInner();
  15 +
  16 + const [registerForm, { getFieldsValue, validate }] = useForm({
  17 + schemas: formSchemas,
  18 + showActionButtonGroup: false,
  19 + layout: 'vertical',
  20 + });
  21 +
  22 + let resolveFn: undefined | ((value: SaveParamsType) => any);
  23 +
  24 + const openCreateRuleChainModal = async (): Promise<{
  25 + name: string;
  26 + additionalInfo: { description: string };
  27 + }> => {
  28 + visible.value = true;
  29 + return new Promise((resolve) => {
  30 + resolveFn = resolve;
  31 + });
  32 + };
  33 +
  34 + const handleSave = async () => {
  35 + await validate();
  36 + const value = getFieldsValue();
  37 + resolveFn?.({
  38 + name: value[FormFieldsEnum.NAME],
  39 + additional: { description: value[FormFieldsEnum.DESCRIPTION] || '' },
  40 + });
  41 + closeModal();
  42 + };
  43 +
  44 + defineExpose({ openCreateRuleChainModal });
  45 +</script>
  46 +
  47 +<template>
  48 + <BasicModal
  49 + v-model:visible="visible"
  50 + @register="register"
  51 + @ok="handleSave"
  52 + title="Create nested rule chain"
  53 + >
  54 + <BasicForm @register="registerForm" />
  55 + </BasicModal>
  56 +</template>
... ...
... ... @@ -24,7 +24,7 @@ export interface RuleChainDetail {
24 24 createdTime: number;
25 25 additionalInfo: AdditionalInfo;
26 26 tenantId: Id;
27   - name: Id;
  27 + name: string;
28 28 type: string;
29 29 firstRuleNodeId: Id;
30 30 root: boolean;
... ...