feat: pipeline-task 交互模块初始版本
- 纯薄交互层,无数据表,调用 pipeline-service 引擎函数 - 6个dspy API(submit/list/detail/node/modify/control) - 4个UI页面(index/list/detail/submit) - pipeline_task.js 交互辅助函数 - load_path.py RBAC 权限注册 - 完整 README 文档
This commit is contained in:
parent
d7bde8ec31
commit
50a38e15e1
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*.egg-info/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# Virtual environment
|
||||||
|
py3/
|
||||||
|
pkgs/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs/
|
||||||
5
pipeline_task/__init__.py
Normal file
5
pipeline_task/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
"""pipeline_task — 产线任务交互层"""
|
||||||
|
|
||||||
|
from .init import load_pipeline_task
|
||||||
|
|
||||||
|
__version__ = "1.0.0"
|
||||||
22
pipeline_task/init.py
Normal file
22
pipeline_task/init.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"""pipeline_task 交互模块 — 产线任务的用户交互层。
|
||||||
|
|
||||||
|
纯薄交互层,无数据表。通过 ServerEnv 调用 pipeline-service 的函数。
|
||||||
|
任何宿主加载 pipeline_service 后,再加载 pipeline_task 即可使用。
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ahserver.serverenv import ServerEnv
|
||||||
|
|
||||||
|
MODULE_NAME = "pipeline_task"
|
||||||
|
MODULE_VERSION = "1.0.0"
|
||||||
|
|
||||||
|
|
||||||
|
def load_pipeline_task():
|
||||||
|
"""注册交互模块到 ServerEnv。"""
|
||||||
|
env = ServerEnv()
|
||||||
|
# 模块元信息
|
||||||
|
env.pipeline_task_info = lambda: {
|
||||||
|
"module": MODULE_NAME,
|
||||||
|
"version": MODULE_VERSION,
|
||||||
|
"depends_on": "pipeline_service",
|
||||||
|
}
|
||||||
|
return True
|
||||||
16
pyproject.toml
Normal file
16
pyproject.toml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=45", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "pipeline_task"
|
||||||
|
version = "1.0.0"
|
||||||
|
description = "产线任务交互模块 — 提交任务、查看状态、修改节点、暂停恢复"
|
||||||
|
requires-python = ">=3.8"
|
||||||
|
dependencies = [
|
||||||
|
"bricks_for_python",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
where = ["."]
|
||||||
|
include = ["pipeline_task*"]
|
||||||
63
scripts/load_path.py
Normal file
63
scripts/load_path.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""pipeline_task 模块 RBAC 权限注册。"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
# Find Sage root
|
||||||
|
SAGE_ROOT = None
|
||||||
|
for candidate in [
|
||||||
|
os.path.join(SCRIPT_DIR, "..", ".."),
|
||||||
|
os.path.expanduser("~/repos/sage"),
|
||||||
|
os.path.expanduser("~/sage"),
|
||||||
|
os.path.expanduser("~/test/pipeline-app"),
|
||||||
|
]:
|
||||||
|
if os.path.isdir(os.path.join(candidate, "wwwroot")) and os.path.isdir(os.path.join(candidate, "py3")):
|
||||||
|
SAGE_ROOT = os.path.abspath(candidate)
|
||||||
|
break
|
||||||
|
|
||||||
|
if not SAGE_ROOT:
|
||||||
|
print("ERROR: Cannot find Sage/pipeline-app root directory")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
SET_ROLE_PERM = os.path.join(SAGE_ROOT, "set_role_perm.py")
|
||||||
|
PYTHON = os.path.join(SAGE_ROOT, "py3", "bin", "python")
|
||||||
|
|
||||||
|
MOD = "pipeline_task"
|
||||||
|
|
||||||
|
PATHS_LOGINED = [
|
||||||
|
f"/{MOD}/index.ui",
|
||||||
|
f"/{MOD}/task_list.ui",
|
||||||
|
f"/{MOD}/task_detail.ui",
|
||||||
|
f"/{MOD}/task_submit.ui",
|
||||||
|
f"/{MOD}/api/task_submit.dspy",
|
||||||
|
f"/{MOD}/api/task_list.dspy",
|
||||||
|
f"/{MOD}/api/task_detail.dspy",
|
||||||
|
f"/{MOD}/api/task_node.dspy",
|
||||||
|
f"/{MOD}/api/task_modify.dspy",
|
||||||
|
f"/{MOD}/api/task_control.dspy",
|
||||||
|
]
|
||||||
|
|
||||||
|
PATHS_ANY = [
|
||||||
|
f"/{MOD}/pipeline_task.js",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def register_paths():
|
||||||
|
for path in PATHS_ANY:
|
||||||
|
subprocess.run([PYTHON, SET_ROLE_PERM, "any", path], cwd=SAGE_ROOT)
|
||||||
|
print(f" any: {path}")
|
||||||
|
|
||||||
|
for path in PATHS_LOGINED:
|
||||||
|
subprocess.run([PYTHON, SET_ROLE_PERM, "logined", path], cwd=SAGE_ROOT)
|
||||||
|
print(f" logined: {path}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(f"=== pipeline_task RBAC registration ===")
|
||||||
|
print(f"Root: {SAGE_ROOT}")
|
||||||
|
register_paths()
|
||||||
|
print("Done.")
|
||||||
20
wwwroot/api/task_control.dspy
Normal file
20
wwwroot/api/task_control.dspy
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
tenant_id = (await get_userorgid()) or '0'
|
||||||
|
task_id = params_kw.get('task_id', '')
|
||||||
|
action = params_kw.get('action', '')
|
||||||
|
|
||||||
|
if not task_id:
|
||||||
|
return json.dumps({"success": False, "message": "缺少task_id"}, ensure_ascii=False)
|
||||||
|
|
||||||
|
if action not in ('pause', 'resume', 'cancel'):
|
||||||
|
return json.dumps({"success": False, "message": "action必须是pause/resume/cancel"}, ensure_ascii=False)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if action == 'pause':
|
||||||
|
result = await pipeline_pause(tenant_id, task_id)
|
||||||
|
elif action == 'resume':
|
||||||
|
result = await pipeline_resume(tenant_id, task_id)
|
||||||
|
else:
|
||||||
|
result = await pipeline_cancel(tenant_id, task_id)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
return json.dumps({"success": False, "message": str(e)}, ensure_ascii=False)
|
||||||
11
wwwroot/api/task_detail.dspy
Normal file
11
wwwroot/api/task_detail.dspy
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
tenant_id = (await get_userorgid()) or '0'
|
||||||
|
task_id = params_kw.get('task_id', '')
|
||||||
|
|
||||||
|
if not task_id:
|
||||||
|
return json.dumps({"success": False, "message": "缺少task_id"}, ensure_ascii=False)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = await pipeline_detail(tenant_id, task_id)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
return json.dumps({"success": False, "message": str(e)}, ensure_ascii=False)
|
||||||
9
wwwroot/api/task_list.dspy
Normal file
9
wwwroot/api/task_list.dspy
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
tenant_id = (await get_userorgid()) or '0'
|
||||||
|
pipeline_id = params_kw.get('pipeline_id', None)
|
||||||
|
limit = int(params_kw.get('limit', 100))
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = await pipeline_list(tenant_id, pipeline_id, limit)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
return json.dumps({"success": False, "message": str(e)}, ensure_ascii=False)
|
||||||
25
wwwroot/api/task_modify.dspy
Normal file
25
wwwroot/api/task_modify.dspy
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
tenant_id = (await get_userorgid()) or '0'
|
||||||
|
task_id = params_kw.get('task_id', '')
|
||||||
|
step_name = params_kw.get('step_name', '')
|
||||||
|
content_raw = params_kw.get('content', '')
|
||||||
|
rerun_from = params_kw.get('rerun_from', 'node')
|
||||||
|
|
||||||
|
if not task_id or not step_name:
|
||||||
|
return json.dumps({"success": False, "message": "缺少task_id或step_name"}, ensure_ascii=False)
|
||||||
|
|
||||||
|
# Parse content
|
||||||
|
if isinstance(content_raw, str):
|
||||||
|
try:
|
||||||
|
content = json.loads(content_raw)
|
||||||
|
except Exception:
|
||||||
|
content = {"text": content_raw}
|
||||||
|
else:
|
||||||
|
content = content_raw
|
||||||
|
|
||||||
|
updates = {step_name: {"content": content}}
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = await pipeline_modify(tenant_id, task_id, updates, rerun_from)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
return json.dumps({"success": False, "message": str(e)}, ensure_ascii=False)
|
||||||
13
wwwroot/api/task_node.dspy
Normal file
13
wwwroot/api/task_node.dspy
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
tenant_id = (await get_userorgid()) or '0'
|
||||||
|
task_id = params_kw.get('task_id', '')
|
||||||
|
step_name = params_kw.get('step_name', '')
|
||||||
|
version = params_kw.get('version', None)
|
||||||
|
|
||||||
|
if not task_id or not step_name:
|
||||||
|
return json.dumps({"success": False, "message": "缺少task_id或step_name"}, ensure_ascii=False)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = await pipeline_node(tenant_id, task_id, step_name, version)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
return json.dumps({"success": False, "message": str(e)}, ensure_ascii=False)
|
||||||
22
wwwroot/api/task_submit.dspy
Normal file
22
wwwroot/api/task_submit.dspy
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
tenant_id = (await get_userorgid()) or '0'
|
||||||
|
pipeline_id = params_kw.get('pipeline_id', '')
|
||||||
|
title = params_kw.get('title', '')
|
||||||
|
owner_id = await get_user()
|
||||||
|
|
||||||
|
if not pipeline_id:
|
||||||
|
return json.dumps({"success": False, "message": "缺少产线ID"}, ensure_ascii=False)
|
||||||
|
if not title:
|
||||||
|
return json.dumps({"success": False, "message": "缺少任务标题"}, ensure_ascii=False)
|
||||||
|
|
||||||
|
# Collect optional params
|
||||||
|
task_params = {}
|
||||||
|
for key in ['input_audio', 'input_video', 'input_text', 'lyrics', 'mode', 'scene']:
|
||||||
|
val = params_kw.get(key, '')
|
||||||
|
if val:
|
||||||
|
task_params[key] = val
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = await pipeline_submit(tenant_id, pipeline_id, owner_id, title, task_params)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
return json.dumps({"success": False, "message": str(e)}, ensure_ascii=False)
|
||||||
28
wwwroot/index.ui
Normal file
28
wwwroot/index.ui
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {"width": "100%", "height": "100%", "padding": "20px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {"width": "100%", "justifyContent": "space-between", "alignItems": "center", "marginBottom": "16px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{"widgettype": "Title", "options": {"text": "产线任务", "cfontsize": 24}},
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {"label": "提交新任务", "icon": "plus"},
|
||||||
|
"binds": [{
|
||||||
|
"wid": "self", "event": "click", "actiontype": "urlwidget",
|
||||||
|
"target": "app.pipeline_task_content",
|
||||||
|
"options": {"url": "{{entire_url('task_submit.ui')}}"},
|
||||||
|
"mode": "replace"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"id": "pipeline_task_content",
|
||||||
|
"options": {"width": "100%", "flex": "1"}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
74
wwwroot/pipeline_task.js
Normal file
74
wwwroot/pipeline_task.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// pipeline_task.js — 产线任务交互辅助函数
|
||||||
|
|
||||||
|
var currentTaskId = '';
|
||||||
|
|
||||||
|
// 加载任务列表
|
||||||
|
function loadTaskList() {
|
||||||
|
var filterPipeline = $('[name="filter_pipeline"]').val() || '';
|
||||||
|
var url = entire_url('api/task_list.dspy');
|
||||||
|
if (filterPipeline) {
|
||||||
|
url += '?pipeline_id=' + filterPipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.get(url, function(resp) {
|
||||||
|
var data = typeof resp === 'string' ? JSON.parse(resp) : resp;
|
||||||
|
if (!data.success) {
|
||||||
|
$('#task_table_area').html('<div class="alert error">' + (data.message || '加载失败') + '</div>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tasks = data.tasks || [];
|
||||||
|
if (tasks.length === 0) {
|
||||||
|
$('#task_table_area').html('<div class="empty-state">暂无任务</div>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var html = '<table class="data-table"><thead><tr>';
|
||||||
|
html += '<th>任务ID</th><th>标题</th><th>状态</th><th>版本</th><th>创建时间</th><th>操作</th>';
|
||||||
|
html += '</tr></thead><tbody>';
|
||||||
|
|
||||||
|
tasks.forEach(function(t) {
|
||||||
|
html += '<tr>';
|
||||||
|
html += '<td>' + (t.id || '').substring(0, 8) + '</td>';
|
||||||
|
html += '<td>' + (t.title || '') + '</td>';
|
||||||
|
html += '<td><span class="badge state-' + (t.state || '') + '">' + (t.state || '') + '</span></td>';
|
||||||
|
html += '<td>v' + (t.current_version || 1) + '</td>';
|
||||||
|
html += '<td>' + (t.created_at || '') + '</td>';
|
||||||
|
html += '<td><button class="btn-small" onclick="viewTask(\'' + t.id + '\')">查看</button></td>';
|
||||||
|
html += '</tr>';
|
||||||
|
});
|
||||||
|
|
||||||
|
html += '</tbody></table>';
|
||||||
|
$('#task_table_area').html(html);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看任务详情
|
||||||
|
function viewTask(taskId) {
|
||||||
|
currentTaskId = taskId;
|
||||||
|
var url = entire_url('task_detail.ui');
|
||||||
|
window.location.href = url + '?task_id=' + taskId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 控制任务(暂停/恢复/取消)
|
||||||
|
function controlTask(action) {
|
||||||
|
if (!currentTaskId) return;
|
||||||
|
|
||||||
|
var url = entire_url('api/task_control.dspy');
|
||||||
|
$.post(url, {task_id: currentTaskId, action: action}, function(resp) {
|
||||||
|
var data = typeof resp === 'string' ? JSON.parse(resp) : resp;
|
||||||
|
if (data.success) {
|
||||||
|
alert('操作成功: ' + data.message);
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
alert('操作失败: ' + (data.message || '未知错误'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面加载完成
|
||||||
|
$(function() {
|
||||||
|
if ($('#task_table_area').length > 0) {
|
||||||
|
loadTaskList();
|
||||||
|
}
|
||||||
|
});
|
||||||
73
wwwroot/task_detail.ui
Normal file
73
wwwroot/task_detail.ui
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {"width": "100%", "padding": "16px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {"width": "100%", "marginBottom": "16px", "gap": "12px", "alignItems": "center"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {"label": "返回列表", "icon": "arrow-left"},
|
||||||
|
"binds": [{
|
||||||
|
"wid": "self", "event": "click", "actiontype": "urlwidget",
|
||||||
|
"target": "app.pipeline_task_content",
|
||||||
|
"options": {"url": "{{entire_url('task_list.ui')}}"},
|
||||||
|
"mode": "replace"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{"widgettype": "Title", "options": {"text": "任务详情", "cfontsize": 20}},
|
||||||
|
{"widgettype": "Text", "options": {"text": "", "id": "detail_task_title"}},
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {"label": "暂停", "icon": "pause", "id": "btn_pause"},
|
||||||
|
"binds": [{
|
||||||
|
"wid": "self", "event": "click", "actiontype": "script",
|
||||||
|
"target": "detail_steps_area",
|
||||||
|
"script": "controlTask('pause');"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {"label": "恢复", "icon": "play", "id": "btn_resume"},
|
||||||
|
"binds": [{
|
||||||
|
"wid": "self", "event": "click", "actiontype": "script",
|
||||||
|
"target": "detail_steps_area",
|
||||||
|
"script": "controlTask('resume');"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {"label": "取消", "icon": "stop", "id": "btn_cancel"},
|
||||||
|
"binds": [{
|
||||||
|
"wid": "self", "event": "click", "actiontype": "script",
|
||||||
|
"target": "detail_steps_area",
|
||||||
|
"script": "controlTask('cancel');"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {"width": "100%", "flex": "1", "gap": "16px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"id": "detail_steps_area",
|
||||||
|
"options": {"width": "50%", "minHeight": "400px", "bgcolor": "var(--card-bg)", "padding": "16px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{"widgettype": "Text", "options": {"text": "步骤列表加载中..."}}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"id": "detail_node_area",
|
||||||
|
"options": {"width": "50%", "minHeight": "400px", "bgcolor": "var(--card-bg)", "padding": "16px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{"widgettype": "Text", "options": {"text": "点击左侧步骤查看产物"}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
42
wwwroot/task_list.ui
Normal file
42
wwwroot/task_list.ui
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {"width": "100%", "padding": "16px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {"width": "100%", "marginBottom": "16px", "gap": "12px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Input",
|
||||||
|
"options": {"name": "filter_pipeline", "placeholder": "按产线筛选", "width": "200px"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {"label": "查询", "icon": "search"},
|
||||||
|
"binds": [{
|
||||||
|
"wid": "self", "event": "click", "actiontype": "script",
|
||||||
|
"target": "task_table_area",
|
||||||
|
"script": "loadTaskList();"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {"label": "刷新", "icon": "refresh"},
|
||||||
|
"binds": [{
|
||||||
|
"wid": "self", "event": "click", "actiontype": "script",
|
||||||
|
"target": "task_table_area",
|
||||||
|
"script": "loadTaskList();"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"id": "task_table_area",
|
||||||
|
"options": {"width": "100%", "flex": "1", "minHeight": "400px", "bgcolor": "var(--card-bg)", "padding": "16px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{"widgettype": "Text", "options": {"text": "加载中..."}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
59
wwwroot/task_submit.ui
Normal file
59
wwwroot/task_submit.ui
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {"width": "100%", "padding": "16px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "HBox",
|
||||||
|
"options": {"width": "100%", "marginBottom": "16px", "alignItems": "center"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {"label": "返回列表", "icon": "arrow-left"},
|
||||||
|
"binds": [{
|
||||||
|
"wid": "self", "event": "click", "actiontype": "urlwidget",
|
||||||
|
"target": "app.pipeline_task_content",
|
||||||
|
"options": {"url": "{{entire_url('task_list.ui')}}"},
|
||||||
|
"mode": "replace"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{"widgettype": "Title", "options": {"text": "提交新任务", "cfontsize": 20}}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {"width": "600px", "bgcolor": "var(--card-bg)", "padding": "24px"},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Form",
|
||||||
|
"options": {
|
||||||
|
"name": "submit_form",
|
||||||
|
"url": "{{entire_url('api/task_submit.dspy')}}",
|
||||||
|
"method": "POST"
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "Input",
|
||||||
|
"options": {"name": "pipeline_id", "label": "产线ID", "required": true, "width": "100%"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Input",
|
||||||
|
"options": {"name": "title", "label": "任务标题", "required": true, "width": "100%"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Input",
|
||||||
|
"options": {"name": "mode", "label": "模式(可选)", "width": "100%"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "TextArea",
|
||||||
|
"options": {"name": "input_text", "label": "输入文本(可选)", "width": "100%", "rows": 6}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "Button",
|
||||||
|
"options": {"label": "提交", "actiontype": "method", "method": "submit"}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user