/** * Collabora Online 配置生成服务 * * 职责: * - 生成 Collabora iframe URL * - 生成 WOPI access token * - 构建完整的 Collabora 配置 * * @encoding UTF-8 */ import type { CollaboraConfig } from '~/components/collabora/types'; import { APP_URL, COLLABORA_URL } from '~/config/api-config'; import { WopiService } from './collabora.wopi.server'; /** * Collabora 配置生成参数 */ export interface GenerateConfigParams { fileId: string; mode: 'view' | 'edit'; userId: string; userName: string; frontendJWT: string; // 用户的前端JWT token(用于调用FastAPI) } /** * 生成 Collabora 配置 * @param params - 配置参数 * @returns Collabora 配置对象 */ export async function generateCollaboraConfig( params: GenerateConfigParams ): Promise { const { fileId, mode, userId, userName, frontendJWT } = params; // 创建 WOPI 服务实例 const wopiService = new WopiService(); // 生成 WOPI access token(2 小时有效期) const accessToken = wopiService.generateAccessToken( { fileId, mode, userId, userName, frontendJWT, }, 7200 // 2 小时 ); // 构建 WOPI Src URL const wopiSrc = `${APP_URL}/api/collabora/wopi/files/${encodeURIComponent(fileId)}`; // 构建 Collabora iframe URL const iframeUrl = buildCollaboraIframeUrl({ collaboraUrl: COLLABORA_URL, wopiSrc, accessToken, mode, }); // 提取文件名 const fileName = fileId.split('/').pop() || 'document.docx'; return { iframeUrl, accessToken, fileName, fileId, collaboraUrl: COLLABORA_URL, wopiSrc, mode, }; } /** * 构建 Collabora iframe URL * @param params - URL 构建参数 * @returns Collabora iframe URL */ function buildCollaboraIframeUrl(params: { collaboraUrl: string; wopiSrc: string; accessToken: string; mode: 'view' | 'edit'; }): string { const { collaboraUrl, wopiSrc, accessToken, mode } = params; // Collabora iframe 基础 URL // fa80579 是 Collabora 的版本号标识,实际部署时可能需要调整 const baseUrl = `${collaboraUrl}/browser/fa80579/cool.html`; const url = new URL(baseUrl); // 设置 WOPI Src url.searchParams.set('WOPISrc', wopiSrc); // 设置 access token url.searchParams.set('access_token', accessToken); // 设置 token 过期时间(毫秒) url.searchParams.set('access_token_ttl', '7200000'); // 2 小时 // UI 定制参数 const uiDefaults = [ 'UIMode=compact', // 紧凑模式 'TextRuler=false', // 隐藏标尺 'TextStatusbar=false', // 隐藏状态栏 'TextSidebar=false', // 隐藏侧边栏 'SavedUIState=false', // 不保存 UI 状态 ].join(';'); url.searchParams.set('ui_defaults', uiDefaults); // 其他 UI 参数 url.searchParams.set('closebutton', '0'); // 隐藏关闭按钮 url.searchParams.set('revisionhistory', 'false'); // 禁用修订历史 url.searchParams.set('lang', 'zh-CN'); // 设置语言为中文 // 根据模式设置权限 if (mode === 'view') { // 只读模式:通过 URL 参数限制权限 url.searchParams.set('permission', 'readonly'); } return url.toString(); }