From b02ee5f34565b0bde17607262149cd0d36c35e6b Mon Sep 17 00:00:00 2001 From: ymq Date: Thu, 17 Sep 2026 23:27:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(workspace):=20=E4=BA=8C=E7=BA=A7URL?= =?UTF-8?q?=E4=B8=8Eoffice=E7=AB=AF=E7=82=B9=E9=80=8F=E4=BC=A0pipeline=5Fi?= =?UTF-8?q?d+=5Fgeneric=E5=88=86=E6=94=AF=E2=80=94=E2=80=94=E9=80=9A?= =?UTF-8?q?=E7=94=A8=E5=8A=A9=E6=89=8B=E6=9F=A5=E7=9C=8B/=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=96=87=E4=BB=B6=E6=8A=A5'=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=8D=E5=AD=98=E5=9C=A8'=E6=A0=B9=E5=9B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 与 f0c4c10(upload_url) 同族缺陷全量排查修复,共5处: 1. workspace_view.dspy: md_url(file_url)只拼session_id漏pipeline_id→ 通用助手(_generic无session_id)下MdWidget二次请求workspace_file.dspy 回退全局项目指针→在别产线空间找文件→弹'文件不存在: projects/调研1/docs/xxx.md' (2026-09-17实测复现+修复验证) 2. workspace_open.dspy: file_url/ws_url(xterm)/univer_url三处同病灶,统一_fq_s双透传 3. workspace_edit.xterm: 根本不读pipeline_id且用无隔离get_project_dir→ 改get_project_dir_pl+_generic锁_general/{uid}(与9个子端点对齐) 4. office_read.dspy/office_save.dspy: 读了pipeline_id但缺_generic分支→ 通用助手在线编辑docx报'未指定文件或无工作空间',补齐分支 univer-office前端main.ts配套透传pipeline_id(独立仓库另行部署) --- wwwroot/api/office_read.dspy | 7 +++++++ wwwroot/api/office_save.dspy | 7 +++++++ wwwroot/api/workspace_open.dspy | 15 ++++++++++++--- wwwroot/api/workspace_view.dspy | 11 ++++++++++- wwwroot/workspace_edit.xterm | 11 ++++++++++- 5 files changed, 46 insertions(+), 5 deletions(-) diff --git a/wwwroot/api/office_read.dspy b/wwwroot/api/office_read.dspy index 7cad223..2ec85a9 100644 --- a/wwwroot/api/office_read.dspy +++ b/wwwroot/api/office_read.dspy @@ -17,6 +17,13 @@ async with DBPools().sqlorContext(dbname) as sor: # 产线隔离:跨产线项目视为无项目(与弹窗入口一致,防绕过) project_dir, _ = await get_project_dir_pl(sor, uid, session_id, pipeline_id) space_dir, _ = await get_space_dir(sor, uid, session_id) + # 通用会话(pipeline_id=_generic):锁用户专属目录 _general/{uid} + # (2026-09-17 补齐:此前缺该分支,通用助手在线编辑 docx 报「未指定文件或无工作空间」) + if pipeline_id == '_generic': + _gd = generic_workspace_dir(uid) + os.makedirs(_gd, exist_ok=True) + project_dir = _gd + space_dir = _gd if not file_id or not space_dir: return {"error": "未指定文件或无工作空间", "markdown": ""} diff --git a/wwwroot/api/office_save.dspy b/wwwroot/api/office_save.dspy index 9c367da..e34ae1f 100644 --- a/wwwroot/api/office_save.dspy +++ b/wwwroot/api/office_save.dspy @@ -19,6 +19,13 @@ async with DBPools().sqlorContext(dbname) as sor: # 产线隔离:跨产线项目视为无项目(与弹窗入口一致,防绕过) project_dir, _ = await get_project_dir_pl(sor, uid, session_id, pipeline_id) space_dir, _ = await get_space_dir(sor, uid, session_id) + # 通用会话(pipeline_id=_generic):锁用户专属目录 _general/{uid} + # (2026-09-17 补齐:此前缺该分支,通用助手在线编辑 docx 保存失败) + if pipeline_id == '_generic': + _gd = generic_workspace_dir(uid) + os.makedirs(_gd, exist_ok=True) + project_dir = _gd + space_dir = _gd if not file_id or not space_dir: return {"success": False, "error": "未指定文件或无工作空间"} diff --git a/wwwroot/api/workspace_open.dspy b/wwwroot/api/workspace_open.dspy index 7dedb78..28491db 100644 --- a/wwwroot/api/workspace_open.dspy +++ b/wwwroot/api/workspace_open.dspy @@ -56,11 +56,20 @@ audio_exts = ['.mp3', '.wav', '.aac', '.flac', '.m4a', '.ogg'] image_exts = ['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.bmp', '.ico'] office_exts = ['.docx'] # 在线编辑(univer-office)。xlsx/ppt 后续接入 Univer sheet/slide 插件 -file_url = entire_url("/pipeline-sdlc/api/workspace_file.dspy") + "?id=" + quote(file_id) + (("&session_id=" + session_id) if session_id else "") +# 二级 URL 双透传 session_id + pipeline_id(2026-09-17 根因同 workspace_view/upload): +# 通用助手(pipeline_id=_generic、无 session_id)下漏拼 pipeline_id 会让下游端点 +# (workspace_file/workspace_edit.xterm/univer-office)回退全局项目指针 → 「文件不存在」。 +_fq = [] +if session_id: + _fq.append("session_id=" + session_id) +if pipeline_id: + _fq.append("pipeline_id=" + pipeline_id) +_fq_s = ("&" + "&".join(_fq)) if _fq else "" +file_url = entire_url("/pipeline-sdlc/api/workspace_file.dspy") + "?id=" + quote(file_id) + _fq_s # 1. 文本/源码 → Wterm + vi 编辑 if ext in text_exts: - ws_url = entire_url("/wss/pipeline-sdlc/workspace_edit.xterm") + "?id=" + quote(file_id) + (("&session_id=" + session_id) if session_id else "") + ws_url = entire_url("/wss/pipeline-sdlc/workspace_edit.xterm") + "?id=" + quote(file_id) + _fq_s return { "widgettype": "PopupWindow", "options": {"title": name + " (vi 编辑)", "width": "85%", "height": "85%", "auto_open": True, "resizable": True}, @@ -109,7 +118,7 @@ if ext in image_exts: # 4. office 文档 → iframe 嵌入 univer-office 在线编辑 if ext in office_exts: - univer_url = entire_url("/univer-office/") + "?file=" + quote(file_id) + (("&session_id=" + session_id) if session_id else "") + univer_url = entire_url("/univer-office/") + "?file=" + quote(file_id) + _fq_s return { "widgettype": "PopupWindow", "options": {"title": name + " (在线编辑)", "width": "85%", "height": "85%", "auto_open": True, "resizable": True}, diff --git a/wwwroot/api/workspace_view.dspy b/wwwroot/api/workspace_view.dspy index 73d64cd..468b70b 100644 --- a/wwwroot/api/workspace_view.dspy +++ b/wwwroot/api/workspace_view.dspy @@ -56,7 +56,16 @@ if not os.path.isfile(full_path): name = os.path.basename(full_path) ext = os.path.splitext(name)[1].lower() -file_url = entire_url("/pipeline-sdlc/api/workspace_file.dspy") + "?id=" + quote(file_id) + (("&session_id=" + session_id) if session_id else "") +# 二级 URL 必须与本级同参数(session_id + pipeline_id 双透传,2026-09-17 根因同 upload_url): +# 通用助手(pipeline_id=_generic、无 session_id)下漏拼 pipeline_id 会让 workspace_file.dspy +# 回退全局项目指针 → 在错误空间找文件 → MdWidget 显示「文件不存在」JSON。 +_fq = [] +if session_id: + _fq.append("session_id=" + session_id) +if pipeline_id: + _fq.append("pipeline_id=" + pipeline_id) +_fq_s = ("&" + "&".join(_fq)) if _fq else "" +file_url = entire_url("/pipeline-sdlc/api/workspace_file.dspy") + "?id=" + quote(file_id) + _fq_s # txt/md/json → VScrollPanel 包裹 MdWidget 渲染(可滚动,长文档不截断;json 直接显示正文不下载) md_exts = ['.md', '.txt', '.json'] diff --git a/wwwroot/workspace_edit.xterm b/wwwroot/workspace_edit.xterm index a0b01f5..5ea3d57 100644 --- a/wwwroot/workspace_edit.xterm +++ b/wwwroot/workspace_edit.xterm @@ -17,12 +17,21 @@ if not uid: return r session_id = (params_kw or {}).get('session_id', '') or '' +pipeline_id = (params_kw or {}).get('pipeline_id', '') or '' dbname = get_module_dbname('pipeline-sdlc') async with DBPools().sqlorContext(dbname) as sor: - project_dir, _ = await get_project_dir(sor, uid, session_id) + # 产线隔离 + pipeline_id 透传(2026-09-17 修复:此前不读 pipeline_id, + # 通用助手 _generic 入口下解析到全局指针的错误项目空间 → 「未指定文件」/编辑错目录) + project_dir, _ = await get_project_dir_pl(sor, uid, session_id, pipeline_id) space_dir, _ = await get_space_dir(sor, uid, session_id) + # 通用会话(pipeline_id=_generic):锁用户专属目录 _general/{uid} + if pipeline_id == '_generic': + _gd = generic_workspace_dir(uid) + os.makedirs(_gd, exist_ok=True) + project_dir = _gd + space_dir = _gd if not file_id or not space_dir: r = DictObject()