diff --git a/wwwroot/api/todo_detail.dspy b/wwwroot/api/todo_detail.dspy index a0d04c4..efda5e0 100644 --- a/wwwroot/api/todo_detail.dspy +++ b/wwwroot/api/todo_detail.dspy @@ -256,6 +256,68 @@ async with DBPools().sqlorContext(dbname) as sor: ] }) + elif task_type == 'opp_report_confirm': + # 商机产线研发报告确认:正文=报告全文(确认人先看内容再拍板) + opp_confirm_url = entire_url("/pipeline-opportunity/api/opp_confirm_report.dspy") + opp_ppt_url = entire_url("/pipeline-opportunity/api/opp_report_ppt.dspy") + rrecs = await sor.sqlExe( + "SELECT id, software, title, content, status, ppt_path FROM opp_reports " + "WHERE confirm_task_id=${t}$", {"t": oid}) + await sor.sqlExe("COMMIT", {}) + if rrecs: + r0 = rrecs[0] + rep_id = _s(getattr(r0, 'id', '')) + md.append('## 报告信息') + md.append('') + md.append('- 方向:' + (_s(getattr(r0, 'software', '')) or '-') + + ' | 状态:' + _s(getattr(r0, 'status', ''))) + md.append('- 数据来源:数据爬取平台(每条引用可查证)') + md.append('') + md.append('## 报告全文(请审阅后确认)') + md.append('') + _content = _s(getattr(r0, 'content', '')) + if len(_content) > 40000: + _content = _content[:40000] + '\n\n…(内容过长已截断,完整内容见 PPT 下载)' + md.append(_content or '(报告正文为空)') + md.append('') + # PPT 下载按钮(报告以 PPT 存储,确认人可下载审阅) + _ppt_path = _s(getattr(r0, 'ppt_path', '')) + if _ppt_path: + action_widgets.append({ + "widgettype": "HBox", + "options": {"width": "100%", "gap": "8px", "padding": "4px 14px", "alignItems": "center"}, + "subwidgets": [ + {"widgettype": "Text", "options": {"text": "📑 报告已存为 PPT:", + "cfontsize": 0.8, "color": "#64748b", "halign": "left"}}, + {"widgettype": "Button", "options": {"label": "下载 PPT", "css": "small"}, + "binds": [{"wid": "self", "event": "click", "actiontype": "script", + "target": "self", + "script": "window.open(" + _json.dumps(opp_ppt_url + "?report_id=" + rep_id) + ",'_blank');"}]} + ] + }) + else: + md.append('## 报告信息') + md.append('') + md.append('未找到该确认任务对应的研发报告。') + md.append('') + ok_script = (_post_js(opp_confirm_url, [('human_task_id', _json.dumps(oid)), + ('decision', "'approve'")]) + _tail) + no_script = (_read_input_js('opp_confirm_comment') + + _post_js(opp_confirm_url, [('human_task_id', _json.dumps(oid)), + ('decision', "'reject'"), + ('comment', 'cv')]) + _tail) + action_widgets.append(_input_box('opp_confirm_comment', '退回意见(退回时填写,帮助修改)', '可选:修改意见')) + 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) + ] + }) + elif task_type == 'bug_acceptance': if bug_id: brecs = await sor.sqlExe( diff --git a/wwwroot/api/workspace_popup.dspy b/wwwroot/api/workspace_popup.dspy index e59a666..81e4fbb 100644 --- a/wwwroot/api/workspace_popup.dspy +++ b/wwwroot/api/workspace_popup.dspy @@ -10,10 +10,13 @@ dbname = get_module_dbname('pipeline-sdlc') import os session_id = (params_kw or {}).get('session_id', '') or '' +pipeline_id = (params_kw or {}).get('pipeline_id', '') or '' _sid_q = ("?session_id=" + session_id) if session_id else "" async with DBPools().sqlorContext(dbname) as sor: - project_dir, _ = await get_project_dir(sor, uid, session_id) + # 产线隔离:传了 pipeline_id 时,会话项目跨产线则视为无项目 + # (商机/投标产线入口不显示开发产线项目的空间) + project_dir, _ = await get_project_dir_pl(sor, uid, session_id, pipeline_id) pname = os.path.basename(project_dir) if project_dir else ''