fix: 1. 重新对齐交叉评查的接口。

2. 确认评查结果的接口对接。 3. 新增评查点适配省级创建的响应数据和其他用户创建的单条响应数据。  4. 文档列表的文档类型通过通用的查询接口查询文档类型。优化加载状态的时机。
This commit is contained in:
2025-12-11 11:16:50 +08:00
parent ba517d7b9c
commit d8bba607fc
18 changed files with 3435 additions and 1086 deletions
+28 -5
View File
@@ -91,8 +91,15 @@ export async function loader({ request }: LoaderFunctionArgs) {
if (!tasksResponse.success) {
console.error('获取任务列表失败:', tasksResponse.error);
return Response.json({
error: tasksResponse.error || '获取任务列表失败',
status: 500
tasks: [],
totalCount: 0,
currentPage: params.page,
pageSize: params.pageSize,
totalPages: 0,
stats: { totalTasks: 0, pendingTasks: 0, inProgressTasks: 0, completedTasks: 0 },
frontendJWT,
documentTypes: [],
error: tasksResponse.error || '获取任务列表失败'
}, { status: 500 });
}
@@ -119,8 +126,15 @@ export async function loader({ request }: LoaderFunctionArgs) {
} catch (error) {
console.error('加载交叉评查任务列表失败:', error);
return Response.json({
error: error || '加载任务列表失败',
status: 500
tasks: [],
totalCount: 0,
currentPage: params.page,
pageSize: params.pageSize,
totalPages: 0,
stats: { totalTasks: 0, pendingTasks: 0, inProgressTasks: 0, completedTasks: 0 },
frontendJWT: undefined,
documentTypes: [],
error: error instanceof Error ? error.message : '加载任务列表失败'
}, { status: 500 });
}
}
@@ -219,7 +233,16 @@ const docTypeConfig = {
export default function CrossCheckingIndex() {
const loaderData = useLoaderData<typeof loader>();
const { tasks, totalCount, currentPage, pageSize, stats, frontendJWT, documentTypes, documentTypesError } = loaderData;
const {
tasks = [],
totalCount = 0,
currentPage = 1,
pageSize = 10,
stats = { totalTasks: 0, pendingTasks: 0, inProgressTasks: 0, completedTasks: 0 },
frontendJWT,
documentTypes = [],
documentTypesError
} = loaderData || {};
const [searchParams, setSearchParams] = useSearchParams();
const dateFrom = searchParams.get('dateFrom') || '';
const dateTo = searchParams.get('dateTo') || '';
+1 -1
View File
@@ -642,7 +642,7 @@ export default function CrossCheckingResult() {
console.log('[完成评查] 用户点击确认,开始更新状态');
setIsLoading(true);
try {
const res = await confirmReviewResults(document.id, jwtToken);
const res = await confirmReviewResults(taskId, document.id, jwtToken);
if (res.error) {
toastService.error(res.error);
+30 -29
View File
@@ -11,10 +11,9 @@ import { FilterPanel, FilterSelect, SearchFilter, DateRangeFilter } from "~/comp
import { TableRowSkeleton, LoadingIndicator, NumberSkeleton } from '~/components/ui/SkeletonScreen';
import documentsIndexStyles from "~/styles/pages/documents_index.css?url";
import documentVersionStyles from "~/styles/components/document-version.css?url";
import { deleteDocument, getDocumentsListFromAPI, type DocumentUI, type DocumentVersionUI } from "~/api/files/documents";
import { getDocumentTypesByIds, deleteDocument, getDocumentsListFromAPI, type DocumentUI, type DocumentVersionUI } from "~/api/files/documents";
// import { IssuesDiff } from "~/components/ui/IssuesDiff";
import { ResultStats } from "~/components/ui/ResultStats";
import { getDocumentTypes } from "~/api/document-types/document-types";
import { updateDocumentAuditStatus } from "~/api/evaluation_points/rules-files";
import { appendContractAttachments, uploadContractTemplate } from "~/api/files/files-upload";
import { toastService } from "~/components/ui/Toast";
@@ -50,12 +49,12 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
const pageSize = parseInt(url.searchParams.get("pageSize") || "10", 10);
// 获取文档类型列表(服务端需要显式传递 token,客户端依赖 axios 拦截器)
const typesResponse = await getDocumentTypes({ pageSize: 500 }, frontendJWT);
const documentTypes = typesResponse.data?.types || [];
const documentTypeOptions = documentTypes.map(type => ({
value: type.id,
label: type.name
}));
// const typesResponse = await getDocumentTypes(frontendJWT);
// const documentTypes = typesResponse.data?.types || [];
// const documentTypeOptions = documentTypes.map(type => ({
// value: type.id,
// label: type.name
// }));
// 初始返回空数据,将在客户端根据 sessionStorage 中的 documentTypeIds 加载实际数据
return Response.json({
@@ -63,7 +62,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
total: 0,
page,
pageSize,
documentTypeOptions,
documentTypeOptions: [],
userInfo, // 传递用户信息到客户端
frontendJWT, // 传递 JWT 到客户端
initialLoad: true // 标记这是初始加载
@@ -190,6 +189,8 @@ export default function DocumentsIndex() {
// 添加页面加载状态管理
const [isLoadingData, setIsLoadingData] = useState(true);
// 是否已完成初始化(区分"还没开始加载"和"加载完成但没有数据")
const [hasInitialized, setHasInitialized] = useState(false);
const [documents, setDocuments] = useState<DocumentUI[]>([]);
const [total, setTotal] = useState(0);
const [filteredDocumentTypeOptions, setFilteredDocumentTypeOptions] = useState(loaderData.documentTypeOptions);
@@ -314,10 +315,7 @@ export default function DocumentsIndex() {
setTotal(result.data.total);
// 获取经过过滤的文档类型列表
const filteredTypesResponse = await getDocumentTypes({
pageSize: 500,
documentTypeIds: typeIds
}, jwtToken);
const filteredTypesResponse = await getDocumentTypesByIds(typeIds, jwtToken);
const filteredDocumentTypes = filteredTypesResponse.data?.types || [];
const filteredOptions = filteredDocumentTypes.map(type => ({
value: type.id,
@@ -330,6 +328,7 @@ export default function DocumentsIndex() {
toastService.error('获取文档列表失败: ' + (error instanceof Error ? error.message : '未知错误'));
} finally {
setIsLoadingData(false);
setHasInitialized(true); // 标记初始化完成
loadingBarService.hide();
}
}, [search, documentNumber, documentType, auditStatus, fileStatus, dateFrom, dateTo, currentPage, pageSize, loaderData.frontendJWT]);
@@ -344,14 +343,22 @@ export default function DocumentsIndex() {
console.log('📋 [useEffect] 从 sessionStorage 获取文档类型IDs:', typeIds);
setDocumentTypeIds(typeIds);
// 加载数据
// 加载数据(fetchData 中会自动获取并设置过滤后的文档类型选项)
fetchData(typeIds);
} else {
console.warn('⚠️ [useEffect] sessionStorage 中没有 documentTypeIds');
// 没有 documentTypeIds 时,标记初始化完成但无数据
setIsLoadingData(false);
setHasInitialized(true);
loadingBarService.hide();
}
}
} catch (error) {
console.error('❌ [useEffect] 获取 sessionStorage 中的 documentTypeIds 失败:', error);
// 出错时也标记初始化完成
setIsLoadingData(false);
setHasInitialized(true);
loadingBarService.hide();
}
}, [fetchData]);
@@ -394,23 +401,16 @@ export default function DocumentsIndex() {
}
}, [documents, expandedRows]);
// 使用并更新缓存数据
// 更新缓存数据并处理 loader 错误
useEffect(() => {
// 如果有缓存数据,先显示缓存,再在后台加载新数据
if (dataCache.current) {
setIsLoadingData(false);
} else {
// 显示加载状态 - 确保显示加载条
loadingBarService.show();
setIsLoadingData(true);
}
// 设置缓存数据
// 设置缓存数据(用于后续可能的优化)
dataCache.current = loaderData;
// 处理loader错误
if (loaderData.error) {
toastService.error(loaderData.error);
setIsLoadingData(false);
setHasInitialized(true);
}
}, [loaderData]);
@@ -1490,7 +1490,7 @@ export default function DocumentsIndex() {
<div className="flex justify-between items-center mb-4">
<div className="flex items-center">
<h2 className="text-xl font-medium"></h2>
{isLoadingData ? (
{!hasInitialized || isLoadingData ? (
<div className="ml-4">
<NumberSkeleton />
</div>
@@ -1622,11 +1622,12 @@ export default function DocumentsIndex() {
</div>
<div className="overflow-x-auto">
{isLoadingData && documents.length === 0 ? (
{/* 未初始化完成时显示骨架屏,初始化完成后根据数据显示内容或"暂无数据" */}
{!hasInitialized || (isLoadingData && documents.length === 0) ? (
<TableRowSkeleton count={5} />
) : documents.length === 0 ? (
<div className="text-center py-8 text-gray-500">
{isLoadingData ? "加载中..." : "暂无数据"}
</div>
) : (
<table className="w-full border-collapse">
+34 -2
View File
@@ -853,11 +853,43 @@ export default function RuleNew() {
setIsLoading(false);
} else if (response.data) {
// 获取新创建或更新的评查点ID
const savedPointId = response.data.id;
let savedPointId: number | undefined;
let successMessage = '';
if (isEditMode) {
// 编辑模式:直接从 response.data.id 获取
savedPointId = response.data.id;
successMessage = '评查点更新成功!';
} else {
// 创建模式:从 items 数组中找到 code 不包含 '--' 后缀的基础评查点
const responseData = response.data as {
success?: boolean;
total_created?: number;
message?: string;
items?: Array<{ id: number; code: string; [key: string]: unknown }>;
};
if (responseData.items && Array.isArray(responseData.items) && responseData.items.length > 0) {
// 查找 code 不包含 '--' 的评查点(基础评查点)
const baseItem = responseData.items.find(item => !item.code.includes('--'));
if (baseItem) {
savedPointId = baseItem.id;
} else {
// 如果所有 code 都包含 '--',取第一个
savedPointId = responseData.items[0].id;
}
// 使用后端返回的消息,或生成默认消息
successMessage = responseData.message || `评查点创建成功! 共创建 ${responseData.total_created || responseData.items.length} 个地区的评查点`;
} else if (response.data.id) {
// 兼容旧格式:直接返回单个评查点
savedPointId = response.data.id;
successMessage = '评查点创建成功!';
}
}
if (savedPointId) {
// 显示成功消息
toastService.success(`评查点${isEditMode ? '更新' : '创建'}成功!`);
toastService.success(successMessage);
// 保存成功后跳转到编辑页面并重新加载数据
navigate(`/rules/new?id=${savedPointId}`, { replace: true });