`1️⃣ 前端请求流程 用户点击预览 ↓ CollaboraViewer.tsx (组件) ↓ fetch('/api/collabora/view?fileId=xxx&mode=view&userId=xxx&userName=xxx') ↓ 后端 API: app/api/collabora/view/route.ts ↓ 返回配置 { iframeUrl, accessToken, wopiSrc, ... } ↓ 前端渲染 2️⃣ Collabora 加载文档流程 浏览器加载 iframe ↓ Collabora 服务器 ([http://172.16.0.81:9980](http://172.16.0.81:9980)) ↓ Collabora 解析 URL 中的 WOPISrc 和 access_token ↓ Collabora 调用: GET {WOPISrc}?access_token=xxx 实际: GET [http://172.16.0.78:3000/api/collabora/wopi/files/contracts/xxx.docx?access_token=xxx](http://172.16.0.78:3000/api/collabora/wopi/files/contracts/xxx.docx?access_token=xxx) ↓ 后端 WOPI 端点: app/api/collabora/wopi/files/[...fileId]/route.ts - 验证 JWT token - 返回 CheckFileInfo (文件元数据) ↓ Collabora 再次调用: GET {WOPISrc}/contents?access_token=xxx ↓ 后端 WOPI 端点检测到 /contents 后缀 - 从 MinIO 读取文件内容 - 返回文件二进制数据 ↓ Collabora 在 iframe 中渲染文档 3️⃣ 保存文档流程(编辑模式) 用户编辑文档 → 点击保存/关闭 ↓ Collabora 调用: POST {WOPISrc}/contents?access_token=xxx 请求体: 编辑后的文档二进制数据 ↓ 后端 WOPI 端点 POST 处理器 - 验证 token 和权限 - 将文档保存到 MinIO(覆盖原文件) ↓ 返回 200 OK ↓ Collabora 显示保存成功