From 524abb23e6fb660120d6a49125e55df1268b2f9a Mon Sep 17 00:00:00 2001 From: ymq Date: Mon, 24 Aug 2026 16:40:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(workspace):=20=E5=B7=A5=E4=BD=9C=E7=A9=BA?= =?UTF-8?q?=E9=97=B4=E7=AB=AF=E7=82=B9=E6=8C=89=E4=BC=9A=E8=AF=9D=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E9=A1=B9=E7=9B=AE(session=5Fid)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - workspace_popup/tree/files/view/open/delete/upload/file + office_read/save 读 session_id 传 get_workspace_dir - 内部 URL 链路(查看/编辑/删除/上传/文件/vi编辑/univer-office)透传 session_id - workspace_edit.xterm 手写项目解析收敛到 get_workspace_dir(session_id) --- wwwroot/api/office_read.dspy | 4 +++- wwwroot/api/office_save.dspy | 4 +++- wwwroot/api/workspace_delete.dspy | 4 +++- wwwroot/api/workspace_file.dspy | 4 +++- wwwroot/api/workspace_files.dspy | 6 ++++-- wwwroot/api/workspace_open.dspy | 10 ++++++---- wwwroot/api/workspace_popup.dspy | 16 ++++++++++------ wwwroot/api/workspace_tree.dspy | 4 +++- wwwroot/api/workspace_upload.dspy | 4 +++- wwwroot/api/workspace_view.dspy | 6 ++++-- wwwroot/workspace_edit.xterm | 18 +++--------------- 11 files changed, 45 insertions(+), 35 deletions(-) diff --git a/wwwroot/api/office_read.dspy b/wwwroot/api/office_read.dspy index c407e3f..e4d462a 100644 --- a/wwwroot/api/office_read.dspy +++ b/wwwroot/api/office_read.dspy @@ -8,10 +8,12 @@ uid = await get_user() if not uid: uid = 'user-01' +session_id = (params_kw or {}).get('session_id', '') or '' + dbname = get_module_dbname('pipeline-sdlc') async with DBPools().sqlorContext(dbname) as sor: - ws_dir, _ = await get_workspace_dir(sor, uid) + ws_dir, _ = await get_workspace_dir(sor, uid, session_id) if not file_id or not ws_dir: return {"error": "未指定文件或无工作空间", "markdown": ""} diff --git a/wwwroot/api/office_save.dspy b/wwwroot/api/office_save.dspy index 4de63a5..42ef18e 100644 --- a/wwwroot/api/office_save.dspy +++ b/wwwroot/api/office_save.dspy @@ -10,10 +10,12 @@ uid = await get_user() if not uid: uid = 'user-01' +session_id = (params_kw or {}).get('session_id', '') or '' + dbname = get_module_dbname('pipeline-sdlc') async with DBPools().sqlorContext(dbname) as sor: - ws_dir, _ = await get_workspace_dir(sor, uid) + ws_dir, _ = await get_workspace_dir(sor, uid, session_id) if not file_id or not ws_dir: return {"success": False, "error": "未指定文件或无工作空间"} diff --git a/wwwroot/api/workspace_delete.dspy b/wwwroot/api/workspace_delete.dspy index 71cafb4..198b7f2 100644 --- a/wwwroot/api/workspace_delete.dspy +++ b/wwwroot/api/workspace_delete.dspy @@ -8,10 +8,12 @@ uid = await get_user() if not uid: uid = 'user-01' +session_id = (params_kw or {}).get('session_id', '') or '' + dbname = get_module_dbname('pipeline-sdlc') async with DBPools().sqlorContext(dbname) as sor: - ws_dir, _ = await get_workspace_dir(sor, uid) + ws_dir, _ = await get_workspace_dir(sor, uid, session_id) if not file_id or file_id == '__root__': return {"status": "error", "message": "不能删除根目录"} diff --git a/wwwroot/api/workspace_file.dspy b/wwwroot/api/workspace_file.dspy index 9fa4a6e..6ff647c 100644 --- a/wwwroot/api/workspace_file.dspy +++ b/wwwroot/api/workspace_file.dspy @@ -11,10 +11,12 @@ uid = await get_user() if not uid: uid = 'user-01' +session_id = (params_kw or {}).get('session_id', '') or '' + dbname = get_module_dbname('pipeline-sdlc') async with DBPools().sqlorContext(dbname) as sor: - ws_dir, _ = await get_workspace_dir(sor, uid) + ws_dir, _ = await get_workspace_dir(sor, uid, session_id) if not file_id or file_id == '__root__': return {"widgettype": "Message", "options": {"title": "错误", "message": "未指定文件"}} diff --git a/wwwroot/api/workspace_files.dspy b/wwwroot/api/workspace_files.dspy index 0289d14..b97c07d 100644 --- a/wwwroot/api/workspace_files.dspy +++ b/wwwroot/api/workspace_files.dspy @@ -9,10 +9,12 @@ uid = await get_user() if not uid: uid = 'user-01' +session_id = (params_kw or {}).get('session_id', '') or '' + dbname = get_module_dbname('pipeline-sdlc') async with DBPools().sqlorContext(dbname) as sor: - ws_dir, _ = await get_workspace_dir(sor, uid) + ws_dir, _ = await get_workspace_dir(sor, uid, session_id) if not folder_id or folder_id == '__root__': full_dir = ws_dir @@ -22,7 +24,7 @@ else: if not os.path.isdir(full_dir): return {"widgettype": "Text", "options": {"text": "目录不可用: " + folder_id, "cfontsize": 0.9}} -upload_url = entire_url("/pipeline-sdlc/api/workspace_upload.dspy") +upload_url = entire_url("/pipeline-sdlc/api/workspace_upload.dspy") + (("?session_id=" + session_id) if session_id else "") # 拖拽上传脚本:读取文件 → base64 → form-encoded POST → 刷新浏览器 upload_script = ( diff --git a/wwwroot/api/workspace_open.dspy b/wwwroot/api/workspace_open.dspy index adb1779..24f1a4c 100644 --- a/wwwroot/api/workspace_open.dspy +++ b/wwwroot/api/workspace_open.dspy @@ -10,10 +10,12 @@ uid = await get_user() if not uid: uid = 'user-01' +session_id = (params_kw or {}).get('session_id', '') or '' + dbname = get_module_dbname('pipeline-sdlc') async with DBPools().sqlorContext(dbname) as sor: - ws_dir, _ = await get_workspace_dir(sor, uid) + ws_dir, _ = await get_workspace_dir(sor, uid, session_id) if not file_id: return {"widgettype": "Message", "options": {"title": "打开失败", "message": "未指定文件"}} @@ -34,11 +36,11 @@ 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) +file_url = entire_url("/pipeline-sdlc/api/workspace_file.dspy") + "?id=" + quote(file_id) + (("&session_id=" + session_id) if session_id else "") # 1. 文本/源码 → Wterm + vi 编辑 if ext in text_exts: - ws_url = entire_url("/wss/pipeline-sdlc/workspace_edit.xterm") + "?id=" + quote(file_id) + ws_url = entire_url("/wss/pipeline-sdlc/workspace_edit.xterm") + "?id=" + quote(file_id) + (("&session_id=" + session_id) if session_id else "") return { "widgettype": "PopupWindow", "options": {"title": name + " (vi 编辑)", "width": "85%", "height": "85%", "auto_open": True, "resizable": True}, @@ -87,7 +89,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) + univer_url = entire_url("/univer-office/") + "?file=" + quote(file_id) + (("&session_id=" + session_id) if session_id else "") return { "widgettype": "PopupWindow", "options": {"title": name + " (在线编辑)", "width": "85%", "height": "85%", "auto_open": True, "resizable": True}, diff --git a/wwwroot/api/workspace_popup.dspy b/wwwroot/api/workspace_popup.dspy index 617eb11..0fce5a7 100644 --- a/wwwroot/api/workspace_popup.dspy +++ b/wwwroot/api/workspace_popup.dspy @@ -9,8 +9,11 @@ if not uid: dbname = get_module_dbname('pipeline-sdlc') import os +session_id = (params_kw or {}).get('session_id', '') or '' +_sid_q = ("?session_id=" + session_id) if session_id else "" + async with DBPools().sqlorContext(dbname) as sor: - ws_dir, _ = await get_workspace_dir(sor, uid) + ws_dir, _ = await get_workspace_dir(sor, uid, session_id) pname = os.path.basename(ws_dir) if ws_dir else '' @@ -26,12 +29,13 @@ async with DBPools().sqlorContext(dbname) as sor: else: view_url = entire_url("/pipeline-sdlc/api/workspace_view.dspy") edit_url = entire_url("/pipeline-sdlc/api/workspace_open.dspy") - delete_url = entire_url("/pipeline-sdlc/api/workspace_delete.dspy") + delete_url = entire_url("/pipeline-sdlc/api/workspace_delete.dspy") + _sid_q + _sid_js = _json.dumps(("&session_id=" + session_id) if session_id else "") # 查看:txt/md 用 MdWidget 渲染,其他下载查看 view_script = ( "if(!bricks.app._ws_sel)return;" - "var r=await fetch(" + _json.dumps(view_url) + "+'?id='+encodeURIComponent(bricks.app._ws_sel.id));" + "var r=await fetch(" + _json.dumps(view_url) + "+'?id='+encodeURIComponent(bricks.app._ws_sel.id)+" + _sid_js + ");" "var d=await r.json();" "bricks.widgetBuild(d,bricks.app);" ) @@ -39,7 +43,7 @@ async with DBPools().sqlorContext(dbname) as sor: # 编辑:文本 vi 编辑、媒体播放、图片预览、其他下载 edit_script = ( "if(!bricks.app._ws_sel)return;" - "var r=await fetch(" + _json.dumps(edit_url) + "+'?id='+encodeURIComponent(bricks.app._ws_sel.id));" + "var r=await fetch(" + _json.dumps(edit_url) + "+'?id='+encodeURIComponent(bricks.app._ws_sel.id)+" + _sid_js + ");" "var d=await r.json();" "bricks.widgetBuild(d,bricks.app);" ) @@ -73,7 +77,7 @@ async with DBPools().sqlorContext(dbname) as sor: "tree_options": { "widgettype": "Tree", "options": { - "dataurl": entire_url("/pipeline-sdlc/api/workspace_tree.dspy"), + "dataurl": entire_url("/pipeline-sdlc/api/workspace_tree.dspy") + _sid_q, "textField": "label", "idField": "id", "cfontsize": 1.0 @@ -82,7 +86,7 @@ async with DBPools().sqlorContext(dbname) as sor: "browser_options": { "widgettype": "urlwidget", "options": { - "url": entire_url("/pipeline-sdlc/api/workspace_files.dspy") + "url": entire_url("/pipeline-sdlc/api/workspace_files.dspy") + _sid_q }, "tools": [ { diff --git a/wwwroot/api/workspace_tree.dspy b/wwwroot/api/workspace_tree.dspy index a1774e3..232be20 100644 --- a/wwwroot/api/workspace_tree.dspy +++ b/wwwroot/api/workspace_tree.dspy @@ -8,10 +8,12 @@ uid = await get_user() if not uid: uid = 'user-01' +session_id = (params_kw or {}).get('session_id', '') or '' + dbname = get_module_dbname('pipeline-sdlc') async with DBPools().sqlorContext(dbname) as sor: - ws_dir, _ = await get_workspace_dir(sor, uid) + ws_dir, _ = await get_workspace_dir(sor, uid, session_id) if not ws_dir or not os.path.isdir(ws_dir): if not node_id: diff --git a/wwwroot/api/workspace_upload.dspy b/wwwroot/api/workspace_upload.dspy index 0c4c486..5e1b33f 100644 --- a/wwwroot/api/workspace_upload.dspy +++ b/wwwroot/api/workspace_upload.dspy @@ -11,10 +11,12 @@ uid = await get_user() if not uid: uid = 'user-01' +session_id = (params_kw or {}).get('session_id', '') or '' + dbname = get_module_dbname('pipeline-sdlc') async with DBPools().sqlorContext(dbname) as sor: - ws_dir, _ = await get_workspace_dir(sor, uid) + ws_dir, _ = await get_workspace_dir(sor, uid, session_id) if not ws_dir or not os.path.isdir(ws_dir): return {"status": "error", "message": "工作空间目录不可用"} diff --git a/wwwroot/api/workspace_view.dspy b/wwwroot/api/workspace_view.dspy index f0eb136..8467cec 100644 --- a/wwwroot/api/workspace_view.dspy +++ b/wwwroot/api/workspace_view.dspy @@ -10,10 +10,12 @@ uid = await get_user() if not uid: uid = 'user-01' +session_id = (params_kw or {}).get('session_id', '') or '' + dbname = get_module_dbname('pipeline-sdlc') async with DBPools().sqlorContext(dbname) as sor: - ws_dir, _ = await get_workspace_dir(sor, uid) + ws_dir, _ = await get_workspace_dir(sor, uid, session_id) if not file_id or file_id == '__root__': return {"widgettype": "Message", "options": {"title": "查看失败", "message": "未指定文件"}} @@ -32,7 +34,7 @@ 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) +file_url = entire_url("/pipeline-sdlc/api/workspace_file.dspy") + "?id=" + quote(file_id) + (("&session_id=" + session_id) if session_id else "") # txt/md → VScrollPanel 包裹 MdWidget 渲染(可滚动,长文档不截断) md_exts = ['.md', '.txt'] diff --git a/wwwroot/workspace_edit.xterm b/wwwroot/workspace_edit.xterm index aec918a..885a80d 100644 --- a/wwwroot/workspace_edit.xterm +++ b/wwwroot/workspace_edit.xterm @@ -8,24 +8,12 @@ uid = await get_user() if not uid: uid = 'user-01' +session_id = (params_kw or {}).get('session_id', '') or '' + dbname = get_module_dbname('pipeline-sdlc') -workspace_base = '/d/pipeline/workspaces' 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 '' - ws_dir = '' - if pid: - proj = await sor.sqlExe("SELECT name, org_id, workspace_dir FROM sd_projects WHERE id=${p}$", {"p": pid}) - if proj: - ws = getattr(proj[0], 'workspace_dir', '') or '' - if ws.startswith('/'): - ws_dir = ws - else: - pname = getattr(proj[0], 'name', '') - org_id = getattr(proj[0], 'org_id', '0') or '0' - ws_dir = workspace_base + '/' + org_id + '/' + pname + ws_dir, _ = await get_workspace_dir(sor, uid, session_id) if not file_id or not ws_dir: r = DictObject()