feat(sdlc): 流程裁剪确认UI——flow_plan_confirm.dspy确认/驳回端点(用户专属,agent无确认权);todo_detail/my_todos_popup加flow_plan_confirm待办分支(裁剪方案对照+风险提示+确认/驳回按钮)

This commit is contained in:
ymq 2026-09-11 12:58:26 +08:00
parent 4e2a10a84b
commit 4e621852da
3 changed files with 85 additions and 0 deletions

View File

@ -0,0 +1,36 @@
# flow_plan_confirm.dspy - 产线流程裁剪计划的用户确认/驳回端点
#
# 入参form-encoded
# plan_id 流程计划 idpipeline_flow_plans.id
# decision confirm | reject
# comment 驳回意见reject 时必填confirm 可空)
#
# 安全:确认动作是用户专属(同机构 + owner.superuser/项目创建者校验在
# flow_plan_capability._check_confirm_operatoragent 无对应工具,无法代替确认。
# 驳回意见落 reject_comment会话 agent 用 get_flow_plan 读到后按意见修订重提version+1
user_id = await get_user()
if not user_id:
return json.dumps({"success": False, "error": "未登录"}, ensure_ascii=False)
plan_id = str((params_kw or {}).get('plan_id') or '').strip()
decision = str((params_kw or {}).get('decision') or '').strip().lower()
comment = str((params_kw or {}).get('comment') or '').strip()
if not plan_id:
return json.dumps({"success": False, "error": "缺少 plan_id"}, ensure_ascii=False)
if decision == 'confirm':
ok, msg = await flow_plan_confirm(plan_id, operator_id=user_id)
elif decision == 'reject':
if not comment:
return json.dumps({"success": False, "error": "驳回必须填写意见(助手按意见修订流程)"},
ensure_ascii=False)
ok, msg = await flow_plan_reject(plan_id, comment, operator_id=user_id)
else:
return json.dumps({"success": False, "error": "decision 必须是 confirm 或 reject"},
ensure_ascii=False)
if ok:
return json.dumps({"success": True, "message": msg}, ensure_ascii=False)
return json.dumps({"success": False, "error": msg}, ensure_ascii=False)

View File

@ -15,11 +15,13 @@ TYPE_LABEL = {
'requirement_confirmation': '需求确认',
'design_confirmation': '设计确认',
'bug_acceptance': 'Bug 验收',
'flow_plan_confirm': '流程裁剪确认',
}
TYPE_COLOR = {
'requirement_confirmation': '#2563eb',
'design_confirmation': '#2563eb',
'bug_acceptance': '#f0a040',
'flow_plan_confirm': '#7c3aed',
}
detail_url = entire_url("/pipeline-sdlc/api/todo_detail.dspy")

View File

@ -22,12 +22,14 @@ TYPE_LABEL = {
'design_confirmation': '设计确认',
'bug_acceptance': 'Bug 验收',
'kb_ingest_confirm': '知识库入库建议',
'flow_plan_confirm': '流程裁剪确认',
}
TYPE_COLOR = {
'requirement_confirmation': '#2563eb',
'design_confirmation': '#2563eb',
'bug_acceptance': '#f0a040',
'kb_ingest_confirm': '#10b981',
'flow_plan_confirm': '#7c3aed',
}
@ -527,6 +529,51 @@ async with DBPools().sqlorContext(dbname) as sor:
md.append('未找到该项目的标书文件记录。')
md.append('')
elif task_type == 'flow_plan_confirm':
# 产线流程裁剪确认正文description已含裁剪方案对照表propose 时渲染),
# 这里补确认/驳回按钮。plan 由 confirm_task_id 反查。
fp_url = entire_url("/pipeline-sdlc/api/flow_plan_confirm.dspy")
fprecs = await sor.sqlExe(
"SELECT id, status, version FROM pipeline_flow_plans WHERE confirm_task_id=${t}$ "
"ORDER BY version DESC LIMIT 1", {"t": oid})
await sor.sqlExe("COMMIT", {})
if fprecs:
fp = fprecs[0]
plan_id = _s(getattr(fp, 'id', ''))
fp_status = _s(getattr(fp, 'status', ''))
sub_lines.append('计划版本v' + _s(getattr(fp, 'version', '')))
if fp_status != 'pending_confirm':
md.append('## 计划状态')
md.append('')
md.append('该计划已处理(当前状态:' + fp_status + '),无需再确认。')
md.append('')
else:
action_widgets.append(_input_box(
'fp_comment', '驳回意见(驳回时必填,助手按意见修订流程后重新提案)',
'请填写驳回意见'))
ok_script = (_post_js(fp_url, [('plan_id', _json.dumps(plan_id)),
('decision', "'confirm'"), ('comment', "''")]) + _tail)
no_script = (_read_input_js('fp_comment') +
"if(!cv){var mn=new bricks.Message({title:'请填写驳回意见',"
"message:'驳回前请说明需要怎么改(助手按意见修订重提)'});mn.open();return;}" +
_post_js(fp_url, [('plan_id', _json.dumps(plan_id)),
('decision', "'reject'"), ('comment', 'cv')]) + _tail)
action_widgets.append({
"widgettype": "HBox",
"options": {"width": "100%", "gap": "8px", "padding": "12px 14px", "halign": "right"},
"subwidgets": [
_btn('确认并启用', 'primary', ok_script,
conform={"title": "确认流程裁剪", "message": "确认后流程按裁剪方案生效,且不可再修改。确认?",
"conform": {"label": "确认启用"}, "discard": {"label": "再看看"}}),
_btn('驳回(按意见修订)', 'small', no_script)
]
})
else:
md.append('## 计划状态')
md.append('')
md.append('未找到对应的流程裁剪计划记录。')
md.append('')
elif task_type == 'kb_ingest_confirm':
# PM 建议文件入知识库:展示建议详情 + 文件(打开/下载)+ 批准/驳回
_sg = None