From fe75b4fabdc5afd479fce4b239b4c08c7d780f67 Mon Sep 17 00:00:00 2001 From: yorn <1057707203@qq.com> Date: Wed, 26 Nov 2025 10:49:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=201.=20=E5=B0=86=E4=BA=A4=E5=8F=89?= =?UTF-8?q?=E8=AF=84=E6=9F=A5=E8=BD=AC=E7=A7=BB=E5=9C=A8=E5=85=A5=E5=8F=A3?= =?UTF-8?q?=E9=A1=B5=E3=80=82=202.=20=E4=BA=A4=E5=8F=89=E8=AF=84=E6=9F=A5?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E7=9A=84pdf=E9=A2=84=E8=A7=88=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E5=A4=8D=E7=94=A8=E8=AF=84=E6=9F=A5=E7=82=B9=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E7=9A=84=EF=BC=8C=E5=90=8C=E6=97=B6=E5=9C=A8=E8=AF=84?= =?UTF-8?q?=E6=9F=A5=E7=BB=93=E6=9E=9C=E4=B8=AD=E7=9A=84=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E4=B9=9F=E6=B7=BB=E5=8A=A0=E5=9D=90=E6=A0=87=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cross-checking/ReviewPointsList.tsx | 108 ++++++++++-------- app/components/cross-checking/index.ts | 2 +- app/components/layout/Sidebar.tsx | 28 ++++- app/components/reviews/FilePreview.tsx | 18 +-- .../reviews/previewComponents/PdfPreview.tsx | 16 +-- app/routes/_index.tsx | 59 +++++++++- app/routes/cross-checking.result.tsx | 31 ++--- app/routes/reviews.tsx | 12 +- 8 files changed, 181 insertions(+), 93 deletions(-) diff --git a/app/components/cross-checking/ReviewPointsList.tsx b/app/components/cross-checking/ReviewPointsList.tsx index eaa9f73..8f0c453 100644 --- a/app/components/cross-checking/ReviewPointsList.tsx +++ b/app/components/cross-checking/ReviewPointsList.tsx @@ -80,6 +80,16 @@ const getRuleTypeText = (type?: string): string => { return ruleTypeMap[type] || type; }; +/** + * 字符位置类型定义 + * 用于定位文档中具体的文字位置 + */ +export interface CharPosition { + box: number[][]; // 字符边界框坐标 + char: string; // 字符内容 + score: number; // OCR识别置信度 +} + /** * 评查点类型定义 * 用于展示单个评查结果 @@ -172,7 +182,7 @@ interface ReviewPointsListProps { reviewPoints: ReviewPoint[]; statistics: Statistics; activeReviewPointResultId: string | null; - onReviewPointSelect: (id: string, page?: number) => void; + onReviewPointSelect: (id: string, page?: number, charPositions?: CharPosition[]) => void; onStatusChange?: (id: string, editAuditStatusId: string | number, status: string, message: string) => void; scoringProposals?: ScoringProposal[]; jwtToken?: string; // 添加JWT token参数 @@ -1110,15 +1120,15 @@ export function ReviewPointsList({ // console.log('singleReviewPoint-------', singleReviewPoint); // 检查是否存在配置和pairs数组 - const config = singleReviewPoint.config as { - logic?: string; - pairs?: Array<{ - sourceField: Record; - targetField: Record; + const config = singleReviewPoint.config as { + logic?: string; + pairs?: Array<{ + sourceField: Record; + targetField: Record; res: boolean; compareMethod?: string; - }>; - selectedFields?: string[] + }>; + selectedFields?: string[] } | undefined; if (!config || !config.pairs || !Array.isArray(config.pairs) || config.pairs.length === 0) { @@ -1159,27 +1169,28 @@ export function ReviewPointsList({ // 查找链条关系 const findChains = () => { - type ChainItem = { - field: string; - data: { - key: string; - page: number; - value: string - }; + type ChainItem = { + field: string; + data: { + key: string; + page: number; + value: string; + char_positions?: CharPosition[]; + }; res: boolean; - compareMethod?: string; + compareMethod?: string; }; - + const chains: Array> = []; const visited = new Set(); - + // 构建字段映射关系 - const fieldMap = new Map>(); @@ -1396,7 +1407,7 @@ export function ReviewPointsList({ for (const item of chain) { if (item.data.page && typeof onReviewPointSelect === 'function') { hasPage = true; - onReviewPointSelect(reviewPoint.id, Number(item.data.page)); + onReviewPointSelect(reviewPoint.id, Number(item.data.page), item.data.char_positions); break; } } @@ -1410,7 +1421,7 @@ export function ReviewPointsList({ // 遍历chain找到第一个有效的page for (const item of chain) { if (item.data.page && typeof onReviewPointSelect === 'function') { - onReviewPointSelect(reviewPoint.id, Number(item.data.page)); + onReviewPointSelect(reviewPoint.id, Number(item.data.page), item.data.char_positions); break; } } @@ -1450,7 +1461,7 @@ export function ReviewPointsList({ // 假设onReviewPointSelect在作用域内可用 const reviewPointId = reviewPoint.id as string; if (reviewPointId && typeof onReviewPointSelect === 'function') { - onReviewPointSelect(reviewPointId, Number(item.data.page)); + onReviewPointSelect(reviewPointId, Number(item.data.page), item.data.char_positions); } } else if(reviewPoint.contentPage && reviewPoint.contentPage[item.field]){ @@ -1533,7 +1544,7 @@ export function ReviewPointsList({ if (chain[0].data.page) { const reviewPointId = reviewPoint.id as string; if (reviewPointId && typeof onReviewPointSelect === 'function') { - onReviewPointSelect(reviewPointId, chain[0].data.page); + onReviewPointSelect(reviewPointId, chain[0].data.page, chain[0].data.char_positions); } } else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[0].field]){ @@ -1559,7 +1570,7 @@ export function ReviewPointsList({ if (chain[1].data.page) { const reviewPointId = reviewPoint.id as string; if (reviewPointId && typeof onReviewPointSelect === 'function') { - onReviewPointSelect(reviewPointId, chain[1].data.page); + onReviewPointSelect(reviewPointId, chain[1].data.page, chain[1].data.char_positions); } } else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[1].field]){ @@ -1632,12 +1643,13 @@ export function ReviewPointsList({ */ const renderOtherRule = (otherRule: Record, reviewPoint: ReviewPoint) => { const fieldKey = otherRule.fieldKey as string; - const fieldValue = otherRule.fieldValue as { - type: Record; + char_positions?: CharPosition[]; + }>; }; // 获取res的综合结果 @@ -1698,7 +1710,7 @@ export function ReviewPointsList({ onClick={(e) => { e.stopPropagation(); if (mainTypeValue.page && typeof onReviewPointSelect === 'function') { - onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page)); + onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), mainTypeValue.char_positions); }else if(reviewPoint.contentPage && reviewPoint.contentPage[fieldKey]){ onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[fieldKey])); }else{ @@ -1709,7 +1721,7 @@ export function ReviewPointsList({ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); if (mainTypeValue.page && typeof onReviewPointSelect === 'function') { - onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page)); + onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), mainTypeValue.char_positions); }else{ toastService.error(`没有找到${fieldKey}对应的索引内容`); } @@ -1772,12 +1784,13 @@ export function ReviewPointsList({ const renderModelRule = (aiRule: Record, reviewPoint: ReviewPoint) => { // 从aiRule中提取配置信息 - const config = aiRule.config as { - model?: string; - fields?: Record; + char_positions?: CharPosition[]; + }>; message?: string; res?: boolean; } | undefined; @@ -1819,7 +1832,7 @@ export function ReviewPointsList({ onClick={(e) => { e.stopPropagation(); if (value.page && typeof onReviewPointSelect === 'function') { - onReviewPointSelect(reviewPoint.id, Number(value.page)); + onReviewPointSelect(reviewPoint.id, Number(value.page), value.char_positions); }else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){ onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key])); }else{ @@ -1831,7 +1844,7 @@ export function ReviewPointsList({ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); if (value.page && typeof onReviewPointSelect === 'function') { - onReviewPointSelect(reviewPoint.id, Number(value.page)); + onReviewPointSelect(reviewPoint.id, Number(value.page), value.char_positions); }else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){ onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key])); }else{ @@ -1946,6 +1959,7 @@ export function ReviewPointsList({ interface RuleFieldValue { page?: number | string; value?: string; + char_positions?: CharPosition[]; type: Record; } @@ -1964,7 +1978,7 @@ export function ReviewPointsList({ // 使用类型断言获取config对象的具体结构 const config = rule.config as { res: boolean; - fields: Record; + fields: Record; logic?: string; }; @@ -2011,7 +2025,7 @@ export function ReviewPointsList({ // 使用类型断言获取config对象的具体结构 const config = rule.config as { res: boolean; - field: Record; + field: Record; formatType?: string; parameters?: string; }; @@ -2045,7 +2059,7 @@ export function ReviewPointsList({ logic: string; res: boolean; conditions: Array<{ - field: Record; + field: Record; value: string; operator: string; res: boolean; @@ -2080,7 +2094,7 @@ export function ReviewPointsList({ // 使用类型断言获取config对象的具体结构 const config = rule.config as { res: boolean; - field: Record; + field: Record; pattern?: string; matchType?: string; selectedFields?: string[]; @@ -2115,6 +2129,7 @@ export function ReviewPointsList({ res: boolean; page?: number | string; value?: string; + char_positions?: CharPosition[] }>; }; }> = []; @@ -2127,6 +2142,7 @@ export function ReviewPointsList({ res: boolean; page?: number | string; value?: string; + char_positions?: CharPosition[] }>; }; }> = {}; @@ -2138,9 +2154,10 @@ export function ReviewPointsList({ const typeKey = Object.keys(fieldValue.type)[0]; // 获取类型名称(exists/logic/regex/format) const typeValue = fieldValue.type[typeKey]; // 获取类型值(true/false) - // 提取页码和值 + // 提取页码和值和字符位置 const page = fieldValue.page; const value = fieldValue.value; + const char_positions = fieldValue.char_positions // 如果是第一次遇到这个fieldKey,创建新条目 if (!fieldKeyMap[fieldKey]) { @@ -2157,7 +2174,8 @@ export function ReviewPointsList({ fieldKeyMap[fieldKey].fieldValue.type[typeKey] = { res: typeValue, page, - value + value, + char_positions }; }); diff --git a/app/components/cross-checking/index.ts b/app/components/cross-checking/index.ts index 65a0b91..131ddc0 100644 --- a/app/components/cross-checking/index.ts +++ b/app/components/cross-checking/index.ts @@ -3,7 +3,7 @@ */ export { FileInfo } from './FileInfo'; -export { FilePreview } from './FilePreview'; +export { FilePreview } from '../reviews/FilePreview'; export { ReviewPointsList } from './ReviewPointsList'; export type { ReviewPoint } from './ReviewPointsList'; export { DocumentListModal } from './DocumentListModal'; \ No newline at end of file diff --git a/app/components/layout/Sidebar.tsx b/app/components/layout/Sidebar.tsx index eb55325..cd52023 100644 --- a/app/components/layout/Sidebar.tsx +++ b/app/components/layout/Sidebar.tsx @@ -90,16 +90,18 @@ export function Sidebar({ onToggle, collapsed, userRole, frontendJWT = '' }: Sid fetchUserRoutes(); }, [userRole, frontendJWT, navigate]); - // 🔑 检查是否处于系统设置模式 + // 🔑 检查是否处于系统设置模式或交叉评查模式 const [isSettingsMode, setIsSettingsMode] = useState(false); + const [isCrossCheckingMode, setIsCrossCheckingMode] = useState(false); - // 从 sessionStorage 读取当前选中的模块名称和图片路径,以及系统设置模式标志 + // 从 sessionStorage 读取当前选中的模块名称和图片路径,以及各种模式标志 useEffect(() => { if (typeof window !== 'undefined') { try { const moduleName = sessionStorage.getItem('selectedModuleName'); const modulePicPath = sessionStorage.getItem('selectedModulePicPath'); const settingsMode = sessionStorage.getItem('settingsMode'); + const crossCheckingMode = sessionStorage.getItem('crossCheckingMode'); if (moduleName) { setSelectedModuleName(moduleName); @@ -114,9 +116,19 @@ export function Sidebar({ onToggle, collapsed, userRole, frontendJWT = '' }: Sid // 🔑 检查是否处于系统设置模式 if (settingsMode === 'true') { setIsSettingsMode(true); + setIsCrossCheckingMode(false); // 互斥 console.log('⚙️ [Sidebar] 进入系统设置模式'); - } else { + } + // 🔑 检查是否处于交叉评查模式 + else if (crossCheckingMode === 'true') { + setIsCrossCheckingMode(true); + setIsSettingsMode(false); // 互斥 + console.log('🔀 [Sidebar] 进入交叉评查模式'); + } + // 普通模式 + else { setIsSettingsMode(false); + setIsCrossCheckingMode(false); } } catch (error) { console.error('❌ [Sidebar] 读取 sessionStorage 失败:', error); @@ -177,11 +189,21 @@ export function Sidebar({ onToggle, collapsed, userRole, frontendJWT = '' }: Sid return item.path === '/settings' || item.path?.startsWith('/settings/'); } + // 🔑 优先检查:如果处于交叉评查模式,只显示 /cross-checking 及其子路由 + if (isCrossCheckingMode) { + return item.path === '/cross-checking' || item.path?.startsWith('/cross-checking/'); + } + // 🔑 重要:非系统设置模式下,隐藏所有 /settings 相关菜单 if (item.path === '/settings' || item.path?.startsWith('/settings/')) { return false; } + // 🔑 重要:非交叉评查模式下,隐藏所有 /cross-checking 相关菜单 + if (item.path === '/cross-checking' || item.path?.startsWith('/cross-checking/')) { + return false; + } + // 如果是省局访问 // if(isPort51707){ // if (selectedModuleName === '智慧法务大模型'){ diff --git a/app/components/reviews/FilePreview.tsx b/app/components/reviews/FilePreview.tsx index 36d7bd2..222ed12 100644 --- a/app/components/reviews/FilePreview.tsx +++ b/app/components/reviews/FilePreview.tsx @@ -181,18 +181,18 @@ export function FilePreview({ fileContent, activeReviewPointResultId, targetPage }, [targetPage, numPages, fileContent, activeReviewPointResultId, isStructuredView, isPdf]); // 调试日志 - console.log('[FilePreview] 组件渲染', { - real_path, - fileExtension, - isDocx, - isPdf, - hasPath: !!fileContent.path, - hasTemplatePath: !!fileContent.template_contract_path - }); + // console.log('[FilePreview] 组件渲染', { + // real_path, + // fileExtension, + // isDocx, + // isPdf, + // hasPath: !!fileContent.path, + // hasTemplatePath: !!fileContent.template_contract_path + // }); // 如果是PDF文件,直接使用PdfPreview组件 if (isPdf && real_path) { - console.log('[FilePreview] 渲染PDF预览', { real_path, targetPage, charPositions }); + // console.log('[FilePreview] 渲染PDF预览', { real_path, targetPage, charPositions }); const pageOffset = fileContent.ocrResult?.__meta?.page_offset || 0; return ( (null); diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index c3326b5..c216e8a 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -51,6 +51,8 @@ export async function loader({ request }: LoaderFunctionArgs) { // 🔑 检查用户是否有系统设置权限 let hasSettingsAccess = false; + let hasCrossCheckingAccess = false; + if (userRole && frontendJWT) { const { getUserRoutesByRole } = await import('~/api/auth/user-routes'); const routesResult = await getUserRoutesByRole(userRole, frontendJWT, true); // includeHidden=true @@ -58,12 +60,15 @@ export async function loader({ request }: LoaderFunctionArgs) { if (routesResult.success && routesResult.data) { // 检查是否存在顶级路由 '/settings' hasSettingsAccess = routesResult.data.some(route => route.path === '/settings'); + // 检查是否存在顶级路由 '/cross-checking' + hasCrossCheckingAccess = routesResult.data.some(route => route.path === '/cross-checking'); // console.log(`🔑 [Index Loader] 用户${hasSettingsAccess ? '有' : '没有'}系统设置权限`); + // console.log(`🔑 [Index Loader] 用户${hasCrossCheckingAccess ? '有' : '没有'}交叉评查权限`); } } - // 返回用户信息、入口模块和系统设置权限给客户端 - return Response.json({ userRole, userInfo, entryModules, hasSettingsAccess }); + // 返回用户信息、入口模块和权限给客户端 + return Response.json({ userRole, userInfo, entryModules, hasSettingsAccess, hasCrossCheckingAccess }); } export default function Index() { @@ -108,13 +113,20 @@ export default function Index() { // console.log('👤 [Index] 当前用户信息:', userInfo); }, [userRole, userInfo]); - // 🔑 清除系统设置模式标志(当用户返回首页时) + // 🔑 清除系统设置模式和交叉评查模式标志(当用户返回首页时) useEffect(() => { if (typeof window !== 'undefined') { const settingsMode = sessionStorage.getItem('settingsMode'); + const crossCheckingMode = sessionStorage.getItem('crossCheckingMode'); + if (settingsMode === 'true') { sessionStorage.removeItem('settingsMode'); - console.log('🔄 [Index] 清除系统设置模式标志'); + // console.log('🔄 [Index] 清除系统设置模式标志'); + } + + if (crossCheckingMode === 'true') { + sessionStorage.removeItem('crossCheckingMode'); + // console.log('🔄 [Index] 清除交叉评查模式标志'); } } }, []); // 只在组件挂载时执行一次 @@ -233,12 +245,31 @@ export default function Index() { sessionStorage.removeItem('selectedModuleId'); sessionStorage.removeItem('selectedModuleName'); sessionStorage.removeItem('selectedModulePicPath'); + // 清除交叉评查模式标志 + sessionStorage.removeItem('crossCheckingMode'); } // 跳转到系统设置的默认页面 navigate('/rule-groups'); }; + // 处理进入交叉评查 + const handleEnterCrossChecking = () => { + if (typeof window !== 'undefined') { + // 🔑 设置标志:表示用户通过交叉评查入口进入 + sessionStorage.setItem('crossCheckingMode', 'true'); + // 清除模块相关的标志(因为不是从入口模块进入) + sessionStorage.removeItem('selectedModuleId'); + sessionStorage.removeItem('selectedModuleName'); + sessionStorage.removeItem('selectedModulePicPath'); + // 清除系统设置模式标志 + sessionStorage.removeItem('settingsMode'); + } + + // 跳转到交叉评查的默认页面 + navigate('/cross-checking'); + }; + return (
{/* 登出表单 - 隐藏 */} @@ -309,6 +340,25 @@ export default function Index() {
))} + {/* 🔑 交叉评查入口 - 只有有权限的用户才能看到 */} + {loaderData.hasCrossCheckingAccess && ( +
{ + if (e.key === 'Enter' || e.key === ' ') { + handleEnterCrossChecking(); + } + }} + role="button" + tabIndex={0} + aria-label="交叉评查" + > + + 交叉评查 +
+ )} + {/* 🔑 系统设置入口 - 只有有权限的用户才能看到 */} {loaderData.hasSettingsAccess && (
系统设置
)} + ) : (
diff --git a/app/routes/cross-checking.result.tsx b/app/routes/cross-checking.result.tsx index 56280df..e1d1e46 100644 --- a/app/routes/cross-checking.result.tsx +++ b/app/routes/cross-checking.result.tsx @@ -37,8 +37,8 @@ import { ReviewPointsList } from "~/components/cross-checking"; -// 从ReviewPointsList组件中导入ReviewPoint类型 -import { type ReviewPoint } from '~/components/cross-checking'; +// 从ReviewPointsList组件中导入ReviewPoint类型和CharPosition类型 +import { type ReviewPoint, type CharPosition } from '~/components/cross-checking'; import { messageService } from "~/components/ui/MessageModal"; import { loadingBarService } from "~/components/ui/LoadingBar"; import { Breadcrumb } from "~/components/layout/Breadcrumb"; @@ -297,7 +297,7 @@ export async function action({ request }: ActionFunctionArgs) { } export default function CrossCheckingResult() { - console.log('[组件] CrossCheckingResult 渲染'); + // console.log('[组件] CrossCheckingResult 渲染'); const navigate = useNavigate(); const loaderData = useLoaderData(); @@ -306,18 +306,19 @@ export default function CrossCheckingResult() { const [reviewData, setReviewData] = useState(null); const [activeReviewPointResultId, setActiveReviewPointResultId] = useState(null); const [targetPage, setTargetPage] = useState(undefined); + const [charPositions, setCharPositions] = useState(undefined); const [localScoringProposals, setLocalScoringProposals] = useState(scoring_proposals || []); // 本地状态管理scoringProposals // 使用ref来跟踪loading状态,避免不必要的重新渲染 const isProcessingRef = useRef(false); // 添加组件挂载/卸载日志 - useEffect(() => { - console.log('[组件] CrossCheckingResult 挂载'); - return () => { - console.log('[组件] CrossCheckingResult 卸载'); - }; - }, []); + // useEffect(() => { + // console.log('[组件] CrossCheckingResult 挂载'); + // return () => { + // console.log('[组件] CrossCheckingResult 卸载'); + // }; + // }, []); // 同步外部scoring_proposals到本地状态 useEffect(() => { @@ -387,19 +388,22 @@ export default function CrossCheckingResult() { }, [document, reviewPoints, statistics, reviewInfo]); - const handleReviewPointSelect = useCallback((reviewPointId: string, page?: number) => { + const handleReviewPointSelect = useCallback((reviewPointId: string, page?: number, charPositions?: CharPosition[]) => { // 如果点击的是相同的评查点,但有page参数,先重置targetPage以确保useEffect能够触发 if (reviewPointId === activeReviewPointResultId && page) { setTargetPage(undefined); - // 使用setTimeout确保状态更新后再设置新的targetPage + setCharPositions(undefined); + // 使用setTimeout确保状态更新后再设置新的targetPage和charPositions setTimeout(() => { setActiveReviewPointResultId(reviewPointId); setTargetPage(page); + setCharPositions(charPositions); }, 0); } else { - // 正常设置activeReviewPointId和targetPage + // 正常设置activeReviewPointId、targetPage和charPositions setActiveReviewPointResultId(reviewPointId); setTargetPage(page); + setCharPositions(charPositions); } }, [activeReviewPointResultId]); @@ -724,11 +728,12 @@ export default function CrossCheckingResult() {
{/* 左侧:文件预览 */}
-
diff --git a/app/routes/reviews.tsx b/app/routes/reviews.tsx index eda0085..4802f02 100644 --- a/app/routes/reviews.tsx +++ b/app/routes/reviews.tsx @@ -234,7 +234,7 @@ export async function action({ request }: ActionFunctionArgs) { const result = formData.get("result") as string; const message = formData.get("message") as string; - console.log('更新评查结果参数:', { reviewPointResultId, editAuditStatusId, result, message }); + // console.log('更新评查结果参数:', { reviewPointResultId, editAuditStatusId, result, message }); try { const response = await updateReviewResult(reviewPointResultId, editAuditStatusId, result, message, request); @@ -257,7 +257,7 @@ export async function action({ request }: ActionFunctionArgs) { if (intent === "confirmReviewResults") { const documentId = formData.get("documentId") as string; - console.log('确认评查结果参数:', { documentId }); + // console.log('确认评查结果参数:', { documentId }); try { const response = await confirmReviewResults(documentId, request); @@ -293,17 +293,9 @@ export default function ReviewDetails() { const navigate = useNavigate(); const loaderData = useLoaderData(); - // 调试:查看loaderData内容 - 强制刷新 - console.log('[Reviews Component] loaderData keys:', Object.keys(loaderData)); - console.log('[Reviews Component] loaderData:', loaderData); - const fetcher = useFetcher(); const { document, reviewPoints, statistics, reviewInfo, comparison_document, frontendJWT } = loaderData; - // 调试:查看解构后的数据 - console.log('[Reviews Component] 解构后的document:', document); - console.log('[Reviews Component] 解构后的reviewPoints length:', reviewPoints?.length); - const [isLoading, setIsLoading] = useState(false); // 已经通过loader加载了数据,不需要再显示加载状态 const [activeTab, setActiveTab] = useState('preview'); // 'preview', 'analysis', 'fileinfo' const [reviewData, setReviewData] = useState(null);