/** * 旧版数据格式适配层 * 将旧版前端数据格式转换为后端期望的协议格式 */ /** * 将旧版 nodes/edges 转换为后端执行器期望的格式 */ import { PortModel } from '../model/PortModel' export function toExecutorPayload(data: { nodes: any[] edges: any[] settings?: any globalContext?: any }) { const { nodes, edges, settings, globalContext } = data // 转换节点 const buildParams = (node: any) => { if (node.params && typeof node.params === 'object') return node.params const meta = node.meta || node.data?.meta || {} const schema = meta.param_schema if (schema) { let names: string[] = [] if (Array.isArray(schema)) { names = schema.map((s: any) => s && s.name).filter(Boolean) } else if (schema && typeof schema === 'object') { names = Object.keys(schema) } const out: Record = {} names.forEach((k) => { if (node.data && Object.prototype.hasOwnProperty.call(node.data, k)) out[k] = node.data[k] else if (node.params && Object.prototype.hasOwnProperty.call(node.params, k)) out[k] = node.params[k] else out[k] = null }) return out } const source = (node.params && typeof node.params === 'object') ? node.params : (node.data && typeof node.data === 'object' ? node.data : {}) const reserved = new Set(['meta', 'label', 'position', 'updim', 'file_path', 'file', 'dirty']) const out: Record = {} Object.entries(source).forEach(([k, v]) => { if (!reserved.has(k)) out[k] = v }) return out } const nodesOut = nodes.map((n: any) => { // Support both React-view nodes and exported workflow nodes const className = n.class_name || n.data?.meta?.class_name || n.schemaName || (n.meta && n.meta.class_name) || n.type || 'UnknownNode' const nodeTypeRaw = n.data?.meta?.node_type || n.meta?.node_type || n.node_type || 'normal' const nodeType = nodeTypeRaw ? nodeTypeRaw.toString().toLowerCase() : 'normal' return { id: n.id, node_type: nodeType, class_name: className, params: buildParams(n), sub_workflow_nodes: n.sub_workflow_nodes || n.sub_workflow?.nodes || null, sub_workflow_edges: n.sub_workflow_edges || n.sub_workflow?.edges || null } }) // Helper: get port type from node meta const findPortType = (node: any, portName: string, portSide: 'outputs' | 'inputs') => { const meta = node?.meta || node?.data?.meta || {} const ports = meta[portSide] || [] if (!ports || !Array.isArray(ports)) return undefined const p = ports.find((x: PortModel) => x && x.name === portName) return PortModel.getTypeInfo(p.type || '') } // 转换边并重新计算 dimension_mode const edgesOut = edges.map((e: any) => { const source = e.source const target = e.target const source_port = e.source_port const target_port = e.target_port const srcNode = nodes.find((n: any) => n.id === source) || {} const tgtNode = nodes.find((n: any) => n.id === target) || {} const srcInfo = findPortType(srcNode, source_port, 'outputs') const tgtInfo = findPortType(tgtNode, target_port, 'inputs') const upDimension = srcNode.upDimension const srcDim = (srcInfo.dim || 0) + (upDimension || 0) const tgtDim = tgtInfo.dim || 0 // default to provided or 'none' let dimension_mode = e.dimension_mode || 'none' // If multiple edges into same port, mark as 'up' (collapse/pack) if (srcDim < tgtDim) { dimension_mode = 'up' }else if (srcDim > tgtDim) { dimension_mode = 'down' } else { dimension_mode = 'none' } return { source, source_port, target, target_port, dimension_mode } }) const payload: any = { nodes: nodesOut, edges: edgesOut } if (settings) payload.settings = settings if (globalContext) payload.global_context = globalContext return payload } /** * 将后端节点 meta 转换为前端期望的格式 */ export function transformNodeMeta(meta: any) { return { ...meta, display_name: meta.display_name || meta.name || 'Unknown', category: meta.category || 'Other', param_schema: normalizeParamSchema(meta.param_schema), inputs: normalizeInputs(meta.inputs), outputs: normalizeOutputs(meta.outputs) } } /** * 标准化参数模式 */ function normalizeParamSchema(raw: any): Array { if (Array.isArray(raw)) return raw if (raw && typeof raw === 'object') { return Object.entries(raw).map(([name, spec]: [string, any]) => ({ name, ...(spec || {}) })) } return [] } /** * 标准化输入端口 */ function normalizeInputs(raw: any): Array { if (Array.isArray(raw)) return raw if (raw && typeof raw === 'object') { return Object.entries(raw).map(([name, spec]: [string, any]) => ({ name, ...(spec || {}) })) } return [] } /** * 标准化输出端口 */ function normalizeOutputs(raw: any): Array { if (Array.isArray(raw)) return raw if (raw && typeof raw === 'object') { return Object.entries(raw).map(([name, spec]: [string, any]) => ({ name, ...(spec || {}) })) } return [] }