加入审查详情页面转换
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* 文件预览组件
|
||||
* 显示文档内容和评查点高亮
|
||||
*/
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
|
||||
// 定义评查点类型
|
||||
interface ReviewPoint {
|
||||
id: string;
|
||||
title: string;
|
||||
status: string;
|
||||
content: string;
|
||||
suggestion: string;
|
||||
position?: {
|
||||
section: string;
|
||||
index: number;
|
||||
};
|
||||
}
|
||||
|
||||
// 定义文档内容类型
|
||||
interface FileContent {
|
||||
title: string;
|
||||
contractNumber: string;
|
||||
parties: {
|
||||
partyA: {
|
||||
name: string;
|
||||
address: string;
|
||||
representative: string;
|
||||
phone: string;
|
||||
};
|
||||
partyB: {
|
||||
name: string;
|
||||
address: string;
|
||||
representative: string;
|
||||
phone: string;
|
||||
};
|
||||
};
|
||||
sections: {
|
||||
title: string;
|
||||
content: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
interface FilePreviewProps {
|
||||
fileContent: FileContent;
|
||||
reviewPoints: ReviewPoint[];
|
||||
activeReviewPointId: string | null;
|
||||
}
|
||||
|
||||
export function FilePreview({ fileContent, reviewPoints, activeReviewPointId }: FilePreviewProps) {
|
||||
const [zoomLevel, setZoomLevel] = useState(100);
|
||||
const [highlightsVisible, setHighlightsVisible] = useState(true);
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// 放大文档
|
||||
const handleZoomIn = () => {
|
||||
if (zoomLevel < 200) {
|
||||
setZoomLevel(prevZoom => prevZoom + 10);
|
||||
}
|
||||
};
|
||||
|
||||
// 缩小文档
|
||||
const handleZoomOut = () => {
|
||||
if (zoomLevel > 50) {
|
||||
setZoomLevel(prevZoom => prevZoom - 10);
|
||||
}
|
||||
};
|
||||
|
||||
// 切换高亮显示
|
||||
const toggleHighlights = () => {
|
||||
setHighlightsVisible(!highlightsVisible);
|
||||
};
|
||||
|
||||
// 当选中的评查点变化时,滚动到对应位置
|
||||
useEffect(() => {
|
||||
if (activeReviewPointId && contentRef.current) {
|
||||
const highlightElement = contentRef.current.querySelector(`[data-review-id="${activeReviewPointId}"]`);
|
||||
if (highlightElement) {
|
||||
highlightElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
|
||||
// 添加临时突出显示效果
|
||||
highlightElement.classList.add('highlight-focus');
|
||||
setTimeout(() => {
|
||||
highlightElement.classList.remove('highlight-focus');
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
}, [activeReviewPointId]);
|
||||
|
||||
// 获取评查点对应的样式类
|
||||
const getHighlightClass = (status: string) => {
|
||||
switch (status) {
|
||||
case 'warning':
|
||||
return 'warning';
|
||||
case 'error':
|
||||
return 'error';
|
||||
case 'success':
|
||||
return 'success';
|
||||
default:
|
||||
return 'warning';
|
||||
}
|
||||
};
|
||||
|
||||
// 渲染文档内容
|
||||
const renderDocumentContent = () => {
|
||||
return (
|
||||
<div className="word-document" ref={contentRef} style={{transform: `scale(${zoomLevel/100})`, transformOrigin: 'center top'}}>
|
||||
<h1>{fileContent.title}</h1>
|
||||
<p style={{textAlign: 'right'}}>合同编号:{fileContent.contractNumber}</p>
|
||||
|
||||
<div style={{margin: '20px 0'}}>
|
||||
<p><strong>甲方(供方):</strong>{fileContent.parties.partyA.name}</p>
|
||||
<p>地址:{fileContent.parties.partyA.address}</p>
|
||||
<p>法定代表人:{fileContent.parties.partyA.representative}</p>
|
||||
<p>联系电话:{fileContent.parties.partyA.phone}</p>
|
||||
<p> </p>
|
||||
<p><strong>乙方(需方):</strong>{fileContent.parties.partyB.name}</p>
|
||||
<p>地址:{fileContent.parties.partyB.address}</p>
|
||||
<p>法定代表人:{fileContent.parties.partyB.representative}</p>
|
||||
<p>联系电话:{fileContent.parties.partyB.phone}</p>
|
||||
</div>
|
||||
|
||||
<p>根据《中华人民共和国合同法》及有关法律法规的规定,经双方协商一致,签订本合同,共同遵守。</p>
|
||||
|
||||
{fileContent.sections.map((section, sectionIndex) => (
|
||||
<div key={sectionIndex}>
|
||||
<h2>{section.title}</h2>
|
||||
{renderSectionContent(section.content, section.title, sectionIndex)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// 渲染章节内容,处理高亮
|
||||
const renderSectionContent = (content: string, sectionTitle: string, sectionIndex: number) => {
|
||||
const lines = content.split('\n');
|
||||
|
||||
return lines.map((line, lineIndex) => {
|
||||
// 查找该行对应的评查点
|
||||
const reviewPoint = reviewPoints.find(point =>
|
||||
point.position &&
|
||||
point.position.section === sectionTitle &&
|
||||
point.position.index === lineIndex
|
||||
);
|
||||
|
||||
if (reviewPoint && highlightsVisible) {
|
||||
// 如果有对应的评查点,添加高亮
|
||||
const isActive = reviewPoint.id === activeReviewPointId;
|
||||
return (
|
||||
<div
|
||||
key={`${sectionIndex}-${lineIndex}`}
|
||||
className={`highlight-area ${getHighlightClass(reviewPoint.status)} ${isActive ? 'highlight-focus' : ''}`}
|
||||
data-review-id={reviewPoint.id}
|
||||
style={isActive ? {zIndex: 20, boxShadow: '0 0 0 2px yellow, 0 0 10px rgba(0,0,0,0.3)'} : {}}
|
||||
>
|
||||
<p>{line}</p>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
// 没有评查点,正常显示
|
||||
return <p key={`${sectionIndex}-${lineIndex}`}>{line}</p>;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="file-preview">
|
||||
<div className="file-preview-header py-2 px-4">
|
||||
<div className="flex items-center">
|
||||
<i className="ri-file-text-line text-primary mr-2"></i>
|
||||
<span className="font-medium text-primary">文件预览</span>
|
||||
</div>
|
||||
<div className="file-preview-actions">
|
||||
<button
|
||||
className="ant-btn ant-btn-sm ant-btn-default py-0 px-1 text-xs h-5 leading-5"
|
||||
onClick={handleZoomIn}
|
||||
>
|
||||
<i className="ri-zoom-in-line"></i>
|
||||
</button>
|
||||
<button
|
||||
className="ant-btn ant-btn-sm ant-btn-default py-0 px-1 text-xs h-5 leading-5"
|
||||
onClick={handleZoomOut}
|
||||
>
|
||||
<i className="ri-zoom-out-line"></i>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
<div className="file-preview-content">
|
||||
{renderDocumentContent()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user