画布模式:无限画布(无固定宽高),节点无限扩展、无固定根节点,仅记录两两之间的无方向多对多关联。
通用说明:
api 路由组下,需要登录态(bindToken / bindExportToken / checkLogin / checkSign / checkCompany 中间件)。{ "msg": "", "code": 0, "data": {...} };出错时 code 为错误码,msg 为错误信息。mp_,节点类型为字符串小写。创建或更新画布节点。不传 node_id 表示创建,传 node_id 表示更新(更新时节点类型以库中为准,不允许变更)。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
canvas_id |
int | 是 | 画布 ID |
node_id |
int | 否 | 节点 ID,更新时必传,创建时不传 |
node_type |
string | 创建时是 | 节点类型,枚举:theme-主题、subject-主体、scene-场景、prop-道具、segment-分镜、text-文字、image-图片、video-视频、audio-音频 |
name |
string | 否 | 节点名称 |
content |
string | 否 | 节点内容(主要用于text 文字节点) |
text_prompt |
string | 否 | 文字提示词 |
pic_prompt |
string | 否 | 图片提示词 |
image_url |
string | 否 | 图片 URL |
video_url |
string | 否 | 视频 URL |
audio_url |
string | 否 | 音频 URL |
thumbnail_url |
string | 否 | 缩略图 URL |
duration |
int | 否 | 时长(秒),视频/音频/分镜使用 |
pos_x |
number | 否 | 节点在画布上的 X 坐标,默认0 |
pos_y |
number | 否 | 节点在画布上的 Y 坐标,默认0 |
z_index |
int | 否 | 节点层级,默认0 |
size_w |
number | 否 | 节点显示宽度(可空) |
size_h |
number | 否 | 节点显示高度(可空) |
source_type |
string | 否 | 关联来源,枚举:none-无、product-全局资产库、episode-动漫分集,默认 none |
source_product_id |
int | 否 | 全局资产 ID(mp_products.id),source_type=product 时使用 |
source_anime_id |
int | 否 | 动漫 ID(mp_animes.id),source_type=episode 时使用 |
source_episode_id |
int | 否 | 剧集 ID(mp_anime_episodes.id),source_type=episode 时使用 |
source_ref |
string | 否 | 来源明细引用,如剧集 JSON 列表中的 key,用于定位具体列表项 |
ext |
object/string | 否 | 扩展信息,传对象或 JSON 字符串均可,库内以 JSON 存储 |
segment |
object | 否 | 分镜数据子对象,仅node_type=segment 时生效(见 1.2) |
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
segment_number |
int | 否 | 分镜序号,默认1 |
name |
string | 否 | 分镜名称,缺省时取节点级name |
text_prompt |
string | 否 | 文字提示词,缺省时取节点级text_prompt |
pic_prompt |
string | 否 | 图片提示词,缺省时取节点级pic_prompt |
image_url |
string | 否 | 图片 URL,缺省时取节点级image_url |
video_url |
string | 否 | 视频 URL,缺省时取节点级video_url |
audio_url |
string | 否 | 音频 URL,缺省时取节点级audio_url |
duration |
int | 否 | 时长(秒) |
status |
string | 否 | 状态,枚举:draft-草稿、generating-生成中、completed-已完成、failed-失败,默认 draft |
ext |
object/string | 否 | 分镜扩展信息 JSON |
保存分镜节点时,接口会同时写入节点表与画布分镜表(
mp_canvas_segments);查询节点时返回的数据以分镜表字段为准。
创建普通节点(图片):
{
"canvas_id": 1,
"node_type": "image",
"name": "图片-林默立绘",
"image_url": "https://example.com/linmo.png",
"thumbnail_url": "https://example.com/linmo_thumb.png",
"pos_x": 280,
"pos_y": 380
}
创建分镜节点:
{
"canvas_id": 1,
"node_type": "segment",
"name": "分镜1-雨夜相遇",
"pos_x": 480,
"pos_y": 220,
"segment": {
"segment_number": 1,
"text_prompt": "林默在雨夜街头偶遇苏晴",
"pic_prompt": "写实。全景,雨夜街头,两人对视",
"image_url": "https://example.com/seg1.png",
"video_url": "",
"audio_url": "",
"duration": 8,
"status": "completed"
}
}
更新节点(复用动漫分集中的主体列表项):
{
"canvas_id": 1,
"node_id": 2,
"name": "主体-林默",
"source_type": "episode",
"source_anime_id": 10,
"source_episode_id": 3,
"source_ref": "roles.0",
"pos_x": 300,
"pos_y": 100
}
{
"msg": "",
"code": 0,
"data": {
"node_id": 21
}
}
保存某个节点的关联列表。整体替换语义:先清空该节点的全部关联,再写入新关联;返回实际写入的关联条数。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
canvas_id |
int | 是 | 画布 ID |
node_id |
int | 是 | 中心节点 ID |
related_ids |
array | 是 | 要关联的节点 ID 数组;也可传逗号分隔的字符串(如"3,7,9")。传空数组/空字符串表示清空该节点的所有关联 |
A 关联 B 与 B 关联 A 等价,内部统一按(小 id,大 id)存储,同一对节点只保留一条。related_ids 会整体替换该节点原有全部关联,不需要前端先查再删。{
"canvas_id": 1,
"node_id": 2,
"related_ids": [6, 8, 12, 16]
}
清空节点 2 的全部关联:
{
"canvas_id": 1,
"node_id": 2,
"related_ids": []
}
{
"msg": "",
"code": 0,
"data": {
"success": 1,
"rel_count": 4
}
}
入参:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
canvas_id |
int | 是 | 画布 ID |
node_id |
int | 是 | 节点 ID |
返回:rel_ids(关联节点 ID 数组)+ related_nodes(关联节点完整信息数组)。
入参:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
canvas_id |
int | 是 | 画布 ID |
node_id |
int | 否 | 中心节点 ID;不传返回画布全部节点与关联,传了返回以该节点为中心的局部子图 |
depth |
int | 否 | 局部子图深度(1-5),默认1,仅 node_id 传入时生效 |
返回:nodes(节点数组)+ rels(关联数组,每项含 node_id_a / node_id_b),局部子图模式额外返回 center_node_id、depth、levels。
局部子图模式下(传了 node_id),节点与关联都附带 level 字段,并提供 levels 层级摘要,方便前端逐层加载与动画:
nodes[].level:节点距中心节点的跳数,中心节点为 0,直接邻居为 1,以此类推;rels[].level:关联首次被 BFS 触及的轮次(depth=1 时全部为 1,即中心节点的直接关联);levels:数组,每项 { level, node_ids, rel_ids },node_ids / rel_ids 分别为该层包含的节点 ID 与关联 ID 列表(level=0 为中心节点)。前端渲染建议:直接用平铺的 nodes / rels 画节点和连线;需要"逐层展开/动画"时,按 level 过滤即可(如 nodes.filter(n => n.level <= 1)),或直接遍历 levels 摘要。
局部子图的
rels只包含从中心节点展开过程中触及的关联:depth=1时仅返回中心节点的直接关联,不会返回"邻居之间的边"(例如节点 9 的邻居 5 与 18 之间若存在关联,不会在depth=1的结果中出现,需depth=2才会包含)。以演示数据中心节点 9、
depth=2为例的返回结果图示见 canvas_subgraph_depth2.png:返回 9 个节点、9 条边;节点 1 与 2 之间的边虽然两者都在子图内,但 BFS 展开过程中未触及,因此不返回。
入参:canvas_id、node_id。返回节点完整信息(分镜节点含分镜数据)+ rel_ids + related_nodes。
仓库内已提供演示数据生成器 database/seeders/CanvasDemoSeeder.php,会生成一个名为「接口测试画布-示例」的画布,包含:
运行前确认画布数据表已创建(php artisan migrate),然后执行:
# 指定测试用户的 uid / cpid(不指定默认 uid=1, cpid=1)
$env:CANVAS_DEMO_UID = 123
$env:CANVAS_DEMO_CPID = 456
php artisan db:seed --class=CanvasDemoSeeder
重复执行会先清理同名演示画布再重新生成。执行成功后控制台会输出 canvas_id 与 20 个节点的编号→ID 映射,便于直接拼接测试请求。
测试建议顺序:
GET api/canvas/list 查看画布;GET api/canvas/graph?canvas_id=1 查看全部节点与关联;GET api/canvas/nodeRels?canvas_id=1&node_id=8 查看分镜节点的关联;POST api/canvas/saveRels 修改某节点关联后,再调用 graph 或 nodeRels 验证;POST api/canvas/saveNode 新建/更新节点后,用 nodeInfo 验证。