From 9d40816facc9b316892ca59083545f9735ca0260 Mon Sep 17 00:00:00 2001 From: ymq Date: Wed, 2 Sep 2026 19:01:18 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20get=5Fsession=5Fproject=5Fid=E4=BA=A7?= =?UTF-8?q?=E7=BA=BF=E4=B8=8D=E5=8C=B9=E9=85=8D=E4=B8=8D=E5=86=8D=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E9=A1=B9=E7=9B=AE=E6=8C=87=E9=92=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因: _valid只返回空串,调用方无法区分'项目已删'(应清理自愈)和 '跨产线合法上下文'(必须保留)。原实现产线不匹配也删全局/会话指针—— 平台页点一次「工作空间」就把用户在投标页的当前项目清掉(复现脚本实锤)。 修复: _valid返回(vpid, reason), gone才清理, cross只视为无项目回退 --- pipeline_service/workspace.py | 52 ++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/pipeline_service/workspace.py b/pipeline_service/workspace.py index 81a8488..a234317 100644 --- a/pipeline_service/workspace.py +++ b/pipeline_service/workspace.py @@ -152,13 +152,13 @@ async def get_session_project_id(sor, uid, session_id='', pipeline_id=''): return '' async def _valid(pid): - """pid 存在(且产线匹配,若指定)则返回 pid;否则 ''。""" + """返回 (vpid, reason):vpid 有效则返回;否则 '' + 原因('gone'=项目已删, 'cross'=跨产线)。""" pl = await _project_pipeline(pid) if pl is None: - return '' + return '', 'gone' if pipeline_id and pl and pl != pipeline_id: - return '' - return pid + return '', 'cross' + return pid, '' if session_id: try: @@ -169,18 +169,21 @@ async def get_session_project_id(sor, uid, session_id='', pipeline_id=''): if recs: pid = getattr(recs[0], 'current_project_id', '') or '' if pid: - vpid = await _valid(pid) + vpid, reason = await _valid(pid) if vpid: return vpid - # 悬空引用:清掉死记录,回退全局 - try: - await sor.sqlExe( - "DELETE FROM pipeline_session_settings " - "WHERE user_id=${u}$ AND session_id=${s}$", - {"u": uid, "s": session_id}) - await sor.sqlExe("COMMIT", {}) - except Exception: - pass + if reason == 'gone': + # 悬空引用:项目已删除 → 清掉死记录(自愈),回退全局 + try: + await sor.sqlExe( + "DELETE FROM pipeline_session_settings " + "WHERE user_id=${u}$ AND session_id=${s}$", + {"u": uid, "s": session_id}) + await sor.sqlExe("COMMIT", {}) + except Exception: + pass + # reason == 'cross':跨产线的合法上下文,不删除(删除会让用户 + # 在该产线页面丢失当前项目),只视为本会话无项目继续回退 except Exception: pass try: @@ -189,16 +192,21 @@ async def get_session_project_id(sor, uid, session_id='', pipeline_id=''): {"u": uid}) pid = getattr(recs[0], 'current_project_id', '') if recs else '' if pid: - vpid = await _valid(pid) + vpid, reason = await _valid(pid) if vpid: return vpid - try: - await sor.sqlExe( - "UPDATE pipeline_agent_settings SET current_project_id='' " - "WHERE user_id=${u}$", {"u": uid}) - await sor.sqlExe("COMMIT", {}) - except Exception: - pass + if reason == 'gone': + # 悬空引用:项目已删除 → 清全局指针(自愈) + try: + await sor.sqlExe( + "UPDATE pipeline_agent_settings SET current_project_id='' " + "WHERE user_id=${u}$", {"u": uid}) + await sor.sqlExe("COMMIT", {}) + except Exception: + pass + # reason == 'cross':全局项目属于另一产线的合法上下文,不删除 + # (2026-09-02 修复:原实现产线不匹配也删全局指针,平台页点一次 + # 「工作空间」就把用户在投标页的当前项目清掉) return '' except Exception: return ''