feat: hook document list to leaudit list api

This commit is contained in:
wren
2026-04-29 12:20:16 +08:00
parent c10b70b286
commit 23ab13dd1e
2 changed files with 225 additions and 128 deletions
+209 -122
View File
@@ -130,6 +130,57 @@ export interface DocumentVersionUI {
previous_manual_count?: number | null; // 上一版本人工数量
}
interface LeauditHistoryVersion {
documentId: number;
fileId?: number | null;
versionNo: number;
fileName?: string | null;
fileExt?: string | null;
processingStatus?: string | null;
runStatus?: string | null;
resultStatus?: string | null;
updatedAt?: string | null;
}
interface LeauditListItem {
documentId: number;
internalDocumentNo: number;
versionGroupKey: string;
versionNo: number;
rootVersionId: number;
previousVersionId?: number | null;
typeId?: number | null;
typeCode?: string | null;
region: string;
normalizedName?: string | null;
fileId?: number | null;
fileName?: string | null;
fileExt?: string | null;
mimeType?: string | null;
fileSize?: number | null;
ossUrl?: string | null;
processingStatus?: string | null;
currentRunId?: number | null;
runStatus?: string | null;
resultStatus?: string | null;
totalScore?: number | null;
passedCount?: number | null;
failedCount?: number | null;
skippedCount?: number | null;
updatedAt?: string | null;
hasHistory?: boolean;
totalVersions?: number;
historyVersions?: LeauditHistoryVersion[];
}
interface LeauditListPage {
total: number;
page: number;
pageSize: number;
totalPages: number;
documents: LeauditListItem[];
}
/**
* 获取文件扩展名
* @param filename 文件名
@@ -140,6 +191,61 @@ function getFileExtension(filename: string): string {
return parts.length > 1 ? parts.pop()?.toLowerCase() || '' : '';
}
function mapProcessingStatusToFileStatus(status?: string | null): string {
const normalized = (status || '').toLowerCase();
if (normalized === 'completed') return 'Processed';
if (normalized === 'failed') return 'Failed';
if (normalized === 'running' || normalized === 'queued' || normalized === 'dispatch') return 'Evaluationing';
if (normalized === 'waiting' || normalized === 'pending') return 'Waiting';
return 'Waiting';
}
function mapLeauditDocToAuditStatus(doc: {
processingStatus?: string | null;
runStatus?: string | null;
passedCount?: number | null;
failedCount?: number | null;
}): number {
const processingStatus = (doc.processingStatus || '').toLowerCase();
const runStatus = (doc.runStatus || '').toLowerCase();
if (runStatus === 'queued' || runStatus === 'running' || processingStatus === 'running') {
return 2;
}
if (processingStatus === 'waiting' || processingStatus === 'pending') {
return 0;
}
if (processingStatus === 'failed') {
return -1;
}
if ((doc.failedCount || 0) > 0) {
return -1;
}
if ((doc.passedCount || 0) > 0) {
return 1;
}
return 0;
}
function typeNameFromCode(typeCode?: string | null): string {
if (!typeCode) return '未知类型';
const typeMap: Record<string, string> = {
'contract.sale': '购销合同',
'contract.purchase': '采购合同',
'contract.lease': '租赁合同',
'contract.service': '服务合同',
};
if (typeMap[typeCode]) return typeMap[typeCode];
return typeCode;
}
function buildDocumentNumber(doc: LeauditListItem | LeauditHistoryVersion): string {
if ('versionNo' in doc && doc.versionNo) {
return `v${doc.versionNo}`;
}
return '';
}
/**
* 获取评查结果
* @param id 评查结果ID
@@ -401,20 +507,12 @@ export async function getDocumentTypesByIds(ids: number[], frontendJWT?: string)
return { data: { types: [], total: 0 } };
}
const response = await postgrestGet<DocumentType[]>(
'/api/postgrest/proxy/document_types',
{
filter: {
'id': `in.(${ids.join(',')})`
},
token: frontendJWT
});
const response = await getDocumentTypes({ ids, page: 1, pageSize: Math.max(ids.length, 10) }, frontendJWT);
if (response.error) {
return { error: response.error, status: response.status };
}
const extractedData = extractApiData<DocumentType[]>(response.data);
const extractedData = response.data?.types;
if (!extractedData) {
return { error: '获取文档类型列表失败', status: 500 };
}
@@ -556,30 +654,45 @@ export async function getDocumentsListFromAPI(searchParams: {
token
} = searchParams;
// 构建查询参数
const params: Record<string, any> = {
page,
page_size: pageSize
pageSize
};
// 添加可选参数
if (name) params.name = name;
if (documentNumber) params.document_number = documentNumber;
if (auditStatus) params.audit_status = parseInt(auditStatus, 10);
if (fileStatus) params.status = fileStatus;
if (dateFrom) params.start_time = dateFrom;
if (dateTo) params.end_time = dateTo;
// 处理文档类型ID数组 - 转换为逗号分隔的字符串
if (documentTypeIds && documentTypeIds.length > 0) {
params.type_id = documentTypeIds.join(',');
// 新接口已落地的筛选项
if (name) params.keyword = name;
if (fileStatus) {
const normalizedFileStatus = fileStatus.toLowerCase();
if (normalizedFileStatus === 'processed') {
params.processingStatus = 'completed';
} else if (normalizedFileStatus === 'failed') {
params.processingStatus = 'failed';
} else {
params.processingStatus = 'running';
}
}
// console.log('📤 [getDocumentsListFromAPI] 请求参数:', params);
if (documentTypeIds && documentTypeIds.length === 1) {
const typeResponse = await getDocumentTypes({ ids: documentTypeIds, page: 1, pageSize: 10 }, token);
const matchedType = typeResponse.data?.types?.[0];
if (matchedType?.code) {
params.typeCode = matchedType.code;
}
}
// 下面几个旧筛选项在新系统版列表接口里暂未一一对齐:
// - documentNumber
// - auditStatus
// - dateFrom/dateTo
// - 多个 documentTypeIds 的组合筛选
// 先保留参数签名,后续再单独接新后端的类型/状态体系。
void documentNumber;
void auditStatus;
void dateFrom;
void dateTo;
// 调用后端API
const axios = await import('axios').then(m => m.default);
const response = await axios.get(`${API_BASE_URL}/admin/versions/documents-list`, {
const response = await axios.get(`${API_BASE_URL}/api/documents/list`, {
params,
headers: {
'Authorization': `Bearer ${token}`,
@@ -587,105 +700,79 @@ export async function getDocumentsListFromAPI(searchParams: {
}
});
const data = response.data;
const backendDocuments = data.documents || [];
const totalCount = data.total || 0;
const totalPages = data.total_pages || 0;
const pageData = extractApiData<LeauditListPage>(response.data);
if (!pageData) {
return { error: '获取文档列表失败', status: response.status };
}
// console.log(`📥 [getDocumentsListFromAPI] 获取到 ${backendDocuments.length} 个文档,总数: ${totalCount}`);
const backendDocuments = pageData.documents || [];
const totalCount = pageData.total || 0;
const totalPages = pageData.totalPages || Math.ceil(totalCount / pageSize) || 0;
// 转换后端数据为前端 DocumentUI 格式
const convertedDocuments: DocumentUI[] = backendDocuments.map((doc: any) => {
// 转换历史版本数据
const historyVersions: DocumentVersionUI[] = (doc.history_versions || []).map((hv: any, index: number) => {
// 计算与下一个版本(更早的版本)的问题数量差异
let issuesDiff: number | undefined;
let issuesDiffType: 'increase' | 'decrease' | 'same' | undefined;
if (index < doc.history_versions.length - 1) {
const olderDoc = doc.history_versions[index + 1];
if (hv.issue_count != null && olderDoc.issue_count != null) {
const diff = hv.issue_count - olderDoc.issue_count;
issuesDiff = Math.abs(diff);
if (diff > 0) {
issuesDiffType = 'increase';
} else if (diff < 0) {
issuesDiffType = 'decrease';
} else {
issuesDiffType = 'same';
}
}
}
// 获取前一个版本的统计数据(如果存在)
const prevVersion = index < doc.history_versions.length - 1 ? doc.history_versions[index + 1] : null;
return {
id: hv.id,
name: hv.name || doc.name,
documentNumber: hv.document_number || doc.document_number || '',
type: hv.type_id?.toString() || doc.type_id?.toString() || '',
typeName: hv.type_name || doc.type_name || '未知类型',
size: hv.file_size || 0,
auditStatus: hv.audit_status ?? 0,
fileStatus: hv.status || 'Processed',
issues: hv.issue_count ?? null,
issuesDiff,
issuesDiffType,
uploadTime: formatDate(hv.created_at),
fileType: getFileExtension(hv.name || doc.name),
path: hv.path || '',
isTest: hv.is_test_document || false,
updatedAt: formatDate(hv.updated_at || hv.created_at),
pageCount: hv.ocr_result?.__meta?.page_count || 0,
ocrResult: hv.ocr_result,
versionNumber: hv.version_number,
// 结果统计字段
pass_count: hv.pass_count ?? null,
warning_count: hv.warning_count ?? null,
error_count: hv.error_count ?? null,
manual_count: hv.manual_count ?? null,
// 前一版本统计(用于差异对比)
previous_pass_count: prevVersion?.pass_count ?? null,
previous_warning_count: prevVersion?.warning_count ?? null,
previous_error_count: prevVersion?.error_count ?? null,
previous_manual_count: prevVersion?.manual_count ?? null
};
});
const convertedDocuments: DocumentUI[] = backendDocuments.map((doc) => {
const historyVersions: DocumentVersionUI[] = (doc.historyVersions || []).map((hv) => ({
id: hv.documentId,
name: hv.fileName || doc.fileName || doc.normalizedName || '未命名文档',
documentNumber: buildDocumentNumber(hv),
type: doc.typeId?.toString() || '',
typeName: typeNameFromCode(doc.typeCode),
size: 0,
auditStatus: mapLeauditDocToAuditStatus({
processingStatus: hv.processingStatus,
runStatus: hv.runStatus,
passedCount: null,
failedCount: null,
}),
fileStatus: mapProcessingStatusToFileStatus(hv.processingStatus),
issues: null,
uploadTime: formatDate(hv.updatedAt || ''),
fileType: hv.fileExt || getFileExtension(hv.fileName || doc.fileName || ''),
path: '',
isTest: false,
updatedAt: formatDate(hv.updatedAt || ''),
pageCount: 0,
ocrResult: undefined,
versionNumber: hv.versionNo,
pass_count: null,
warning_count: 0,
error_count: null,
manual_count: null,
previous_pass_count: null,
previous_warning_count: null,
previous_error_count: null,
previous_manual_count: null
}));
return {
id: doc.id,
name: doc.name,
documentNumber: doc.document_number || '',
type: doc.type_id?.toString() || '',
typeName: doc.type_name || '未知类型',
size: doc.file_size || 0,
auditStatus: doc.audit_status ?? 0,
fileStatus: doc.status || '',
issues: doc.issue_count ?? null,
uploadTime: formatDate(doc.upload_time || doc.created_at),
fileType: getFileExtension(doc.name),
path: doc.path || '',
isTest: doc.is_test_document || false,
updatedAt: formatDate(doc.updated_at || doc.created_at),
pageCount: doc.ocr_result?.__meta?.page_count || 0,
ocrResult: doc.ocr_result,
// 结果统计字段
pass_count: doc.pass_count ?? null,
warning_count: doc.warning_count ?? null,
error_count: doc.error_count ?? null,
manual_count: doc.manual_count ?? null,
// 消息详情字段
warning_messages: doc.warning_messages || [],
error_messages: doc.error_messages || [],
manual_messages: doc.manual_messages || [],
// 版本管理字段
historyCount: (doc.total_versions || 1) - 1, // 总版本数 - 1 = 历史版本数
previousIssues: doc.history_versions?.[0]?.issue_count ?? null,
previous_pass_count: doc.history_versions?.[0]?.pass_count ?? null,
previous_warning_count: doc.history_versions?.[0]?.warning_count ?? null,
previous_error_count: doc.history_versions?.[0]?.error_count ?? null,
previous_manual_count: doc.history_versions?.[0]?.manual_count ?? null,
id: doc.documentId,
name: doc.fileName || doc.normalizedName || '未命名文档',
documentNumber: buildDocumentNumber(doc),
type: doc.typeId?.toString() || '',
typeName: typeNameFromCode(doc.typeCode),
size: doc.fileSize || 0,
auditStatus: mapLeauditDocToAuditStatus(doc),
fileStatus: mapProcessingStatusToFileStatus(doc.processingStatus),
issues: doc.failedCount ?? null,
uploadTime: formatDate(doc.updatedAt || ''),
fileType: doc.fileExt || getFileExtension(doc.fileName || ''),
path: doc.ossUrl || '',
isTest: false,
updatedAt: formatDate(doc.updatedAt || ''),
pageCount: 0,
ocrResult: undefined,
pass_count: doc.passedCount ?? null,
warning_count: 0,
error_count: doc.failedCount ?? null,
manual_count: doc.skippedCount ?? null,
warning_messages: [],
error_messages: [],
manual_messages: [],
historyCount: Math.max(0, (doc.totalVersions || 1) - 1),
previousIssues: historyVersions[0]?.issues ?? null,
previous_pass_count: historyVersions[0]?.pass_count ?? null,
previous_warning_count: historyVersions[0]?.warning_count ?? null,
previous_error_count: historyVersions[0]?.error_count ?? null,
previous_manual_count: historyVersions[0]?.manual_count ?? null,
historyVersions: historyVersions.length > 0 ? historyVersions : undefined
};
});
@@ -694,7 +781,7 @@ export async function getDocumentsListFromAPI(searchParams: {
data: {
documents: convertedDocuments,
total: totalCount,
page: data.page || page,
page: pageData.page || page,
totalPages
}
};
+16 -6
View File
@@ -322,12 +322,22 @@ export default function DocumentsIndex() {
// 获取经过过滤的文档类型列表
const filteredTypesResponse = await getDocumentTypesByIds(typeIds, jwtToken);
const filteredDocumentTypes = filteredTypesResponse.data?.types || [];
const filteredOptions = filteredDocumentTypes.map(type => ({
value: type.id,
label: type.name
}));
setFilteredDocumentTypeOptions(filteredOptions);
if (filteredTypesResponse.data?.types?.length) {
const filteredOptions = filteredTypesResponse.data.types.map(type => ({
value: type.id,
label: type.name
}));
setFilteredDocumentTypeOptions(filteredOptions);
} else {
const fallbackOptions = Array.from(
new Map(
result.data.documents
.filter(doc => doc.type && doc.typeName)
.map(doc => [doc.type, { value: Number(doc.type), label: doc.typeName }])
).values()
);
setFilteredDocumentTypeOptions(fallbackOptions);
}
} catch (error) {
console.error('❌ [fetchData] 获取文档列表失败:', error);