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()