fix: 1. 优化collabora的高亮效果,不固定主要页面。
2. 优化评查结果中的下载按钮,如果加载docx文件的话需要先保存再下载。 3. 交叉评查结果中添加返回按钮,并实现打开对应的任务的文档列表。 4. 文档类型的添加,添加绑定合同管理为入口的时候文档类型名称必须是要附带‘合同’字符。
This commit is contained in:
@@ -185,9 +185,10 @@ export const CollaboraViewer = forwardRef<CollaboraViewerHandle, CollaboraViewer
|
||||
}), [unoCommands, isDocumentLoaded, mode]);
|
||||
|
||||
// 5. 监听 targetPage 和 highlightText 变化,自动跳转并高亮
|
||||
// 根据是否有 targetPage 参数选择高亮方式:
|
||||
// - 有 targetPage:使用 Python 脚本(支持跨页搜索和精确跳转)
|
||||
// - 无 targetPage:使用 UNO 命令(当前页面高亮,性能更好)
|
||||
// 新逻辑:从指定页(默认第1页)开始向下搜索第一个匹配项并高亮
|
||||
// - 先跳转到指定页面
|
||||
// - 使用 UNO 搜索从当前位置向下找第一个匹配项(UNO 搜索自带循环功能)
|
||||
// - 对搜索到的文本设置高亮背景色
|
||||
useEffect(() => {
|
||||
// 如果文档未加载完成,不执行跳转和高亮
|
||||
if (!isDocumentLoaded || !iframeRef.current?.contentWindow) {
|
||||
@@ -199,10 +200,12 @@ export const CollaboraViewer = forwardRef<CollaboraViewerHandle, CollaboraViewer
|
||||
const performHighlight = async () => {
|
||||
const iframeWindow = iframeRef.current!.contentWindow!;
|
||||
const textToHighlight = highlightText.trim();
|
||||
// 确定起始页码:有 targetPage 则使用,否则默认从第1页开始
|
||||
const startPage = (targetPage !== undefined && targetPage !== null) ? targetPage : 1;
|
||||
|
||||
try {
|
||||
// 步骤1:清除之前的所有高亮
|
||||
console.log('[CollaboraViewer] 步骤1:清除旧高亮...');
|
||||
// console.log('[CollaboraViewer] 步骤1:清除旧高亮...');
|
||||
await clearHighlights(iframeWindow, {
|
||||
color: 16776960, // 黄色
|
||||
timeout: 5000,
|
||||
@@ -211,36 +214,38 @@ export const CollaboraViewer = forwardRef<CollaboraViewerHandle, CollaboraViewer
|
||||
// 短暂延迟,确保清除操作完成
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
// 步骤2:根据是否有 targetPage 选择高亮方式
|
||||
if (targetPage !== undefined && targetPage !== null) {
|
||||
// 方案A:有 targetPage - 使用 Python 脚本(跨页搜索 + 高亮 + 跳转)
|
||||
console.log(`[CollaboraViewer] 步骤2A:使用 Python 脚本跳转到第 ${targetPage} 页并高亮 "${textToHighlight}"`);
|
||||
|
||||
const result = await pythonHighlightText(iframeWindow, textToHighlight, {
|
||||
color: 16776960, // 黄色
|
||||
page: targetPage,
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
console.log(`[CollaboraViewer] ✓ Python 高亮成功: "${textToHighlight}" (第${targetPage}页, 共${result.highlightedCount}处)`);
|
||||
} else {
|
||||
console.error('[CollaboraViewer] ✗ Python 高亮失败:', result.message);
|
||||
}
|
||||
} else {
|
||||
// 方案B:无 targetPage - 使用 UNO 命令(当前页面高亮)
|
||||
console.log(`[CollaboraViewer] 步骤2B:使用 UNO 命令在当前页高亮 "${textToHighlight}"`);
|
||||
|
||||
unoHighlightText(iframeWindow, textToHighlight, 16776960); // 黄色
|
||||
|
||||
// 短暂延迟,确保高亮操作完成
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
// 取消选中状态(避免高亮后文本仍被选中)
|
||||
console.log('[CollaboraViewer] 步骤3:取消选中状态...');
|
||||
sendUnoCommand(iframeWindow, '.uno:Escape', {});
|
||||
|
||||
console.log(`[CollaboraViewer] ✓ UNO 高亮完成: "${textToHighlight}"`);
|
||||
// 步骤2:跳转到起始页面
|
||||
// console.log(`[CollaboraViewer] 步骤2:跳转到第 ${startPage} 页...`);
|
||||
try {
|
||||
await customGotoPage(iframeWindow, startPage);
|
||||
// 等待页面跳转完成
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
} catch (gotoError) {
|
||||
console.warn('[CollaboraViewer] 页面跳转失败,继续在当前位置搜索:', gotoError);
|
||||
}
|
||||
|
||||
// 步骤3:使用 UNO 搜索从当前位置向下找第一个匹配项
|
||||
// UNO 搜索会自动跳转到匹配位置,如果到文档末尾没找到会循环回开头继续搜索
|
||||
console.log(`[CollaboraViewer] 步骤3:从第 ${startPage} 页开始向下搜索...`);
|
||||
unoSearchNext(iframeWindow, textToHighlight);
|
||||
|
||||
// 等待搜索完成
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
|
||||
// 步骤4:对搜索到的文本(当前选中)设置高亮背景色
|
||||
// console.log('[CollaboraViewer] 步骤4:设置高亮背景色...');
|
||||
sendUnoCommand(iframeWindow, '.uno:BackColor', {
|
||||
BackColor: { type: 'long', value: 16776960 }, // 黄色
|
||||
});
|
||||
|
||||
// 短暂延迟,确保高亮操作完成
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
// 步骤5:取消选中状态(避免高亮后文本仍被选中)
|
||||
// console.log('[CollaboraViewer] 步骤5:取消选中状态...');
|
||||
sendUnoCommand(iframeWindow, '.uno:Escape', {});
|
||||
|
||||
console.log(`[CollaboraViewer] ✓ 搜索高亮完成:(从第${startPage}页开始搜索)`);
|
||||
} catch (error) {
|
||||
console.error('[CollaboraViewer] 高亮失败:', error);
|
||||
}
|
||||
@@ -329,7 +334,7 @@ export const CollaboraViewer = forwardRef<CollaboraViewerHandle, CollaboraViewer
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
|
||||
// 步骤3:自动搜索下一个相同的占位符(如果还有的话)
|
||||
console.log(`[CollaboraViewer] 步骤3:定位到下一个 "${newSearchText}"`);
|
||||
// console.log(`[CollaboraViewer] 步骤3:定位到下一个 "${newSearchText}"`);
|
||||
unoSearchNext(iframeRef.current.contentWindow, newSearchText);
|
||||
|
||||
console.log('[CollaboraViewer] ✓ 静默替换完成,已定位到下一个占位符(如有)');
|
||||
|
||||
@@ -80,7 +80,7 @@ export function unoSearchNext(
|
||||
'Quiet': { type: 'boolean', value: quiet },
|
||||
});
|
||||
|
||||
console.log('[SearchReplace] 搜索下一个:', text, options);
|
||||
// console.log('[SearchReplace] 搜索下一个:', text, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -650,7 +650,7 @@ export function DocumentListModal({
|
||||
placeholder="搜索文件名称或文档编号"
|
||||
value={searchKeyword}
|
||||
onChange={(e) => handleSearchChange(e.target.value)}
|
||||
className="pl-9 pr-4 py-2 border border-gray-300 rounded-md text-sm w-64 focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
|
||||
className="pl-9 pr-4 py-2 border border-gray-300 rounded-md text-sm w-64 focus:outline-none focus:ring-0"
|
||||
/>
|
||||
<i className="ri-search-line absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"></i>
|
||||
{searchKeyword && (
|
||||
|
||||
@@ -1502,6 +1502,7 @@ export function ReviewPointsList({
|
||||
if (mainTypeValue.page && typeof onReviewPointSelect === 'function') {
|
||||
console.log("点击了其他评查点", mainTypeValue)
|
||||
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), mainTypeValue.char_positions, mainTypeValue.value);
|
||||
// onReviewPointSelect(reviewPoint.id, undefined, mainTypeValue.char_positions, mainTypeValue.value);
|
||||
}else if(reviewPoint.contentPage && reviewPoint.contentPage[fieldKey]){
|
||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[fieldKey]), mainTypeValue.char_positions, mainTypeValue.value);
|
||||
}else{
|
||||
|
||||
@@ -28,13 +28,16 @@ interface ReviewTabsProps {
|
||||
};
|
||||
onConfirmResults: () => void;
|
||||
jwtToken?: string | null;
|
||||
/** 下载前保存文档的回调,返回 true 表示保存成功可以继续下载 */
|
||||
onSaveBeforeDownload?: () => Promise<boolean>;
|
||||
}
|
||||
|
||||
export function ReviewTabs({ activeTab, onTabChange, children, fileInfo, onConfirmResults, jwtToken }: ReviewTabsProps) {
|
||||
export function ReviewTabs({ activeTab, onTabChange, children, fileInfo, onConfirmResults, jwtToken, onSaveBeforeDownload }: ReviewTabsProps) {
|
||||
const [isNavigating, setIsNavigating] = useState(false);
|
||||
const [isReuploadModalOpen, setIsReuploadModalOpen] = useState(false);
|
||||
const [selectedTemplateFiles, setSelectedTemplateFiles] = useState<File[]>([]);
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
const [isSaving, setIsSaving] = useState(false); // 下载前保存文档的状态
|
||||
const uploadAreaRef = useRef<UploadAreaRef>(null);
|
||||
const navigate = useNavigate();
|
||||
const revalidator = useRevalidator();
|
||||
@@ -64,6 +67,23 @@ export function ReviewTabs({ activeTab, onTabChange, children, fileInfo, onConfi
|
||||
// 下载原文件
|
||||
const handleDownloadFile = async () => {
|
||||
try {
|
||||
// 如果有保存回调,先执行保存(仅对 DOCX 文件有效)
|
||||
if (onSaveBeforeDownload) {
|
||||
setIsSaving(true);
|
||||
toastService.info('正在保存文档...');
|
||||
|
||||
const saveSuccess = await onSaveBeforeDownload();
|
||||
|
||||
setIsSaving(false);
|
||||
|
||||
if (!saveSuccess) {
|
||||
toastService.error('保存失败,下载已取消');
|
||||
return;
|
||||
}
|
||||
|
||||
toastService.success('文档已保存,开始下载...');
|
||||
}
|
||||
|
||||
// 使用 PDF 代理路由获取文件,自动添加 JWT 认证
|
||||
const downloadUrl = `/api/pdf-proxy?path=${encodeURIComponent(fileInfo.path || '')}`;
|
||||
|
||||
@@ -95,7 +115,7 @@ export function ReviewTabs({ activeTab, onTabChange, children, fileInfo, onConfi
|
||||
}, 100);
|
||||
} catch (error) {
|
||||
console.error('下载文件失败:', error);
|
||||
alert(`下载文件失败: ${error instanceof Error ? error.message : '未知错误'}`);
|
||||
toastService.error(`下载文件失败: ${error instanceof Error ? error.message : '未知错误'}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -279,8 +299,17 @@ export function ReviewTabs({ activeTab, onTabChange, children, fileInfo, onConfi
|
||||
<button
|
||||
className="ant-btn ant-btn-default inline-flex items-center my-2"
|
||||
onClick={handleDownloadFile}
|
||||
disabled={isSaving}
|
||||
>
|
||||
<i className="ri-file-download-line mr-1"></i> 下载
|
||||
{isSaving ? (
|
||||
<>
|
||||
<i className="ri-loader-4-line mr-1 animate-spin"></i> 保存中...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<i className="ri-file-download-line mr-1"></i> 下载
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
{/* <button
|
||||
className="ant-btn ant-btn-default flex items-center"
|
||||
|
||||
Reference in New Issue
Block a user