2026-08-29 21:10:23 +08:00

90 lines
4.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: drag
description: 拖拽编程画布模块W-09——可视化块编排、连线、参数校验、编译为 script_engine 可执行脚本,提供画布/模板 CRUD 与 block_defs/graph_save/graph_compile/graph_validate/graph_publish 接口,通过 load_drag() 挂载。
---
# drag 拖拽编程画布模块
元景 W-09把事件/逻辑/动作/变量/表达式块拖拽连线成流程图,校验后编译为
script_engine 可执行 Python 脚本script_type=0。宿主应用scense/d/scense/scense_app
## 架构
```
bricks 前端 (editor.ui + drag-canvas.js + drag-editor.js)
│ block_defs / graph_save / graph_compile / graph_validate / graph_publish
drag 模块 (init.py 挂载)
├── blocks.py 块定义 JSONcategories + blocks唯一事实源
├── validator.py 图校验(无入口/孤立/环形/参数/变量引用)
└── compiler.py 图 → Python 脚本(变量提升/函数区/事件分支/控制流)
drag_graph / drag_template 表drag 库)+ script_engine 发布
```
## 数据模型
- `drag_graph`id(32 PK)、name(100)、description(255)、blocks(text JSON)、
connections(text JSON)、content(text 编译产物)、status(16, drag_status 0草稿/1启用)、
created_at、updated_at。索引 idx_drag_graph_name/status。
- `drag_template`id、name、category(32, 通用/移动/弹球/计时)、description、
blocks(text)、connections(text)、created_at、updated_at。
- 编码drag_status0 草稿 / 1 启用)→ appcodesinit/data.json Format B
## 块契约block JSON
```json
{"type":"action_move","category":"action","label":"移动","icon":"fa fa-arrows-alt",
"params":[{"name":"entity","label":"目标实体","uitype":"entity","required":true},
{"name":"x","label":"X 位移","uitype":"number","default":"0"}],
"ports":{"inputs":[{"name":"in","label":"上一步"}],
"outputs":[{"name":"out","label":"下一步"}]}}
```
- 事件块category=event无输入端口 = 天然入口,不能作为连线目标。
- 分叉/并行块用 `dynamic_outputs={"param":"branch_count","prefix":"branch"}` 声明动态端口。
- 参数 uitypetext/number/select/boolean/entity/expression/variable/textarea。
- 表达式参数支持 `@变量名` 引用validator 校验已创建变量)。
## 关键端点(/drag/api/*.dspy宿主挂载后 /drag/api/*.dspy
| 端点 | 方法 | 入参 | 返回 |
|------|------|------|------|
| block_defs.dspy | GET | - | {categories, blocks} |
| graph_save.dspy | POST | {id?, name, blocks, connections} | {success, id, valid, errors, content} |
| graph_list.dspy | GET | {page, rows, name?, status?} | {list, total} |
| graph_get.dspy | GET | {id} | {data:{blocks, connections, content}} |
| graph_delete.dspy | POST | {id} | {success} |
| graph_compile.dspy | POST | {name?, blocks, connections} | {success, content, entry_points} |
| graph_validate.dspy | POST | {blocks, connections} | {valid, errors:[{code,message,block_id,field}]} |
| graph_publish.dspy | POST | {id, script_name?} | {success, script_id, script_name} |
| template_save/list/delete/use.dspy | - | - | - |
| get_search_entity.dspy | GET | - | [{value,text}] 实体下拉 |
## 错误码
PARAM_REQUIRED / PARAM_TYPE / PARAM_RANGE / PARAM_OPTION / INVALID_IDENTIFIER /
VAR_UNDEFINED / FUNC_UNDEFINED / BLOCK_UNKNOWN_TYPE / NO_ENTRY / ORPHAN_BLOCK /
UNREACHABLE_BLOCK / CONN_BLOCK_NOT_FOUND / CONN_PORT_NOT_FOUND / CONN_DUPLICATE /
CONN_SELF_LOOP / CONN_CYCLE / EVENT_AS_TARGET / NOT_FOUND / DB_ERROR / COMPILE_ERROR
## 模块陷阱
- 取库名:.py 用 `ServerEnv().get_module_dbname('drag')`.dspy 直接 `get_module_dbname('drag')`
- dspy 无 import/print/uuid显式 returnhelper 在 init.py三处同步注册
drag/__init__.py 导出 ← drag/init.py 实现 ← load_drag() env.xxx 注册)。
- sor.C/U/D/R + sqlPagingcreated_at/updated_at 必须显式设置。
- CRUD 复数别名 create_drag_graphs 等已注册CRUD 框架约定)。
- 编译产物仅白名单语法(赋值/def/for/while/if-else/函数调用/注释),
动作函数move/rotate/scale/set_property/play_animation/play_sound/show_hide/camera/wait
需宿主演绎层注册到 script_engine 白名单。
- 前端 .js/.css 必须在 load_path.py 注册 any 角色,否则 403。
- 修改 blocks.py 后前端自动通过 block_defs.dspy 拿到新定义,无需改前端。
## 验收口径W-09a~W-09au
- 拖块连块存画布graph_save 落库 drag_graphblocks/connections JSON 往返一致。
- 编译产出可执行脚本graph_compile 返回 Python 源码,无校验错误时可被 script_engine 执行。
- 校验能报孤立块/无入口graph_validate 对孤立块报 ORPHAN_BLOCK、无事件块报 NO_ENTRY。
- 正反用例按 feature-granularity-and-testing每功能点至少 1 正例 + 1 反例。