# 函数节点嵌套 - 快速开始指南 ## 🎯 5分钟快速上手 ### 第1步: 创建一个函数 1. 在画布上设计任何工作流(建议包含 InputNode 和 OutputNode) 2. 在画布**空白处右键** → 选择 **"保存为函数"** 3. 输入函数名(英文,如: `my_first_function`) 4. 输入显示名(中文,如: `我的第一个函数`) 5. 点击确认 ✅ **完成!函数已保存到 `cloud/custom_nodes/functions/` 目录** --- ### 第2步: 使用函数节点 1. 在 NodePalette(左侧)中找到刚创建的函数节点 2. 拖拽到新的或现有的工作流中 3. 连接输入/输出端口 4. **本步完成** --- ### 第3步: 进入函数编辑 1. **双击**函数节点 2. 画布自动显示函数内部的工作流 3. 顶部会出现面包屑导航: **主工作流 / my_first_function (L1)** 4. 可以编辑、删除或添加节点 **你现在在函数内部!** 🎉 --- ### 第4步: 返回主工作流 **3种方式选一种**: #### 方式A: 点击面包屑的"返回"按钮 ``` [← 返回] 主工作流 / my_first_function (L1) ``` #### 方式B: 点击面包屑的"主工作流"链接 ``` [← 返回] [主工作流] / my_first_function (L1) ↑ 点击这里 ``` #### 方式C: 按Ctrl+Z返回(如果实现了快捷键) - 需要自定义扩展 --- ### ✅ 就这么简单! 你现在已经掌握了函数嵌套的基本用法。 --- ## 🚀 高级用法: 多层嵌套 ### 场景: 函数套函数 ``` 主工作流 ├─ InputNode (x1) ├─ 函数节点 A │ ├─ InputNode │ ├─ 函数节点 B ← 可以在这里再嵌套! │ │ ├─ InputNode │ │ ├─ 处理逻辑 │ │ └─ OutputNode │ └─ OutputNode └─ OutputNode ``` ### 操作步骤 1. 进入函数A(双击) 2. 在函数A内创建一个函数B节点(拖拽) 3. 双击函数B节点进入 4. 面包屑显示: **主工作流 / 函数A / 函数B (L2)** 5. 编辑完成后,使用面包屑返回或跳转 ### 支持的最大层级 - 理论无限制 (取决于内存和性能) - 建议不超过 **5层** 以保证良好的用户体验 --- ## 📋 命名规范 ### 函数名称 (function_name) - ✅ 使用英文字母、数字、下划线 - ✅ 以字母或下划线开头 - ❌ 不能有空格、中文、特殊符号 **示例**: ``` good_names: ✅ - extract_data - process_csv_v2 - _private_function - Transform123 bad_names: ❌ - Extract Data (有空格) - 提取数据 (中文) - function-name (有横杠) - 123function (数字开头) ``` ### 显示名称 (display_name) - 可以使用中文、英文、特殊符号 - 在 NodePalette 中显示 - 在面包屑导航中显示 **示例**: ``` ✅ 提取数据 ✅ Extract Data ✅ 数据 → 转换 v2.0 ✅ [高级] 复杂处理 ``` --- ## 🔍 常见问题 ### Q1: 双击函数节点没有反应 **检查清单**: - [ ] 确认是函数节点(不是 InputNode/OutputNode) - [ ] 打开浏览器控制台查看错误 - [ ] 确认后端服务运行: `curl http://127.0.0.1:8000/api/functions/list` - [ ] 检查网络连接 **解决方案**: ```javascript // 在浏览器控制台执行 fetch('http://127.0.0.1:8000/api/functions/list') .then(r => r.json()) .then(d => console.log(d)) ``` ### Q2: 保存函数时提示"函数名称无效" **原因**: 函数名称不符合命名规范 **正确做法**: - ✅ 只用英文字母、数字、下划线 - ✅ 以字母或下划线开头 - ✅ 不含空格或特殊符号 **错误做法**: - ❌ 中文名称 - ❌ 包含空格 - ❌ 包含横杠或其他符号 ### Q3: 面包屑导航不显示 **原因**: - 尚未进入任何函数 (functionStack 为空) - 或者 BreadcrumbNav 组件被隐藏 **解决方案**: 1. 双击函数节点进入 2. 如果还是不显示,打开浏览器开发者工具的"元素检查器" 3. 搜索 "BreadcrumbNav" 或检查 z-index ### Q4: 返回上一层时工作流数据丢失 **原因**: - 进入函数时未正确保存上一层级的状态 - 浏览器 localStorage 被清空 **解决方案**: 1. 重新加载页面(会从 localStorage 恢复) 2. 检查浏览器控制台是否有错误 3. 确认 Workspace 中的 useStore 调用正确 ### Q5: 能否在函数内直接编辑,然后自动保存? **当前行为**: - 编辑自动保存到 localStorage - 但**不会更新** 函数定义文件 (`.json`) **计划改进** (Phase 3): - 添加"保存函数"按钮 - 自动检测函数内部工作流的变化 - 版本控制和历史记录 ### Q6: 支持撤销/重做吗? **当前**: - 基本的 undo/redo (由 zustand store 提供) - 在函数内编辑支持历史记录 **改进方向**: - 函数版本控制 - 编辑历史跟踪 - 比较功能 --- ## 💡 最佳实践 ### ✅ DO (推荐) 1. **按功能划分函数** - 每个函数执行单一功能 - 使用清晰的命名 2. **编写输入/输出节点** - 明确定义函数的输入参数 - 明确定义输出数据 - 便于重用 3. **测试函数** - 创建函数后先测试单独使用 - 确认输入/输出正确 4. **文档函数** - 使用 `display_name` 和 `description` 记录用途 - 后续搜索和使用更方便 5. **保持层级深度** - 不超过 3-5 层为佳 - 过深导致难以理解和维护 ### ❌ DON'T (避免) 1. ❌ 创建无用的函数 - 只有一个节点的函数 - 从未使用过的函数 2. ❌ 过度嵌套 - 函数A包含函数B包含函数C包含函数D... - 难以理解数据流 3. ❌ 混淆输入/输出 - 函数没有清晰的 InputNode/OutputNode - 导致数据流不清楚 4. ❌ 频繁更改已发布的函数 - 可能破坏依赖该函数的工作流 - 建议版本管理 (v1, v2, ...) 5. ❌ 循环依赖 - 函数A包含函数B,函数B包含函数A - 导致无限递归 --- ## 🎓 学习路径 ### 初级 (这节课) - [x] 创建函数 - [x] 使用函数节点 - [x] 进入/退出函数 - [x] 面包屑导航 ### 中级 (下一步) - [ ] 函数参数验证 - [ ] 错误处理 - [ ] 函数文档生成 - [ ] 多版本管理 ### 高级 (进阶) - [ ] 函数库管理 - [ ] 函数搜索和发现 - [ ] 函数分享和导入 - [ ] 性能优化 --- ## 📞 需要帮助? 1. **查看完整文档**: [FUNCTION_NESTING_IMPLEMENTATION.md](FUNCTION_NESTING_IMPLEMENTATION.md) 2. **检查示例函数**: `cloud/custom_nodes/functions/example_function.json` 3. **浏览器控制台**: 按 F12 查看错误和日志 4. **后端日志**: 检查 `server.log` --- **祝你使用愉快!** 🎉 --- *版本: v1.0.0 | 最后更新: 2024-01-15*