Files
leaudit-platform-frontend/app/api/files/documents.ts
T

898 lines
27 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import axios from 'axios';
import { postgrestGet, postgrestDelete } 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 '../document-types/document-types';
/**
* 从不同格式的 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;
groupId?: number | null;
groupName?: string | null;
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;
groupId?: number | null;
groupName?: string | null;
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;
typeName?: string | null;
groupId?: number | null;
groupName?: 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;
documentNumber?: string | null;
auditStatus?: number | null;
isTestDocument?: boolean | null;
updatedAt?: string | null;
hasHistory?: boolean;
totalVersions?: number;
historyVersions?: LeauditHistoryVersion[];
}
interface LeauditListPage {
total: number;
page: number;
pageSize: number;
totalPages: number;
documents: LeauditListItem[];
}
interface LeauditDocumentDetail extends LeauditListItem {
documentNumber?: string | null;
remark?: string | null;
isTestDocument?: boolean | null;
auditStatus?: number | null;
pageCount?: number | null;
}
interface DocumentMetadataUpdateDTO {
documentNumber?: string;
auditStatus?: number;
isTestDocument?: boolean;
remark?: string;
}
/**
* 获取文件扩展名
* @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 '';
}
function isUnsupportedNewDocumentCrud(error: unknown): boolean {
return axios.isAxiosError(error) && [404, 405, 501].includes(error.response?.status || 0);
}
function getErrorMessage(error: unknown, fallback: string): string {
if (axios.isAxiosError(error)) {
return error.response?.data?.message || error.response?.data?.detail || error.message || fallback;
}
return error instanceof Error ? error.message : fallback;
}
function mapHistoryVersionToUI(history: LeauditHistoryVersion, source: LeauditListItem): DocumentVersionUI {
return {
id: history.documentId,
name: history.fileName || source.fileName || source.normalizedName || '未命名文档',
documentNumber: buildDocumentNumber(history),
type: source.typeId?.toString() || '',
typeName: source.typeName || typeNameFromCode(source.typeCode),
groupId: source.groupId ?? null,
groupName: source.groupName ?? null,
size: 0,
auditStatus: mapLeauditDocToAuditStatus({
processingStatus: history.processingStatus,
runStatus: history.runStatus,
passedCount: null,
failedCount: null,
}),
fileStatus: mapProcessingStatusToFileStatus(history.processingStatus),
issues: null,
uploadTime: formatDate(history.updatedAt || ''),
fileType: history.fileExt || getFileExtension(history.fileName || source.fileName || ''),
path: '',
isTest: false,
updatedAt: formatDate(history.updatedAt || ''),
pageCount: 0,
ocrResult: undefined,
versionNumber: history.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
};
}
function mapLeauditDocumentToUI(doc: LeauditListItem | LeauditDocumentDetail): DocumentUI {
const historyVersions = (doc.historyVersions || []).map((history) => mapHistoryVersionToUI(history, doc));
return {
id: doc.documentId,
name: doc.fileName || doc.normalizedName || '未命名文档',
documentNumber: ('documentNumber' in doc && doc.documentNumber) ? doc.documentNumber : buildDocumentNumber(doc),
type: doc.typeId?.toString() || '',
typeName: doc.typeName || typeNameFromCode(doc.typeCode),
groupId: doc.groupId ?? null,
groupName: doc.groupName ?? null,
size: doc.fileSize || 0,
auditStatus: ('auditStatus' in doc && doc.auditStatus !== null && doc.auditStatus !== undefined)
? doc.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: Boolean(('isTestDocument' in doc && doc.isTestDocument) || false),
remark: 'remark' in doc ? (doc.remark || '') : '',
updatedAt: formatDate(doc.updatedAt || ''),
pageCount: ('pageCount' in doc ? (doc.pageCount || 0) : 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
};
}
/**
* 获取评查结果
* @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 };
}
try {
// 新后端接口应基于 JWT 在服务端做数据隔离:
// - provincial_admin: 全量
// - admin: 本地市
// - common: 自己上传的文档
await axios.delete(`${API_BASE_URL}/api/documents/${id}`, {
headers: token ? { 'Authorization': `Bearer ${token}` } : undefined
});
return { success: true };
} catch (error) {
if (!isUnsupportedNewDocumentCrud(error)) {
return {
error: getErrorMessage(error, '删除文档失败'),
status: axios.isAxiosError(error) ? error.response?.status : 500
};
}
}
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 };
}
try {
const response = await axios.get(`${API_BASE_URL}/api/documents/${id}`, {
headers: frontendJWT ? { 'Authorization': `Bearer ${frontendJWT}` } : undefined
});
const detail = extractApiData<LeauditDocumentDetail>(response.data);
if (!detail) {
return { error: '文档不存在', status: 404 };
}
return { data: mapLeauditDocumentToUI(detail) };
} catch (error) {
if (!isUnsupportedNewDocumentCrud(error)) {
return {
error: getErrorMessage(error, '获取文档详情失败'),
status: axios.isAxiosError(error) ? error.response?.status : 500
};
}
}
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 };
}
const apiDocument: DocumentMetadataUpdateDTO = {};
if (document.documentNumber !== undefined) {
apiDocument.documentNumber = document.documentNumber;
}
if (document.auditStatus !== undefined) {
apiDocument.auditStatus = document.auditStatus;
}
if (document.isTest !== undefined) {
apiDocument.isTestDocument = document.isTest;
}
if (document.remark !== undefined) {
apiDocument.remark = document.remark;
}
try {
await axios.put(`${API_BASE_URL}/api/documents/${id}`, apiDocument, {
headers: {
'Content-Type': 'application/json',
...(frontendJWT ? { 'Authorization': `Bearer ${frontendJWT}` } : {})
}
});
} catch (error) {
if (!isUnsupportedNewDocumentCrud(error)) {
console.error('❌ [updateDocument] 更新文档API错误:', error);
return {
error: getErrorMessage(error, '更新文档信息失败'),
status: axios.isAxiosError(error) ? error.response?.status : 500
};
}
// 旧链路回退:仅允许修改自己的文档;新链路上线后应由后端基于地区/角色做数据隔离。
const { apiRequest } = await import('../axios-client');
const response = await apiRequest<Document[]>(
`/api/postgrest/proxy/documents?id=eq.${id}`,
{
method: 'PATCH',
data: {
...(document.documentNumber !== undefined ? { document_number: document.documentNumber } : {}),
...(document.auditStatus !== undefined ? { audit_status: document.auditStatus } : {}),
...(document.isTest !== undefined ? { is_test_document: document.isTest } : {}),
...(document.remark !== undefined ? { remark: document.remark } : {}),
},
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数组
entryModuleId?: number;
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,
entryModuleId,
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 > 0) {
params.type_ids = documentTypeIds.join(',');
}
if (entryModuleId && entryModuleId > 0) {
params.entry_module_id = entryModuleId;
}
if (documentNumber) params.documentNumber = documentNumber;
if (auditStatus !== undefined && auditStatus !== "") {
params.auditStatus = Number(auditStatus);
}
if (dateFrom) params.dateFrom = dateFrom;
if (dateTo) params.dateTo = dateTo;
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) => mapLeauditDocumentToUI(doc));
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
};
}
}