pipeline-sdlc/wwwroot/api/task_io.dspy

157 lines
6.6 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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)