diff --git a/packages/x-flow/src/XFlow.tsx b/packages/x-flow/src/XFlow.tsx index 62c620001..1e4b9d278 100644 --- a/packages/x-flow/src/XFlow.tsx +++ b/packages/x-flow/src/XFlow.tsx @@ -164,11 +164,8 @@ const XFlow: FC = memo(props => { copyNode(selectedNode.id); } } else if ((e.key === 'v' || e.key === 'V') && (e.ctrlKey || e.metaKey)) { - const { copyNodes } = storeApi.getState(); - if (copyNodes?.length > 0) { - e.preventDefault(); - pasteNodeSimple(); - } + e.preventDefault(); + pasteNodeSimple(); } else if (e.key === 'Escape') { setOpenPanel(false); workflowContainerRef.current?.focus(); @@ -327,6 +324,7 @@ const XFlow: FC = memo(props => { }, [activeNode?.id]); const deletable = globalConfig?.edge?.deletable ?? true; + const strokeWidth = globalConfig?.edge?.strokeWidth ?? 1.5 const panelonClose = globalConfig?.nodePanel?.onClose; return ( @@ -352,7 +350,7 @@ const XFlow: FC = memo(props => { defaultEdgeOptions={{ type: 'buttonedge', style: { - strokeWidth: 1.5, // 线粗细 + strokeWidth, // 线粗细 }, markerEnd: { type: MarkerType.ArrowClosed, // 箭头 diff --git a/packages/x-flow/src/components/NodeEditor/index.tsx b/packages/x-flow/src/components/NodeEditor/index.tsx index 472c087a4..6701e0242 100644 --- a/packages/x-flow/src/components/NodeEditor/index.tsx +++ b/packages/x-flow/src/components/NodeEditor/index.tsx @@ -152,6 +152,7 @@ const NodeEditor: FC = forwardRef((props, ref: any) => { setCustomVal(values); handleNodeValueChange({ ...values }); }} + nodeId={id} readOnly={readOnly} ref={nodeWidgetRef} /> @@ -163,6 +164,9 @@ const NodeEditor: FC = forwardRef((props, ref: any) => { form={form} widgets={widgets} watch={watch} + globalProps={{ + nodeId:id + }} readOnly={readOnly} onMount={() => { const initialValues = form.getValues(); @@ -184,6 +188,9 @@ const NodeEditor: FC = forwardRef((props, ref: any) => { widgets={widgets} watch={watch} size={'small'} + globalProps={{ + nodeId:id + }} readOnly={readOnly} configProvider={{ getPopupContainer: triggerNode => triggerNode.parentElement, @@ -198,6 +205,7 @@ const NodeEditor: FC = forwardRef((props, ref: any) => { handleNodeValueChange({ ...val }); }} value={data} + nodeId={id} readOnly={readOnly} /> ); diff --git a/packages/x-flow/src/hooks/useFlow.ts b/packages/x-flow/src/hooks/useFlow.ts index 14455810c..b0e5a7f08 100644 --- a/packages/x-flow/src/hooks/useFlow.ts +++ b/packages/x-flow/src/hooks/useFlow.ts @@ -6,7 +6,7 @@ import { FlowNode } from '../models/store'; import { useStoreApi } from './useStore'; import { useTemporalStore } from './useTemporalStore'; import autoLayoutNodes from '../utils/autoLayoutNodes'; -import { generateCopyNodes, uuid } from '../utils'; +import { generateCopyNodes, safeJSONParse, safeJsonStringify, uuid } from '../utils'; import { message } from 'antd'; // useFlow 维护原则 @@ -113,6 +113,11 @@ export const useFlow = () => { storeApi.setState({ copyTimeoutId: null }); }, 30000); + navigator.clipboard + .writeText(safeJsonStringify(copyNodes)) + .catch((err) => { + message.error('复制失败~'); + }) storeApi.setState({ copyNodes, copyTimeoutId: timeoutId, @@ -148,8 +153,9 @@ export const useFlow = () => { } }); - const pasteNodeSimple = useMemoizedFn(() => { + const pasteNodeSimple = useMemoizedFn(async() => { const mousePosition = storeApi.getState().mousePosition; + const text = await navigator.clipboard.readText().catch(()=>null) if (storeApi.getState().copyNodes.length > 0) { // 清除超时定时器 if (storeApi.getState().copyTimeoutId) { @@ -178,7 +184,24 @@ export const useFlow = () => { copyTimeoutId: null, }); }); - } else { + } else if(text){ + const copyNodeData = safeJSONParse(text,[]) + const flowPos = screenToFlowPosition({ + x: mousePosition.elementX, + y: mousePosition.elementY, + }); + const copyNodes = copyNodeData.map(node => ({ + ...node, + id:uuid(), + position: { + x: flowPos.x, + y: flowPos.y, + }, + })); + record(() => { + storeApi.getState().addNodes(copyNodes, false); + }); + }else{ // message.warning('请先复制节点!'); } }); diff --git a/packages/x-flow/src/types.ts b/packages/x-flow/src/types.ts index 174d03e2b..91445e419 100644 --- a/packages/x-flow/src/types.ts +++ b/packages/x-flow/src/types.ts @@ -125,6 +125,8 @@ export interface TEdge { hideEdgeAddBtn?: boolean; // 是否隐藏两个节点之间,连线上的增加节点按钮 hideEdgeDelBtn?: boolean; // 是否隐藏两个节点之间,连线上的删除节点按钮 deletable?: boolean; // 是否允许删除线条 初始化的edges不受此项影响 + + strokeWidth?:number } export interface TControl{ diff --git a/packages/x-flow/src/utils/index.ts b/packages/x-flow/src/utils/index.ts index 32c5f23cc..2086cb0e6 100644 --- a/packages/x-flow/src/utils/index.ts +++ b/packages/x-flow/src/utils/index.ts @@ -281,6 +281,21 @@ export function safeJsonStringify(obj: Object) { } } +export function safeJSONParse( + jsonString: string | null, + defaultVal: T = {} as any, +): T { + if (typeof jsonString === 'string') { + try { + return JSON.parse(jsonString); + } catch (e) { + return defaultVal; // 或返回默认值 {} + } + } else { + return defaultVal; + } +} + export * from './flow'; // 内置节点状态