进度条优化

This commit is contained in:
2025-04-25 14:12:36 +08:00
parent 0eaaa5b041
commit b9b5be1d47
9 changed files with 377 additions and 270 deletions
+148 -40
View File
@@ -66,7 +66,7 @@ interface FileContent {
interface FilePreviewProps {
fileContent: FileContent;
reviewPoints: ReviewPoint[];
reviewPoints?: ReviewPoint[]; // 设为可选
activeReviewPointResultId: string | null;
targetPage?: number; // 新增目标页码参数
}
@@ -79,6 +79,12 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointResult
const [loadError, setLoadError] = useState<string | null>(null);
const [pageInputValue, setPageInputValue] = useState<string>('');
// 拖拽状态管理
const [dragMode, setDragMode] = useState(false); // 是否处于拖拽模式
const [isDragging, setIsDragging] = useState(false);
const [dragCursor, setDragCursor] = useState('default');
const lastMousePosRef = useRef({ x: 0, y: 0 });
// 放大文档
const handleZoomIn = () => {
if (zoomLevel < 200) {
@@ -93,27 +99,75 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointResult
}
};
// 切换高亮显示
// const toggleHighlights = () => {
// setHighlightsVisible(!highlightsVisible);
// };
// 切换拖拽模式
const toggleDragMode = () => {
setDragMode(prev => !prev);
setDragCursor(prev => prev === 'default' ? 'grab' : 'default');
setIsDragging(false);
};
// 当选中的评查点变化时,滚动到对应位置
// useEffect(() => {
// if (activeReviewPointId && contentRef.current) {
// const highlightElement = contentRef.current.querySelector(`[data-review-id="${activeReviewPointId}"]`);
// if (highlightElement) {
// highlightElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
// // highlightElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
// // 添加临时突出显示效果
// highlightElement.classList.add('highlight-focus');
// setTimeout(() => {
// highlightElement.classList.remove('highlight-focus');
// }, 1500);
// }
// }
// }, [activeReviewPointId]);
// 处理拖拽开始
const handleMouseDown = (e: React.MouseEvent<HTMLButtonElement>) => {
if (!dragMode || e.button !== 0) return; // 只在拖拽模式下响应左键点击
// 防止选中文本
e.preventDefault();
// 设置拖拽状态
setIsDragging(true);
setDragCursor('grabbing');
// 记录鼠标初始位置
lastMousePosRef.current = {
x: e.clientX,
y: e.clientY
};
};
// 处理拖拽过程
const handleMouseMove = (e: React.MouseEvent<HTMLButtonElement>) => {
if (!dragMode || !isDragging || !contentRef.current) return;
// 计算鼠标移动距离
const dx = e.clientX - lastMousePosRef.current.x;
const dy = e.clientY - lastMousePosRef.current.y;
// 更新容器滚动位置
contentRef.current.scrollLeft -= dx;
contentRef.current.scrollTop -= dy;
// 更新鼠标位置记录
lastMousePosRef.current = {
x: e.clientX,
y: e.clientY
};
};
// 处理拖拽结束
const handleMouseUp = () => {
if (!dragMode) return;
setIsDragging(false);
setDragCursor('grab');
};
// 监听鼠标离开窗口事件
useEffect(() => {
const handleMouseLeave = () => {
if (dragMode && isDragging) {
setIsDragging(false);
setDragCursor('grab');
}
};
document.addEventListener('mouseleave', handleMouseLeave);
document.addEventListener('mouseup', handleMouseUp as EventListener);
return () => {
document.removeEventListener('mouseleave', handleMouseLeave);
document.removeEventListener('mouseup', handleMouseUp as EventListener);
};
}, [isDragging, dragMode]);
// 处理页面跳转
const prevTargetPageRef = useRef<number | undefined>(undefined);
@@ -130,6 +184,7 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointResult
}
} catch (error) {
console.error("访问ocrResult时出错:", error);
toastService.error("访问ocrResult时出错:" + (error instanceof Error ? error.message : '未知错误'));
}
const pageElement = document.getElementById(`page-${newTargetPage}`);
@@ -230,11 +285,6 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointResult
// 遍历每一页,生成对应的页面组件
for (let i = 1; i <= numPages; i++) {
// 查找该页面上的评查点,基于position.section匹配页面ID
// const pageReviewPoints = reviewPoints.filter(point =>
// point.position && point.position.section === `page-${i}`
// );
// 计算当前缩放级别下的页面容器样式
const zoomFactor = zoomLevel / 100;
const pageContainerStyle = {
@@ -250,12 +300,13 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointResult
{/* 页面容器,应用缩放变换,设置相对定位用于放置评查点高亮 */}
<div
className="page-wrapper flex justify-center"
className="page-wrapper"
style={{
transform: `scale(${zoomFactor})`, // 根据zoomLevel应用缩放
transformOrigin: 'top center', // 缩放原点设置为顶部中心
position: 'relative', // 相对定位,作为评查点高亮的定位参考
maxWidth: '100%', // 限制最大宽度
display: 'inline-block', // 内联块级元素,宽度由内容决定
margin: '0 auto', // 水平居中
}}
>
{/* 渲染PDF页面组件 */}
@@ -305,7 +356,14 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointResult
// 渲染文档内容
const renderDocumentContent = () => {
return (
<div style={styles.pdfContainer}>
<div
style={{
...styles.pdfContainer,
// 当缩放大于100%时设置最小宽度,确保出现横向滚动条
minWidth: zoomLevel > 100 ? `${zoomLevel}%` : '100%',
overflow: 'visible'
}}
>
<Document
file={'http://172.18.0.100:9000/docauditai/'+fileContent.path}
onLoadSuccess={onDocumentLoadSuccess}
@@ -313,7 +371,7 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointResult
console.error("PDF加载错误:", error);
setLoadError("PDF文档加载失败:" + (error.message || "未知错误"));
}}
className="flex flex-col items-center w-full"
className="w-full"
error={<div className="text-red-500">PDF文档加载失败</div>}
noData={<div></div>}
loading={<div className="text-center py-10">PDF加载中...</div>}
@@ -336,7 +394,7 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointResult
className="ant-btn ant-btn-sm ant-btn-default py-0 px-1 text-xs h-5 leading-5 "
onClick={handleScrollToTop}
>
<i className="ri-arrow-up-double-line "></i>
<i className="ri-arrow-up-double-line"></i>
<span className="ml-1"></span>
</button>
<button
@@ -378,20 +436,70 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointResult
<i className="ri-mark-pen-line"></i> {highlightsVisible ? '隐藏问题' : '显示问题'}
</button> */}
<span className="ml-2 text-xs text-gray-500 inline-block">{"比例:"+zoomLevel+"%"}</span>
<button
className={`ant-btn ant-btn-sm ant-btn-default py-0 px-1 text-xs h-5 leading-5 ml-2 ${dragMode ? 'active bg-green-300' : ''}`}
title="切换拖拽模式"
aria-pressed={dragMode}
onClick={toggleDragMode}
>
<i className="ri-drag-move-line"></i>
<span className="ml-1">{dragMode ? '(已激活)' : ''}</span>
</button>
</div>
</div>
<div
className="file-preview-content relative overflow-y-auto"
className="file-preview-content"
ref={contentRef}
style={{ maxHeight: 'calc(100vh - 150px)' }}
style={{
maxHeight: 'calc(100vh - 150px)',
overflowY: 'auto',
overflowX: 'auto',
cursor: dragCursor,
userSelect: dragMode ? 'none' : 'auto', // 拖拽模式下防止文本被选中
}}
>
{loadError ? (
<div className="text-red-500 p-4">
<p>{loadError}</p>
</div>
) : (
renderDocumentContent()
)}
<button
className="pdf-interactive-container"
aria-label="PDF文档查看区域"
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
onKeyDown={(e) => {
// 添加键盘导航支持
const scrollAmount = 50;
if (e.key === 'ArrowUp') {
if (contentRef.current) contentRef.current.scrollTop -= scrollAmount;
e.preventDefault();
} else if (e.key === 'ArrowDown') {
if (contentRef.current) contentRef.current.scrollTop += scrollAmount;
e.preventDefault();
} else if (e.key === 'ArrowLeft') {
if (contentRef.current) contentRef.current.scrollLeft -= scrollAmount;
e.preventDefault();
} else if (e.key === 'ArrowRight') {
if (contentRef.current) contentRef.current.scrollLeft += scrollAmount;
e.preventDefault();
}
}}
style={{
position: 'relative',
height: '100%',
width: '100%',
display: 'block',
border: 'none',
background: 'transparent',
textAlign: 'center',
padding: 0
}}
>
{loadError ? (
<div className="text-red-500 p-4">
<p>{loadError}</p>
</div>
) : (
renderDocumentContent()
)}
</button>
</div>
</div>
);