/** * Collabora Online 文档查看器组件 * * 功能: * - 加载 Collabora Online iframe * - 管理文档加载状态 * - 提供 UNO 命令接口 * - 支持只读和编辑模式 * * @encoding UTF-8 */ import { useRef, forwardRef, useImperativeHandle, useState } from 'react'; import type { CollaboraViewerProps, CollaboraViewerHandle } from './types'; import { useCollaboraConfig, useDocumentReady, useCollaboraUnoCommands } from './hooks'; import { sendUnoCommand } from './Uno'; import { switchHighlight } from './lib/Highlightselecttext'; /** * Collabora 文档查看器组件 * @param props - 组件属性 * @param ref - 父组件传入的 ref,用于暴露命令接口 */ export const CollaboraViewer = forwardRef( function CollaboraViewer( { fileId, mode = 'view', userId = 'guest', userName = '访客', }, ref ) { const iframeRef = useRef(null); // 调试面板状态 const [unoCmd, setUnoCmd] = useState('.uno:GoToStartOfDoc'); const [unoArgs, setUnoArgs] = useState('{}'); const [unoResult, setUnoResult] = useState(null); // 高亮测试面板状态 const [highlightText, setHighlightText] = useState(''); const [highlightPage, setHighlightPage] = useState(''); const [previousHighlightText, setPreviousHighlightText] = useState(null); const [highlightResult, setHighlightResult] = useState(null); // 1. 加载 Collabora 配置 const { config, loading, error } = useCollaboraConfig(fileId, mode, userId, userName); // 2. 监听文档加载状态 const { isDocumentLoaded } = useDocumentReady(iframeRef); // 3. UNO 命令封装 const unoCommands = useCollaboraUnoCommands(iframeRef); // 4. 暴露接口给父组件 useImperativeHandle(ref, () => ({ unoCommands, isReady: isDocumentLoaded, mode, getIframeWindow: () => iframeRef.current?.contentWindow || null, }), [unoCommands, isDocumentLoaded, mode]); // 加载中状态 if (loading) { return (

加载文档配置中...

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

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

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

); } // 发送 UNO 命令的处理函数(测试用) // const sendUno = () => { // if (!iframeRef.current?.contentWindow) { // setUnoResult('iframe 不可用'); // return; // } // let args: Record = {}; // const raw = (unoArgs || '').trim(); // if (raw !== '') { // try { // args = JSON.parse(raw) as Record; // } catch (err) { // try { // // fallback: replace single quotes with double quotes and parse // args = JSON.parse(raw.replace(/'(.*?)'/g, '"$1"')) as Record; // } catch (err2) { // console.error('解析 UNO Args 失败:', err2); // setUnoResult('Args 解析失败,请使用有效 JSON'); // return; // } // } // } // try { // // 使用正确的 sendUnoCommand 方法 // sendUnoCommand(iframeRef.current.contentWindow, unoCmd, args); // setUnoResult(`已发送: ${unoCmd}`); // console.log('[UNO Debug] 发送命令:', unoCmd, args); // } catch (e) { // console.error('发送 UNO 失败:', e); // setUnoResult('发送失败,请查看控制台'); // } // }; // 高亮测试处理函数 const handleSwitchHighlight = async () => { if (!iframeRef.current?.contentWindow) { setHighlightResult('iframe 未就绪'); return; } if (!highlightText || highlightText.trim() === '') { setHighlightResult('请输入要高亮的文本'); return; } try { // 解析页码 (可选) const page = highlightPage && highlightPage.trim() !== '' ? parseInt(highlightPage.trim(), 10) : undefined; // 验证页码 if (page !== undefined && (isNaN(page) || page < 1)) { setHighlightResult('页码必须是大于0的整数'); return; } await switchHighlight( iframeRef.current.contentWindow, previousHighlightText, highlightText.trim(), { page } ); // 更新上一次高亮的文本 setPreviousHighlightText(highlightText.trim()); const pageInfo = page ? ` (第${page}页)` : ''; setHighlightResult(`✓ 已切换高亮: ${highlightText.trim()}${pageInfo}`); } catch (e) { console.error('切换高亮失败:', e); setHighlightResult(`切换失败: ${e instanceof Error ? e.message : '未知错误'}`); } }; return (
{/* UNO 命令测试面板 */} {/*
setUnoCmd(e.target.value)} placeholder="UNO 命令" aria-label="UNO 命令" /> setUnoArgs(e.target.value)} placeholder="UNO Args (JSON)" aria-label="UNO Args (JSON)" /> {unoResult && {unoResult}}
*/} {/* 高亮测试面板 */}
setHighlightText(e.target.value)} placeholder="输入要高亮的文本 (如: 合同编号)" aria-label="高亮文本" onKeyPress={(e) => { if (e.key === 'Enter') { handleSwitchHighlight(); } }} /> setHighlightPage(e.target.value)} placeholder="页码" aria-label="页码" type="number" min="1" onKeyPress={(e) => { if (e.key === 'Enter') { handleSwitchHighlight(); } }} /> {previousHighlightText && ( 上次: {previousHighlightText} )} {highlightResult && ( {highlightResult} )}
{/* 文档加载提示 */} {!isDocumentLoaded && (

正在加载文档...

{config.fileName}

)} {/* Collabora iframe - tabIndex is needed for keyboard navigation */} {/* eslint-disable jsx-a11y/no-noninteractive-tabindex */}