feat: 1. 将交叉评查转移在入口页。
2. 交叉评查渲染的pdf预览组件复用评查点详情的,同时在评查结果中的数据也添加坐标信息。
This commit is contained in:
+55
-4
@@ -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 (
|
||||
<div className="home-page">
|
||||
{/* 登出表单 - 隐藏 */}
|
||||
@@ -309,6 +340,25 @@ export default function Index() {
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* 🔑 交叉评查入口 - 只有有权限的用户才能看到 */}
|
||||
{loaderData.hasCrossCheckingAccess && (
|
||||
<div
|
||||
className="module-card"
|
||||
onClick={handleEnterCrossChecking}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
handleEnterCrossChecking();
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="交叉评查"
|
||||
>
|
||||
<i className="ri-shuffle-line text-5xl text-primary"></i>
|
||||
<span className="module-name">交叉评查</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 🔑 系统设置入口 - 只有有权限的用户才能看到 */}
|
||||
{loaderData.hasSettingsAccess && (
|
||||
<div
|
||||
@@ -327,6 +377,7 @@ export default function Index() {
|
||||
<span className="module-name">系统设置</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</>
|
||||
) : (
|
||||
<div className="text-center text-gray-500 py-8">
|
||||
|
||||
@@ -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<typeof loader>();
|
||||
@@ -306,18 +306,19 @@ export default function CrossCheckingResult() {
|
||||
const [reviewData, setReviewData] = useState<ReviewData | null>(null);
|
||||
const [activeReviewPointResultId, setActiveReviewPointResultId] = useState<string | null>(null);
|
||||
const [targetPage, setTargetPage] = useState<number | undefined>(undefined);
|
||||
const [charPositions, setCharPositions] = useState<CharPosition[] | undefined>(undefined);
|
||||
const [localScoringProposals, setLocalScoringProposals] = useState<ScoringProposal[]>(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() {
|
||||
<div className="flex flex-col lg:flex-row space-y-4 lg:space-y-0 lg:space-x-4 lg:justify-between">
|
||||
{/* 左侧:文件预览 */}
|
||||
<div className="w-full lg:w-[62%]">
|
||||
<FilePreview
|
||||
<FilePreview
|
||||
fileContent={document}
|
||||
reviewPoints={reviewData.reviewPoints}
|
||||
activeReviewPointResultId={activeReviewPointResultId}
|
||||
targetPage={targetPage}
|
||||
charPositions={charPositions}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
+2
-10
@@ -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<typeof loader>();
|
||||
|
||||
// 调试:查看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<string>('preview'); // 'preview', 'analysis', 'fileinfo'
|
||||
const [reviewData, setReviewData] = useState<ReviewData | null>(null);
|
||||
|
||||
Reference in New Issue
Block a user