添加合同和卷宗数据隔离
This commit is contained in:
+164
-136
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { useState, useEffect, useRef, useCallback } from "react";
|
||||
import { useSearchParams, useLoaderData, useFetcher, useNavigate,Link } from "@remix-run/react";
|
||||
import { type MetaFunction, type ActionFunctionArgs, type LoaderFunctionArgs } from "@remix-run/node";
|
||||
import { Card } from "~/components/ui/Card";
|
||||
@@ -34,63 +34,28 @@ export const meta: MetaFunction = () => {
|
||||
|
||||
// 数据加载器
|
||||
export const loader = async ({ request }: LoaderFunctionArgs) => {
|
||||
// 获取URL查询参数
|
||||
// 获取URL查询参数,只保留必要的分页参数
|
||||
const url = new URL(request.url);
|
||||
const search = url.searchParams.get("search") || "";
|
||||
const documentType = url.searchParams.get("documentType") || "";
|
||||
const auditStatus = url.searchParams.get("auditStatus") || "";
|
||||
const documentNumber = url.searchParams.get("documentNumber") || "";
|
||||
const fileStatus = url.searchParams.get("fileStatus") || "";
|
||||
const dateFrom = url.searchParams.get("dateFrom") || "";
|
||||
const dateTo = url.searchParams.get("dateTo") || "";
|
||||
const page = parseInt(url.searchParams.get("page") || "1", 10);
|
||||
const pageSize = parseInt(url.searchParams.get("pageSize") || "10", 10);
|
||||
|
||||
// 构建搜索参数
|
||||
const searchParams = {
|
||||
name: search || undefined,
|
||||
documentNumber: documentNumber || undefined,
|
||||
documentType: documentType || undefined,
|
||||
auditStatus: auditStatus || undefined,
|
||||
fileStatus: fileStatus || undefined,
|
||||
dateFrom: dateFrom || undefined,
|
||||
dateTo: dateTo || undefined,
|
||||
// 获取文档类型列表,用于筛选条件
|
||||
const typesResponse = await getDocumentTypes({ pageSize: 500 });
|
||||
const documentTypes = typesResponse.data?.types || [];
|
||||
const documentTypeOptions = documentTypes.map(type => ({
|
||||
value: type.id,
|
||||
label: type.name
|
||||
}));
|
||||
|
||||
// 初始返回空数据,将在客户端根据 sessionStorage 中的 reviewType 加载实际数据
|
||||
return Response.json({
|
||||
documents: [],
|
||||
total: 0,
|
||||
page,
|
||||
pageSize
|
||||
};
|
||||
|
||||
try {
|
||||
// 获取文档列表
|
||||
const documentsResponse = await getDocuments(searchParams);
|
||||
// console.log('documentsResponse---1--',JSON.stringify(documentsResponse,null,2));
|
||||
if (documentsResponse.error) {
|
||||
throw new Error(documentsResponse.error);
|
||||
}
|
||||
|
||||
// 获取文档类型列表,用于筛选条件,设置较大的pageSize确保获取所有数据
|
||||
const typesResponse = await getDocumentTypes({ pageSize: 500 });
|
||||
// console.log('typesResponse-----',typesResponse);
|
||||
const documentTypes = typesResponse.data?.types || [];
|
||||
const documentTypeOptions = documentTypes.map(type => ({
|
||||
value: type.id,
|
||||
label: type.name
|
||||
}));
|
||||
|
||||
// console.log('typesResponse-----',JSON.stringify(documentsResponse.data?.documents[1],null,2));
|
||||
return Response.json({
|
||||
documents: documentsResponse.data?.documents || [],
|
||||
total: documentsResponse.data?.total || 0,
|
||||
page,
|
||||
pageSize,
|
||||
documentTypeOptions
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取文档列表失败:', error);
|
||||
return Response.json({
|
||||
error: '获取文档列表失败',
|
||||
status: 500
|
||||
}, { status: 500 });
|
||||
}
|
||||
pageSize,
|
||||
documentTypeOptions,
|
||||
initialLoad: true // 标记这是初始加载
|
||||
});
|
||||
};
|
||||
|
||||
// 定义action返回的数据类型
|
||||
@@ -199,8 +164,14 @@ export default function DocumentsIndex() {
|
||||
const fetcher = useFetcher<ActionResponse>();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// 存储从 sessionStorage 获取的 reviewType
|
||||
const [reviewType, setReviewType] = useState<string | null>(null);
|
||||
|
||||
// 添加页面加载状态管理
|
||||
const [isLoadingData, setIsLoadingData] = useState(true);
|
||||
const [documents, setDocuments] = useState<DocumentUI[]>([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [filteredDocumentTypeOptions, setFilteredDocumentTypeOptions] = useState(loaderData.documentTypeOptions);
|
||||
const dataCache = useRef<typeof loaderData | null>(null);
|
||||
|
||||
// 从URL获取当前筛选条件
|
||||
@@ -214,8 +185,80 @@ export default function DocumentsIndex() {
|
||||
const currentPage = parseInt(searchParams.get("page") || "1", 10);
|
||||
const pageSize = parseInt(searchParams.get("pageSize") || "10", 10);
|
||||
|
||||
// 获取API返回的数据
|
||||
const { documents, total, documentTypeOptions } = loaderData;
|
||||
// 客户端数据请求
|
||||
const fetchData = useCallback(async (storedReviewType: string) => {
|
||||
setIsLoadingData(true);
|
||||
loadingBarService.show();
|
||||
|
||||
try {
|
||||
// 构建搜索参数
|
||||
const searchParams = {
|
||||
name: search || undefined,
|
||||
documentNumber: documentNumber || undefined,
|
||||
documentType: documentType || undefined,
|
||||
auditStatus: auditStatus || undefined,
|
||||
fileStatus: fileStatus || undefined,
|
||||
dateFrom: dateFrom || undefined,
|
||||
dateTo: dateTo || undefined,
|
||||
reviewType: storedReviewType || undefined,
|
||||
page: currentPage,
|
||||
pageSize
|
||||
};
|
||||
|
||||
// 获取文档列表
|
||||
const documentsResponse = await getDocuments(searchParams);
|
||||
if (documentsResponse.error) {
|
||||
throw new Error(documentsResponse.error);
|
||||
}
|
||||
|
||||
// 获取经过过滤的文档类型列表
|
||||
const filteredTypesResponse = await getDocumentTypes({
|
||||
pageSize: 500,
|
||||
reviewType: storedReviewType || undefined
|
||||
});
|
||||
const filteredDocumentTypes = filteredTypesResponse.data?.types || [];
|
||||
const filteredOptions = filteredDocumentTypes.map(type => ({
|
||||
value: type.id,
|
||||
label: type.name
|
||||
}));
|
||||
|
||||
// 更新状态
|
||||
setDocuments(documentsResponse.data?.documents || []);
|
||||
setTotal(documentsResponse.data?.total || 0);
|
||||
setFilteredDocumentTypeOptions(filteredOptions);
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取文档列表失败:', error);
|
||||
toastService.error('获取文档列表失败: ' + (error instanceof Error ? error.message : '未知错误'));
|
||||
} finally {
|
||||
setIsLoadingData(false);
|
||||
loadingBarService.hide();
|
||||
}
|
||||
}, [search, documentNumber, documentType, auditStatus, fileStatus, dateFrom, dateTo, currentPage, pageSize]);
|
||||
|
||||
// 在组件挂载时从 sessionStorage 获取 reviewType 并加载数据
|
||||
useEffect(() => {
|
||||
try {
|
||||
if (typeof window !== 'undefined') {
|
||||
const storedReviewType = sessionStorage.getItem('reviewType');
|
||||
setReviewType(storedReviewType);
|
||||
|
||||
// 如果有 reviewType,则加载数据
|
||||
if (storedReviewType) {
|
||||
fetchData(storedReviewType);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取 sessionStorage 中的 reviewType 失败:', error);
|
||||
}
|
||||
}, [fetchData]);
|
||||
|
||||
// 监听 URL 参数变化,重新获取数据
|
||||
useEffect(() => {
|
||||
if (reviewType) {
|
||||
fetchData(reviewType);
|
||||
}
|
||||
}, [searchParams, fetchData, reviewType]);
|
||||
|
||||
// 使用并更新缓存数据
|
||||
useEffect(() => {
|
||||
@@ -231,10 +274,6 @@ export default function DocumentsIndex() {
|
||||
// 设置缓存数据
|
||||
dataCache.current = loaderData;
|
||||
|
||||
// 数据加载完成后,执行额外的延迟以确保UI效果
|
||||
setIsLoadingData(false);
|
||||
loadingBarService.hide();
|
||||
|
||||
// 处理loader错误
|
||||
if (loaderData.error) {
|
||||
toastService.error(loaderData.error);
|
||||
@@ -808,84 +847,73 @@ export default function DocumentsIndex() {
|
||||
</div>
|
||||
|
||||
{/* 搜索筛选区 */}
|
||||
<FilterPanel
|
||||
actions={
|
||||
<>
|
||||
<Button
|
||||
type="default"
|
||||
icon="ri-refresh-line"
|
||||
onClick={handleReset}
|
||||
className="mr-2"
|
||||
>
|
||||
重置
|
||||
</Button>
|
||||
{/* <Button
|
||||
type="primary"
|
||||
icon="ri-search-line"
|
||||
onClick={() => {
|
||||
// 保持当前筛选条件,刷新数据
|
||||
// 在实际应用中,这里可能需要触发某些操作
|
||||
}}
|
||||
>
|
||||
搜索
|
||||
</Button> */}
|
||||
</>
|
||||
}
|
||||
noActionDivider={true}
|
||||
>
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 w-full">
|
||||
<SearchFilter
|
||||
label="文档名称"
|
||||
placeholder="请输入文档名称"
|
||||
value={search}
|
||||
onSearch={handleNameSearch}
|
||||
instantSearch={true}
|
||||
/>
|
||||
<FilterPanel
|
||||
actions={
|
||||
<>
|
||||
<Button
|
||||
type="default"
|
||||
icon="ri-refresh-line"
|
||||
onClick={handleReset}
|
||||
className="mr-2"
|
||||
>
|
||||
重置
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
noActionDivider={true}
|
||||
>
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 w-full">
|
||||
<SearchFilter
|
||||
label="文档名称"
|
||||
placeholder="请输入文档名称"
|
||||
value={search}
|
||||
onSearch={handleNameSearch}
|
||||
instantSearch={true}
|
||||
/>
|
||||
|
||||
<SearchFilter
|
||||
label="文档编号"
|
||||
placeholder="请输入文档编号"
|
||||
value={documentNumber}
|
||||
onSearch={handleDocumentNumberChange}
|
||||
instantSearch={true}
|
||||
/>
|
||||
|
||||
<FilterSelect
|
||||
label="文档类型"
|
||||
name="documentType"
|
||||
value={documentType}
|
||||
options={documentTypeOptions}
|
||||
onChange={handleDocumentTypeChange}
|
||||
/>
|
||||
|
||||
<FilterSelect
|
||||
label="文件状态"
|
||||
name="fileStatus"
|
||||
value={fileStatus}
|
||||
options={fileStatusOptions}
|
||||
onChange={handleFileStatusChange}
|
||||
/>
|
||||
|
||||
<FilterSelect
|
||||
label="审核状态"
|
||||
name="auditStatus"
|
||||
value={auditStatus}
|
||||
options={auditStatusOptions}
|
||||
onChange={handleStatusChange}
|
||||
/>
|
||||
|
||||
<DateRangeFilter
|
||||
label="上传时间"
|
||||
startDate={dateFrom}
|
||||
endDate={dateTo}
|
||||
onStartDateChange={(value) => handleDateChange('dateFrom', value)}
|
||||
onEndDateChange={(value) => handleDateChange('dateTo', value)}
|
||||
simple={true}
|
||||
colorMode="light"
|
||||
/>
|
||||
</div>
|
||||
</FilterPanel>
|
||||
|
||||
<SearchFilter
|
||||
label="文档编号"
|
||||
placeholder="请输入文档编号"
|
||||
value={documentNumber}
|
||||
onSearch={handleDocumentNumberChange}
|
||||
instantSearch={true}
|
||||
/>
|
||||
|
||||
<FilterSelect
|
||||
label="文档类型"
|
||||
name="documentType"
|
||||
value={documentType}
|
||||
options={filteredDocumentTypeOptions}
|
||||
onChange={handleDocumentTypeChange}
|
||||
/>
|
||||
|
||||
<FilterSelect
|
||||
label="文件状态"
|
||||
name="fileStatus"
|
||||
value={fileStatus}
|
||||
options={fileStatusOptions}
|
||||
onChange={handleFileStatusChange}
|
||||
/>
|
||||
|
||||
<FilterSelect
|
||||
label="审核状态"
|
||||
name="auditStatus"
|
||||
value={auditStatus}
|
||||
options={auditStatusOptions}
|
||||
onChange={handleStatusChange}
|
||||
/>
|
||||
|
||||
<DateRangeFilter
|
||||
label="上传时间"
|
||||
startDate={dateFrom}
|
||||
endDate={dateTo}
|
||||
onStartDateChange={(value) => handleDateChange('dateFrom', value)}
|
||||
onEndDateChange={(value) => handleDateChange('dateTo', value)}
|
||||
simple={true}
|
||||
colorMode="light"
|
||||
/>
|
||||
</div>
|
||||
</FilterPanel>
|
||||
|
||||
{/* 数据表格 */}
|
||||
<Card>
|
||||
|
||||
Reference in New Issue
Block a user