pipeline-sdlc/wwwroot/api/office_read.dspy
ymq 964f475067 feat(workspace): xlsx在线查看/编辑接入(2026-09-18用户要求)
- office_read.dspy: 按扩展名分流——xlsx/xlsm调univer-office的xlsx-to-workbookdata
  返回workbookData;docx原链路不变(顺带f-string改拼接合规)
- office_save.dspy: workbookData/documentData双字段分流,xlsx调workbook-data-to-xlsx回写
- workspace_view/open.dspy: office_exts扩为['.docx','.xlsx','.xlsm'],
  xlsx与docx同享在线查看(mode=view只读)+在线编辑+下载按钮
- 配套: univer-office仓11d83bc(IWorkbookData双向转换器+sheets插件+44断言往返自测)
2026-09-18 10:59:51 +08:00

76 lines
3.0 KiB
Plaintext
Raw Permalink 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.

# office_read.dspy - 读取工作空间 docx 文件,转 markdown 返回给 univer-office 前端
import os
import aiohttp
file_id = (params_kw or {}).get('file', '').strip()
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-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": ""}
full_path = resolve_workspace_path(project_dir, space_dir, file_id)
# 路径穿越校验
real_ws = os.path.realpath(space_dir)
real_full = os.path.realpath(full_path)
if not real_full.startswith(real_ws + os.sep):
return {"error": "非法路径", "markdown": ""}
if not os.path.isfile(full_path):
return {"error": "文件不存在", "markdown": ""}
# 按扩展名分流xlsx → IWorkbookData表格其余docx→ IDocumentData文档
# 2026-09-18 xlsx 在线查看/编辑接入)
_is_sheet = file_id.lower().endswith(('.xlsx', '.xlsm'))
# 读文件 bytes
with open(full_path, 'rb') as f:
file_bytes = f.read()
# 调 univer-office 转换(格式保真,跳过 markdown
try:
timeout = aiohttp.ClientTimeout(total=60)
async with aiohttp.ClientSession(timeout=timeout) as session:
if _is_sheet:
async with session.post(
'http://127.0.0.1:19091/convert/xlsx-to-workbookdata',
data=file_bytes,
headers={'Content-Type': 'application/octet-stream'},
) as resp:
if resp.status != 200:
return {"error": "转换失败 HTTP " + str(resp.status), "workbookData": None}
workbook_data = await resp.json()
return {"workbookData": workbook_data}
else:
async with session.post(
'http://127.0.0.1:19091/convert/docx-to-docdata',
data=file_bytes,
headers={'Content-Type': 'application/octet-stream'},
) as resp:
if resp.status != 200:
return {"error": "转换失败 HTTP " + str(resp.status), "documentData": None}
doc_data = await resp.json()
return {"documentData": doc_data}
except Exception as e:
return {"error": str(e), "documentData": None, "workbookData": None}