diff --git a/wwwroot/api/task_tree.dspy b/wwwroot/api/task_tree.dspy index 9caa3e8..0fc64d3 100644 --- a/wwwroot/api/task_tree.dspy +++ b/wwwroot/api/task_tree.dspy @@ -64,15 +64,24 @@ def _iter_of(task): async with DBPools().sqlorContext(dbname) as sor: - # 当前项目 - recs = await sor.sqlExe( - "SELECT current_project_id FROM pipeline_agent_settings WHERE user_id=${u}$", - {"u": uid}) - pid = getattr(recs[0], 'current_project_id', '') if recs else '' + # 当前项目(2026-09-11 升级:会话级解析——session 优先→全局兜底, + # 含悬空自愈+产线隔离;旧实现只读全局 pipeline_agent_settings,多 tab 串项目) + _sid = (params_kw or {}).get('session_id', '') or '' + pid = '' + try: + from pipeline_service.workspace import get_session_project_id + pid = await get_session_project_id(sor, uid, _sid, 'sdlc_general') or '' + except Exception: + pid = '' + if not pid: + recs = await sor.sqlExe( + "SELECT current_project_id FROM pipeline_agent_settings WHERE user_id=${u}$", + {"u": uid}) + pid = getattr(recs[0], 'current_project_id', '') if recs else '' if not pid: if not node_id: - return json.dumps([{"id": "__root__", "label": "请先选择项目", "is_leaf": True}], ensure_ascii=False) + return json.dumps([{"id": "__root__", "label": "请先选择或新建项目", "is_leaf": True}], ensure_ascii=False) return json.dumps([], ensure_ascii=False) # 项目名 diff --git a/wwwroot/api/workspace_popup.dspy b/wwwroot/api/workspace_popup.dspy index 39220fc..232c9e1 100644 --- a/wwwroot/api/workspace_popup.dspy +++ b/wwwroot/api/workspace_popup.dspy @@ -36,12 +36,38 @@ async with DBPools().sqlorContext(dbname) as sor: pname = os.path.basename(project_dir) if project_dir else '' if not project_dir: + # 2026-09-11 用户要求:没当前项目 → 提示选择或新建项目(给直达按钮,不给死胡同) + _proj_base = entire_url("/pipeline_core/api/agent_project_popup.dspy") + _proj_q = [] + if session_id: + _proj_q.append("session_id=" + session_id) + if pipeline_id: + _proj_q.append("pipeline_id=" + pipeline_id) + + def _pbtn(label, css, op): + _js = ("var r=await fetch(" + _json.dumps(_proj_base + "?op=" + op + + (("&" + "&".join(_proj_q)) if _proj_q else "")) + ");" + "var d=await r.json();if(d){bricks.widgetBuild(d,bricks.app);}") + return {"widgettype": "Button", "options": {"label": label, "css": css}, + "binds": [{"wid": "self", "event": "click", "actiontype": "script", + "target": "self", "script": _js}]} + resp = { "widgettype": "PopupWindow", - "options": {"title": "提示", "cwidth": 30, "cheight": 8, "auto_open": True}, + "id": "ws_no_project_pw", + "options": {"title": "提示", "cwidth": 38, "cheight": 10, "auto_open": True}, "subwidgets": [{ - "widgettype": "Text", - "options": {"text": "请先在会话中切换项目", "cfontsize": 1, "color": "#64748b", "padding": "20px"} + "widgettype": "VBox", + "options": {"width": "100%", "gap": "12px", "padding": "18px 22px"}, + "subwidgets": [ + {"widgettype": "Text", + "options": {"text": "当前会话还没有项目,请先选择或新建项目", + "cfontsize": 1, "color": "#64748b"}}, + {"widgettype": "HBox", + "options": {"width": "100%", "gap": "10px"}, + "subwidgets": [_pbtn("✨ 新建项目", "primary", "new"), + _pbtn("🔀 切换项目", "small", "switch")]} + ] }] } else: