import { type Edge, type Node, useNodesData, useStore } from '@xyflow/svelte'; import type { Parameter } from '#types'; import { getCurrentNodeId, getOptions } from '#components/utils/NodeUtils'; import { getStartNodeParameterLabel } from '#components/utils/startNodeParameterLabel'; import { nodeIcons } from '../../consts'; const fillRefNodeIds = ( refNodeIds: string[], currentNodeId: string, edges: Edge[], ) => { for (const edge of edges) { if (edge.target === currentNodeId && edge.source) { refNodeIds.push(edge.source); fillRefNodeIds(refNodeIds, edge.source, edges); } } }; const getChildren = ( params: any, parentId: string, nodeIsChildren: boolean, nodeType: string, parentPathLabel = '', parentIsCollection = false, ) => { if (!params || params.length === 0) return []; return params.map((param: any) => { const isCollection = param.dataType === 'Array' && param.children && param.children.length > 0; const childBaseLabel = param.formLabel || param.displayName || param.name; const normalizedChildLabel = String(childBaseLabel || '').trim(); const pathLabel = !parentPathLabel ? normalizedChildLabel : parentIsCollection ? `${parentPathLabel}.[].${normalizedChildLabel}` : `${parentPathLabel}.${normalizedChildLabel}`; const dataType = nodeIsChildren ? `Array<${param.dataType || 'String'}>` : param.dataType || 'String'; return { label: pathLabel, dataType: dataType, value: parentId + '.' + param.name, selectable: true, nodeType: nodeType, displayLabel: pathLabel, pathLabel, itemTypeLabel: parentIsCollection ? '数组项字段' : undefined, isCollection, children: getChildren( param.children, parentId + '.' + param.name, nodeIsChildren, nodeType, pathLabel, isCollection, ), }; }); }; const nodeToOptions = ( node: Node, nodeIsChildren: boolean, currentNode: Node, ) => { const options = getOptions(); const nodeType = node.type || ''; let icon: string | undefined = nodeIcons[nodeType]; if (!icon && options?.customNodes && options.customNodes[nodeType]) { icon = options.customNodes[nodeType].icon; } // 如果仍然获取不到,尝试使用 data.icon (作为回退) if (!icon && node.data && node.data.icon) { icon = node.data.icon as string; } const title = node.data.title; if (nodeType === 'startNode') { const parameters = node.data.parameters as Array; const children = []; if (parameters) for (const parameter of parameters) { const dataType = nodeIsChildren ? `Array<${parameter.dataType || 'String'}>` : parameter.dataType || 'String'; const label = getStartNodeParameterLabel(parameter); children.push({ label, dataType: dataType, value: node.id + '.' + parameter.name, selectable: true, nodeType: nodeType, }); } return { label: title, icon: icon, value: node.id, selectable: false, nodeType: nodeType, children, }; } else if (nodeType === 'loopNode' && currentNode.parentId) { return { label: title, icon: icon, value: node.id, selectable: false, nodeType: nodeType, children: [ { label: 'loopItem', dataType: 'Any', value: node.id + '.loopItem', selectable: true, nodeType: nodeType, }, { label: 'index', dataType: 'Number', value: node.id + '.index', selectable: true, nodeType: nodeType, }, ], }; } else { const outputDefs = node.data.outputDefs; if (outputDefs) { return { label: title, icon: icon, value: node.id, selectable: false, nodeType: nodeType, children: getChildren(outputDefs, node.id, nodeIsChildren, nodeType), }; } } }; export const useRefOptions: any = (useChildrenOnly: boolean = false) => { const currentNodeId = getCurrentNodeId(); const currentNode = useNodesData(currentNodeId); const { nodes, edges, nodeLookup } = $derived(useStore()); let selectItems = $derived.by(() => { const resultOptions = []; if (!currentNode.current) { return []; } //通过 nodeLookup.get 才会得到有 parentId 的 node const cNode = nodeLookup.get(currentNodeId)!; if (useChildrenOnly) { for (const node of nodes) { const nodeIsChildren = node.parentId === currentNode.current.id; if (nodeIsChildren) { const nodeOptions = nodeToOptions(node, nodeIsChildren, cNode); nodeOptions && resultOptions.push(nodeOptions); } } } else { const refNodeIds: string[] = []; fillRefNodeIds(refNodeIds, currentNodeId, edges); for (const node of nodes) { if (refNodeIds.includes(node.id)) { const nodeIsChildren = node.parentId === currentNode.current.id; const nodeOptions = nodeToOptions(node, nodeIsChildren, cNode); nodeOptions && resultOptions.push(nodeOptions); } } } return resultOptions; }); return { get current() { return selectItems; }, }; };