pipeline-sdlc/wwwroot/api/workspace_tree.dspy

131 lines
4.2 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# workspace_tree.dspy - 项目目录树:根=项目目录,额外挂项目用到的 apps/modules 子目录
import os
node_id = (params_kw or {}).get('id', '').strip()
# 前端 id 可能被多层编码循环解码2026-09-03 中文目录名根因)
from urllib.parse import unquote as _unq
for _ in range(4):
if '%' not in node_id:
break
_s2 = _unq(node_id)
if _s2 == node_id:
break
node_id = _s2
uid = await get_user()
if not uid:
uid = 'user-01'
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_pl(sor, uid, session_id, pipeline_id)
space_dir, _ = await get_space_dir(sor, uid, session_id)
# 通用会话pipeline_id=_generic锁用户专属目录 _general/{uid}
# 不进入任何项目的工作空间2026-09-08 用户要求)
if pipeline_id == '_generic':
_gd = generic_workspace_dir(uid)
os.makedirs(_gd, exist_ok=True)
project_dir = _gd
space_dir = _gd
# 提前读出项目用到的 apps/modulessor 在块内有效,块外调用会因 sor 关闭返回空)
_apps, _modules = await get_project_apps_modules(sor, uid, session_id)
if not project_dir or not os.path.isdir(project_dir):
if not node_id:
return [{"id": "__root__", "parentid": "", "label": "📁 项目目录(不可用)", "path": project_dir, "is_leaf": False}]
return []
# 初始加载:只返回根节点
if not node_id:
return [{
"id": "__root__",
"parentid": "",
"label": "📁 " + os.path.basename(project_dir),
"path": project_dir,
"is_leaf": False
}]
# 展开节点__root__ 特殊处理(加 apps/modules 引用),@apps/@modules 扫描机构工作空间,其余扫描项目目录
if node_id == '__root__':
scan_path = project_dir
id_prefix = ''
extra_children = True
elif node_id.startswith('@apps/'):
scan_path = os.path.join(space_dir, 'apps', node_id[len('@apps/'):])
id_prefix = node_id + '/'
extra_children = False
elif node_id.startswith('@modules/'):
scan_path = os.path.join(space_dir, 'modules', node_id[len('@modules/'):])
id_prefix = node_id + '/'
extra_children = False
else:
scan_path = resolve_workspace_path(project_dir, space_dir, node_id)
id_prefix = node_id + '/'
extra_children = False
if not os.path.isdir(scan_path):
return []
items = []
# 根节点:额外挂项目用到的 apps 子目录 + modules 子目录
if extra_children:
apps, modules = _apps, _modules
for app in apps:
app_path = os.path.join(space_dir, 'apps', app)
if os.path.isdir(app_path):
items.append({
"id": "@apps/" + app,
"parentid": node_id,
"label": "📱 " + app,
"path": app_path,
"is_leaf": False
})
for m in modules:
m_path = os.path.join(space_dir, 'modules', m)
if os.path.isdir(m_path):
items.append({
"id": "@modules/" + m,
"parentid": node_id,
"label": "📦 " + m,
"path": m_path,
"is_leaf": False
})
# 扫描常规内容(子目录)
try:
entries = sorted(os.listdir(scan_path))
except Exception:
entries = []
for name in entries:
full = os.path.join(scan_path, name)
if name.startswith('.') or name == '__pycache__':
continue
if os.path.isdir(full):
has_subdir = False
try:
for sub in os.listdir(full):
if sub.startswith('.') or sub == '__pycache__':
continue
if os.path.isdir(os.path.join(full, sub)):
has_subdir = True
break
except Exception:
pass
items.append({
"id": id_prefix + name,
"parentid": node_id,
"label": "📁 " + name,
"path": full,
"is_leaf": not has_subdir
})
return items