feat: 1. 完善全局路由的访问权限的验证。 2. 完善接口返回的树形路由结构 3.优化评查点列表的查询,改用表连接的方式,废弃使用数据库的rpc函数,同时进行地区隔离和权限隔离。

4. 删除冗余的评查文件列表。      5.完善上传文档 页面初始化查询数据的时候 查询文件类型(改成动态指定)  6. 添加获取入口模块的查询接口。    7.完善服务端中判断token的有效性,失效则跳转到登录页。
8. 重构layout和sidebar的页面,改成由动态权限路由来渲染对应的菜单栏。       9.重构入口页面,通过动态查询根据不同地区的人返回不同的入口。
This commit is contained in:
2025-11-20 01:35:30 +08:00
parent adfb84a31d
commit 2edde8a8ab
23 changed files with 1201 additions and 2154 deletions
+66 -72
View File
@@ -259,11 +259,11 @@ export async function loader({ request }: LoaderFunctionArgs) {
const url = new URL(request.url);
const mode = url.searchParams.get("mode") || "create";
// 我们不能在服务器端访问 sessionStorage,所以在客户端组件中处理 reviewType 过滤
// 我们不能在服务器端访问 sessionStorage,所以在客户端组件中处理 documentTypeIds 过滤
// 并行加载文档和文档类型
const [documentsResponse, typesResponse] = await Promise.all([
getTodayDocuments(userInfo, undefined, frontendJWT),
getDocumentTypes(undefined, frontendJWT)
getTodayDocuments(userInfo, frontendJWT),
getDocumentTypes(frontendJWT)
]);
// console.log('loader: 文档加载结果:', documentsResponse);
@@ -308,9 +308,9 @@ export default function FilesUpload() {
const [isNavigating, setIsNavigating] = useState(false)
const revalidator = useRevalidator()
// 获取 sessionStorage 中的 reviewType 值
// 获取 sessionStorage 中的 documentTypeIds
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [reviewType, setReviewType] = useState<string | null>(null);
const [documentTypeIds, setDocumentTypeIds] = useState<number[] | null>(null);
// 使用 useLoaderData 获取初始数据
const loaderData = useLoaderData<LoaderData>();
@@ -361,19 +361,20 @@ export default function FilesUpload() {
const [queueFiles, setQueueFiles] = useState<Document[]>([]);
const [documentTypesState, setDocumentTypesState] = useState<DocumentType[]>([]);
// 在组件挂载时从 sessionStorage 获取 reviewType
// 在组件挂载时从 sessionStorage 获取 documentTypeIds
useEffect(() => {
try {
// 在客户端环境中执行
if (typeof window !== 'undefined') {
const storedReviewType = sessionStorage.getItem('reviewType');
setReviewType(storedReviewType);
// 根据 reviewType 过滤文档类型和文档列表
filterDocumentTypes(storedReviewType, loaderData.documentTypes);
filterDocuments(storedReviewType);
// 如果reviewType是contract,自动选择合同文档类型
if (storedReviewType === 'contract') {
const typeIdsStr = sessionStorage.getItem('documentTypeIds');
const typeIds = typeIdsStr ? JSON.parse(typeIdsStr) : null;
setDocumentTypeIds(typeIds);
// 根据 documentTypeIds 过滤文档类型和文档列表
filterDocumentTypes(typeIds, loaderData.documentTypes);
filterDocuments(typeIds);
// 如果包含合同类型(ID=1),自动选择合同文档类型
if (typeIds && typeIds.includes(1)) {
setIsContractType(true);
// 查找ID为1的合同文档类型
const contractType = loaderData.documentTypes.find(type => type.id === 1);
@@ -385,49 +386,39 @@ export default function FilesUpload() {
}
}
} catch (error) {
console.error('获取 sessionStorage 中的 reviewType 失败:', error);
console.error('获取 sessionStorage 中的 documentTypeIds 失败:', error);
}
}, [loaderData]);
// 过滤文档类型列表
const filterDocumentTypes = (reviewType: string | null, types: DocumentType[]) => {
if (!reviewType) {
// 如果没有特定的 reviewType,使用原始数据
const filterDocumentTypes = (documentTypeIds: number[] | null, types: DocumentType[]) => {
if (!documentTypeIds || documentTypeIds.length === 0) {
// 如果没有特定的 documentTypeIds,使用原始数据
setDocumentTypesState(types);
return;
}
let filteredTypes: DocumentType[] = [];
if (reviewType === 'contract') {
// 只保留 id=1 的选项
filteredTypes = types.filter(type => type.id === 1);
} else if (reviewType === 'record') {
// 只保留 id=2 和 id=3 的选项
filteredTypes = types.filter(type => type.id === 2 || type.id === 3 || type.id === 155);
} else {
// 如果reviewType不匹配任何条件,使用原始数据
filteredTypes = types;
}
// 根据 documentTypeIds 过滤文档类型
const filteredTypes = types.filter(type => documentTypeIds.includes(type.id));
setDocumentTypesState(filteredTypes);
};
// 过滤文档列表
const filterDocuments = async (reviewType: string | null) => {
if (!reviewType) {
// 如果没有特定的 reviewType,使用原始数据
const filterDocuments = async (documentTypeIds: number[] | null) => {
if (!documentTypeIds || documentTypeIds.length === 0) {
// 如果没有特定的 documentTypeIds,使用原始数据
const documents = loaderData.documents;
setQueueFiles(documents);
// 启动状态检查定时器
startStatusChecker(documents);
return;
}
try {
// 使用 reviewType 获取过滤后的文档列表
const response = await getTodayDocuments(loaderData.userInfo || undefined, reviewType, loaderData.frontendJWT || undefined);
// 使用 documentTypeIds 获取过滤后的文档列表
const response = await getTodayDocuments(loaderData.userInfo || undefined, loaderData.frontendJWT || undefined, documentTypeIds);
if (response.error) {
console.error('过滤文档列表失败:', response.error);
@@ -559,45 +550,48 @@ export default function FilesUpload() {
const checkQueueStatusWithFiles = async (files: Document[]) => {
try {
// console.log('开始检查队列状态,当前队列文件:', files);
// 直接从sessionStorage读取reviewType,避免异步状态更新问题
const currentReviewType = typeof window !== 'undefined' ? sessionStorage.getItem('reviewType') : null;
// console.log('从sessionStorage读取的reviewType:', currentReviewType);
// 直接从sessionStorage读取documentTypeIds,避免异步状态更新问题
const typeIdsStr = typeof window !== 'undefined' ? sessionStorage.getItem('documentTypeIds') : null;
const currentDocumentTypeIds = typeIdsStr ? JSON.parse(typeIdsStr) : null;
// console.log('从sessionStorage读取的documentTypeIds:', currentDocumentTypeIds);
// 获取所有未完成的文档
const incompleteFiles = files.filter(file =>
const incompleteFiles = files.filter(file =>
file.status !== DocumentStatus.PROCESSED && file.id
);
if (incompleteFiles.length === 0) {
console.log('没有未完成的文档,跳过状态检查');
return;
}
let statusResponse;
// 如果是合同类型,需要分类处理
console.log('当前reviewType:', currentReviewType);
if (currentReviewType === 'contract') {
// 分类文档ID
const mainDocumentIds: number[] = [];
const attachmentIds: number[] = [];
// 如果是合同类型(ID=1),需要分类处理
// console.log('当前documentTypeIds:', currentDocumentTypeIds);
// if (currentDocumentTypeIds && currentDocumentTypeIds.includes(1)) {
// // 分类文档ID
// const mainDocumentIds: number[] = [];
// const attachmentIds: number[] = [];
incompleteFiles.forEach(file => {
// 检查是否存在template_contract_path属性来判断是否为合同附件
if ('template_contract_path' in file && file.template_contract_path) {
attachmentIds.push(file.id);
} else {
mainDocumentIds.push(file.id);
}
});
// incompleteFiles.forEach(file => {
// // 检查是否存在template_contract_path属性来判断是否为合同附件
// if ('template_contract_path' in file && file.template_contract_path) {
// attachmentIds.push(file.id);
// } else {
// mainDocumentIds.push(file.id);
// }
// });
// console.log('合同主文件ID:', mainDocumentIds);
// console.log('合同附件ID:', attachmentIds);
// // console.log('合同主文件ID:', mainDocumentIds);
// // console.log('合同附件ID:', attachmentIds);
// 分别查询状态
statusResponse = await getDocumentsStatus(mainDocumentIds, attachmentIds, loaderData.frontendJWT || undefined);
} else {
// // 分别查询状态
// statusResponse = await getDocumentsStatus(mainDocumentIds, attachmentIds, loaderData.frontendJWT || undefined);
// }
// else
{
// 非合同类型,使用原有逻辑
const incompleteIds = incompleteFiles.map(file => file.id);
// console.log('未完成的文档ID:', incompleteIds);
@@ -959,9 +953,9 @@ export default function FilesUpload() {
setAttachmentRemark("");
setShowAttachmentUpload(false);
setSelectedDocumentId(null);
// 刷新文档列表
await filterDocuments(reviewType);
await filterDocuments(documentTypeIds);
} catch (error) {
console.error('【附件追加】上传失败:', error);
@@ -1028,9 +1022,9 @@ export default function FilesUpload() {
setTemplateFile(null);
setShowTemplateUpload(false);
setSelectedDocumentId(null);
// 刷新文档列表
await filterDocuments(reviewType);
await filterDocuments(documentTypeIds);
} catch (error) {
console.error('【合同模板上传】上传失败:', error);
@@ -1163,7 +1157,7 @@ export default function FilesUpload() {
setCompletedFiles(uploadedFiles);
startProcessing(uploadedFiles);
// 刷新队列
await filterDocuments(reviewType);
await filterDocuments(documentTypeIds);
} catch (error) {
console.error('合同首传上传失败:', error);
messageService.error(`合同上传失败:${error instanceof Error ? error.message : '未知错误'}`);