157 lines
6.6 KiB
Plaintext
157 lines
6.6 KiB
Plaintext
# task_io.dspy - 任务的输入输出(ResourceBrowser 右侧面板,5 秒自动刷新)
|
||
|
||
import json
|
||
|
||
uid = await get_user()
|
||
if not uid:
|
||
uid = 'user-01'
|
||
|
||
task_id = (params_kw or {}).get('id', '').strip()
|
||
|
||
dbname = get_module_dbname('pipeline-sdlc')
|
||
|
||
_state_colors = {
|
||
'completed': '#16a34a',
|
||
'approved': '#16a34a',
|
||
'running': '#2563eb',
|
||
'failed': '#dc2626',
|
||
'waiting': '#f0a040',
|
||
'submitted': '#64748b',
|
||
'review': '#2196f3',
|
||
'rejected': '#dc2626',
|
||
'paused': '#f0a040',
|
||
'cancelled': '#64748b', 'qc_review': '#8b5cf6',
|
||
'qc_rejected': '#dc2626',
|
||
'verify_failed': '#f0a040',
|
||
}
|
||
|
||
if not task_id:
|
||
return json.dumps({
|
||
"widgettype": "Text",
|
||
"options": {"otext": "请选择左侧任务查看输入输出", "text": "请选择左侧任务查看输入输出", "i18n": True, "cfontsize": 0.9, "color": "#94a3b8", "padding": "16px"},
|
||
}, ensure_ascii=False)
|
||
|
||
async with DBPools().sqlorContext(dbname) as sor:
|
||
recs = await sor.sqlExe(
|
||
"SELECT id, title, role, state, params, last_error, created_at, updated_at "
|
||
"FROM pipeline_tasks WHERE id=${t}$", {"t": task_id})
|
||
if not recs:
|
||
return json.dumps({
|
||
"widgettype": "Text",
|
||
"options": {"otext": "任务不存在", "text": "任务不存在", "i18n": True, "cfontsize": 0.9, "color": "#94a3b8", "padding": "16px"},
|
||
}, ensure_ascii=False)
|
||
|
||
task = recs[0]
|
||
title = getattr(task, 'title', '') or ''
|
||
role = getattr(task, 'role', '') or ''
|
||
state = getattr(task, 'state', '') or ''
|
||
last_error = getattr(task, 'last_error', '') or ''
|
||
created_at = str(getattr(task, 'created_at', '') or '')[:16]
|
||
updated_at = str(getattr(task, 'updated_at', '') or '')[:16]
|
||
|
||
# 输入:params 里的 description / input_text
|
||
params_str = getattr(task, 'params', '') or ''
|
||
description = ''
|
||
try:
|
||
p = json.loads(params_str) if params_str else {}
|
||
description = p.get('description', '') or p.get('input_text', '') or p.get('prompt', '') or ''
|
||
except Exception:
|
||
description = params_str
|
||
|
||
# 输出:交付件(md→MdWidget渲染+下载;office/pdf→下载链接;全产线统一)
|
||
dels = await sor.sqlExe(
|
||
"SELECT deliverable_type, title, content, file_path, project_id, review_status, "
|
||
"quality_score, review_comment "
|
||
"FROM pipeline_deliverables WHERE task_id=${t}$ ORDER BY created_at DESC", {"t": task_id})
|
||
|
||
proj_file_url = entire_url("/pipeline-sdlc/api/project_file.dspy")
|
||
|
||
sc = _state_colors.get(state, '#64748b')
|
||
|
||
subwidgets = []
|
||
|
||
# 标题行:任务名 + 状态
|
||
subwidgets.append({
|
||
"widgettype": "Text",
|
||
"options": {"text": title, "halign": "left", "cfontsize": 1.15, "style": {"fontWeight": "bold", "color": "var(--ink-1)"}},
|
||
})
|
||
subwidgets.append({
|
||
"widgettype": "HBox",
|
||
"options": {"gap": "12px", "width": "100%"},
|
||
"subwidgets": [
|
||
{"widgettype": "Text", "options": {"text": state, "cfontsize": 0.75, "color": "#ffffff", "halign": "left", "padding": "1px 10px", "style": {"background": sc, "borderRadius": "12px", "fontWeight": "bold"}}},
|
||
{"widgettype": "Text", "options": {"otext": "角色: ${p0}", "text": "角色: ${p0}", "i18n": True, "i18n_params": {"p0": str(role)}, "cfontsize": 0.8, "color": "#64748b", "halign": "left"}},
|
||
{"widgettype": "Text", "options": {"text": "更新: " + updated_at, "cfontsize": 0.75, "color": "#94a3b8", "halign": "left"}},
|
||
{"widgettype": "Filler"},
|
||
],
|
||
})
|
||
|
||
if last_error:
|
||
subwidgets.append({
|
||
"widgettype": "Text",
|
||
"options": {"text": "错误: " + last_error[:300], "halign": "left", "cfontsize": 0.8, "css": "resp-error", "wrap": True},
|
||
})
|
||
|
||
# 输入
|
||
subwidgets.append({
|
||
"widgettype": "Text",
|
||
"options": {"otext": "—— 输入 ——", "text": "—— 输入 ——", "i18n": True, "halign": "left", "cfontsize": 0.85, "style": {"fontWeight": "bold", "color": "#3b82f6", "marginTop": "8px"}},
|
||
})
|
||
subwidgets.append({
|
||
"widgettype": "Text",
|
||
"options": {"text": (description or "(无)")[:4000], "halign": "left", "cfontsize": 0.85, "color": "var(--ink-2)", "wrap": True, "css": "card"},
|
||
})
|
||
|
||
# 输出
|
||
subwidgets.append({
|
||
"widgettype": "Text",
|
||
"options": {"otext": "—— 输出(交付件)——", "text": "—— 输出(交付件)——", "i18n": True, "halign": "left", "cfontsize": 0.85, "style": {"fontWeight": "bold", "color": "#16a34a", "marginTop": "8px"}},
|
||
})
|
||
if not dels:
|
||
subwidgets.append({
|
||
"widgettype": "Text",
|
||
"options": {"otext": "(暂无交付件)", "text": "(暂无交付件)", "i18n": True, "halign": "left", "cfontsize": 0.8, "color": "#94a3b8"},
|
||
})
|
||
else:
|
||
from pipeline_service.task_io_render import deliverable_card
|
||
for d in dels:
|
||
subwidgets.append(deliverable_card({
|
||
"deliverable_type": getattr(d, 'deliverable_type', '') or '',
|
||
"title": getattr(d, 'title', '') or '',
|
||
"content": getattr(d, 'content', '') or '',
|
||
"file_path": getattr(d, 'file_path', '') or '',
|
||
"project_id": getattr(d, 'project_id', '') or '',
|
||
"review_status": getattr(d, 'review_status', '') or '',
|
||
"quality_score": getattr(d, 'quality_score', '') or '',
|
||
"review_comment": getattr(d, 'review_comment', '') or '',
|
||
}, proj_file_url))
|
||
|
||
# 5 秒刷新:仅非终态任务刷新。终态(completed/approved/failed/rejected/cancelled)不再变化,
|
||
# 切到终态任务时清除定时器;非终态任务设置定时器。params.state 由 binds.params 传入 script。
|
||
refresh_script = (
|
||
"var _term=['completed','approved','failed','rejected','cancelled','qc_rejected'];"
|
||
"if(_term.indexOf(params.state)>=0){"
|
||
"if(window._task_io_timer){clearInterval(window._task_io_timer);window._task_io_timer=null;}"
|
||
"}else if(!window._task_io_timer){"
|
||
"window._task_io_timer=setInterval(function(){"
|
||
"var rb=bricks.getWidgetById('task_rb',bricks.app);"
|
||
"if(rb&&rb.current_id){var cid=rb.current_id;rb.current_id=undefined;rb.render_browser(cid);}"
|
||
"},5000);}"
|
||
)
|
||
|
||
resp = {
|
||
"widgettype": "VBox",
|
||
"options": {"width": "100%", "height": "100%", "padding": "12px", "gap": "6px", "overflowY": "auto"},
|
||
"subwidgets": subwidgets,
|
||
"binds": [{
|
||
"wid": "self",
|
||
"event": "on_parent",
|
||
"actiontype": "script",
|
||
"target": "self",
|
||
"params": {"state": state},
|
||
"script": refresh_script,
|
||
}],
|
||
}
|
||
|
||
return json.dumps(resp, ensure_ascii=False)
|