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}]} + ] +}