新增提示Toast组件

This commit is contained in:
2025-04-21 09:22:13 +08:00
parent 01d93522b8
commit 5c2c367856
36 changed files with 2609 additions and 478 deletions
+95 -44
View File
@@ -12,6 +12,27 @@ pdfjs.GlobalWorkerOptions.workerSrc = '/pdf.worker.js';
// 导入统一的ReviewPoint类型
import { type ReviewPoint } from './';
/**
* 自定义样式
* 这些样式解决了PDF页面在放大时互相重叠的问题
*/
const styles = {
pdfContainer: {
display: 'flex',
flexDirection: 'column' as const,
alignItems: 'center',
width: '100%',
position: 'relative' as const,
},
pageContainer: {
display: 'flex',
flexDirection: 'column' as const,
alignItems: 'center',
width: '100%',
position: 'relative' as const,
}
};
// 定义文档内容类型
interface FileContent {
title: string;
@@ -76,24 +97,28 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointId, ta
};
// 当选中的评查点变化时,滚动到对应位置
useEffect(() => {
if (activeReviewPointId && contentRef.current) {
const highlightElement = contentRef.current.querySelector(`[data-review-id="${activeReviewPointId}"]`);
if (highlightElement) {
highlightElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
// 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]);
// // 添加临时突出显示效果
// highlightElement.classList.add('highlight-focus');
// setTimeout(() => {
// highlightElement.classList.remove('highlight-focus');
// }, 1500);
// }
// }
// }, [activeReviewPointId]);
// 处理页面跳转
const prevTargetPageRef = useRef<number | undefined>(undefined);
useEffect(() => {
if (targetPage && numPages && targetPage <= numPages) {
// 如果有目标页码,并且与上次不同或activeReviewPointId变化了,则执行跳转
if (targetPage && numPages && targetPage <= numPages && (targetPage !== prevTargetPageRef.current || activeReviewPointId)) {
prevTargetPageRef.current = targetPage;
let newTargetPage = targetPage;
try {
// 安全地访问ocrResult
@@ -107,11 +132,11 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointId, ta
const pageElement = document.getElementById(`page-${newTargetPage}`);
if (pageElement) {
console.log(`跳转到第${newTargetPage}`);
pageElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
console.log(`跳转到第${newTargetPage},对应评查点ID: ${activeReviewPointId}`);
pageElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
}, [targetPage, numPages, fileContent]);
}, [targetPage, numPages, fileContent, activeReviewPointId]);
// 获取评查点对应的样式类
const getHighlightClass = (status: string) => {
@@ -133,6 +158,15 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointId, ta
console.log("PDF加载成功,页数:", numPages);
}
// 计算页面在缩放后的实际间距
const calculatePageMargin = (zoomFactor: number) => {
// 基础间距为30px,随着缩放倍数线性增加
const baseMargin = 30;
// 页面缩放后,需要额外添加的间距 = (缩放倍数 - 1) * 页面高度
const additionalMargin = Math.max(0, (zoomFactor - 1) * 800); // 800是估计的页面高度
return baseMargin + additionalMargin;
};
/**
* 渲染PDF文档的所有页面
*
@@ -157,25 +191,35 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointId, ta
const pageReviewPoints = reviewPoints.filter(point =>
point.position && point.position.section === `page-${i}`
);
// console.log("pageReviewPoints-------",pageReviewPoints);
// 计算当前缩放级别下的页面容器样式
const zoomFactor = zoomLevel / 100;
const pageContainerStyle = {
...styles.pageContainer,
marginBottom: `${calculatePageMargin(zoomFactor)}px`, // 动态计算页面间距
};
// 为每一页创建组件
pages.push(
<div key={i} id={`page-${i}`} className="mb-6">
<div key={i} id={`page-${i}`} style={pageContainerStyle}>
{/* 页码标识,显示在页面上方 */}
<div className="text-center text-gray-500 text-sm mb-2"> {i} </div>
{/* 页面容器,应用缩放变换,设置相对定位用于放置评查点高亮 */}
<div style={{
transform: `scale(${zoomLevel / 100})`, // 根据zoomLevel应用缩放
transformOrigin: 'top center', // 缩放原点设置为顶部中心
position: 'relative' // 相对定位,作为评查点高亮的定位参考
}}>
<div
className="page-wrapper flex justify-center"
style={{
transform: `scale(${zoomFactor})`, // 根据zoomLevel应用缩放
transformOrigin: 'top center', // 缩放原点设置为顶部中心
position: 'relative', // 相对定位,作为评查点高亮的定位参考
maxWidth: '100%', // 限制最大宽度
}}
>
{/* 渲染PDF页面组件 */}
<Page
pageNumber={i} // 当前页码
renderTextLayer={true} // 启用文本层,使文本可选择
renderAnnotationLayer={true} // 启用注释层,显示PDF内置注释
pageNumber={i} // 当前页码
renderTextLayer={true} // 启用文本层,使文本可选择
renderAnnotationLayer={true} // 启用注释层,显示PDF内置注释
className="border border-gray-300 shadow-md" // 添加边框和阴影样式
/>
@@ -218,20 +262,22 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointId, ta
// 渲染文档内容
const renderDocumentContent = () => {
return (
<Document
file={'http://172.18.0.100:9000/docauditai/'+fileContent.path}
onLoadSuccess={onDocumentLoadSuccess}
onLoadError={(error) => {
console.error("PDF加载错误:", error);
setLoadError("PDF文档加载失败:" + (error.message || "未知错误"));
}}
className="flex flex-col items-center"
error={<div className="text-red-500">PDF文档加载失败</div>}
noData={<div></div>}
loading={<div className="text-center py-10">PDF加载中...</div>}
>
{renderAllPages()}
</Document>
<div style={styles.pdfContainer}>
<Document
file={'http://172.18.0.100:9000/docauditai/'+fileContent.path}
onLoadSuccess={onDocumentLoadSuccess}
onLoadError={(error) => {
console.error("PDF加载错误:", error);
setLoadError("PDF文档加载失败:" + (error.message || "未知错误"));
}}
className="flex flex-col items-center w-full"
error={<div className="text-red-500">PDF文档加载失败</div>}
noData={<div></div>}
loading={<div className="text-center py-10">PDF加载中...</div>}
>
{renderAllPages()}
</Document>
</div>
);
};
@@ -255,15 +301,20 @@ export function FilePreview({ fileContent, reviewPoints, activeReviewPointId, ta
>
<i className="ri-zoom-out-line"></i>
</button>
<button
{/* <button
className="ant-btn ant-btn-sm ant-btn-default py-0 px-1 text-xs h-5 leading-5"
onClick={toggleHighlights}
>
<i className="ri-mark-pen-line"></i> {highlightsVisible ? '隐藏问题' : '显示问题'}
</button>
</button> */}
<span className="ml-2 text-xs text-gray-500">{"比例:"+zoomLevel+"%"}</span>
</div>
</div>
<div className="file-preview-content" ref={contentRef}>
<div
className="file-preview-content relative overflow-y-auto"
ref={contentRef}
style={{ maxHeight: 'calc(100vh - 150px)' }}
>
{loadError ? (
<div className="text-red-500 p-4">
<p>{loadError}</p>