/** * ASL模块 - API客户端 * * 负责所有与后端的API交互 */ import type { ScreeningProject, CreateProjectRequest, Literature, ScreeningResult, ScreeningTask, ApiResponse, PaginatedResponse, ProjectStatistics } from '../types'; import { getAccessToken } from '../../../framework/auth/api'; // API基础URL const API_BASE_URL = '/api/v1/asl'; /** * 获取带认证的请求头 */ function getAuthHeaders(): HeadersInit { const headers: Record = { 'Content-Type': 'application/json', }; const token = getAccessToken(); if (token) { headers['Authorization'] = `Bearer ${token}`; } return headers; } // 通用请求函数 async function request( url: string, options?: RequestInit ): Promise { const response = await fetch(`${API_BASE_URL}${url}`, { ...options, headers: { ...getAuthHeaders(), ...options?.headers, }, }); if (!response.ok) { // 尝试解析错误响应 let errorMessage = `HTTP ${response.status}: ${response.statusText}`; try { const errorData = await response.json(); errorMessage = errorData.error || errorData.message || errorMessage; } catch (e) { // 如果响应体不是JSON,使用状态文本 const text = await response.text().catch(() => ''); if (text) { errorMessage = text; } } console.error('❌ API请求失败:', { url: `${API_BASE_URL}${url}`, status: response.status, error: errorMessage }); throw new Error(errorMessage); } return response.json(); } // ==================== 项目管理API ==================== /** * 创建筛选项目 */ export async function createProject( data: CreateProjectRequest ): Promise> { return request('/projects', { method: 'POST', body: JSON.stringify(data), }); } /** * 获取项目列表 */ export async function listProjects(): Promise> { return request('/projects'); } /** * 获取项目详情 */ export async function getProject( projectId: string ): Promise> { return request(`/projects/${projectId}`); } /** * 更新项目 */ export async function updateProject( projectId: string, data: Partial ): Promise> { return request(`/projects/${projectId}`, { method: 'PUT', body: JSON.stringify(data), }); } /** * 删除项目 */ export async function deleteProject( projectId: string ): Promise> { return request(`/projects/${projectId}`, { method: 'DELETE', }); } // ==================== 文献管理API ==================== /** * 批量导入文献(JSON格式) */ export async function importLiteratures(data: { projectId: string; literatures: Array>; }): Promise> { return request('/literatures/import', { method: 'POST', body: JSON.stringify(data), }); } /** * 获取文献列表 */ export async function listLiteratures( projectId: string, params?: { page?: number; pageSize?: number; } ): Promise>> { const queryString = new URLSearchParams( params as Record ).toString(); return request(`/projects/${projectId}/literatures?${queryString}`); } /** * 删除文献 */ export async function deleteLiterature( projectId: string, literatureId: string ): Promise> { return request(`/projects/${projectId}/literatures/${literatureId}`, { method: 'DELETE', }); } // ==================== 筛选任务API ==================== /** * 启动筛选任务 */ export async function startScreening( projectId: string ): Promise> { return request(`/projects/${projectId}/screening/start`, { method: 'POST', }); } /** * 查询任务进度 */ export async function getTaskProgress( taskId: string ): Promise> { return request(`/screening/tasks/${taskId}/progress`); } // ==================== 筛选结果API ==================== /** * 获取筛选结果列表 */ export async function getScreeningResults( projectId: string, params?: { conflictOnly?: boolean; finalDecision?: 'include' | 'exclude' | 'pending'; page?: number; pageSize?: number; } ): Promise>> { const queryString = new URLSearchParams( params as Record ).toString(); return request(`/projects/${projectId}/screening/results?${queryString}`); } /** * 更新单个筛选结果 */ export async function updateScreeningResult( resultId: string, data: { finalDecision?: 'include' | 'exclude' | 'pending'; reviewComment?: string; } ): Promise> { return request(`/screening/results/${resultId}`, { method: 'PUT', body: JSON.stringify(data), }); } /** * 批量更新筛选结果 */ export async function batchUpdateScreeningResults(data: { resultIds: string[]; finalDecision: 'include' | 'exclude' | 'pending'; decisionMethod?: string; reviewComment?: string; }): Promise> { return request('/screening/results/batch-update', { method: 'POST', body: JSON.stringify(data), }); } // ==================== 导出API ==================== /** * 导出筛选结果为Excel */ export async function exportScreeningResults( projectId: string, params?: { filter?: 'all' | 'included' | 'excluded' | 'pending'; } ): Promise { const queryString = new URLSearchParams( params as Record ).toString(); const response = await fetch( `${API_BASE_URL}/projects/${projectId}/screening/results/export?${queryString}`, { headers: getAuthHeaders() } ); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return response.blob(); } // ==================== 统计API ==================== /** * 获取项目统计信息 */ export async function getProjectStatistics( projectId: string ): Promise> { return request(`/projects/${projectId}/statistics`); } // ==================== Day 3 新增API ==================== /** * 获取筛选任务进度(新) * GET /projects/:projectId/screening-task */ export async function getScreeningTask( projectId: string ): Promise> { return request(`/projects/${projectId}/screening-task`); } /** * 获取筛选结果列表(新,支持分页和筛选) * GET /projects/:projectId/screening-results */ export async function getScreeningResultsList( projectId: string, params?: { page?: number; pageSize?: number; filter?: 'all' | 'conflict' | 'included' | 'excluded' | 'pending' | 'reviewed'; } ): Promise> { const queryString = new URLSearchParams( params as Record ).toString(); return request(`/projects/${projectId}/screening-results?${queryString}`); } /** * 获取单个筛选结果详情(新) * GET /screening-results/:resultId */ export async function getScreeningResultDetail( resultId: string ): Promise> { return request(`/screening-results/${resultId}`); } /** * 提交人工复核(新) * POST /screening-results/:resultId/review */ export async function reviewScreeningResult( resultId: string, data: { decision: 'include' | 'exclude'; note?: string; } ): Promise> { return request(`/screening-results/${resultId}/review`, { method: 'POST', body: JSON.stringify(data), }); } // ==================== 健康检查API ==================== /** * 模块健康检查 */ export async function healthCheck(): Promise> { return request('/health'); } // ==================== 全文复筛API (Day 5-8 新增) ==================== /** * 创建全文复筛任务 */ export async function createFulltextTask(data: { projectId: string; literatureIds: string[]; modelA?: string; modelB?: string; }): Promise> { return request('/fulltext-screening/tasks', { method: 'POST', body: JSON.stringify(data), }); } /** * 获取全文复筛任务进度 */ export async function getFulltextTaskProgress( taskId: string ): Promise> { return request(`/fulltext-screening/tasks/${taskId}`); } /** * 获取全文复筛任务结果 */ export async function getFulltextTaskResults( taskId: string, params?: { filter?: 'all' | 'conflict' | 'pending' | 'reviewed'; page?: number; pageSize?: number; sortBy?: 'priority' | 'createdAt'; sortOrder?: 'asc' | 'desc'; } ): Promise> { const queryString = new URLSearchParams( params as Record ).toString(); return request(`/fulltext-screening/tasks/${taskId}/results?${queryString}`); } /** * 更新全文复筛人工决策 */ export async function updateFulltextDecision( resultId: string, data: { finalDecision: 'include' | 'exclude'; exclusionReason?: string; reviewNotes?: string; } ): Promise> { return request(`/fulltext-screening/results/${resultId}/decision`, { method: 'PUT', body: JSON.stringify(data), }); } /** * 导出全文复筛结果(Excel) */ export async function exportFulltextResults( taskId: string ): Promise { const response = await fetch( `${API_BASE_URL}/fulltext-screening/tasks/${taskId}/export`, { headers: getAuthHeaders() } ); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return response.blob(); } // ==================== 智能文献检索API (DeepSearch) ==================== /** * 创建智能文献检索任务 */ export async function createResearchTask(data: { projectId: string; query: string; }): Promise> { return request('/research/tasks', { method: 'POST', body: JSON.stringify(data), }); } /** * 获取智能文献检索任务状态 */ export async function getResearchTaskStatus( taskId: string ): Promise; errorMessage?: string; }>> { return request(`/research/tasks/${taskId}/status`); } // ==================== Deep Research V2.0 API ==================== import type { DataSourceConfig, GenerateRequirementRequest, GenerateRequirementResponse, DeepResearchTask, DeepResearchTaskSummary, } from '../types/deepResearch'; /** * 获取数据源配置列表 */ export async function getDeepResearchDataSources(): Promise> { return request('/research/data-sources'); } /** * 需求扩写(PICOS + MeSH) */ export async function generateRequirement( data: GenerateRequirementRequest ): Promise> { return request('/research/generate-requirement', { method: 'POST', body: JSON.stringify(data), }); } /** * 启动异步执行 */ export async function executeDeepResearchTask( taskId: string, confirmedRequirement: string ): Promise> { return request(`/research/tasks/${taskId}/execute`, { method: 'PUT', body: JSON.stringify({ confirmedRequirement }), }); } /** * 获取 V2.0 任务历史列表(最近 100 条,不含 draft) */ export async function listDeepResearchTasks(): Promise> { return request('/research/v2/tasks'); } /** * 删除 V2.0 检索任务 */ export async function deleteDeepResearchTask(taskId: string): Promise> { return request(`/research/tasks/${taskId}`, { method: 'DELETE' }); } /** * 获取 V2.0 任务详情(状态 + 日志 + 结果) */ export async function getDeepResearchTask( taskId: string ): Promise> { return request(`/research/tasks/${taskId}`); } // ==================== 工具 3:全文智能提取 API ==================== export async function getExtractionTemplates(): Promise> { return request('/extraction/templates'); } export async function getExtractionTemplate(templateId: string): Promise> { return request(`/extraction/templates/${templateId}`); } export async function cloneExtractionTemplate( projectId: string, baseTemplateId: string ): Promise> { return request('/extraction/templates/clone', { method: 'POST', body: JSON.stringify({ projectId, baseTemplateId }), }); } export async function getExtractionKnowledgeBases(): Promise> { return request('/extraction/knowledge-bases'); } export async function getExtractionDocuments(kbId: string): Promise> { return request(`/extraction/knowledge-bases/${kbId}/documents`); } export async function createExtractionTask(params: { projectId: string; projectTemplateId: string; pkbKnowledgeBaseId: string; documentIds: string[]; idempotencyKey?: string; }): Promise> { return request('/extraction/tasks', { method: 'POST', body: JSON.stringify(params), }); } export async function getExtractionTaskStatus( taskId: string ): Promise> { return request(`/extraction/tasks/${taskId}`); } export async function getExtractionTaskResults( taskId: string ): Promise> { return request(`/extraction/tasks/${taskId}/results`); } export async function getExtractionResultDetail( resultId: string ): Promise> { return request(`/extraction/results/${resultId}`); } export async function reviewExtractionResult( resultId: string, data: { reviewStatus: 'approved' | 'rejected' } ): Promise> { return request(`/extraction/results/${resultId}/review`, { method: 'PUT', body: JSON.stringify(data), }); } export async function exportExtractionResults( taskId: string ): Promise { const response = await fetch( `${API_BASE_URL}/extraction/tasks/${taskId}/export`, { headers: getAuthHeaders() } ); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return response.blob(); } // ==================== 工具 4:SR 图表生成器 API ==================== export async function getChartingPrismaData( projectId: string ): Promise> { return request(`/charting/prisma-data/${projectId}`); } export async function getChartingBaselineData( projectId: string ): Promise> { return request(`/charting/baseline-data/${projectId}`); } // ==================== 工具 5:Meta 分析引擎 API ==================== export async function runMetaAnalysis(body: { data: Record[]; params: { data_type: string; model?: string; effect_measure?: string; }; }): Promise { return request('/meta-analysis/run', { method: 'POST', body: JSON.stringify(body), }); } export async function getMetaProjectData( projectId: string ): Promise<{ rows: any[]; detectedType: string | null; count: number }> { return request(`/meta-analysis/project-data/${projectId}`); } export async function getMetaHealthCheck(): Promise<{ rServiceAvailable: boolean }> { return request('/meta-analysis/health'); } // ==================== 统一导出API对象 ==================== /** * ASL API统一导出对象 */ export const aslApi = { // 项目管理 createProject, listProjects, getProject, updateProject, deleteProject, // 文献管理 importLiteratures, listLiteratures, deleteLiterature, // 筛选任务 startScreening, getTaskProgress, getScreeningTask, // Day 3 新增 // 筛选结果 getScreeningResults, getScreeningResultsList, // Day 3 新增(分页版本) getScreeningResultDetail, // Day 3 新增 updateScreeningResult, batchUpdateScreeningResults, reviewScreeningResult, // Day 3 新增(人工复核) // 导出 exportScreeningResults, // 统计 getProjectStatistics, // 全文复筛 (Day 5-8 新增) createFulltextTask, getFulltextTaskProgress, getFulltextTaskResults, updateFulltextDecision, exportFulltextResults, // 健康检查 healthCheck, // 智能文献检索 (DeepSearch V1.x) createResearchTask, getResearchTaskStatus, // Deep Research V2.0 getDeepResearchDataSources, generateRequirement, executeDeepResearchTask, listDeepResearchTasks, deleteDeepResearchTask, getDeepResearchTask, // 工具 3:全文智能提取 getExtractionTemplates, getExtractionTemplate, cloneExtractionTemplate, getExtractionKnowledgeBases, getExtractionDocuments, createExtractionTask, getExtractionTaskStatus, getExtractionTaskResults, getExtractionResultDetail, reviewExtractionResult, exportExtractionResults, // 工具 4:SR 图表生成器 getChartingPrismaData, getChartingBaselineData, // 工具 5:Meta 分析引擎 runMetaAnalysis, getMetaProjectData, getMetaHealthCheck, };