4.8 KiB
4.8 KiB
| name | description |
|---|---|
| drag | 拖拽编程画布模块(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 块定义 JSON(categories + 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_status(0 草稿 / 1 启用)→ appcodes(init/data.json Format B)。
块契约(block 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"}声明动态端口。 - 参数 uitype:text/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;显式 return;helper 在 init.py;三处同步注册 (drag/init.py 导出 ← drag/init.py 实现 ← load_drag() env.xxx 注册)。
- sor.C/U/D/R + sqlPaging;created_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_graph,blocks/connections JSON 往返一致。
- 编译产出可执行脚本:graph_compile 返回 Python 源码,无校验错误时可被 script_engine 执行。
- 校验能报孤立块/无入口:graph_validate 对孤立块报 ORPHAN_BLOCK、无事件块报 NO_ENTRY。
- 正反用例按 feature-granularity-and-testing:每功能点至少 1 正例 + 1 反例。