fix(workspace): 二级URL与office端点透传pipeline_id+_generic分支——通用助手查看/编辑文件报'文件不存在'根因

与 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(独立仓库另行部署)
This commit is contained in:
ymq 2026-09-17 23:27:19 +08:00
parent 6b326e5563
commit b02ee5f345
5 changed files with 46 additions and 5 deletions

View File

@ -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": ""}

View File

@ -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": "未指定文件或无工作空间"}

View File

@ -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_id2026-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},

View File

@ -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']

View File

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