{% set ns = namespace() %} {% set task_data = get_task_data(request) %} {% if not task_data.success %} { "widgettype": "VBox", "options": {"width": "100%", "padding": "16px"}, "subwidgets": [ { "widgettype": "Button", "options": {"label": "返回列表"}, "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": "{{task_data.message or '加载失败'}}"}} ] } {% else %} {% set task = task_data.task %} {% set steps = task.steps or [] %} {% set state_labels = {'submitted':'已提交','running':'运行中','completed':'已完成','failed':'失败','paused':'已暂停','cancelled':'已取消','waiting':'等待人工'} %} {% set step_state_labels = {'pending':'待执行','running':'执行中','completed':'已完成','failed':'失败','skipped':'已跳过','waiting':'等待人工','rejected':'已驳回'} %} {% set is_done = task.state in ('completed', 'failed', 'cancelled') %} { "widgettype": "VBox", "options": {"width": "100%", "padding": "16px"}, "subwidgets": [ { "widgettype": "HBox", "options": {"width": "100%", "marginBottom": "12px", "gap": "12px", "alignItems": "center"}, "subwidgets": [ { "widgettype": "Button", "options": {"label": "返回列表"}, "binds": [{ "wid": "self", "event": "click", "actiontype": "urlwidget", "target": "app.pipeline_task_content", "options": {"url": "{{entire_url('index.ui')}}"}, "mode": "replace" }] }, {"widgettype": "Title", "options": {"text": "任务详情 - {{json.dumps(task.title or '', ensure_ascii=False)}}", "cfontsize": 18}}, {"widgettype": "Text", "options": {"text": "状态: {{state_labels.get(task.state, task.state)}} | 版本: v{{task.current_version or 1}}"}} ] }, { "widgettype": "HBox", "options": {"width": "100%", "marginBottom": "12px", "gap": "8px"}, "subwidgets": [ {% if task.state == 'running' %} { "widgettype": "Button", "options": {"label": "暂停", "css": "warning"}, "binds": [{ "wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": "var u='{{entire_url('api/task_control.dspy')}}';var fd=new URLSearchParams();fd.append('task_id','{{task.id}}');fd.append('action','pause');fetch(u,{method:'POST',body:fd,credentials:'include'}).then(function(r){return r.json()}).then(function(d){if(d.success){location.reload()}else{alert(d.message)}})" }] }, {% endif %} {% if task.state == 'paused' %} { "widgettype": "Button", "options": {"label": "恢复", "css": "primary"}, "binds": [{ "wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": "var u='{{entire_url('api/task_control.dspy')}}';var fd=new URLSearchParams();fd.append('task_id','{{task.id}}');fd.append('action','resume');fetch(u,{method:'POST',body:fd,credentials:'include'}).then(function(r){return r.json()}).then(function(d){if(d.success){location.reload()}else{alert(d.message)}})" }] }, {% endif %} {% if not is_done %} { "widgettype": "Button", "options": {"label": "取消", "css": "danger"}, "binds": [{ "wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": "if(!confirm('确定取消任务?'))return;var u='{{entire_url('api/task_control.dspy')}}';var fd=new URLSearchParams();fd.append('task_id','{{task.id}}');fd.append('action','cancel');fetch(u,{method:'POST',body:fd,credentials:'include'}).then(function(r){return r.json()}).then(function(d){if(d.success){location.reload()}else{alert(d.message)}})" }] }, {% endif %} {% if is_done %} { "widgettype": "Button", "options": {"label": "重新开始", "css": "primary"}, "binds": [{ "wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": "if(!confirm('确定重新开始?'))return;var u='{{entire_url('api/task_restart.dspy')}}';var fd=new URLSearchParams();fd.append('task_id','{{task.id}}');fetch(u,{method:'POST',body:fd,credentials:'include'}).then(function(r){return r.json()}).then(function(d){if(d.success){location.reload()}else{alert(d.message)}})" }] } {% endif %} ] }, { "widgettype": "Text", "options": {"text": "步骤列表 ({{steps|length}} 个步骤)", "cfontsize": 14} }, {% for step in steps %} { "widgettype": "VBox", "options": {"width": "100%", "bgcolor": "var(--card-bg)", "padding": "12px", "marginBottom": "8px"}, "subwidgets": [ { "widgettype": "HBox", "options": {"width": "100%", "justifyContent": "space-between", "alignItems": "center", "marginBottom": "8px"}, "subwidgets": [ { "widgettype": "Text", "options": {"text": "{{json.dumps(step.display_name or step.step_name, ensure_ascii=False)}}{% if step.state == 'waiting' %} ⚠{% endif %}", "cfontsize": 14} }, { "widgettype": "Text", "options": {"text": "{{step_state_labels.get(step.state, step.state)}}", "color": "{% if step.state == 'completed' %}#4caf50{% elif step.state == 'waiting' %}#ff9800{% elif step.state == 'failed' %}#f44336{% else %}#888{% endif %}"} } ] }, { "widgettype": "Text", "options": {"text": "类型: {{step.step_type or '-'}} | 依赖: {{json.dumps(step.deps if step.deps is string else (step.deps or [])|join(',') or '无', ensure_ascii=False)}}"} }, {% if step.state == 'waiting' and step.human_task %} { "widgettype": "HBox", "options": {"width": "100%", "marginTop": "8px", "gap": "8px", "alignItems": "flex-start"}, "subwidgets": [ { "widgettype": "VBox", "options": {"width": "50%"}, "subwidgets": [ {"widgettype": "Text", "options": {"text": "⚠ 人工任务: {{step.human_task.task_type or '-'}}", "color": "#ff9800"}}, {"widgettype": "Text", "options": {"text": "处理状态: {{step.human_task.status or '-'}}"}}, {% if step.human_task.assignee_role %} {"widgettype": "Text", "options": {"text": "处理角色: {{step.human_task.assignee_role}}"}}, {% endif %} {% if step.human_task.form_schema %} {"widgettype": "Text", "options": {"text": "表单: {{json.dumps(step.human_task.form_schema, ensure_ascii=False)}}"}}, {% endif %} { "widgettype": "Button", "options": {"label": "查看产物", "css": "text"}, "binds": [{ "wid": "self", "event": "click", "actiontype": "urlwidget", "target": "app.pipeline_task_content", "options": {"url": "{{entire_url('step_panel.ui')}}?task_id={{task.id}}&step_name={{step.step_name}}"}, "mode": "replace" }] } ] }, {% if step.human_task.task_type == 'human_task' and step.human_task.status == 'pending' %} { "widgettype": "Form", "options": { "width": "50%", "name": "human_form_{{loop.index}}", "submit_url": "{{entire_url('api/human_complete.dspy')}}", "fields": [ {"name": "task_id", "uitype": "hide", "value": "{{task.id}}"}, {"name": "step_name", "uitype": "hide", "value": "{{step.step_name}}"}, {"name": "result", "uitype": "text", "label": "处理结果 (JSON)", "required": true, "placeholder": "{\"status\":\"ok\",\"note\":\"已完成\"}"} ] }, "binds": [{ "wid": "self", "event": "submited", "actiontype": "script", "target": "self", "script": "location.reload()" }] }, {% elif step.human_task.task_type == 'approval_gate' and step.human_task.status == 'pending' %} { "widgettype": "VBox", "options": {"width": "50%", "gap": "8px"}, "subwidgets": [ { "widgettype": "Button", "options": {"label": "✓ 通过", "css": "primary"}, "binds": [{ "wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": "var u='{{entire_url('api/approval_approve.dspy')}}';var fd=new URLSearchParams();fd.append('task_id','{{task.id}}');fd.append('step_name','{{step.step_name}}');fetch(u,{method:'POST',body:fd,credentials:'include'}).then(function(r){return r.json()}).then(function(d){if(d.success){location.reload()}else{alert(d.message)}})" }] }, { "widgettype": "Button", "options": {"label": "✗ 驳回", "css": "danger"}, "binds": [{ "wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": "var reason=prompt('驳回理由:');if(!reason)return;var u='{{entire_url('api/approval_reject.dspy')}}';var fd=new URLSearchParams();fd.append('task_id','{{task.id}}');fd.append('step_name','{{step.step_name}}');fd.append('comments',reason);fetch(u,{method:'POST',body:fd,credentials:'include'}).then(function(r){return r.json()}).then(function(d){if(d.success){location.reload()}else{alert(d.message)}})" }] } ] }, {% endif %} {"widgettype": "Filler"} ] }, {% elif step.state in ('completed', 'failed') %} { "widgettype": "HBox", "options": {"width": "100%", "marginTop": "8px", "gap": "8px"}, "subwidgets": [ { "widgettype": "Button", "options": {"label": "查看产物", "css": "text"}, "binds": [{ "wid": "self", "event": "click", "actiontype": "urlwidget", "target": "app.pipeline_task_content", "options": {"url": "{{entire_url('step_panel.ui')}}?task_id={{task.id}}&step_name={{step.step_name}}"}, "mode": "replace" }] }, { "widgettype": "Button", "options": {"label": "修改并重跑", "css": "warning"}, "binds": [{ "wid": "self", "event": "click", "actiontype": "urlwidget", "target": "app.pipeline_task_content", "options": {"url": "{{entire_url('step_panel.ui')}}?task_id={{task.id}}&step_name={{step.step_name}}&mode=edit"}, "mode": "replace" }] } ] }, {% else %} { "widgettype": "Button", "options": {"label": "查看详情", "css": "text"}, "binds": [{ "wid": "self", "event": "click", "actiontype": "urlwidget", "target": "app.pipeline_task_content", "options": {"url": "{{entire_url('step_panel.ui')}}?task_id={{task.id}}&step_name={{step.step_name}}"}, "mode": "replace" }] }, {% endif %} {"widgettype": "Filler"} ] }{% if not loop.last %},{% endif %} {% endfor %} ] } {% endif %}