fix: stabilize review detail and collabora loading
This commit is contained in:
@@ -106,7 +106,7 @@ export const CollaboraViewer = forwardRef<CollaboraViewerHandle, CollaboraViewer
|
||||
const { config, loading, error } = useCollaboraConfig(fileId, mode, userId, userName);
|
||||
|
||||
// 2. 监听文档加载状态
|
||||
const { isDocumentLoaded } = useDocumentReady(iframeRef);
|
||||
const { isDocumentLoaded } = useDocumentReady(iframeRef, config?.iframeUrl);
|
||||
|
||||
// 2.5. 保存 iframe window 引用并在文档加载时清除所有高亮
|
||||
useEffect(() => {
|
||||
@@ -1194,4 +1194,3 @@ export const CollaboraViewer = forwardRef<CollaboraViewerHandle, CollaboraViewer
|
||||
// 导出类型和 hook
|
||||
export { useCollaboraUnoCommands };
|
||||
export type { CollaboraViewerHandle };
|
||||
|
||||
|
||||
@@ -110,35 +110,75 @@ export function useCollaboraConfig(
|
||||
* @param iframeRef - iframe 引用
|
||||
* @returns 文档加载状态
|
||||
*/
|
||||
export function useDocumentReady(iframeRef: RefObject<HTMLIFrameElement>) {
|
||||
export function useDocumentReady(
|
||||
iframeRef: RefObject<HTMLIFrameElement>,
|
||||
iframeUrl?: string
|
||||
) {
|
||||
const [isDocumentLoaded, setIsDocumentLoaded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
// 验证消息来源
|
||||
const collaboraOrigin = new URL(COLLABORA_URL).origin;
|
||||
setIsDocumentLoaded(false);
|
||||
|
||||
if (event.origin !== collaboraOrigin) {
|
||||
const iframe = iframeRef.current;
|
||||
const expectedOrigin = iframeUrl
|
||||
? new URL(iframeUrl).origin
|
||||
: new URL(COLLABORA_URL).origin;
|
||||
let fallbackTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
const markLoaded = (source: string) => {
|
||||
setIsDocumentLoaded((prev) => {
|
||||
if (!prev) {
|
||||
console.log(`[DocumentReady] 文档已就绪(${source})`);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
const handleIframeLoad = () => {
|
||||
// 某些环境下 Collabora 不一定会抛出 Document_Loaded 消息,
|
||||
// 先在 iframe load 后给一个兜底超时,避免页面一直被遮罩层盖住。
|
||||
fallbackTimer = setTimeout(() => {
|
||||
markLoaded('iframe-load-fallback');
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
if (event.origin !== expectedOrigin) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (iframeRef.current?.contentWindow && event.source !== iframeRef.current.contentWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const msg = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
|
||||
|
||||
if (msg.MessageId === 'App_LoadingStatus' && msg.Values?.Status === 'Document_Loaded') {
|
||||
console.log('[DocumentReady] 文档加载完成');
|
||||
setIsDocumentLoaded(true);
|
||||
if (
|
||||
msg?.MessageId === 'App_LoadingStatus' &&
|
||||
['Document_Loaded', 'Document_Loaded_Editing', 'UI_Loaded'].includes(msg.Values?.Status)
|
||||
) {
|
||||
if (fallbackTimer) {
|
||||
clearTimeout(fallbackTimer);
|
||||
fallbackTimer = null;
|
||||
}
|
||||
markLoaded(`postmessage:${msg.Values?.Status}`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[DocumentReady] 解析消息失败:', err);
|
||||
} catch {
|
||||
// Collabora 也会发送非 JSON 消息,这里忽略即可。
|
||||
}
|
||||
};
|
||||
|
||||
iframe?.addEventListener('load', handleIframeLoad);
|
||||
window.addEventListener('message', handleMessage);
|
||||
return () => {
|
||||
if (fallbackTimer) {
|
||||
clearTimeout(fallbackTimer);
|
||||
}
|
||||
iframe?.removeEventListener('load', handleIframeLoad);
|
||||
window.removeEventListener('message', handleMessage);
|
||||
};
|
||||
}, [iframeRef]);
|
||||
}, [iframeRef, iframeUrl]);
|
||||
|
||||
return { isDocumentLoaded };
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export default function Chat() {
|
||||
|
||||
// 权限检查
|
||||
const { hasPermission: checkPerm } = usePermission();
|
||||
const canChat = checkPerm('dify:chat:use');
|
||||
const canChat = checkPerm('rag:chat:use');
|
||||
|
||||
// 侧边栏状态
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
|
||||
|
||||
@@ -61,7 +61,7 @@ const ChatSidebar = forwardRef<ChatSidebarRef, ChatSidebarProps>(({
|
||||
conversationReadOnly = false,
|
||||
}, ref) => {
|
||||
const { hasPermission } = usePermission();
|
||||
const canDeleteConversation = hasPermission('dify:conversation:delete');
|
||||
const canDeleteConversation = hasPermission('rag:conversation:delete');
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const [renameModalVisible, setRenameModalVisible] = useState(false);
|
||||
const [deleteModalVisible, setDeleteModalVisible] = useState(false);
|
||||
|
||||
Reference in New Issue
Block a user