From 17b9f1f7f0dcd7b00d4332c5c1842a58ffd01c93 Mon Sep 17 00:00:00 2001 From: ymq Date: Wed, 19 Aug 2026 13:31:53 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B7=A5=E4=BD=9C=E7=A9=BA=E9=97=B4?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=88=97=E8=A1=A8=E5=A2=9E=E5=8A=A0=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=8C=89=E9=92=AE(=E5=A4=8D=E7=94=A8=E5=8E=9F?= =?UTF-8?q?=E6=89=93=E5=BC=80=E9=80=BB=E8=BE=91)=EF=BC=8C=E6=9F=A5?= =?UTF-8?q?=E7=9C=8B=E6=8C=89=E9=92=AE=E6=94=B9=E4=B8=BA=20txt/md=20?= =?UTF-8?q?=E7=94=A8=20MdWidget=20=E6=B8=B2=E6=9F=93=E3=80=81=E5=85=B6?= =?UTF-8?q?=E4=BB=96=E4=B8=8B=E8=BD=BD=E6=9F=A5=E7=9C=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/load_path.py | 1 + wwwroot/api/workspace_popup.dspy | 26 ++++++++++---- wwwroot/api/workspace_view.dspy | 62 ++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 wwwroot/api/workspace_view.dspy diff --git a/scripts/load_path.py b/scripts/load_path.py index 5fe6d29..3038107 100644 --- a/scripts/load_path.py +++ b/scripts/load_path.py @@ -108,6 +108,7 @@ PATHS_LOGINED = [ f"/{MOD}/api/workspace_tree.dspy", f"/{MOD}/api/workspace_files.dspy", f"/{MOD}/api/workspace_open.dspy", + f"/{MOD}/api/workspace_view.dspy", f"/{MOD}/api/workspace_file.dspy", f"/{MOD}/api/download_project.dspy", f"/{MOD}/api/workspace_upload.dspy", diff --git a/wwwroot/api/workspace_popup.dspy b/wwwroot/api/workspace_popup.dspy index fcd4252..191ac05 100644 --- a/wwwroot/api/workspace_popup.dspy +++ b/wwwroot/api/workspace_popup.dspy @@ -24,13 +24,22 @@ async with DBPools().sqlorContext(dbname) as sor: }] } else: - open_url = entire_url("/pipeline-sdlc/api/workspace_open.dspy") + 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") - # 打开:预览选中文件 - open_script = ( + # 查看:txt/md 用 MdWidget 渲染,其他下载查看 + view_script = ( "if(!bricks.app._ws_sel)return;" - "var r=await fetch(" + _json.dumps(open_url) + "+'?id='+encodeURIComponent(bricks.app._ws_sel.id));" + "var r=await fetch(" + _json.dumps(view_url) + "+'?id='+encodeURIComponent(bricks.app._ws_sel.id));" + "var d=await r.json();" + "bricks.widgetBuild(d,bricks.app);" + ) + + # 编辑:文本 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 d=await r.json();" "bricks.widgetBuild(d,bricks.app);" ) @@ -78,8 +87,13 @@ async with DBPools().sqlorContext(dbname) as sor: "tools": [ { "widgettype": "Button", - "options": {"label": "打开", "css": "small"}, - "binds": [{"wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": open_script}] + "options": {"label": "查看", "css": "small"}, + "binds": [{"wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": view_script}] + }, + { + "widgettype": "Button", + "options": {"label": "编辑", "css": "small"}, + "binds": [{"wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": edit_script}] }, { "widgettype": "Button", diff --git a/wwwroot/api/workspace_view.dspy b/wwwroot/api/workspace_view.dspy new file mode 100644 index 0000000..ef1b7c4 --- /dev/null +++ b/wwwroot/api/workspace_view.dspy @@ -0,0 +1,62 @@ +# workspace_view.dspy - 查看文件:txt/md 用 MdWidget 渲染,其他文档下载查看 + +import os +import json as _json +from urllib.parse import quote + +file_id = (params_kw or {}).get('id', '').strip() + +uid = await get_user() +if not uid: + uid = 'user-01' + +dbname = get_module_dbname('pipeline-sdlc') + +async with DBPools().sqlorContext(dbname) as sor: + ws_dir, _ = await get_workspace_dir(sor, uid) + +if not file_id or file_id == '__root__': + return {"widgettype": "Message", "options": {"title": "查看失败", "message": "未指定文件"}} + +full_path = ws_dir + '/' + file_id if ws_dir else file_id + +# 路径穿越校验 +real_ws = os.path.realpath(ws_dir) +real_full = os.path.realpath(full_path) +if not real_full.startswith(real_ws + os.sep): + return {"widgettype": "Message", "options": {"title": "错误", "message": "非法路径"}} + +if not os.path.isfile(full_path): + return {"widgettype": "Message", "options": {"title": "查看失败", "message": "文件不存在: " + file_id}} + +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) + +# txt/md → MdWidget 渲染 +md_exts = ['.md', '.txt'] +if ext in md_exts: + return { + "widgettype": "PopupWindow", + "options": {"title": name + " (查看)", "width": "85%", "height": "85%", "auto_open": True, "resizable": True}, + "subwidgets": [{ + "widgettype": "MdWidget", + "options": {"md_url": file_url, "width": "100%", "height": "100%"} + }] + } + +# 其他 → 下载查看 +download_url = file_url + "&download=1" +download_script = ( + "window.open(" + _json.dumps(download_url) + ",'_blank');" +) +return { + "widgettype": "PopupWindow", + "options": {"title": name, "cwidth": 34, "cheight": 12, "auto_open": True, "resizable": True}, + "subwidgets": [ + {"widgettype": "Text", "options": {"text": "该文件类型需下载后查看", "cfontsize": 1, "padding": "16px", "halign": "middle"}}, + {"widgettype": "Button", "options": {"label": "下载文件", "css": "primary"}, + "binds": [{"wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": download_script}]} + ] +}