714 lines
18 KiB
Markdown
714 lines
18 KiB
Markdown
# 🔄 节点功能与目录分离重构
|
||
|
||
## 📋 需求分析
|
||
|
||
### 原有问题
|
||
`category` 字段承担双重职责:
|
||
1. 表示节点功能(Loader/Transform/Visualizer)→ 用于节点颜色、图标、Handle 显示
|
||
2. 表示目录分类 → 用于 NodePalette 树状展示
|
||
|
||
**冲突**:无法实现 "Loader/CSV"、"Transform/Filter" 这样的二级目录分类
|
||
|
||
### 解决方案
|
||
将 `category` 和节点功能分离:
|
||
- **`function`**: 节点功能(Loader/Transform/Visualizer)
|
||
- **`category`**: 树状目录路径(Loader/CSV, Transform/Filter)
|
||
|
||
同时弃用前端的 `node.type` 属性,统一使用 `function` 字段。
|
||
|
||
---
|
||
|
||
## ✅ 后端修改(main.py)
|
||
|
||
### 所有节点添加 `function` 字段
|
||
|
||
```python
|
||
# 修改前
|
||
"CSVLoader": {
|
||
"display_name": "CSV 数据加载器",
|
||
"category": "Loader", # 既表示功能又表示目录
|
||
"node_logic": "standard",
|
||
# ...
|
||
}
|
||
|
||
# 修改后
|
||
"CSVLoader": {
|
||
"display_name": "CSV 数据加载器",
|
||
"function": "Loader", # ✅ 节点功能:加载器
|
||
"category": "Loader/CSV", # ✅ 树状目录:加载器/CSV
|
||
"node_logic": "standard",
|
||
# ...
|
||
}
|
||
```
|
||
|
||
### 元数据结构完整示例
|
||
|
||
```python
|
||
{
|
||
"CSVLoader": {
|
||
"display_name": "CSV 数据加载器",
|
||
"function": "Loader", # 节点功能
|
||
"category": "Loader/CSV", # 树状目录
|
||
"node_logic": "standard", # 节点逻辑
|
||
"supports_preview": True,
|
||
"inputs": [],
|
||
"outputs": [{"name": "table", "type": "DataTable"}],
|
||
"param_schema": {...}
|
||
},
|
||
|
||
"UTraceLoader": {
|
||
"display_name": "UTrace 文件加载器",
|
||
"function": "Loader",
|
||
"category": "Loader/Trace", # 二级目录:Trace
|
||
# ...
|
||
},
|
||
|
||
"FilterRows": {
|
||
"display_name": "行过滤器",
|
||
"function": "Transform",
|
||
"category": "Transform/Filter", # 二级目录:Filter
|
||
# ...
|
||
},
|
||
|
||
"SelectColumns": {
|
||
"display_name": "列选择器",
|
||
"function": "Transform",
|
||
"category": "Transform/Select", # 二级目录:Select
|
||
# ...
|
||
},
|
||
|
||
"Aggregator": {
|
||
"display_name": "数据聚合",
|
||
"function": "Transform",
|
||
"category": "Transform/Aggregate",
|
||
"node_logic": "aggregate",
|
||
"allow_multiple_inputs": True, # ✅ 多输入支持
|
||
# ...
|
||
},
|
||
|
||
"TimeRangeFilter": {
|
||
"display_name": "时间范围过滤",
|
||
"function": "Transform",
|
||
"category": "Transform/Filter", # 与 FilterRows 共享目录
|
||
# ...
|
||
},
|
||
|
||
"ChartVisualizer": {
|
||
"display_name": "图表可视化",
|
||
"function": "Visualizer",
|
||
"category": "Visualizer/Chart",
|
||
# ...
|
||
},
|
||
|
||
"TableOutput": {
|
||
"display_name": "表格输出",
|
||
"function": "Visualizer",
|
||
"category": "Visualizer/Table",
|
||
# ...
|
||
}
|
||
}
|
||
```
|
||
|
||
### 完整节点清单
|
||
|
||
| 节点类型 | function | category | node_logic | allow_multiple_inputs |
|
||
|----------|----------|----------|------------|----------------------|
|
||
| CSVLoader | Loader | Loader/CSV | standard | false |
|
||
| UTraceLoader | Loader | Loader/Trace | standard | false |
|
||
| FilterRows | Transform | Transform/Filter | standard | false |
|
||
| SelectColumns | Transform | Transform/Select | standard | false |
|
||
| Aggregator | Transform | Transform/Aggregate | aggregate | ✅ true |
|
||
| TimeRangeFilter | Transform | Transform/Filter | standard | false |
|
||
| ChartVisualizer | Visualizer | Visualizer/Chart | standard | false |
|
||
| TableOutput | Visualizer | Visualizer/Table | standard | false |
|
||
|
||
---
|
||
|
||
## ✅ 前端修改
|
||
|
||
### 1. UniversalNode.tsx
|
||
|
||
#### 接口重构
|
||
```typescript
|
||
// 修改前
|
||
interface UniversalNodeProps {
|
||
data: {
|
||
meta?: {
|
||
category?: 'Loader' | 'Transform' | 'Visualizer' // ❌ 混用
|
||
}
|
||
}
|
||
}
|
||
|
||
// 修改后
|
||
interface UniversalNodeProps {
|
||
data: {
|
||
meta?: {
|
||
function?: 'Loader' | 'Transform' | 'Visualizer' // ✅ 节点功能
|
||
category?: string // ✅ 树状目录路径(如 "Loader/CSV")
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 常量重命名
|
||
```typescript
|
||
// 修改前
|
||
const CATEGORY_COLORS: Record<string, string> = {
|
||
Loader: '#3b82f6',
|
||
Transform: '#8b5cf6',
|
||
Visualizer: '#22c55e',
|
||
}
|
||
|
||
// 修改后
|
||
const FUNCTION_COLORS: Record<string, string> = {
|
||
Loader: '#3b82f6',
|
||
Transform: '#8b5cf6',
|
||
Visualizer: '#22c55e',
|
||
}
|
||
```
|
||
|
||
#### 组件实现
|
||
```typescript
|
||
// 修改前
|
||
const category = data.meta?.category || 'Transform'
|
||
const headerColor = CATEGORY_COLORS[category] || '#6b7280'
|
||
const showInput = category === 'Transform' || category === 'Visualizer'
|
||
const showOutput = category === 'Loader' || category === 'Transform'
|
||
|
||
// 修改后
|
||
const nodeFunction = data.meta?.function || 'Transform'
|
||
const headerColor = FUNCTION_COLORS[nodeFunction] || '#6b7280'
|
||
const showInput = nodeFunction === 'Transform' || nodeFunction === 'Visualizer'
|
||
const showOutput = nodeFunction === 'Loader' || nodeFunction === 'Transform'
|
||
```
|
||
|
||
#### Header 显示
|
||
```typescript
|
||
// 修改前
|
||
<div>{categoryIcon[category] || '🔹'}</div>
|
||
<div>{category}</div>
|
||
|
||
// 修改后
|
||
<div>{functionIcon[nodeFunction] || '🔹'}</div>
|
||
<div>{nodeFunction}</div> {/* 显示 Loader/Transform/Visualizer */}
|
||
```
|
||
|
||
---
|
||
|
||
### 2. Inspector.tsx
|
||
|
||
#### 图标映射
|
||
```typescript
|
||
// 修改前
|
||
<span>
|
||
{node.type === 'csv' ? '📂' :
|
||
node.type === 'transform' ? '⚙️' :
|
||
node.type === 'output' ? '📊' : '📦'}
|
||
</span>
|
||
|
||
// 修改后
|
||
<span>
|
||
{node.data?.meta?.function === 'Loader' ? '📥' :
|
||
node.data?.meta?.function === 'Transform' ? '⚙️' :
|
||
node.data?.meta?.function === 'Visualizer' ? '📊' : '📦'}
|
||
</span>
|
||
```
|
||
|
||
#### 标题显示
|
||
```typescript
|
||
// 修改前
|
||
<h3>{node.type.toUpperCase()}</h3> {/* CSV, TRANSFORM, OUTPUT */}
|
||
|
||
// 修改后
|
||
<h3>{node.data?.meta?.display_name || 'Node'}</h3> {/* CSV 数据加载器 */}
|
||
```
|
||
|
||
#### 系统属性
|
||
```typescript
|
||
// 修改前
|
||
<div>
|
||
<label>节点类型</label>
|
||
<input value={node.type} disabled /> {/* csv, transform, output */}
|
||
</div>
|
||
|
||
// 修改后
|
||
<div>
|
||
<label>节点功能</label>
|
||
<input value={node.data?.meta?.function || 'Unknown'} disabled /> {/* Loader */}
|
||
</div>
|
||
|
||
<div>
|
||
<label>目录分类</label>
|
||
<input value={node.data?.meta?.category} disabled /> {/* Loader/CSV */}
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
### 3. Workspace.tsx
|
||
|
||
#### MiniMap 颜色映射
|
||
```typescript
|
||
// 修改前
|
||
<MiniMap
|
||
nodeColor={(node) => {
|
||
const category = node.data?.meta?.category
|
||
if (category === 'Loader') return '#3b82f6'
|
||
if (category === 'Transform') return '#8b5cf6'
|
||
if (category === 'Visualizer') return '#22c55e'
|
||
return '#64748b'
|
||
}}
|
||
/>
|
||
|
||
// 修改后
|
||
<MiniMap
|
||
nodeColor={(node) => {
|
||
const nodeFunction = node.data?.meta?.function
|
||
if (nodeFunction === 'Loader') return '#3b82f6'
|
||
if (nodeFunction === 'Transform') return '#8b5cf6'
|
||
if (nodeFunction === 'Visualizer') return '#22c55e'
|
||
return '#64748b'
|
||
}}
|
||
/>
|
||
```
|
||
|
||
---
|
||
|
||
### 4. NodePalette.tsx
|
||
|
||
#### 接口更新
|
||
```typescript
|
||
// 修改前
|
||
interface PluginMeta {
|
||
display_name?: string
|
||
category?: string // 混用
|
||
}
|
||
|
||
// 修改后
|
||
interface PluginMeta {
|
||
display_name?: string
|
||
function?: string // 节点功能
|
||
category?: string // 树状目录
|
||
}
|
||
```
|
||
|
||
#### 二级目录解析
|
||
```typescript
|
||
// 修改前
|
||
const groups: Record<string, { key: string; items: Array<...> }> = {}
|
||
for (const [k, v] of Object.entries(plugins)) {
|
||
const cat = (v.category || 'Other').split('/')[0]
|
||
if (!groups[cat]) groups[cat] = { key: cat, items: [] }
|
||
groups[cat].items.push({ type: k, meta: v })
|
||
}
|
||
|
||
// 修改后
|
||
const groups: Record<string, {
|
||
key: string;
|
||
items: Array<{ type: string; meta: PluginMeta; subCategory?: string }>
|
||
}> = {}
|
||
|
||
for (const [k, v] of Object.entries(plugins)) {
|
||
const categoryPath = v.category || 'Other'
|
||
const [mainCat, subCat] = categoryPath.split('/')
|
||
|
||
if (!groups[mainCat]) {
|
||
groups[mainCat] = { key: mainCat, items: [] }
|
||
}
|
||
|
||
groups[mainCat].items.push({
|
||
type: k,
|
||
meta: v,
|
||
subCategory: subCat // 保存二级分类
|
||
})
|
||
}
|
||
```
|
||
|
||
#### 算子卡片显示
|
||
```typescript
|
||
// 修改前
|
||
<div>
|
||
<span>
|
||
{group.key === 'Loaders' ? '📂' :
|
||
group.key === 'Transforms' ? '⚙️' : '📦'}
|
||
</span>
|
||
<span>{item.meta.display_name}</span>
|
||
</div>
|
||
|
||
// 修改后
|
||
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
|
||
{/* 主行:图标 + 名称 */}
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||
<span>
|
||
{item.meta.function === 'Loader' ? '📥' :
|
||
item.meta.function === 'Transform' ? '⚙️' :
|
||
item.meta.function === 'Visualizer' ? '📊' : '📦'}
|
||
</span>
|
||
<span>{item.meta.display_name}</span>
|
||
</div>
|
||
|
||
{/* 二级分类标签 */}
|
||
{item.subCategory && (
|
||
<div style={{ fontSize: 10, color: 'rgba(255,255,255,0.4)' }}>
|
||
{item.subCategory} {/* CSV, Trace, Filter, Select */}
|
||
</div>
|
||
)}
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 视觉效果对比
|
||
|
||
### NodePalette 显示
|
||
|
||
**修改前**:
|
||
```
|
||
▸ Loaders (2)
|
||
📂 CSV 数据加载器
|
||
📂 UTrace 文件加载器
|
||
|
||
▸ Transforms (4)
|
||
⚙️ 行过滤器
|
||
⚙️ 列选择器
|
||
⚙️ 数据聚合
|
||
⚙️ 时间范围过滤
|
||
```
|
||
|
||
**修改后**:
|
||
```
|
||
▸ Loader (2)
|
||
📥 CSV 数据加载器
|
||
CSV ← 二级分类标签
|
||
📥 UTrace 文件加载器
|
||
Trace ← 二级分类标签
|
||
|
||
▸ Transform (4)
|
||
⚙️ 行过滤器
|
||
Filter ← 二级分类标签
|
||
⚙️ 列选择器
|
||
Select
|
||
⚙️ 数据聚合
|
||
Aggregate
|
||
⚙️ 时间范围过滤
|
||
Filter ← 相同二级目录
|
||
```
|
||
|
||
### Inspector 面板
|
||
|
||
**修改前**:
|
||
```
|
||
┌─ 系统信息 ────────┐
|
||
│ 节点 ID: n_xxx │
|
||
│ 节点类型: csv │ ← 前端类型(混乱)
|
||
│ 分类: Loader │ ← 混用
|
||
└──────────────────┘
|
||
```
|
||
|
||
**修改后**:
|
||
```
|
||
┌─ 系统信息 ────────────┐
|
||
│ 节点 ID: n_xxx │
|
||
│ 节点功能: Loader │ ← 清晰的功能标识
|
||
│ 目录分类: Loader/CSV │ ← 完整的目录路径
|
||
└──────────────────────┘
|
||
```
|
||
|
||
### 节点本体显示
|
||
|
||
**修改前**:
|
||
```
|
||
┌─ CSV 数据加载器 ──┐
|
||
│ Loader │ ← 显示 category
|
||
│ file_path: ... │
|
||
└──────────────────┘
|
||
```
|
||
|
||
**修改后**:
|
||
```
|
||
┌─ CSV 数据加载器 ──┐
|
||
│ LOADER │ ← 显示 function(功能)
|
||
│ file_path: ... │
|
||
└──────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 数据流追踪
|
||
|
||
### 从后端到前端的完整流程
|
||
|
||
```
|
||
1️⃣ 后端定义(main.py)
|
||
↓
|
||
GET /plugins
|
||
↓
|
||
{
|
||
"CSVLoader": {
|
||
"function": "Loader", ← 节点功能
|
||
"category": "Loader/CSV" ← 树状目录
|
||
}
|
||
}
|
||
↓
|
||
2️⃣ NodePalette 接收
|
||
↓
|
||
解析 category: "Loader/CSV"
|
||
├─ mainCat: "Loader" ← 一级目录
|
||
└─ subCat: "CSV" ← 二级目录
|
||
↓
|
||
显示:
|
||
Loader (2)
|
||
📥 CSV 数据加载器
|
||
CSV ← subCategory 标签
|
||
↓
|
||
3️⃣ 拖拽到画布
|
||
↓
|
||
创建节点:
|
||
{
|
||
id: "n_xxx",
|
||
type: "universal", ← 所有节点统一类型
|
||
data: {
|
||
meta: {
|
||
function: "Loader", ← 用于功能判断
|
||
category: "Loader/CSV" ← 用于显示目录
|
||
}
|
||
}
|
||
}
|
||
↓
|
||
4️⃣ UniversalNode 渲染
|
||
↓
|
||
读取 function: "Loader"
|
||
├─ 决定颜色:#3b82f6(蓝色)
|
||
├─ 决定图标:📥
|
||
├─ 决定 Handle:只显示 Output
|
||
└─ 显示文字:LOADER
|
||
↓
|
||
5️⃣ Inspector 显示
|
||
↓
|
||
系统信息:
|
||
- 节点功能: Loader ← function
|
||
- 目录分类: Loader/CSV ← category
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 关键概念对比
|
||
|
||
### function vs category
|
||
|
||
| 字段 | 用途 | 值域 | 示例 | 前端使用位置 |
|
||
|------|------|------|------|-------------|
|
||
| **function** | 节点功能 | Loader, Transform, Visualizer | `"Loader"` | UniversalNode 颜色、图标、Handle 逻辑 |
|
||
| **category** | 树状目录 | 任意路径(支持 / 分隔) | `"Loader/CSV"` | NodePalette 分组、Inspector 显示 |
|
||
|
||
### 节点类型演变
|
||
|
||
| 阶段 | 前端类型 | 后端类型 | 功能标识 | 目录标识 |
|
||
|------|---------|---------|---------|---------|
|
||
| **Phase 1** | node.type = 'csv' | N/A | ❌ 混乱 | ❌ 无 |
|
||
| **Phase 2** | node.type = 'universal' | meta.category | ⚠️ category 混用 | ⚠️ category 混用 |
|
||
| **Phase 3 (现在)** | node.type = 'universal' | meta.function | ✅ function | ✅ category |
|
||
|
||
---
|
||
|
||
## 🧪 测试验证
|
||
|
||
### 测试 1:后端 API 验证
|
||
|
||
```bash
|
||
# 访问后端
|
||
curl http://127.0.0.1:8000/plugins
|
||
|
||
# 验证响应包含
|
||
{
|
||
"plugins": {
|
||
"CSVLoader": {
|
||
"function": "Loader", ✅
|
||
"category": "Loader/CSV", ✅
|
||
"allow_multiple_inputs": false
|
||
},
|
||
"Aggregator": {
|
||
"function": "Transform",
|
||
"category": "Transform/Aggregate",
|
||
"allow_multiple_inputs": true ✅
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 测试 2:NodePalette 二级目录
|
||
|
||
```
|
||
操作:打开应用
|
||
预期:左侧面板显示
|
||
|
||
✅ Loader (2)
|
||
📥 CSV 数据加载器
|
||
CSV ← 二级分类标签
|
||
📥 UTrace 文件加载器
|
||
Trace
|
||
|
||
✅ Transform (4)
|
||
⚙️ 行过滤器
|
||
Filter
|
||
⚙️ 列选择器
|
||
Select
|
||
⚙️ 数据聚合
|
||
Aggregate
|
||
⚙️ 时间范围过滤
|
||
Filter ← 相同目录共享
|
||
```
|
||
|
||
### 测试 3:节点功能识别
|
||
|
||
```
|
||
操作:拖拽 CSV Loader 到画布
|
||
预期:
|
||
1. 节点颜色:蓝色(#3b82f6) ✅
|
||
2. 节点图标:📥 ✅
|
||
3. Handle 显示:只有 Output ✅
|
||
4. 节点 Header:显示 "LOADER" ✅
|
||
|
||
操作:拖拽 FilterRows 到画布
|
||
预期:
|
||
1. 节点颜色:紫色(#8b5cf6) ✅
|
||
2. 节点图标:⚙️ ✅
|
||
3. Handle 显示:Input + Output ✅
|
||
4. 节点 Header:显示 "TRANSFORM" ✅
|
||
```
|
||
|
||
### 测试 4:Inspector 显示
|
||
|
||
```
|
||
操作:选中 CSV Loader 节点
|
||
预期 Inspector 显示:
|
||
|
||
┌─ 系统信息 ─────────────┐
|
||
│ 节点 ID: n_xxx │ ✅
|
||
│ 节点功能: Loader │ ✅ (原来是 node.type)
|
||
│ 目录分类: Loader/CSV │ ✅ (新增)
|
||
└───────────────────────┘
|
||
|
||
┌─ 参数配置 ─────────────┐
|
||
│ file_path: [输入框] │
|
||
│ delimiter: [输入框] │
|
||
└───────────────────────┘
|
||
```
|
||
|
||
### 测试 5:MiniMap 颜色
|
||
|
||
```
|
||
操作:拖拽多种节点到画布
|
||
预期 MiniMap 显示:
|
||
- Loader 节点:蓝色 ✅
|
||
- Transform 节点:紫色 ✅
|
||
- Visualizer 节点:绿色 ✅
|
||
```
|
||
|
||
---
|
||
|
||
## 📁 修改文件清单
|
||
|
||
### 后端
|
||
1. **server/main.py**
|
||
- ✅ 所有节点添加 `"function"` 字段
|
||
- ✅ 修改 `"category"` 为树状路径(支持 `/` 分隔)
|
||
- ✅ Aggregator 添加 `"allow_multiple_inputs": True`
|
||
|
||
### 前端
|
||
2. **web/src/components/nodes/UniversalNode.tsx**
|
||
- ✅ `CATEGORY_COLORS` → `FUNCTION_COLORS`
|
||
- ✅ `meta.category` → `meta.function`
|
||
- ✅ `categoryIcon` → `functionIcon`
|
||
- ✅ Header 显示 `nodeFunction` 代替 `category`
|
||
|
||
3. **web/src/components/Inspector.tsx**
|
||
- ✅ 图标映射:`node.type` → `node.data.meta.function`
|
||
- ✅ 标题显示:`node.type.toUpperCase()` → `node.data.meta.display_name`
|
||
- ✅ 系统属性:删除 `node.type`,添加 `function` 和 `category` 显示
|
||
|
||
4. **web/src/components/Workspace.tsx**
|
||
- ✅ MiniMap 颜色:`meta.category` → `meta.function`
|
||
|
||
5. **web/src/components/NodePalette.tsx**
|
||
- ✅ 接口添加 `function` 字段
|
||
- ✅ 二级目录解析:`category.split('/')` → `[mainCat, subCat]`
|
||
- ✅ 算子卡片:显示 `function` 图标 + `subCategory` 标签
|
||
|
||
---
|
||
|
||
## 🎨 设计亮点
|
||
|
||
### 1. 职责分离
|
||
- **function**: 节点功能逻辑(颜色、图标、Handle)
|
||
- **category**: UI 组织结构(树状目录、分组)
|
||
|
||
### 2. 可扩展性
|
||
```python
|
||
# 轻松添加三级目录
|
||
"category": "Transform/Filter/Advanced"
|
||
|
||
# 前端自动支持
|
||
categoryPath.split('/') → ['Transform', 'Filter', 'Advanced']
|
||
```
|
||
|
||
### 3. 语义化
|
||
```typescript
|
||
// 修改前(混乱)
|
||
if (node.type === 'csv') { ... } // 前端类型
|
||
if (meta.category === 'Loader') { ... } // 既是功能又是目录
|
||
|
||
// 修改后(清晰)
|
||
if (meta.function === 'Loader') { ... } // 节点功能
|
||
if (meta.category.startsWith('Loader/')) { ... } // 目录位置
|
||
```
|
||
|
||
### 4. 向后兼容
|
||
- 前端 `node.type` 统一为 `'universal'`,不再依赖具体类型
|
||
- 所有节点使用相同的 UniversalNode 组件
|
||
- 元数据驱动,易于扩展
|
||
|
||
---
|
||
|
||
## 🚀 后续增强建议
|
||
|
||
### 1. 动态树状目录
|
||
```typescript
|
||
// 支持折叠二级目录
|
||
Loader (2)
|
||
▸ CSV (1)
|
||
- CSV 数据加载器
|
||
▸ Trace (1)
|
||
- UTrace 文件加载器
|
||
|
||
Transform (4)
|
||
▸ Filter (2)
|
||
- 行过滤器
|
||
- 时间范围过滤
|
||
▸ Select (1)
|
||
▸ Aggregate (1)
|
||
```
|
||
|
||
### 2. 功能徽章
|
||
```typescript
|
||
// 节点卡片显示功能标签
|
||
┌─ CSV 数据加载器 ────────┐
|
||
│ [Loader] [CSV] [⚡Preview] │
|
||
│ file_path: ... │
|
||
└─────────────────────────┘
|
||
```
|
||
|
||
### 3. 搜索增强
|
||
```typescript
|
||
// 支持按 function 和 category 过滤
|
||
搜索:Loader → 显示所有 Loader 功能节点
|
||
搜索:Filter → 显示所有 Filter 目录节点
|
||
搜索:Loader/CSV → 显示特定路径节点
|
||
```
|
||
|
||
---
|
||
|
||
**完成时间**:2026-01-07
|
||
**版本**:Function & Category Separation v1.0
|
||
**状态**:✅ 重构完成,功能与目录完全分离
|