806 lines
24 KiB
TypeScript
806 lines
24 KiB
TypeScript
import { postgrestGet, postgrestDelete, postgrestPut, postgrestPost } from '../postgrest-client';
|
||
import { getDocumentTypes } from '../document-types/document-types';
|
||
import { formatDate } from '../../utils';
|
||
import { API_BASE_URL } from '~/config/api-config';
|
||
import type { DocumentType } from './files-upload';
|
||
|
||
/**
|
||
* 从不同格式的 API 响应中提取数据
|
||
* @param responseData API 响应数据
|
||
* @returns 提取后的数据或 null
|
||
*/
|
||
function extractApiData<T>(responseData: unknown): T | null {
|
||
if (!responseData) return null;
|
||
|
||
// 格式1: { code: number, msg: string, data: T }
|
||
if (typeof responseData === 'object' && responseData !== null &&
|
||
'code' in responseData &&
|
||
'data' in responseData &&
|
||
(responseData as { data: unknown }).data) {
|
||
return (responseData as { data: T }).data;
|
||
}
|
||
|
||
// 格式2: 直接是数据对象
|
||
return responseData as T;
|
||
}
|
||
|
||
|
||
/**
|
||
* 数据库文档结构
|
||
*/
|
||
export interface Document {
|
||
id: number;
|
||
user_id: number | null;
|
||
type_id: number;
|
||
name: string;
|
||
document_number: string;
|
||
path: string;
|
||
storage_type: string;
|
||
file_size: number;
|
||
upload_time: string;
|
||
is_test_document: boolean;
|
||
evaluation_level: string;
|
||
status: 'pass' | 'warning' | 'waiting' | 'processing' | 'fail';
|
||
file_status: 'Waiting' | 'Cutting' | 'Extractioning' | 'Evaluationing' | 'Processed';
|
||
audit_status: number; // -1: 不通过, 0: 待审核, 1: 通过, 2: 警告, 3: 审核中
|
||
ocr_result?: {
|
||
__meta?: {
|
||
page_count?: number;
|
||
}
|
||
};
|
||
extracted_results?: unknown;
|
||
summary?: unknown;
|
||
remark?: string;
|
||
created_at: string;
|
||
updated_at: string;
|
||
}
|
||
|
||
/**
|
||
* 前端UI文档结构
|
||
*/
|
||
export interface DocumentUI {
|
||
id: number;
|
||
name: string;
|
||
documentNumber: string;
|
||
type: string;
|
||
typeName: string;
|
||
size: number;
|
||
auditStatus: number; // -1: 不通过, 0: 待审核, 1: 通过, 2: 警告, 3: 审核中
|
||
fileStatus: string; // Waiting, Cutting, Extractioning, Failed, Evaluationing, Processed
|
||
issues: number | null;
|
||
uploadTime: string;
|
||
fileType: string;
|
||
path: string;
|
||
isTest: boolean;
|
||
remark?: string;
|
||
updatedAt?: string;
|
||
pageCount?: number;
|
||
ocrResult?: unknown;
|
||
// 结果统计字段
|
||
pass_count?: number | null; // 通过数量
|
||
warning_count?: number | null; // 警告数量
|
||
error_count?: number | null; // 错误数量
|
||
manual_count?: number | null; // 人工审核数量
|
||
// 消息详情字段
|
||
warning_messages?: string[]; // 警告消息列表
|
||
error_messages?: string[]; // 错误消息列表
|
||
manual_messages?: string[]; // 人工审核消息列表
|
||
// 版本管理相关字段
|
||
historyCount?: number; // 历史版本数量(不含当前版本)
|
||
previousIssues?: number | null; // 上一个版本的问题数量
|
||
previous_pass_count?: number | null; // 上一版本通过数量
|
||
previous_warning_count?: number | null; // 上一版本警告数量
|
||
previous_error_count?: number | null; // 上一版本错误数量
|
||
previous_manual_count?: number | null; // 上一版本人工数量
|
||
isExpanded?: boolean; // 是否展开历史版本(前端状态)
|
||
historyVersions?: DocumentVersionUI[]; // 历史版本列表
|
||
}
|
||
|
||
/**
|
||
* 文档历史版本结构
|
||
*/
|
||
export interface DocumentVersionUI {
|
||
id: number;
|
||
name: string;
|
||
documentNumber: string;
|
||
type: string;
|
||
typeName: string;
|
||
size: number;
|
||
auditStatus: number;
|
||
fileStatus: string;
|
||
issues: number | null;
|
||
issuesDiff?: number; // 与上一个版本的问题数量差异(绝对值)
|
||
issuesDiffType?: 'increase' | 'decrease' | 'same'; // 差异类型
|
||
uploadTime: string;
|
||
fileType: string;
|
||
path: string;
|
||
isTest: boolean;
|
||
updatedAt?: string;
|
||
pageCount?: number;
|
||
ocrResult?: unknown;
|
||
versionNumber?: number; // 版本号(v2, v3, v4...)
|
||
// 结果统计字段
|
||
pass_count: number | null; // 通过数量
|
||
warning_count: number | null; // 警告数量
|
||
error_count: number | null; // 错误数量
|
||
manual_count: number | null; // 人工审核数量
|
||
previous_pass_count?: number | null; // 上一版本通过数量
|
||
previous_warning_count?: number | null; // 上一版本警告数量
|
||
previous_error_count?: number | null; // 上一版本错误数量
|
||
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 文件名
|
||
* @returns 文件扩展名
|
||
*/
|
||
function getFileExtension(filename: string): string {
|
||
const parts = filename.split('.');
|
||
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
|
||
* @returns 评查结果
|
||
*/
|
||
async function getEvaluationResults(id: number, frontendJWT?: string) {
|
||
const response = await postgrestGet<[]>('/api/postgrest/proxy/evaluation_results', {
|
||
filter: {
|
||
'document_id': `eq.${id}`
|
||
},
|
||
token: frontendJWT
|
||
});
|
||
if (response.error) {
|
||
return { error: response.error, status: response.status };
|
||
}
|
||
const evaluationResult = extractApiData<[]>(response.data);
|
||
return evaluationResult;
|
||
}
|
||
|
||
|
||
/**
|
||
* 将API文档转换为UI文档
|
||
*/
|
||
async function convertToUIDocument(doc: Document, frontendJWT?: string): Promise<DocumentUI> {
|
||
// 获取文档类型信息
|
||
const typeResponse = await getDocumentTypes(undefined, frontendJWT);
|
||
const documentTypes = typeResponse.data?.types || [];
|
||
const docType = documentTypes.find(type => type.id.toString() === doc.type_id.toString());
|
||
const evaluationResult = await getEvaluationResults(doc.id, frontendJWT);
|
||
let issues = 0;
|
||
|
||
interface EvaluationResultItem {
|
||
evaluated_results?: {
|
||
result?: string;
|
||
[key: string]: unknown;
|
||
};
|
||
[key: string]: unknown;
|
||
}
|
||
|
||
if (evaluationResult && Array.isArray(evaluationResult)) {
|
||
evaluationResult.forEach((result: EvaluationResultItem) => {
|
||
if(result && result.evaluated_results && !result.evaluated_results.result){
|
||
issues++;
|
||
}
|
||
});
|
||
}
|
||
|
||
|
||
return {
|
||
id: doc.id,
|
||
name: doc.name,
|
||
documentNumber: doc.document_number,
|
||
type: doc.type_id.toString(),
|
||
typeName: docType?.name || '未知类型',
|
||
size: doc.file_size,
|
||
auditStatus: doc.audit_status || 0,
|
||
fileStatus: doc.status || '', // 默认为''
|
||
issues: issues, // 使用计算得到的issues
|
||
uploadTime: formatDate(doc.updated_at),
|
||
fileType: getFileExtension(doc.name),
|
||
path: doc.path,
|
||
isTest: doc.is_test_document,
|
||
remark: doc.remark,
|
||
updatedAt: formatDate(doc.updated_at),
|
||
pageCount: doc.ocr_result?.__meta?.page_count || 0,
|
||
ocrResult: doc.ocr_result
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 后端SQL函数返回的文档结构
|
||
*/
|
||
interface DocumentFromSQL {
|
||
id: number;
|
||
name: string;
|
||
document_number: string;
|
||
type_id: number;
|
||
type_name: string;
|
||
file_size: number;
|
||
audit_status: number;
|
||
status: string;
|
||
false_count: number;
|
||
updated_at: string;
|
||
path: string;
|
||
is_test_document: boolean;
|
||
ocr_result: {
|
||
__meta?: {
|
||
page_count?: number;
|
||
}
|
||
};
|
||
}
|
||
|
||
|
||
/**
|
||
* 删除文档
|
||
* @param id 文档ID
|
||
* @param userId 用户ID
|
||
* @param token JWT token (可选)
|
||
* @returns 删除结果
|
||
*/
|
||
export async function deleteDocument(id: string, userId: string, token?: string): Promise<{
|
||
success?: boolean;
|
||
error?: string;
|
||
status?: number;
|
||
}> {
|
||
try {
|
||
if (!id) {
|
||
return { error: '文档ID不能为空', status: 400 };
|
||
}
|
||
|
||
if (!userId) {
|
||
return { error: '用户身份验证失败', status: 401 };
|
||
}
|
||
|
||
const response = await postgrestDelete(
|
||
'/api/postgrest/proxy/documents',
|
||
{
|
||
filter: {
|
||
'id': `eq.${id}`,
|
||
'user_id': `eq.${userId}` // 确保只能删除自己的文档
|
||
},
|
||
token
|
||
}
|
||
);
|
||
|
||
if (response.error) {
|
||
return { error: response.error, status: response.status };
|
||
}
|
||
|
||
return { success: true };
|
||
} catch (error) {
|
||
console.error('删除文档失败:', error);
|
||
return {
|
||
error: error instanceof Error ? error.message : '删除文档失败',
|
||
status: 500
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取单个文档详情
|
||
* @param id 文档ID
|
||
* @returns 文档详情
|
||
*/
|
||
export async function getDocument(id: string, userId: string, frontendJWT?: string): Promise<{
|
||
data?: DocumentUI;
|
||
error?: string;
|
||
status?: number;
|
||
}> {
|
||
try {
|
||
if (!id) {
|
||
return { error: '文档ID不能为空', status: 400 };
|
||
}
|
||
|
||
if (!userId) {
|
||
return { error: '用户身份验证失败', status: 401 };
|
||
}
|
||
|
||
const response = await postgrestGet<Document[]>(
|
||
'/api/postgrest/proxy/documents',
|
||
{
|
||
filter: {
|
||
'id': `eq.${id}`,
|
||
'user_id': `eq.${userId}`
|
||
},
|
||
limit: 1,
|
||
token: frontendJWT
|
||
}
|
||
);
|
||
|
||
if (response.error) {
|
||
return { error: response.error, status: response.status };
|
||
}
|
||
|
||
const extractedData = extractApiData<Document[]>(response.data);
|
||
if (!extractedData || extractedData.length === 0) {
|
||
return { error: '文档不存在', status: 404 };
|
||
}
|
||
|
||
const documentUI = await convertToUIDocument(extractedData[0], frontendJWT);
|
||
|
||
return { data: documentUI };
|
||
} catch (error) {
|
||
console.error('获取文档详情失败:', error);
|
||
return {
|
||
error: error instanceof Error ? error.message : '获取文档详情失败',
|
||
status: 500
|
||
};
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 获取单个文档详情
|
||
* @param id 文档ID
|
||
* @returns 文档详情
|
||
*/
|
||
// export async function getDocumentWithNoUserId(id: string, frontendJWT?: string): Promise<{
|
||
// data?: DocumentUI;
|
||
// error?: string;
|
||
// status?: number;
|
||
// }> {
|
||
// try {
|
||
// if (!id) {
|
||
// return { error: '文档ID不能为空', status: 400 };
|
||
// }
|
||
|
||
// // console.log("get单个文档id", id)
|
||
|
||
// const response = await postgrestGet<Document[]>(
|
||
// '/api/postgrest/proxy/documents',
|
||
// {
|
||
// filter: {
|
||
// 'id': `eq.${id}`,
|
||
// },
|
||
// limit: 1,
|
||
// token: frontendJWT
|
||
// }
|
||
// );
|
||
|
||
// if (response.error) {
|
||
// return { error: response.error, status: response.status };
|
||
// }
|
||
|
||
// // console.log("respose", response)
|
||
// const extractedData = extractApiData<Document[]>(response.data);
|
||
// if (!extractedData || extractedData.length === 0) {
|
||
// return { error: '文档不存在', status: 404 };
|
||
// }
|
||
|
||
// // console.log('extractedData', extractedData);
|
||
// const documentUI = await convertToUIDocument(extractedData[0], frontendJWT);
|
||
|
||
// return { data: documentUI };
|
||
// } catch (error) {
|
||
// console.error('获取文档详情失败:', error);
|
||
// return {
|
||
// error: error instanceof Error ? error.message : '获取文档详情失败',
|
||
// status: 500
|
||
// };
|
||
// }
|
||
// }
|
||
|
||
|
||
|
||
/**
|
||
* 获取文档类型列表(按IDs过滤版本)
|
||
* @param ids 文档类型ID数组(必填)
|
||
* @param frontendJWT JWT token(可选)
|
||
* @returns 文档类型列表
|
||
*/
|
||
export async function getDocumentTypesByIds(ids: number[], frontendJWT?: string): Promise<{
|
||
data?: { types: DocumentType[], total: number };
|
||
error?: string;
|
||
status?: number;
|
||
}> {
|
||
try {
|
||
if (!ids || ids.length === 0) {
|
||
return { data: { types: [], total: 0 } };
|
||
}
|
||
|
||
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 = response.data?.types;
|
||
if (!extractedData) {
|
||
return { error: '获取文档类型列表失败', status: 500 };
|
||
}
|
||
|
||
return { data: { types: extractedData, total: extractedData.length } };
|
||
} catch (error) {
|
||
console.error('获取文档类型列表失败:', error);
|
||
return {
|
||
error: error instanceof Error ? error.message : '获取文档类型列表失败',
|
||
status: 500
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新文档信息
|
||
*
|
||
* 使用 PATCH 方法调用 /api/postgrest/proxy/documents 接口
|
||
* 后端会自动注入 user_id 过滤条件,确保用户只能更新自己的文档
|
||
*
|
||
* @param id 文档ID
|
||
* @param document 部分文档数据(可更新字段:document_number, audit_status, is_test_document, remark)
|
||
* @param userId 用户ID(用于权限验证)
|
||
* @param frontendJWT JWT Token(可选,如不传则使用 localStorage 中的 access_token)
|
||
* @returns 更新结果
|
||
*
|
||
* @see auth_doc/document_update_api.md 接口文档
|
||
*/
|
||
export async function updateDocument(id: string, document: Partial<DocumentUI> & { remark?: string }, userId: string, frontendJWT?: string): Promise<{
|
||
data?: DocumentUI;
|
||
error?: string;
|
||
status?: number;
|
||
}> {
|
||
try {
|
||
if (!id) {
|
||
return { error: '文档ID不能为空', status: 400 };
|
||
}
|
||
|
||
if (!userId) {
|
||
return { error: '用户身份验证失败', status: 401 };
|
||
}
|
||
|
||
// 准备API数据 - 将UI数据转换为API格式
|
||
// 根据文档,可更新字段:document_number, audit_status, is_test_document, remark
|
||
const apiDocument: Partial<Document> = {};
|
||
|
||
if (document.documentNumber !== undefined) {
|
||
apiDocument.document_number = document.documentNumber;
|
||
}
|
||
|
||
if (document.auditStatus !== undefined) {
|
||
apiDocument.audit_status = document.auditStatus;
|
||
}
|
||
|
||
if (document.isTest !== undefined) {
|
||
apiDocument.is_test_document = document.isTest;
|
||
}
|
||
|
||
if (document.remark !== undefined) {
|
||
apiDocument.remark = document.remark;
|
||
}
|
||
|
||
// console.log('📤 [updateDocument] 更新文档API数据:', apiDocument);
|
||
|
||
// 使用 axios-client 的 apiRequest 方法(支持自定义 headers)
|
||
// 接口路径: /api/postgrest/proxy/documents?id=eq.{id}
|
||
// 后端会自动注入 user_id 过滤条件(根据JWT中的用户信息)
|
||
const { apiRequest } = await import('../axios-client');
|
||
const response = await apiRequest<Document[]>(
|
||
`/api/postgrest/proxy/documents?id=eq.${id}`,
|
||
{
|
||
method: 'PATCH',
|
||
data: apiDocument,
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
...(frontendJWT ? { 'Authorization': `Bearer ${frontendJWT}` } : {})
|
||
}
|
||
}
|
||
);
|
||
|
||
if (response.error) {
|
||
console.error('❌ [updateDocument] 更新文档API错误:', response.error);
|
||
return { error: response.error, status: response.status };
|
||
}
|
||
|
||
// 检查返回数据
|
||
// 成功时返回更新后的文档数组,空数组表示文档不存在或无权访问
|
||
const responseData = response.data;
|
||
if (!responseData || (Array.isArray(responseData) && responseData.length === 0)) {
|
||
return { error: '文档不存在或无权访问', status: 404 };
|
||
}
|
||
|
||
// 获取更新后的完整文档数据(包含关联的文档类型信息)
|
||
const updatedResponse = await getDocument(id, userId, frontendJWT);
|
||
|
||
return updatedResponse;
|
||
} catch (error) {
|
||
console.error('❌ [updateDocument] 更新文档信息失败:', error);
|
||
return {
|
||
error: error instanceof Error ? error.message : '更新文档信息失败',
|
||
status: 500
|
||
};
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 获取文档列表(使用新的后端API)
|
||
* @param searchParams 搜索参数
|
||
* @returns 文档列表和总数
|
||
*/
|
||
export async function getDocumentsListFromAPI(searchParams: {
|
||
page?: number;
|
||
pageSize?: number;
|
||
name?: string;
|
||
documentNumber?: string;
|
||
documentTypeIds?: number[]; // 文档类型ID数组
|
||
auditStatus?: string;
|
||
fileStatus?: string;
|
||
dateFrom?: string;
|
||
dateTo?: string;
|
||
token: string; // JWT token (必填)
|
||
}): Promise<{
|
||
data?: { documents: DocumentUI[], total: number, page: number, totalPages: number };
|
||
error?: string;
|
||
status?: number;
|
||
}> {
|
||
try {
|
||
const {
|
||
page = 1,
|
||
pageSize = 10,
|
||
name,
|
||
documentNumber,
|
||
documentTypeIds,
|
||
auditStatus,
|
||
fileStatus,
|
||
dateFrom,
|
||
dateTo,
|
||
token
|
||
} = searchParams;
|
||
|
||
const params: Record<string, any> = {
|
||
page,
|
||
pageSize
|
||
};
|
||
|
||
// 新接口已落地的筛选项
|
||
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';
|
||
}
|
||
}
|
||
|
||
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;
|
||
|
||
const axios = await import('axios').then(m => m.default);
|
||
const response = await axios.get(`${API_BASE_URL}/api/documents/list`, {
|
||
params,
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`,
|
||
'Content-Type': 'application/json'
|
||
}
|
||
});
|
||
|
||
const pageData = extractApiData<LeauditListPage>(response.data);
|
||
if (!pageData) {
|
||
return { error: '获取文档列表失败', status: response.status };
|
||
}
|
||
|
||
const backendDocuments = pageData.documents || [];
|
||
const totalCount = pageData.total || 0;
|
||
const totalPages = pageData.totalPages || Math.ceil(totalCount / pageSize) || 0;
|
||
|
||
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.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
|
||
};
|
||
});
|
||
|
||
return {
|
||
data: {
|
||
documents: convertedDocuments,
|
||
total: totalCount,
|
||
page: pageData.page || page,
|
||
totalPages
|
||
}
|
||
};
|
||
} catch (error) {
|
||
console.error('❌ [getDocumentsListFromAPI] 获取文档列表失败:', error);
|
||
|
||
// 处理axios错误
|
||
if (error && typeof error === 'object' && 'response' in error) {
|
||
const axiosError = error as { response?: { data?: any; status?: number; statusText?: string } };
|
||
return {
|
||
error: axiosError.response?.data?.message || axiosError.response?.statusText || '获取文档列表失败',
|
||
status: axiosError.response?.status || 500
|
||
};
|
||
}
|
||
|
||
return {
|
||
error: error instanceof Error ? error.message : '获取文档列表失败',
|
||
status: 500
|
||
};
|
||
}
|
||
}
|