From b9fe57c5fa0aaf1def18de6fb52a1be2ccd0ef66 Mon Sep 17 00:00:00 2001 From: PingChuan <1259732256@qq.com> Date: Thu, 20 Nov 2025 20:36:42 +0800 Subject: [PATCH] =?UTF-8?q?temp:=E4=B8=B4=E6=97=B6=E5=A4=87=E4=BB=BD?= =?UTF-8?q?=EF=BC=8C=E6=B5=8B=E8=AF=95=E5=90=88=E5=B9=B6=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 88 +++++- app/components/collabora/CollaboraViewer.tsx | 112 +++++++ app/components/collabora/Uno.ts | 168 +++++++++++ app/components/collabora/hooks.ts | 284 ++++++++++++++++++ app/components/collabora/types.ts | 37 +++ app/components/reviews/FilePreview.tsx | 19 +- app/config/api-config.ts | 86 ++++-- app/lib/collabora/config.server.ts | 125 ++++++++ app/lib/collabora/wopi.server.ts | 258 ++++++++++++++++ app/routes/api.collabora.config.tsx | 63 ++++ .../api.collabora.wopi.files.$fileId.tsx | 98 ++++++ app/routes/contract-template.detail.$id.tsx | 8 +- 12 files changed, 1310 insertions(+), 36 deletions(-) create mode 100644 app/components/collabora/CollaboraViewer.tsx create mode 100644 app/components/collabora/Uno.ts create mode 100644 app/components/collabora/hooks.ts create mode 100644 app/components/collabora/types.ts create mode 100644 app/lib/collabora/config.server.ts create mode 100644 app/lib/collabora/wopi.server.ts create mode 100644 app/routes/api.collabora.config.tsx create mode 100644 app/routes/api.collabora.wopi.files.$fileId.tsx diff --git a/CLAUDE.md b/CLAUDE.md index f2e9eaf..19e3357 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -146,7 +146,93 @@ The system uses a **port-based multi-client architecture** where: - `MessageModal.tsx` - Confirmation/alert modal system - `Toast.tsx` - Toast notification provider - `LoadingBar.tsx` - Top loading bar for route transitions -- `FilePreview.tsx` - PDF/Word document preview +- `FilePreview.tsx` - PDF/Word document preview (react-pdf + Collabora integration) + +### Document Preview System + +**Current Implementation** (`app/components/reviews/FilePreview.tsx`): +- **PDF files**: Rendered using `react-pdf` library +- **DOCX files**: Needs Collabora Online integration (planned) + +**Integration Plan - Collabora Online for DOCX Preview**: + +The FilePreview component should support multiple file types: +1. `.pdf` → Use react-pdf (current implementation) +2. `.docx` → Use Collabora Online viewer (to be integrated from collabora-test project) + +**Key Pages Using FilePreview**: +- `app/routes/reviews.tsx` - Document review page (uses `document.path`) +- `app/routes/contract-template.detail.$id.tsx` - Contract template details (uses `template.file_path`) + +**Data Flow for Collabora Integration**: +``` +Page Component (reviews.tsx / contract-template.detail.$id.tsx) + ↓ passes fileContent.path +FilePreview Component (detects file extension) + ↓ if .docx +CollaboraViewer Component (app/components/collabora/) + ↓ calls API +app/routes/api.collabora.config.tsx (Remix loader) + ↓ generates JWT + WOPISrc URL + ↓ returns { iframeUrl, accessToken } +CollaboraViewer renders iframe + ↓ Collabora Online loads document + ↓ calls WOPI endpoints +app/routes/api.collabora.wopi.files.$fileId.tsx (Remix loader/action) + ↓ CheckFileInfo (GET) / GetFile (GET /contents) / PutFile (POST /contents) + ↓ interacts with MinIO storage +Returns document data to Collabora +``` + +**Files to Migrate from collabora-test**: +- `CollaboraViewer.tsx` - Main viewer component +- `hooks.ts` - useCollaboraConfig, useCollaboraUICustomization, useDocumentReady, useCollaboraUnoCommands +- `api.ts` - API client for Collabora config +- `Uno.ts` - LibreOffice UNO commands wrapper +- `CollaboraIframeUI.ts` - UI customization utilities +- `types.ts` - TypeScript type definitions + +**Backend API Routes to Create**: +1. `app/routes/api.collabora.config.tsx` - Generate Collabora iframe URL and JWT token +2. `app/routes/api.collabora.wopi.files.$fileId.tsx` - WOPI protocol implementation (CheckFileInfo, GetFile, PutFile) + +**Environment Variables Needed**: +```bash +# Collabora Online server URL +COLLABORA_URL=http://10.79.97.17:9980 + +# Application base URL (must be accessible from Collabora server) +APP_URL=http://10.79.97.17:51703 + +# JWT secret for WOPI token signing (reuse existing JWT_SECRET) +``` + +**Security Considerations**: +- JWT token must include `fileId` for WOPI endpoint validation +- File path sanitization to prevent directory traversal attacks +- CORS configuration for Collabora server to access WOPI endpoints +- WOPI CheckFileInfo should return pure JSON (not wrapped in API response format) + +**File Type Detection in FilePreview**: +```typescript +const fileExtension = fileContent.path.split('.').pop()?.toLowerCase(); + +if (fileExtension === 'pdf') { + // Use react-pdf + return ; +} else if (fileExtension === 'docx') { + // Use Collabora + return ; +} else { + // Unsupported format + return ; +} +``` + +**Reference Implementation**: +- See `collabora-test` workspace for complete working example +- Adapt Next.js API routes to Remix loader/action pattern +- Convert Next.js `route.ts` GET/POST to Remix `loader()` and `action()` functions **RemixIcon Usage**: - Icons are locally hosted in `public/fonts/` diff --git a/app/components/collabora/CollaboraViewer.tsx b/app/components/collabora/CollaboraViewer.tsx new file mode 100644 index 0000000..60189cf --- /dev/null +++ b/app/components/collabora/CollaboraViewer.tsx @@ -0,0 +1,112 @@ +/** + * Collabora Online 文档查看器组件 + * + * 功能: + * - 加载 Collabora Online iframe + * - 管理文档加载状态 + * - 提供 UNO 命令接口 + * - 支持只读和编辑模式 + * + * @encoding UTF-8 + */ + +import { useRef } from 'react'; +import type { CollaboraViewerProps } from './types'; +import { useCollaboraConfig, useDocumentReady, useCollaboraUnoCommands } from './hooks'; + +/** + * Collabora 文档查看器组件 + * @param props - 组件属性 + */ +export function CollaboraViewer({ + fileId, + mode = 'view', + userId = 'guest', + userName = '访客', +}: CollaboraViewerProps) { + const iframeRef = useRef(null); + + // 1. 加载 Collabora 配置 + const { config, loading, error } = useCollaboraConfig(fileId, mode, userId, userName); + + // 2. 监听文档加载状态 + const { isDocumentLoaded } = useDocumentReady(iframeRef); + + // 3. UNO 命令封装 + const unoCommands = useCollaboraUnoCommands(iframeRef); + + // 加载中状态 + if (loading) { + return ( +
+
+
+

加载文档配置中...

+
+
+ ); + } + + // 错误状态 + if (error || !config) { + return ( +
+
+ +

{error || '加载配置失败'}

+

请刷新页面重试或联系管理员

+
+
+ ); + } + + return ( +
+ {/* 文档加载提示 */} + {!isDocumentLoaded && ( +
+
+
+

正在加载文档...

+

{config.fileName}

+
+
+ )} + + {/* Collabora iframe */} +