Summary: - Fix methodology score display issue in task list (show score instead of 'warn') - Add methodology_score field to database schema - Fix report display when only methodology agent is selected - Implement Word document export using docx library - Update documentation to v3.0/v3.1 Backend changes: - Add methodologyScore to Prisma schema and TaskSummary type - Update reviewWorker to save methodologyScore - Update getTaskList to return methodologyScore Frontend changes: - Install docx and file-saver libraries - Implement handleExportReport with Word generation - Fix activeTab auto-selection based on available data - Add proper imports for docx components Documentation: - Update RVW module status to 90% (Phase 1-5 complete) - Update system status document to v3.0 Tested: All review workflows verified, Word export functional
1038 lines
40 KiB
Plaintext
1038 lines
40 KiB
Plaintext
generator client {
|
||
provider = "prisma-client-js"
|
||
previewFeatures = ["multiSchema"]
|
||
}
|
||
|
||
datasource db {
|
||
provider = "postgresql"
|
||
url = env("DATABASE_URL")
|
||
schemas = ["admin_schema", "aia_schema", "asl_schema", "common_schema", "dc_schema", "iit_schema", "pkb_schema", "platform_schema", "public", "rvw_schema", "ssa_schema", "st_schema"]
|
||
}
|
||
|
||
/// 应用缓存表 - Postgres-Only架构
|
||
/// 用于替代Redis缓存,支持LLM结果缓存、健康检查缓存等
|
||
model AppCache {
|
||
id Int @id @default(autoincrement())
|
||
key String @unique @db.VarChar(500)
|
||
value Json
|
||
expiresAt DateTime @map("expires_at") @db.Timestamp(6)
|
||
createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(6)
|
||
|
||
@@index([expiresAt], map: "idx_app_cache_expires")
|
||
@@index([key, expiresAt], map: "idx_app_cache_key_expires")
|
||
@@map("app_cache")
|
||
@@schema("platform_schema")
|
||
}
|
||
|
||
model User {
|
||
id String @id @default(uuid())
|
||
email String @unique
|
||
password String
|
||
name String?
|
||
avatarUrl String? @map("avatar_url")
|
||
role String @default("user")
|
||
status String @default("active")
|
||
kbQuota Int @default(3) @map("kb_quota")
|
||
kbUsed Int @default(0) @map("kb_used")
|
||
trialEndsAt DateTime? @map("trial_ends_at")
|
||
isTrial Boolean @default(true) @map("is_trial")
|
||
lastLoginAt DateTime? @map("last_login_at")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([createdAt], map: "idx_platform_users_created_at")
|
||
@@index([email], map: "idx_platform_users_email")
|
||
@@index([status], map: "idx_platform_users_status")
|
||
@@map("users")
|
||
@@schema("platform_schema")
|
||
}
|
||
|
||
model Project {
|
||
id String @id @default(uuid())
|
||
userId String @map("user_id")
|
||
name String
|
||
background String @default("")
|
||
researchType String @default("observational") @map("research_type")
|
||
conversationCount Int @default(0) @map("conversation_count")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
// 关系字段(手动添加)
|
||
conversations Conversation[] @relation("ProjectConversations")
|
||
|
||
@@index([createdAt], map: "idx_aia_projects_created_at")
|
||
@@index([deletedAt], map: "idx_aia_projects_deleted_at")
|
||
@@index([userId], map: "idx_aia_projects_user_id")
|
||
@@map("projects")
|
||
@@schema("aia_schema")
|
||
}
|
||
|
||
model Conversation {
|
||
id String @id @default(uuid())
|
||
userId String @map("user_id")
|
||
projectId String? @map("project_id")
|
||
agentId String @map("agent_id")
|
||
title String
|
||
modelName String @default("deepseek-v3") @map("model_name")
|
||
messageCount Int @default(0) @map("message_count")
|
||
totalTokens Int @default(0) @map("total_tokens")
|
||
metadata Json?
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
// 关系字段(手动添加)
|
||
project Project? @relation("ProjectConversations", fields: [projectId], references: [id], onDelete: SetNull)
|
||
messages Message[] @relation("ConversationMessages")
|
||
|
||
@@index([agentId], map: "idx_aia_conversations_agent_id")
|
||
@@index([createdAt], map: "idx_aia_conversations_created_at")
|
||
@@index([deletedAt], map: "idx_aia_conversations_deleted_at")
|
||
@@index([projectId], map: "idx_aia_conversations_project_id")
|
||
@@index([userId], map: "idx_aia_conversations_user_id")
|
||
@@map("conversations")
|
||
@@schema("aia_schema")
|
||
}
|
||
|
||
model Message {
|
||
id String @id @default(uuid())
|
||
conversationId String @map("conversation_id")
|
||
role String
|
||
content String
|
||
model String?
|
||
metadata Json?
|
||
tokens Int?
|
||
isPinned Boolean @default(false) @map("is_pinned")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
// 关系字段(手动添加)
|
||
conversation Conversation @relation("ConversationMessages", fields: [conversationId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([conversationId], map: "idx_aia_messages_conversation_id")
|
||
@@index([createdAt], map: "idx_aia_messages_created_at")
|
||
@@index([isPinned], map: "idx_aia_messages_is_pinned")
|
||
@@map("messages")
|
||
@@schema("aia_schema")
|
||
}
|
||
|
||
model KnowledgeBase {
|
||
id String @id @default(uuid())
|
||
userId String @map("user_id")
|
||
name String
|
||
description String?
|
||
difyDatasetId String @map("dify_dataset_id")
|
||
fileCount Int @default(0) @map("file_count")
|
||
totalSizeBytes BigInt @default(0) @map("total_size_bytes")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// 关系字段(手动添加)
|
||
documents Document[] @relation("KnowledgeBaseDocuments")
|
||
batchTasks BatchTask[] @relation("KnowledgeBaseBatchTasks")
|
||
|
||
@@index([difyDatasetId], map: "idx_pkb_knowledge_bases_dify_dataset_id")
|
||
@@index([userId], map: "idx_pkb_knowledge_bases_user_id")
|
||
@@map("knowledge_bases")
|
||
@@schema("pkb_schema")
|
||
}
|
||
|
||
model Document {
|
||
id String @id @default(uuid())
|
||
kbId String @map("kb_id")
|
||
userId String @map("user_id")
|
||
filename String
|
||
fileType String @map("file_type")
|
||
fileSizeBytes BigInt @map("file_size_bytes")
|
||
fileUrl String @map("file_url")
|
||
difyDocumentId String @map("dify_document_id")
|
||
status String @default("uploading")
|
||
progress Int @default(0)
|
||
errorMessage String? @map("error_message")
|
||
segmentsCount Int? @map("segments_count")
|
||
tokensCount Int? @map("tokens_count")
|
||
extractionMethod String? @map("extraction_method")
|
||
extractionQuality Float? @map("extraction_quality")
|
||
charCount Int? @map("char_count")
|
||
language String?
|
||
extractedText String? @map("extracted_text")
|
||
uploadedAt DateTime @default(now()) @map("uploaded_at")
|
||
processedAt DateTime? @map("processed_at")
|
||
|
||
// 关系字段(手动添加)
|
||
knowledgeBase KnowledgeBase @relation("KnowledgeBaseDocuments", fields: [kbId], references: [id], onDelete: Cascade)
|
||
batchResults BatchResult[] @relation("DocumentBatchResults")
|
||
|
||
@@index([difyDocumentId], map: "idx_pkb_documents_dify_document_id")
|
||
@@index([extractionMethod], map: "idx_pkb_documents_extraction_method")
|
||
@@index([kbId], map: "idx_pkb_documents_kb_id")
|
||
@@index([status], map: "idx_pkb_documents_status")
|
||
@@index([userId], map: "idx_pkb_documents_user_id")
|
||
@@map("documents")
|
||
@@schema("pkb_schema")
|
||
}
|
||
|
||
model BatchTask {
|
||
id String @id @default(uuid())
|
||
userId String @map("user_id")
|
||
kbId String @map("kb_id")
|
||
name String
|
||
templateType String @map("template_type")
|
||
templateId String? @map("template_id")
|
||
prompt String
|
||
status String
|
||
totalDocuments Int @map("total_documents")
|
||
completedCount Int @default(0) @map("completed_count")
|
||
failedCount Int @default(0) @map("failed_count")
|
||
modelType String @map("model_type")
|
||
concurrency Int @default(3)
|
||
startedAt DateTime? @map("started_at")
|
||
completedAt DateTime? @map("completed_at")
|
||
durationSeconds Int? @map("duration_seconds")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// 关系字段(手动添加)
|
||
knowledgeBase KnowledgeBase @relation("KnowledgeBaseBatchTasks", fields: [kbId], references: [id], onDelete: Cascade)
|
||
results BatchResult[] @relation("TaskBatchResults")
|
||
|
||
@@index([createdAt], map: "idx_pkb_batch_tasks_created_at")
|
||
@@index([kbId], map: "idx_pkb_batch_tasks_kb_id")
|
||
@@index([status], map: "idx_pkb_batch_tasks_status")
|
||
@@index([userId], map: "idx_pkb_batch_tasks_user_id")
|
||
@@map("batch_tasks")
|
||
@@schema("pkb_schema")
|
||
}
|
||
|
||
model BatchResult {
|
||
id String @id @default(uuid())
|
||
taskId String @map("task_id")
|
||
documentId String @map("document_id")
|
||
status String
|
||
data Json?
|
||
rawOutput String? @map("raw_output")
|
||
errorMessage String? @map("error_message")
|
||
processingTimeMs Int? @map("processing_time_ms")
|
||
tokensUsed Int? @map("tokens_used")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
// 关系字段(手动添加)
|
||
task BatchTask @relation("TaskBatchResults", fields: [taskId], references: [id], onDelete: Cascade)
|
||
document Document @relation("DocumentBatchResults", fields: [documentId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([documentId], map: "idx_pkb_batch_results_document_id")
|
||
@@index([status], map: "idx_pkb_batch_results_status")
|
||
@@index([taskId], map: "idx_pkb_batch_results_task_id")
|
||
@@map("batch_results")
|
||
@@schema("pkb_schema")
|
||
}
|
||
|
||
model TaskTemplate {
|
||
id String @id @default(uuid())
|
||
userId String @map("user_id")
|
||
name String
|
||
description String?
|
||
prompt String
|
||
isPublic Boolean @default(false) @map("is_public")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
outputFields Json
|
||
|
||
@@index([userId], map: "idx_pkb_task_templates_user_id")
|
||
@@map("task_templates")
|
||
@@schema("pkb_schema")
|
||
}
|
||
|
||
model AdminLog {
|
||
id Int @id @default(autoincrement())
|
||
adminId String @map("admin_id")
|
||
action String
|
||
resourceType String? @map("resource_type")
|
||
resourceId String? @map("resource_id")
|
||
details Json?
|
||
ipAddress String? @map("ip_address")
|
||
userAgent String? @map("user_agent")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
admin users @relation(fields: [adminId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([adminId])
|
||
@@index([createdAt])
|
||
@@index([action])
|
||
@@map("admin_logs")
|
||
@@schema("public")
|
||
}
|
||
|
||
model GeneralConversation {
|
||
id String @id @default(uuid())
|
||
userId String @map("user_id")
|
||
title String
|
||
modelName String? @map("model_name")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
@@index([createdAt], map: "idx_aia_general_conversations_created_at")
|
||
@@index([updatedAt], map: "idx_aia_general_conversations_updated_at")
|
||
@@index([userId], map: "idx_aia_general_conversations_user_id")
|
||
@@map("general_conversations")
|
||
@@schema("aia_schema")
|
||
}
|
||
|
||
model GeneralMessage {
|
||
id String @id @default(uuid())
|
||
conversationId String @map("conversation_id")
|
||
role String
|
||
content String
|
||
model String?
|
||
metadata Json?
|
||
tokens Int?
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([conversationId], map: "idx_aia_general_messages_conversation_id")
|
||
@@index([createdAt], map: "idx_aia_general_messages_created_at")
|
||
@@map("general_messages")
|
||
@@schema("aia_schema")
|
||
}
|
||
|
||
model ReviewTask {
|
||
id String @id @default(uuid())
|
||
userId String @map("user_id")
|
||
fileName String @map("file_name")
|
||
fileSize Int @map("file_size")
|
||
filePath String? @map("file_path")
|
||
extractedText String @map("extracted_text")
|
||
wordCount Int? @map("word_count")
|
||
status String @default("pending")
|
||
|
||
// 🆕 智能体选择(Phase 2新增)
|
||
selectedAgents String[] @default(["editorial", "methodology"]) @map("selected_agents")
|
||
|
||
// 评估结果
|
||
editorialReview Json? @map("editorial_review")
|
||
methodologyReview Json? @map("methodology_review")
|
||
overallScore Float? @map("overall_score")
|
||
|
||
// 🆕 结果摘要(Phase 2新增,用于列表展示)
|
||
editorialScore Float? @map("editorial_score")
|
||
methodologyScore Float? @map("methodology_score")
|
||
methodologyStatus String? @map("methodology_status") // pass/warn/fail
|
||
|
||
// 🆕 预留字段(暂不使用)
|
||
picoExtract Json? @map("pico_extract")
|
||
isArchived Boolean @default(false) @map("is_archived")
|
||
archivedAt DateTime? @map("archived_at")
|
||
|
||
// 元数据
|
||
modelUsed String? @map("model_used")
|
||
startedAt DateTime? @map("started_at")
|
||
completedAt DateTime? @map("completed_at")
|
||
durationSeconds Int? @map("duration_seconds")
|
||
errorMessage String? @map("error_message")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
user users @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([userId])
|
||
@@index([status])
|
||
@@index([createdAt])
|
||
@@index([isArchived])
|
||
@@map("review_tasks")
|
||
@@schema("public")
|
||
}
|
||
|
||
model AslScreeningProject {
|
||
id String @id @default(uuid())
|
||
userId String @map("user_id")
|
||
projectName String @map("project_name")
|
||
picoCriteria Json @map("pico_criteria")
|
||
inclusionCriteria String @map("inclusion_criteria")
|
||
exclusionCriteria String @map("exclusion_criteria")
|
||
status String @default("draft")
|
||
screeningConfig Json? @map("screening_config")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// 关系字段(手动添加)
|
||
literatures AslLiterature[] @relation("ProjectLiteratures")
|
||
screeningResults AslScreeningResult[] @relation("ProjectScreeningResults")
|
||
screeningTasks AslScreeningTask[] @relation("ProjectScreeningTasks")
|
||
fulltextTasks AslFulltextScreeningTask[] @relation("ProjectFulltextTasks")
|
||
fulltextResults AslFulltextScreeningResult[] @relation("ProjectFulltextResults")
|
||
|
||
@@index([status], map: "idx_screening_projects_status")
|
||
@@index([userId], map: "idx_screening_projects_user_id")
|
||
@@map("screening_projects")
|
||
@@schema("asl_schema")
|
||
}
|
||
|
||
model AslLiterature {
|
||
id String @id @default(uuid())
|
||
projectId String @map("project_id")
|
||
pmid String?
|
||
title String
|
||
abstract String
|
||
authors String?
|
||
journal String?
|
||
publicationYear Int? @map("publication_year")
|
||
doi String?
|
||
pdfUrl String? @map("pdf_url")
|
||
pdfOssKey String? @map("pdf_oss_key")
|
||
pdfFileSize Int? @map("pdf_file_size")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
stage String @default("imported") @map("stage")
|
||
hasPdf Boolean @default(false) @map("has_pdf")
|
||
pdfStorageType String? @map("pdf_storage_type")
|
||
pdfStorageRef String? @map("pdf_storage_ref")
|
||
pdfStatus String? @map("pdf_status")
|
||
pdfUploadedAt DateTime? @map("pdf_uploaded_at")
|
||
fullTextStorageType String? @map("full_text_storage_type")
|
||
fullTextStorageRef String? @map("full_text_storage_ref")
|
||
fullTextUrl String? @map("full_text_url")
|
||
fullTextFormat String? @map("full_text_format")
|
||
fullTextSource String? @map("full_text_source")
|
||
fullTextTokenCount Int? @map("full_text_token_count")
|
||
fullTextExtractedAt DateTime? @map("full_text_extracted_at")
|
||
|
||
// 关系字段(手动添加)
|
||
project AslScreeningProject @relation("ProjectLiteratures", fields: [projectId], references: [id], onDelete: Cascade)
|
||
screeningResults AslScreeningResult[] @relation("LiteratureScreeningResults")
|
||
fulltextResults AslFulltextScreeningResult[] @relation("LiteratureFulltextResults")
|
||
|
||
@@unique([projectId, pmid], map: "unique_project_pmid")
|
||
@@index([doi], map: "idx_literatures_doi")
|
||
@@index([hasPdf], map: "idx_literatures_has_pdf")
|
||
@@index([pdfStatus], map: "idx_literatures_pdf_status")
|
||
@@index([projectId], map: "idx_literatures_project_id")
|
||
@@index([stage], map: "idx_literatures_stage")
|
||
@@map("literatures")
|
||
@@schema("asl_schema")
|
||
}
|
||
|
||
model AslScreeningResult {
|
||
id String @id @default(uuid())
|
||
projectId String @map("project_id")
|
||
literatureId String @map("literature_id")
|
||
dsModelName String @map("ds_model_name")
|
||
dsPJudgment String? @map("ds_p_judgment")
|
||
dsIJudgment String? @map("ds_i_judgment")
|
||
dsCJudgment String? @map("ds_c_judgment")
|
||
dsSJudgment String? @map("ds_s_judgment")
|
||
dsConclusion String? @map("ds_conclusion")
|
||
dsConfidence Float? @map("ds_confidence")
|
||
dsPEvidence String? @map("ds_p_evidence")
|
||
dsIEvidence String? @map("ds_i_evidence")
|
||
dsCEvidence String? @map("ds_c_evidence")
|
||
dsSEvidence String? @map("ds_s_evidence")
|
||
dsReason String? @map("ds_reason")
|
||
qwenModelName String @map("qwen_model_name")
|
||
qwenPJudgment String? @map("qwen_p_judgment")
|
||
qwenIJudgment String? @map("qwen_i_judgment")
|
||
qwenCJudgment String? @map("qwen_c_judgment")
|
||
qwenSJudgment String? @map("qwen_s_judgment")
|
||
qwenConclusion String? @map("qwen_conclusion")
|
||
qwenConfidence Float? @map("qwen_confidence")
|
||
qwenPEvidence String? @map("qwen_p_evidence")
|
||
qwenIEvidence String? @map("qwen_i_evidence")
|
||
qwenCEvidence String? @map("qwen_c_evidence")
|
||
qwenSEvidence String? @map("qwen_s_evidence")
|
||
qwenReason String? @map("qwen_reason")
|
||
conflictStatus String @default("none") @map("conflict_status")
|
||
conflictFields Json? @map("conflict_fields")
|
||
finalDecision String? @map("final_decision")
|
||
finalDecisionBy String? @map("final_decision_by")
|
||
finalDecisionAt DateTime? @map("final_decision_at")
|
||
exclusionReason String? @map("exclusion_reason")
|
||
aiProcessingStatus String @default("pending") @map("ai_processing_status")
|
||
aiProcessedAt DateTime? @map("ai_processed_at")
|
||
aiErrorMessage String? @map("ai_error_message")
|
||
promptVersion String @default("v1.0.0") @map("prompt_version")
|
||
rawOutput Json? @map("raw_output")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// 关系字段(手动添加)
|
||
project AslScreeningProject @relation("ProjectScreeningResults", fields: [projectId], references: [id], onDelete: Cascade)
|
||
literature AslLiterature @relation("LiteratureScreeningResults", fields: [literatureId], references: [id], onDelete: Cascade)
|
||
|
||
@@unique([projectId, literatureId], map: "unique_project_literature")
|
||
@@index([conflictStatus], map: "idx_screening_results_conflict_status")
|
||
@@index([finalDecision], map: "idx_screening_results_final_decision")
|
||
@@index([literatureId], map: "idx_screening_results_literature_id")
|
||
@@index([projectId], map: "idx_screening_results_project_id")
|
||
@@map("screening_results")
|
||
@@schema("asl_schema")
|
||
}
|
||
|
||
model AslScreeningTask {
|
||
id String @id @default(uuid())
|
||
projectId String @map("project_id")
|
||
taskType String @map("task_type")
|
||
status String @default("pending")
|
||
totalItems Int @map("total_items")
|
||
processedItems Int @default(0) @map("processed_items")
|
||
successItems Int @default(0) @map("success_items")
|
||
failedItems Int @default(0) @map("failed_items")
|
||
conflictItems Int @default(0) @map("conflict_items")
|
||
startedAt DateTime? @map("started_at")
|
||
completedAt DateTime? @map("completed_at")
|
||
estimatedEndAt DateTime? @map("estimated_end_at")
|
||
errorMessage String? @map("error_message")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// 关系字段(手动添加)
|
||
project AslScreeningProject @relation("ProjectScreeningTasks", fields: [projectId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([projectId], map: "idx_screening_tasks_project_id")
|
||
@@index([status], map: "idx_screening_tasks_status")
|
||
@@map("screening_tasks")
|
||
@@schema("asl_schema")
|
||
}
|
||
|
||
model AslFulltextScreeningTask {
|
||
id String @id @default(uuid())
|
||
projectId String @map("project_id")
|
||
modelA String @map("model_a")
|
||
modelB String @map("model_b")
|
||
promptVersion String @default("v1.0.0") @map("prompt_version")
|
||
status String @default("pending")
|
||
totalCount Int @map("total_count")
|
||
processedCount Int @default(0) @map("processed_count")
|
||
successCount Int @default(0) @map("success_count")
|
||
failedCount Int @default(0) @map("failed_count")
|
||
degradedCount Int @default(0) @map("degraded_count")
|
||
totalTokens Int @default(0) @map("total_tokens")
|
||
totalCost Float @default(0) @map("total_cost")
|
||
startedAt DateTime? @map("started_at")
|
||
completedAt DateTime? @map("completed_at")
|
||
estimatedEndAt DateTime? @map("estimated_end_at")
|
||
errorMessage String? @map("error_message")
|
||
errorStack String? @map("error_stack")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// 关系字段(手动添加)
|
||
project AslScreeningProject @relation("ProjectFulltextTasks", fields: [projectId], references: [id], onDelete: Cascade)
|
||
results AslFulltextScreeningResult[] @relation("TaskFulltextResults")
|
||
|
||
@@index([createdAt], map: "idx_fulltext_tasks_created_at")
|
||
@@index([projectId], map: "idx_fulltext_tasks_project_id")
|
||
@@index([status], map: "idx_fulltext_tasks_status")
|
||
@@map("fulltext_screening_tasks")
|
||
@@schema("asl_schema")
|
||
}
|
||
|
||
model AslFulltextScreeningResult {
|
||
id String @id @default(uuid())
|
||
taskId String @map("task_id")
|
||
projectId String @map("project_id")
|
||
literatureId String @map("literature_id")
|
||
modelAName String @map("model_a_name")
|
||
modelAStatus String @map("model_a_status")
|
||
modelAFields Json @map("model_a_fields")
|
||
modelAOverall Json @map("model_a_overall")
|
||
modelAProcessingLog Json? @map("model_a_processing_log")
|
||
modelAVerification Json? @map("model_a_verification")
|
||
modelATokens Int? @map("model_a_tokens")
|
||
modelACost Float? @map("model_a_cost")
|
||
modelAError String? @map("model_a_error")
|
||
modelBName String @map("model_b_name")
|
||
modelBStatus String @map("model_b_status")
|
||
modelBFields Json @map("model_b_fields")
|
||
modelBOverall Json @map("model_b_overall")
|
||
modelBProcessingLog Json? @map("model_b_processing_log")
|
||
modelBVerification Json? @map("model_b_verification")
|
||
modelBTokens Int? @map("model_b_tokens")
|
||
modelBCost Float? @map("model_b_cost")
|
||
modelBError String? @map("model_b_error")
|
||
medicalLogicIssues Json? @map("medical_logic_issues")
|
||
evidenceChainIssues Json? @map("evidence_chain_issues")
|
||
isConflict Boolean @default(false) @map("is_conflict")
|
||
conflictSeverity String? @map("conflict_severity")
|
||
conflictFields String[] @map("conflict_fields")
|
||
conflictDetails Json? @map("conflict_details")
|
||
reviewPriority Int? @map("review_priority")
|
||
reviewDeadline DateTime? @map("review_deadline")
|
||
finalDecision String? @map("final_decision")
|
||
finalDecisionBy String? @map("final_decision_by")
|
||
finalDecisionAt DateTime? @map("final_decision_at")
|
||
exclusionReason String? @map("exclusion_reason")
|
||
reviewNotes String? @map("review_notes")
|
||
processingStatus String @default("pending") @map("processing_status")
|
||
isDegraded Boolean @default(false) @map("is_degraded")
|
||
degradedModel String? @map("degraded_model")
|
||
processedAt DateTime? @map("processed_at")
|
||
promptVersion String @default("v1.0.0") @map("prompt_version")
|
||
rawOutputA Json? @map("raw_output_a")
|
||
rawOutputB Json? @map("raw_output_b")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// 关系字段(手动添加)
|
||
task AslFulltextScreeningTask @relation("TaskFulltextResults", fields: [taskId], references: [id], onDelete: Cascade)
|
||
project AslScreeningProject @relation("ProjectFulltextResults", fields: [projectId], references: [id], onDelete: Cascade)
|
||
literature AslLiterature @relation("LiteratureFulltextResults", fields: [literatureId], references: [id], onDelete: Cascade)
|
||
|
||
@@unique([projectId, literatureId], map: "unique_project_literature_fulltext")
|
||
@@index([finalDecision], map: "idx_fulltext_results_final_decision")
|
||
@@index([isConflict], map: "idx_fulltext_results_is_conflict")
|
||
@@index([literatureId], map: "idx_fulltext_results_literature_id")
|
||
@@index([projectId], map: "idx_fulltext_results_project_id")
|
||
@@index([reviewPriority], map: "idx_fulltext_results_review_priority")
|
||
@@index([taskId], map: "idx_fulltext_results_task_id")
|
||
@@map("fulltext_screening_results")
|
||
@@schema("asl_schema")
|
||
}
|
||
|
||
model DCHealthCheck {
|
||
id String @id @default(uuid())
|
||
userId String @map("user_id")
|
||
fileName String @map("file_name")
|
||
columnName String @map("column_name")
|
||
emptyRate Float @map("empty_rate")
|
||
avgLength Float @map("avg_length")
|
||
totalRows Int @map("total_rows")
|
||
estimatedTokens Int @map("estimated_tokens")
|
||
status String @map("status")
|
||
message String @map("message")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([userId, fileName])
|
||
@@map("dc_health_checks")
|
||
@@schema("dc_schema")
|
||
}
|
||
|
||
model DCTemplate {
|
||
id String @id @default(uuid())
|
||
diseaseType String @map("disease_type")
|
||
reportType String @map("report_type")
|
||
displayName String @map("display_name")
|
||
fields Json @map("fields")
|
||
promptTemplate String @map("prompt_template")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@unique([diseaseType, reportType])
|
||
@@map("dc_templates")
|
||
@@schema("dc_schema")
|
||
}
|
||
|
||
model DCExtractionTask {
|
||
id String @id @default(uuid())
|
||
userId String @map("user_id")
|
||
projectName String @map("project_name")
|
||
sourceFileKey String @map("source_file_key")
|
||
textColumn String @map("text_column")
|
||
diseaseType String @map("disease_type")
|
||
reportType String @map("report_type")
|
||
targetFields Json @map("target_fields")
|
||
modelA String @default("deepseek-v3") @map("model_a")
|
||
modelB String @default("qwen-max") @map("model_b")
|
||
status String @default("pending") @map("status")
|
||
totalCount Int @default(0) @map("total_count")
|
||
processedCount Int @default(0) @map("processed_count")
|
||
cleanCount Int @default(0) @map("clean_count")
|
||
conflictCount Int @default(0) @map("conflict_count")
|
||
failedCount Int @default(0) @map("failed_count")
|
||
totalTokens Int @default(0) @map("total_tokens")
|
||
totalCost Float @default(0) @map("total_cost")
|
||
error String? @map("error")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
startedAt DateTime? @map("started_at")
|
||
completedAt DateTime? @map("completed_at")
|
||
items DCExtractionItem[]
|
||
|
||
@@index([userId, status])
|
||
@@map("dc_extraction_tasks")
|
||
@@schema("dc_schema")
|
||
}
|
||
|
||
model DCExtractionItem {
|
||
id String @id @default(uuid())
|
||
taskId String @map("task_id")
|
||
rowIndex Int @map("row_index")
|
||
originalText String @map("original_text")
|
||
resultA Json? @map("result_a")
|
||
resultB Json? @map("result_b")
|
||
status String @default("pending") @map("status")
|
||
conflictFields String[] @default([]) @map("conflict_fields")
|
||
finalResult Json? @map("final_result")
|
||
tokensA Int @default(0) @map("tokens_a")
|
||
tokensB Int @default(0) @map("tokens_b")
|
||
error String? @map("error")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
resolvedAt DateTime? @map("resolved_at")
|
||
task DCExtractionTask @relation(fields: [taskId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([taskId, status])
|
||
@@map("dc_extraction_items")
|
||
@@schema("dc_schema")
|
||
}
|
||
|
||
model DcToolCSession {
|
||
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
||
userId String @map("user_id") @db.VarChar(255)
|
||
fileName String @map("file_name") @db.VarChar(500)
|
||
fileKey String @map("file_key") @db.VarChar(500)
|
||
totalRows Int? @map("total_rows")
|
||
totalCols Int? @map("total_cols")
|
||
columns Json? @map("columns")
|
||
encoding String? @map("encoding") @db.VarChar(50)
|
||
fileSize Int @map("file_size")
|
||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(6)
|
||
updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamp(6)
|
||
expiresAt DateTime @map("expires_at") @db.Timestamp(6)
|
||
dataStats Json? @map("data_stats")
|
||
columnMapping Json? @map("column_mapping")
|
||
cleanDataKey String? @map("clean_data_key") @db.VarChar(1000)
|
||
|
||
@@index([expiresAt], map: "idx_dc_tool_c_sessions_expires_at")
|
||
@@index([userId], map: "idx_dc_tool_c_sessions_user_id")
|
||
@@map("dc_tool_c_sessions")
|
||
@@schema("dc_schema")
|
||
}
|
||
|
||
model DcToolCAiHistory {
|
||
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
||
sessionId String @map("session_id") @db.VarChar(255)
|
||
userId String @map("user_id") @db.VarChar(255)
|
||
role String @map("role") @db.VarChar(50)
|
||
content String
|
||
generatedCode String? @map("generated_code")
|
||
codeExplanation String? @map("code_explanation")
|
||
executeStatus String? @map("execute_status") @db.VarChar(50)
|
||
executeResult Json? @map("execute_result")
|
||
executeError String? @map("execute_error")
|
||
retryCount Int? @default(0) @map("retry_count")
|
||
model String? @map("model") @db.VarChar(100)
|
||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(6)
|
||
|
||
@@index([createdAt], map: "idx_dc_tool_c_ai_history_created_at")
|
||
@@index([sessionId], map: "idx_dc_tool_c_ai_history_session_id")
|
||
@@index([userId], map: "idx_dc_tool_c_ai_history_user_id")
|
||
@@map("dc_tool_c_ai_history")
|
||
@@schema("dc_schema")
|
||
}
|
||
|
||
/// This table is a partition table and requires additional setup for migrations. Visit https://pris.ly/d/partition-tables for more info.
|
||
model job {
|
||
id String @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
||
name String
|
||
priority Int @default(0)
|
||
data Json?
|
||
state job_state @default(created)
|
||
retry_limit Int @default(2)
|
||
retry_count Int @default(0)
|
||
retry_delay Int @default(0)
|
||
retry_backoff Boolean @default(false)
|
||
retry_delay_max Int?
|
||
expire_seconds Int @default(900)
|
||
deletion_seconds Int @default(604800)
|
||
singleton_key String?
|
||
singleton_on DateTime? @db.Timestamp(6)
|
||
start_after DateTime @default(now()) @db.Timestamptz(6)
|
||
created_on DateTime @default(now()) @db.Timestamptz(6)
|
||
started_on DateTime? @db.Timestamptz(6)
|
||
completed_on DateTime? @db.Timestamptz(6)
|
||
keep_until DateTime @default(dbgenerated("(now() + '336:00:00'::interval)")) @db.Timestamptz(6)
|
||
output Json?
|
||
dead_letter String?
|
||
policy String?
|
||
|
||
@@id([name, id])
|
||
@@schema("platform_schema")
|
||
}
|
||
|
||
/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
|
||
model queue {
|
||
name String @id
|
||
policy String
|
||
retry_limit Int
|
||
retry_delay Int
|
||
retry_backoff Boolean
|
||
retry_delay_max Int?
|
||
expire_seconds Int
|
||
retention_seconds Int
|
||
deletion_seconds Int
|
||
dead_letter String?
|
||
partition Boolean
|
||
table_name String
|
||
deferred_count Int @default(0)
|
||
queued_count Int @default(0)
|
||
warning_queued Int @default(0)
|
||
active_count Int @default(0)
|
||
total_count Int @default(0)
|
||
singletons_active String[]
|
||
monitor_on DateTime? @db.Timestamptz(6)
|
||
maintain_on DateTime? @db.Timestamptz(6)
|
||
created_on DateTime @default(now()) @db.Timestamptz(6)
|
||
updated_on DateTime @default(now()) @db.Timestamptz(6)
|
||
queue queue? @relation("queueToqueue", fields: [dead_letter], references: [name], onDelete: NoAction, onUpdate: NoAction)
|
||
other_queue queue[] @relation("queueToqueue")
|
||
schedule schedule[]
|
||
subscription subscription[]
|
||
|
||
@@schema("platform_schema")
|
||
}
|
||
|
||
model schedule {
|
||
name String
|
||
key String @default("")
|
||
cron String
|
||
timezone String?
|
||
data Json?
|
||
options Json?
|
||
created_on DateTime @default(now()) @db.Timestamptz(6)
|
||
updated_on DateTime @default(now()) @db.Timestamptz(6)
|
||
queue queue @relation(fields: [name], references: [name], onDelete: Cascade, onUpdate: NoAction)
|
||
|
||
@@id([name, key])
|
||
@@schema("platform_schema")
|
||
}
|
||
|
||
model subscription {
|
||
event String
|
||
name String
|
||
created_on DateTime @default(now()) @db.Timestamptz(6)
|
||
updated_on DateTime @default(now()) @db.Timestamptz(6)
|
||
queue queue @relation(fields: [name], references: [name], onDelete: Cascade, onUpdate: NoAction)
|
||
|
||
@@id([event, name])
|
||
@@schema("platform_schema")
|
||
}
|
||
|
||
model version {
|
||
version Int @id
|
||
cron_on DateTime? @db.Timestamptz(6)
|
||
|
||
@@schema("platform_schema")
|
||
}
|
||
|
||
model users {
|
||
id String @id
|
||
email String @unique
|
||
password String
|
||
name String?
|
||
avatar_url String?
|
||
role String @default("user")
|
||
status String @default("active")
|
||
kb_quota Int @default(3)
|
||
kb_used Int @default(0)
|
||
trial_ends_at DateTime?
|
||
is_trial Boolean @default(true)
|
||
last_login_at DateTime?
|
||
created_at DateTime @default(now())
|
||
updated_at DateTime
|
||
adminLogs AdminLog[]
|
||
reviewTasks ReviewTask[]
|
||
|
||
@@index([created_at])
|
||
@@index([email])
|
||
@@index([status])
|
||
@@schema("public")
|
||
}
|
||
|
||
enum job_state {
|
||
created
|
||
retry
|
||
active
|
||
completed
|
||
cancelled
|
||
failed
|
||
|
||
@@schema("platform_schema")
|
||
}
|
||
|
||
// ==============================
|
||
// IIT Manager Schema (V1.1)
|
||
// ==============================
|
||
|
||
/// IIT项目表
|
||
model IitProject {
|
||
id String @id @default(uuid())
|
||
name String
|
||
description String? @db.Text
|
||
|
||
// Protocol知识库
|
||
difyDatasetId String? @unique @map("dify_dataset_id")
|
||
protocolFileKey String? @map("protocol_file_key")
|
||
|
||
// V1.1 新增:Dify性能优化 - 缓存关键规则
|
||
cachedRules Json? @map("cached_rules")
|
||
|
||
// 字段映射配置(JSON)
|
||
fieldMappings Json @map("field_mappings")
|
||
|
||
// REDCap配置
|
||
redcapProjectId String @map("redcap_project_id")
|
||
redcapApiToken String @db.Text @map("redcap_api_token")
|
||
redcapUrl String @map("redcap_url")
|
||
|
||
// V1.1 新增:同步管理 - 记录上次同步时间
|
||
lastSyncAt DateTime? @map("last_sync_at")
|
||
|
||
// 项目状态
|
||
status String @default("active")
|
||
|
||
// 时间戳
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
// 关系
|
||
pendingActions IitPendingAction[]
|
||
taskRuns IitTaskRun[]
|
||
userMappings IitUserMapping[]
|
||
auditLogs IitAuditLog[]
|
||
|
||
@@index([status, deletedAt])
|
||
@@map("projects")
|
||
@@schema("iit_schema")
|
||
}
|
||
|
||
/// 影子状态表(核心)
|
||
model IitPendingAction {
|
||
id String @id @default(uuid())
|
||
projectId String @map("project_id")
|
||
recordId String @map("record_id")
|
||
fieldName String @map("field_name")
|
||
|
||
// 数据对比
|
||
currentValue Json? @map("current_value")
|
||
suggestedValue Json? @map("suggested_value")
|
||
|
||
// 状态流转
|
||
status String // PROPOSED/APPROVED/REJECTED/EXECUTED/FAILED
|
||
agentType String @map("agent_type") // DATA_QUALITY/TASK_DRIVEN/COUNSELING/REPORTING
|
||
|
||
// AI推理信息
|
||
reasoning String @db.Text
|
||
evidence Json
|
||
|
||
// 人类确认信息
|
||
approvedBy String? @map("approved_by")
|
||
approvedAt DateTime? @map("approved_at")
|
||
rejectionReason String? @db.Text @map("rejection_reason")
|
||
|
||
// 执行信息
|
||
executedAt DateTime? @map("executed_at")
|
||
errorMessage String? @db.Text @map("error_message")
|
||
|
||
// 时间戳
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// 关系
|
||
project IitProject @relation(fields: [projectId], references: [id])
|
||
|
||
@@index([projectId, status])
|
||
@@index([projectId, recordId])
|
||
@@index([status, createdAt])
|
||
@@map("pending_actions")
|
||
@@schema("iit_schema")
|
||
}
|
||
|
||
/// 任务运行记录(与 pg-boss 关联)
|
||
model IitTaskRun {
|
||
id String @id @default(uuid())
|
||
projectId String @map("project_id")
|
||
taskType String @map("task_type")
|
||
|
||
// 关联 pg-boss job
|
||
jobId String? @unique @map("job_id")
|
||
|
||
// 任务状态
|
||
status String
|
||
|
||
// 业务结果
|
||
totalItems Int @map("total_items")
|
||
processedItems Int @default(0) @map("processed_items")
|
||
successItems Int @default(0) @map("success_items")
|
||
failedItems Int @default(0) @map("failed_items")
|
||
|
||
// 时间信息
|
||
startedAt DateTime? @map("started_at")
|
||
completedAt DateTime? @map("completed_at")
|
||
duration Int? // 秒
|
||
|
||
// 时间戳
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// 关系
|
||
project IitProject @relation(fields: [projectId], references: [id])
|
||
|
||
@@index([projectId, taskType, status])
|
||
@@index([jobId])
|
||
@@map("task_runs")
|
||
@@schema("iit_schema")
|
||
}
|
||
|
||
/// 用户映射表(异构系统身份关联)
|
||
model IitUserMapping {
|
||
id String @id @default(uuid())
|
||
projectId String @map("project_id")
|
||
|
||
// 系统用户ID(本系统)
|
||
systemUserId String @map("system_user_id")
|
||
|
||
// REDCap用户名
|
||
redcapUsername String @map("redcap_username")
|
||
|
||
// 企微OpenID
|
||
wecomUserId String? @map("wecom_user_id")
|
||
|
||
// V1.1 新增:小程序支持
|
||
miniProgramOpenId String? @unique @map("mini_program_open_id")
|
||
sessionKey String? @map("session_key")
|
||
|
||
// 角色
|
||
role String
|
||
|
||
// 时间戳
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// 关系
|
||
project IitProject @relation(fields: [projectId], references: [id])
|
||
|
||
@@unique([projectId, systemUserId])
|
||
@@unique([projectId, redcapUsername])
|
||
@@index([wecomUserId])
|
||
@@index([miniProgramOpenId])
|
||
@@map("user_mappings")
|
||
@@schema("iit_schema")
|
||
}
|
||
|
||
/// 审计日志表
|
||
model IitAuditLog {
|
||
id String @id @default(uuid())
|
||
projectId String @map("project_id")
|
||
|
||
// 操作信息
|
||
userId String @map("user_id")
|
||
actionType String @map("action_type")
|
||
entityType String @map("entity_type")
|
||
entityId String @map("entity_id")
|
||
|
||
// 详细信息
|
||
details Json?
|
||
|
||
// 追踪链
|
||
traceId String @map("trace_id")
|
||
|
||
// 时间戳
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
// 关系
|
||
project IitProject @relation(fields: [projectId], references: [id])
|
||
|
||
@@index([projectId, createdAt])
|
||
@@index([userId, createdAt])
|
||
@@index([actionType, createdAt])
|
||
@@index([traceId])
|
||
@@map("audit_logs")
|
||
@@schema("iit_schema")
|
||
}
|