Merge branch 'PingChuan' into shiy-login

# Conflicts:
#	app/components/reviews/ReviewTabs.tsx
This commit is contained in:
2025-11-25 15:05:48 +08:00
17 changed files with 1317 additions and 973 deletions
+132 -29
View File
@@ -5,7 +5,8 @@
import { useState, useEffect, useRef, ChangeEvent } from 'react';
import { Document, Page, pdfjs } from 'react-pdf';
import { DOCUMENT_URL } from '~/api/axios-client';
import { CollaboraViewer } from '~/components/collabora/CollaboraViewer';
import { CollaboraViewer, type CollaboraViewerHandle } from '~/components/collabora/CollaboraViewer';
import { requestPageInfo, customGotoPage } from '~/components/collabora/lib';
// 导入react-pdf的CSS样式(文本层和注释层必需)
import 'react-pdf/dist/esm/Page/TextLayer.css';
@@ -89,10 +90,60 @@ export function FilePreview({ fileContent, activeReviewPointResultId, targetPage
const [zoomLevel, setZoomLevel] = useState(100);
// const [highlightsVisible, setHighlightsVisible] = useState(true);
const contentRef = useRef<HTMLDivElement>(null);
const collaboraViewerRef = useRef<CollaboraViewerHandle>(null);
const [numPages, setNumPages] = useState<number | null>(null);
const [loadError, setLoadError] = useState<string | null>(null);
const [pageInputValue, setPageInputValue] = useState<string>('');
// 获取文件类型
const real_path = fileContent.path || fileContent.template_contract_path || '';
const fileExtension = real_path.split('.').pop()?.toLowerCase();
const isDocx = fileExtension === 'docx';
const isPdf = fileExtension === 'pdf';
// DOCX 页数获取: 使用 requestPageInfo 方法
useEffect(() => {
if (!isDocx) return;
// console.log('[FilePreview] DOCX 文档加载,尝试获取页数');
let intervalCleared = false;
// 等待 CollaboraViewer 准备就绪
const checkInterval = setInterval(() => {
if (intervalCleared) return;
if (!collaboraViewerRef.current?.isReady) {
console.log('[FilePreview] 等待 Collabora 就绪...');
return;
}
// console.log('[FilePreview] Collabora 已就绪,尝试获取页数');
clearInterval(checkInterval);
intervalCleared = true;
const iframeWindow = collaboraViewerRef.current.getIframeWindow?.();
if (!iframeWindow) {
console.warn('[FilePreview] 无法获取 iframe window');
return;
}
// 使用 requestPageInfo 获取页数
requestPageInfo(iframeWindow)
.then((info) => {
setNumPages(info.totalPages);
})
.catch((error) => {
console.warn('[FilePreview] 获取 DOCX 页数失败:', error.message);
});
}, 500);
// 清理定时器
return () => {
clearInterval(checkInterval);
};
}, [isDocx]);
// 拖拽状态管理
const [dragMode, setDragMode] = useState(false); // 是否处于拖拽模式
const [isDragging, setIsDragging] = useState(false);
@@ -101,15 +152,35 @@ export function FilePreview({ fileContent, activeReviewPointResultId, targetPage
// 放大文档
const handleZoomIn = () => {
if (zoomLevel < 200) {
setZoomLevel(prevZoom => prevZoom + 10);
if (isDocx) {
// DOCX 文件:调用 Collabora UNO 命令
if (!collaboraViewerRef.current?.isReady) {
toastService.warning('文档尚未加载完成,请稍候...');
return;
}
collaboraViewerRef.current?.unoCommands.zoomIn();
} else if (isPdf) {
// PDF 文件:修改 zoomLevel 状态
if (zoomLevel < 200) {
setZoomLevel(prevZoom => prevZoom + 10);
}
}
};
// 缩小文档
const handleZoomOut = () => {
if (zoomLevel > 50) {
setZoomLevel(prevZoom => prevZoom - 10);
if (isDocx) {
// DOCX 文件:调用 Collabora UNO 命令
if (!collaboraViewerRef.current?.isReady) {
toastService.warning('文档尚未加载完成,请稍候...');
return;
}
collaboraViewerRef.current?.unoCommands.zoomOut();
} else if (isPdf) {
// PDF 文件:修改 zoomLevel 状态
if (zoomLevel > 50) {
setZoomLevel(prevZoom => prevZoom - 10);
}
}
};
@@ -246,22 +317,47 @@ export function FilePreview({ fileContent, activeReviewPointResultId, targetPage
};
// 处理页码跳转
const handlePageJump = () => {
if (!pageInputValue || !numPages) return;
const handlePageJump = async () => {
if (!pageInputValue) return;
const targetPageNum = parseInt(pageInputValue, 10);
// 验证页码是否在有效范围内
if (targetPageNum > 0 && targetPageNum <= numPages) {
// 找到目标页面元素并滚动到该位置
const pageElement = document.getElementById(`page-${targetPageNum}`);
if (pageElement) {
pageElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
if (isDocx) {
// DOCX 文件:调用自定义页面跳转
const iframeWindow = collaboraViewerRef.current?.getIframeWindow?.();
if (!iframeWindow) {
toastService.warning('文档尚未加载完成,请稍候...');
return;
}
if (targetPageNum > 0) {
try {
await customGotoPage(iframeWindow, targetPageNum);
// 跳转成功,清空输入框
setPageInputValue('');
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '未知错误';
toastService.error(`跳转失败: ${errorMessage}`);
}
} else {
toastService.warning('请输入有效页码');
setPageInputValue('');
}
} else if (isPdf) {
// PDF 文件:验证页码并滚动到目标页面
if (!numPages) return;
if (targetPageNum > 0 && targetPageNum <= numPages) {
// 找到目标页面元素并滚动到该位置
const pageElement = document.getElementById(`page-${targetPageNum}`);
if (pageElement) {
pageElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
} else {
// 页码超出范围,显示错误信息或重置输入
toastService.warning(`请输入有效页码 (1-${numPages})`);
setPageInputValue('');
}
} else {
// 页码超出范围,显示错误信息或重置输入
toastService.warning(`请输入有效页码 (1-${numPages})`);
setPageInputValue('');
}
};
@@ -289,8 +385,18 @@ export function FilePreview({ fileContent, activeReviewPointResultId, targetPage
// 滚动到顶部
const handleScrollToTop = () => {
if (contentRef.current) {
contentRef.current.scrollTo({ top: 0, behavior: 'smooth' });
if (isDocx) {
// DOCX 文件:调用 Collabora UNO 命令
if (!collaboraViewerRef.current?.isReady) {
toastService.warning('文档尚未加载完成,请稍候...');
return;
}
collaboraViewerRef.current?.unoCommands.scrollToTop();
} else {
// PDF 文件:滚动容器到顶部
if (contentRef.current) {
contentRef.current.scrollTo({ top: 0, behavior: 'smooth' });
}
}
};
@@ -389,8 +495,6 @@ export function FilePreview({ fileContent, activeReviewPointResultId, targetPage
// 渲染文档内容
const renderDocumentContent = () => {
const real_path = fileContent.path || fileContent.template_contract_path || '';
// 如果路径无效,显示错误信息
if (!real_path) {
if(!fileContent.template_contract_path){
@@ -408,9 +512,7 @@ export function FilePreview({ fileContent, activeReviewPointResultId, targetPage
}
// console.log('real_path',real_path);
// 获取文件扩展名
const fileExtension = real_path.split('.').pop()?.toLowerCase();
// PDF内容渲染
const renderPdfContent = () => (
<div
@@ -474,8 +576,9 @@ export function FilePreview({ fileContent, activeReviewPointResultId, targetPage
// DOCX文件使用Collabora Online预览
return (
<CollaboraViewer
ref={collaboraViewerRef}
fileId={real_path}
mode="view"
mode="edit"
userId={userInfo?.sub || 'guest'}
userName={userInfo?.nick_name || '访客'}
/>