diff --git a/COMMIT_DAY1.txt b/COMMIT_DAY1.txt index 7fe2399b..99343d69 100644 --- a/COMMIT_DAY1.txt +++ b/COMMIT_DAY1.txt @@ -37,3 +37,4 @@ Status: Day 1 complete (11/11 tasks), ready for Day 2 + diff --git a/DC模块代码恢复指南.md b/DC模块代码恢复指南.md index 062fbf3e..6b50c485 100644 --- a/DC模块代码恢复指南.md +++ b/DC模块代码恢复指南.md @@ -265,5 +265,6 @@ + diff --git a/SAE_WECHAT_MP_DEPLOY_STEPS.md b/SAE_WECHAT_MP_DEPLOY_STEPS.md index 43142be6..78494dbc 100644 --- a/SAE_WECHAT_MP_DEPLOY_STEPS.md +++ b/SAE_WECHAT_MP_DEPLOY_STEPS.md @@ -213,3 +213,4 @@ https://iit.xunzhengyixue.com/api/v1/iit/health + diff --git a/backend/DEPLOY_TO_SAE_FOR_WECHAT_MP.md b/backend/DEPLOY_TO_SAE_FOR_WECHAT_MP.md index 2dd7966b..01307229 100644 --- a/backend/DEPLOY_TO_SAE_FOR_WECHAT_MP.md +++ b/backend/DEPLOY_TO_SAE_FOR_WECHAT_MP.md @@ -142,3 +142,4 @@ https://iit.xunzhengyixue.com/api/v1/iit/health + diff --git a/backend/RESTART_SERVER_NOW.md b/backend/RESTART_SERVER_NOW.md index 40520db1..e81a28b1 100644 --- a/backend/RESTART_SERVER_NOW.md +++ b/backend/RESTART_SERVER_NOW.md @@ -43,3 +43,4 @@ + diff --git a/backend/WECHAT_MP_CONFIG_READY.md b/backend/WECHAT_MP_CONFIG_READY.md index c8f24536..3181af4b 100644 --- a/backend/WECHAT_MP_CONFIG_READY.md +++ b/backend/WECHAT_MP_CONFIG_READY.md @@ -303,3 +303,4 @@ npx tsx src/modules/iit-manager/test-patient-wechat-url-verify.ts + diff --git a/backend/WECHAT_MP_QUICK_FIX.md b/backend/WECHAT_MP_QUICK_FIX.md index f66c4baf..3c83688a 100644 --- a/backend/WECHAT_MP_QUICK_FIX.md +++ b/backend/WECHAT_MP_QUICK_FIX.md @@ -165,3 +165,4 @@ npm run dev + diff --git a/backend/migrations/add_data_stats_to_tool_c_session.sql b/backend/migrations/add_data_stats_to_tool_c_session.sql index 16223a9b..7d8c728c 100644 --- a/backend/migrations/add_data_stats_to_tool_c_session.sql +++ b/backend/migrations/add_data_stats_to_tool_c_session.sql @@ -60,5 +60,6 @@ WHERE table_schema = 'dc_schema' + diff --git a/backend/prisma/manual-migrations/001_add_postgres_cache_and_checkpoint.sql b/backend/prisma/manual-migrations/001_add_postgres_cache_and_checkpoint.sql index f6aa0170..b204e706 100644 --- a/backend/prisma/manual-migrations/001_add_postgres_cache_and_checkpoint.sql +++ b/backend/prisma/manual-migrations/001_add_postgres_cache_and_checkpoint.sql @@ -98,5 +98,6 @@ ORDER BY ordinal_position; + diff --git a/backend/prisma/manual-migrations/run-migration-002.ts b/backend/prisma/manual-migrations/run-migration-002.ts index 9173d402..8f847cd7 100644 --- a/backend/prisma/manual-migrations/run-migration-002.ts +++ b/backend/prisma/manual-migrations/run-migration-002.ts @@ -111,5 +111,6 @@ runMigration() + diff --git a/backend/prisma/migrations/20251208_add_column_mapping/migration.sql b/backend/prisma/migrations/20251208_add_column_mapping/migration.sql index 148abe0d..89902921 100644 --- a/backend/prisma/migrations/20251208_add_column_mapping/migration.sql +++ b/backend/prisma/migrations/20251208_add_column_mapping/migration.sql @@ -45,5 +45,6 @@ COMMENT ON COLUMN "dc_schema"."dc_tool_c_sessions"."column_mapping" IS '列名 + diff --git a/backend/prisma/migrations/create_tool_c_session.sql b/backend/prisma/migrations/create_tool_c_session.sql index 42711926..2d2e576f 100644 --- a/backend/prisma/migrations/create_tool_c_session.sql +++ b/backend/prisma/migrations/create_tool_c_session.sql @@ -72,5 +72,6 @@ COMMENT ON COLUMN dc_schema.dc_tool_c_sessions.expires_at IS '过期时间(创 + diff --git a/backend/rebuild-and-push.ps1 b/backend/rebuild-and-push.ps1 index 6e4517d3..cd1a0008 100644 --- a/backend/rebuild-and-push.ps1 +++ b/backend/rebuild-and-push.ps1 @@ -114,3 +114,4 @@ Write-Host "" + diff --git a/backend/recover-code-from-cursor-db.js b/backend/recover-code-from-cursor-db.js index f7aa7340..d5661ed6 100644 --- a/backend/recover-code-from-cursor-db.js +++ b/backend/recover-code-from-cursor-db.js @@ -222,5 +222,6 @@ function extractCodeBlocks(obj, blocks = []) { + diff --git a/backend/scripts/check-dc-tables.mjs b/backend/scripts/check-dc-tables.mjs index 1273a367..faa30607 100644 --- a/backend/scripts/check-dc-tables.mjs +++ b/backend/scripts/check-dc-tables.mjs @@ -241,5 +241,6 @@ checkDCTables(); + diff --git a/backend/scripts/create-tool-c-ai-history-table.mjs b/backend/scripts/create-tool-c-ai-history-table.mjs index 6f2d15bb..5c24334b 100644 --- a/backend/scripts/create-tool-c-ai-history-table.mjs +++ b/backend/scripts/create-tool-c-ai-history-table.mjs @@ -193,5 +193,6 @@ createAiHistoryTable() + diff --git a/backend/scripts/create-tool-c-table.js b/backend/scripts/create-tool-c-table.js index da2a2ce7..047c9c6b 100644 --- a/backend/scripts/create-tool-c-table.js +++ b/backend/scripts/create-tool-c-table.js @@ -180,5 +180,6 @@ createToolCTable() + diff --git a/backend/scripts/create-tool-c-table.mjs b/backend/scripts/create-tool-c-table.mjs index 49422719..9ee120dd 100644 --- a/backend/scripts/create-tool-c-table.mjs +++ b/backend/scripts/create-tool-c-table.mjs @@ -177,5 +177,6 @@ createToolCTable() + diff --git a/backend/scripts/test-pkb-apis-simple.ts b/backend/scripts/test-pkb-apis-simple.ts index 9569debc..e44c751a 100644 --- a/backend/scripts/test-pkb-apis-simple.ts +++ b/backend/scripts/test-pkb-apis-simple.ts @@ -326,3 +326,4 @@ runTests().catch(error => { + diff --git a/backend/scripts/verify-pkb-rvw-schema.ts b/backend/scripts/verify-pkb-rvw-schema.ts index 13989e48..b3762055 100644 --- a/backend/scripts/verify-pkb-rvw-schema.ts +++ b/backend/scripts/verify-pkb-rvw-schema.ts @@ -291,3 +291,4 @@ verifySchemas() + diff --git a/backend/src/common/jobs/utils.ts b/backend/src/common/jobs/utils.ts index 5daea4cf..b23e7895 100644 --- a/backend/src/common/jobs/utils.ts +++ b/backend/src/common/jobs/utils.ts @@ -309,5 +309,6 @@ export function getBatchItems( + diff --git a/backend/src/modules/asl/fulltext-screening/__tests__/api-integration-test.ts b/backend/src/modules/asl/fulltext-screening/__tests__/api-integration-test.ts index eee2b917..58c55d2d 100644 --- a/backend/src/modules/asl/fulltext-screening/__tests__/api-integration-test.ts +++ b/backend/src/modules/asl/fulltext-screening/__tests__/api-integration-test.ts @@ -345,5 +345,6 @@ runTests().catch((error) => { + diff --git a/backend/src/modules/asl/fulltext-screening/__tests__/e2e-real-test-v2.ts b/backend/src/modules/asl/fulltext-screening/__tests__/e2e-real-test-v2.ts index f7a2ab58..c225238a 100644 --- a/backend/src/modules/asl/fulltext-screening/__tests__/e2e-real-test-v2.ts +++ b/backend/src/modules/asl/fulltext-screening/__tests__/e2e-real-test-v2.ts @@ -286,5 +286,6 @@ runTest() + diff --git a/backend/src/modules/asl/fulltext-screening/__tests__/fulltext-screening-api.http b/backend/src/modules/asl/fulltext-screening/__tests__/fulltext-screening-api.http index 074cfe94..41850d46 100644 --- a/backend/src/modules/asl/fulltext-screening/__tests__/fulltext-screening-api.http +++ b/backend/src/modules/asl/fulltext-screening/__tests__/fulltext-screening-api.http @@ -324,5 +324,6 @@ Content-Type: application/json + diff --git a/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts b/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts index 73b70da4..b767e42a 100644 --- a/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts +++ b/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts @@ -260,5 +260,6 @@ export const conflictDetectionService = new ConflictDetectionService(); + diff --git a/backend/src/modules/dc/tool-c/README.md b/backend/src/modules/dc/tool-c/README.md index b50ea9dc..513cad58 100644 --- a/backend/src/modules/dc/tool-c/README.md +++ b/backend/src/modules/dc/tool-c/README.md @@ -210,5 +210,6 @@ curl -X POST http://localhost:3000/api/v1/dc/tool-c/test/execute \ + diff --git a/backend/src/modules/dc/tool-c/controllers/StreamAIController.ts b/backend/src/modules/dc/tool-c/controllers/StreamAIController.ts index 1e9d95c2..2565894f 100644 --- a/backend/src/modules/dc/tool-c/controllers/StreamAIController.ts +++ b/backend/src/modules/dc/tool-c/controllers/StreamAIController.ts @@ -264,5 +264,6 @@ export const streamAIController = new StreamAIController(); + diff --git a/backend/src/modules/iit-manager/agents/SessionMemory.ts b/backend/src/modules/iit-manager/agents/SessionMemory.ts index dec1c012..64e030c6 100644 --- a/backend/src/modules/iit-manager/agents/SessionMemory.ts +++ b/backend/src/modules/iit-manager/agents/SessionMemory.ts @@ -175,3 +175,4 @@ logger.info('[SessionMemory] 会话记忆管理器已启动', { + diff --git a/backend/src/modules/iit-manager/check-iit-table-structure.ts b/backend/src/modules/iit-manager/check-iit-table-structure.ts index 0698625a..a13d6d55 100644 --- a/backend/src/modules/iit-manager/check-iit-table-structure.ts +++ b/backend/src/modules/iit-manager/check-iit-table-structure.ts @@ -109,3 +109,4 @@ checkTableStructure(); + diff --git a/backend/src/modules/iit-manager/check-project-config.ts b/backend/src/modules/iit-manager/check-project-config.ts index 6e8e0bd4..bfbb1efd 100644 --- a/backend/src/modules/iit-manager/check-project-config.ts +++ b/backend/src/modules/iit-manager/check-project-config.ts @@ -96,3 +96,4 @@ checkProjectConfig().catch(console.error); + diff --git a/backend/src/modules/iit-manager/check-test-project-in-db.ts b/backend/src/modules/iit-manager/check-test-project-in-db.ts index f6414320..6887c756 100644 --- a/backend/src/modules/iit-manager/check-test-project-in-db.ts +++ b/backend/src/modules/iit-manager/check-test-project-in-db.ts @@ -78,3 +78,4 @@ main(); + diff --git a/backend/src/modules/iit-manager/docs/微信服务号接入指南.md b/backend/src/modules/iit-manager/docs/微信服务号接入指南.md index 10c9c453..1a32aa37 100644 --- a/backend/src/modules/iit-manager/docs/微信服务号接入指南.md +++ b/backend/src/modules/iit-manager/docs/微信服务号接入指南.md @@ -535,3 +535,4 @@ URL: https://iit.xunzhengyixue.com/api/v1/iit/patient-wechat/callback + diff --git a/backend/src/modules/iit-manager/generate-wechat-tokens.ts b/backend/src/modules/iit-manager/generate-wechat-tokens.ts index 732ccdfb..2b26e99a 100644 --- a/backend/src/modules/iit-manager/generate-wechat-tokens.ts +++ b/backend/src/modules/iit-manager/generate-wechat-tokens.ts @@ -170,3 +170,4 @@ console.log(''); + diff --git a/backend/src/modules/iit-manager/services/PatientWechatService.ts b/backend/src/modules/iit-manager/services/PatientWechatService.ts index 149140f2..b499f8cb 100644 --- a/backend/src/modules/iit-manager/services/PatientWechatService.ts +++ b/backend/src/modules/iit-manager/services/PatientWechatService.ts @@ -487,3 +487,4 @@ export const patientWechatService = new PatientWechatService(); + diff --git a/backend/src/modules/iit-manager/test-chatservice-dify.ts b/backend/src/modules/iit-manager/test-chatservice-dify.ts index b7c7253c..a42b10f8 100644 --- a/backend/src/modules/iit-manager/test-chatservice-dify.ts +++ b/backend/src/modules/iit-manager/test-chatservice-dify.ts @@ -132,3 +132,4 @@ testDifyIntegration().catch(error => { + diff --git a/backend/src/modules/iit-manager/test-iit-database.ts b/backend/src/modules/iit-manager/test-iit-database.ts index 4f95a9d0..06f2f5bc 100644 --- a/backend/src/modules/iit-manager/test-iit-database.ts +++ b/backend/src/modules/iit-manager/test-iit-database.ts @@ -161,3 +161,4 @@ testIitDatabase() + diff --git a/backend/src/modules/iit-manager/test-patient-wechat-config.ts b/backend/src/modules/iit-manager/test-patient-wechat-config.ts index 959711a7..1fc8dfe7 100644 --- a/backend/src/modules/iit-manager/test-patient-wechat-config.ts +++ b/backend/src/modules/iit-manager/test-patient-wechat-config.ts @@ -147,3 +147,4 @@ if (hasError) { + diff --git a/backend/src/modules/iit-manager/test-patient-wechat-url-verify.ts b/backend/src/modules/iit-manager/test-patient-wechat-url-verify.ts index 199185da..8513045b 100644 --- a/backend/src/modules/iit-manager/test-patient-wechat-url-verify.ts +++ b/backend/src/modules/iit-manager/test-patient-wechat-url-verify.ts @@ -173,3 +173,4 @@ async function testUrlVerification() { + diff --git a/backend/src/modules/iit-manager/test-redcap-query-from-db.ts b/backend/src/modules/iit-manager/test-redcap-query-from-db.ts index 2ce08def..eedce761 100644 --- a/backend/src/modules/iit-manager/test-redcap-query-from-db.ts +++ b/backend/src/modules/iit-manager/test-redcap-query-from-db.ts @@ -254,3 +254,4 @@ main().catch((error) => { + diff --git a/backend/src/modules/iit-manager/test-wechat-mp-local.ps1 b/backend/src/modules/iit-manager/test-wechat-mp-local.ps1 index f52c5b31..1590689f 100644 --- a/backend/src/modules/iit-manager/test-wechat-mp-local.ps1 +++ b/backend/src/modules/iit-manager/test-wechat-mp-local.ps1 @@ -138,3 +138,4 @@ Write-Host "" + diff --git a/backend/src/modules/iit-manager/types/index.ts b/backend/src/modules/iit-manager/types/index.ts index 6819f382..2a57cb6f 100644 --- a/backend/src/modules/iit-manager/types/index.ts +++ b/backend/src/modules/iit-manager/types/index.ts @@ -231,3 +231,4 @@ export interface CachedProtocolRules { + diff --git a/backend/src/modules/pkb/routes/health.ts b/backend/src/modules/pkb/routes/health.ts index dc3275db..d485740d 100644 --- a/backend/src/modules/pkb/routes/health.ts +++ b/backend/src/modules/pkb/routes/health.ts @@ -44,3 +44,4 @@ export default async function healthRoutes(fastify: FastifyInstance) { + diff --git a/backend/src/tests/README.md b/backend/src/tests/README.md index 2ade2ecd..f42c1447 100644 --- a/backend/src/tests/README.md +++ b/backend/src/tests/README.md @@ -410,5 +410,6 @@ SET session_replication_role = 'origin'; + diff --git a/backend/src/tests/verify-test1-database.sql b/backend/src/tests/verify-test1-database.sql index ef7b7cee..13836eab 100644 --- a/backend/src/tests/verify-test1-database.sql +++ b/backend/src/tests/verify-test1-database.sql @@ -112,5 +112,6 @@ WHERE key = 'verify_test'; + diff --git a/backend/src/tests/verify-test1-database.ts b/backend/src/tests/verify-test1-database.ts index dc4dfb98..890e919c 100644 --- a/backend/src/tests/verify-test1-database.ts +++ b/backend/src/tests/verify-test1-database.ts @@ -255,5 +255,6 @@ verifyDatabase() + diff --git a/backend/src/types/global.d.ts b/backend/src/types/global.d.ts index 3c5c1cdc..aac1b490 100644 --- a/backend/src/types/global.d.ts +++ b/backend/src/types/global.d.ts @@ -45,5 +45,6 @@ export {} + diff --git a/backend/sync-dc-database.ps1 b/backend/sync-dc-database.ps1 index d1033b4c..e56963ba 100644 --- a/backend/sync-dc-database.ps1 +++ b/backend/sync-dc-database.ps1 @@ -68,5 +68,6 @@ Write-Host "✅ 完成!" -ForegroundColor Green + diff --git a/backend/test-pkb-migration.http b/backend/test-pkb-migration.http index 618b8ab4..faf0491f 100644 --- a/backend/test-pkb-migration.http +++ b/backend/test-pkb-migration.http @@ -158,3 +158,4 @@ DELETE {{baseUrl}}/api/v2/pkb/knowledge/knowledge-bases/{{testKbId}} + diff --git a/backend/test-tool-c-advanced-scenarios.mjs b/backend/test-tool-c-advanced-scenarios.mjs index 2f8d3c14..98fc4580 100644 --- a/backend/test-tool-c-advanced-scenarios.mjs +++ b/backend/test-tool-c-advanced-scenarios.mjs @@ -355,5 +355,6 @@ runAdvancedTests().catch(error => { + diff --git a/backend/test-tool-c-day2.mjs b/backend/test-tool-c-day2.mjs index 40dea2a1..448d79ee 100644 --- a/backend/test-tool-c-day2.mjs +++ b/backend/test-tool-c-day2.mjs @@ -421,5 +421,6 @@ runAllTests() + diff --git a/backend/test-tool-c-day3.mjs b/backend/test-tool-c-day3.mjs index 8b721345..0b45e268 100644 --- a/backend/test-tool-c-day3.mjs +++ b/backend/test-tool-c-day3.mjs @@ -379,5 +379,6 @@ runAllTests() + diff --git a/deploy-to-sae.ps1 b/deploy-to-sae.ps1 index d6143bec..9810f793 100644 --- a/deploy-to-sae.ps1 +++ b/deploy-to-sae.ps1 @@ -163,5 +163,6 @@ Set-Location .. + diff --git a/docs/00-系统总体设计/00-系统当前状态与开发指南.md b/docs/00-系统总体设计/00-系统当前状态与开发指南.md index 749275cc..d17da068 100644 --- a/docs/00-系统总体设计/00-系统当前状态与开发指南.md +++ b/docs/00-系统总体设计/00-系统当前状态与开发指南.md @@ -1,10 +1,10 @@ # AIclinicalresearch 系统当前状态与开发指南 -> **文档版本:** v2.7 +> **文档版本:** v2.8 > **创建日期:** 2025-11-28 > **维护者:** 开发团队 > **最后更新:** 2026-01-07 -> **重大进展:** 🎉 **PKB模块前端V3设计实现完成!** - Dashboard + Workspace + 3种工作模式 +> **重大进展:** 🎉 **PKB模块核心功能全部实现,具备生产可用性!** - 批处理完整流程验证通过 > **部署状态:** ✅ 生产环境运行中 | 公网地址:http://8.140.53.236/ > **文档目的:** 快速了解系统当前状态,为新AI助手提供上下文 @@ -39,7 +39,7 @@ | 模块代号 | 模块名称 | 核心功能 | 商业价值 | 当前状态 | 优先级 | |---------|---------|---------|---------|---------|--------| | **AIA** | AI智能问答 | 10+专业智能体(选题评价、PICO梳理等) | ⭐⭐⭐⭐ | ✅ 已完成 | P1 | -| **PKB** | 个人知识库 | RAG问答、私人文献库 | ⭐⭐⭐ | ✅ **前端V3设计完成(75%)** | P1 | +| **PKB** | 个人知识库 | RAG问答、私人文献库 | ⭐⭐⭐ | ✅ **核心功能完成(90%)** | P1 | | **ASL** | AI智能文献 | 文献筛选、Meta分析、证据图谱 | ⭐⭐⭐⭐⭐ | 🚧 **正在开发** | **P0** | | **DC** | 数据清洗整理 | ETL + 医学NER(百万行级数据) | ⭐⭐⭐⭐⭐ | ✅ **Tool B完成 + Tool C 99%(异步架构+性能优化-99%+多指标转换+7大功能)** | **P0** | | **IIT** | IIT Manager Agent | AI驱动IIT研究助手 - 智能质控+REDCap集成 | ⭐⭐⭐⭐⭐ | 🎉 **Phase 1.5完成(60%)- AI对话+REDCap数据集成** | **P0** | @@ -658,8 +658,9 @@ AIclinicalresearch/ | **2025-12-31** | **IIT Agent启动** 🎯 | ✅ Day 1完成(数据库+企微配置+模块骨架) | | **2026-01-01** | **企微可信域名** 🌐 | ✅ iit.xunzhengyixue.com域名验证完成 | | **2026-01-02** | **REDCap对接方案** 🏆 | ✅ REDCap环境部署 + DET+REST API方案确定 | -| **2026-01-07** | **PKB前端V3** 🎉 | ✅ PKB模块前端V3设计实现完成(Dashboard+Workspace+3种工作模式) | -| **当前** | PKB优化中 | 🔧 批处理API调试 + UI精细化 | +| **2026-01-07 上午** | **PKB前端V3** 🎉 | ✅ PKB模块前端V3设计实现完成(Dashboard+Workspace+3种工作模式) | +| **2026-01-07 下午** | **PKB批处理完善** 🏆 | ✅ 批处理完整流程调试通过(执行+进度+结果导出)+ 文档上传功能 + UI优化 | +| **当前** | **PKB模块生产可用** | ✅ 核心功能全部实现(90%),具备生产环境部署条件 | --- @@ -951,9 +952,9 @@ if (items.length >= 50) { --- -**文档版本**:v2.7 +**文档版本**:v2.8 **最后更新**:2026-01-07 -**下次更新**:PKB批处理功能调试完成 或 IIT Manager Agent Phase 2 +**下次更新**:ASL智能文献筛选模块启动 或 IIT Manager Agent Phase 2 --- @@ -963,10 +964,32 @@ if (items.length >= 50) { ## 📝 最新更新(2026-01-07) -**PKB模块前端V3设计完成 🎉**: +**PKB模块核心功能全部实现 🎉**: + +### 上午:前端V3设计实现 1. ✅ **后端模块迁移**:迁移到 /modules/pkb,v2 API路由注册 2. ✅ **Dashboard页面**:基于知识库仪表盘V5原型实现 3. ✅ **Workspace页面**:基于工作台V3原型实现 + +### 下午:批处理完整流程验证通过 +4. ✅ **三种工作模式**:全文阅读、逐篇精读、批处理全部实现 +5. ✅ **批处理功能**: + - 模板选择(临床研究信息提取,8个字段) + - 文档选择(3-50篇) + - 实时进度显示 + - 结果表格(多行显示+Tooltip) + - CSV导出 +6. ✅ **Chat组件集成**:Ant Design X,支持流式响应和自定义渲染 +7. ✅ **文档上传功能**:拖拽上传 + 进度显示 + Modal弹窗 +8. ✅ **UI优化**:参考文献格式化、表格多行显示、输入框清除、自动滚动 + +### 技术亮点 +- **问题解决**:修复10+个技术问题(API路径、字段映射、状态同步等) +- **性能优化**:批处理3篇文档~17-28秒 +- **用户体验**:严格按照原型图实现,界面美观易用 + +### 里程碑意义 +**PKB模块已具备生产环境可用性**,为后续功能扩展奠定坚实基础! 4. ✅ **3种工作模式**:全文阅读、逐篇精读、批处理 5. ✅ **Chat组件集成**:复用Ant Design X通用Chat组件 6. ✅ **响应式布局**:单层Header + 紧凑工作模式栏 + 最大化聊天区域 diff --git a/docs/02-通用能力层/Postgres-Only异步任务处理指南.md b/docs/02-通用能力层/Postgres-Only异步任务处理指南.md index 7018ae42..9a7d56b9 100644 --- a/docs/02-通用能力层/Postgres-Only异步任务处理指南.md +++ b/docs/02-通用能力层/Postgres-Only异步任务处理指南.md @@ -605,5 +605,6 @@ async saveProcessedData(recordId, newData) { + diff --git a/docs/02-通用能力层/通用能力层技术债务清单.md b/docs/02-通用能力层/通用能力层技术债务清单.md index 2b75218d..9607211a 100644 --- a/docs/02-通用能力层/通用能力层技术债务清单.md +++ b/docs/02-通用能力层/通用能力层技术债务清单.md @@ -792,5 +792,6 @@ export const AsyncProgressBar: React.FC = ({ + diff --git a/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md b/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md index a810efb2..c0ce7e22 100644 --- a/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md +++ b/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md @@ -1285,5 +1285,6 @@ interface FulltextScreeningResult { + diff --git a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md index a2e4cfa1..c3bc47d2 100644 --- a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md +++ b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md @@ -399,5 +399,6 @@ GET /api/v1/asl/fulltext-screening/tasks/:taskId/export + diff --git a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md index cf2a37a8..15e4df10 100644 --- a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md +++ b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md @@ -342,5 +342,6 @@ Linter错误:0个 + diff --git a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-11-23_Day5_全文复筛API开发.md b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-11-23_Day5_全文复筛API开发.md index 7c84896e..84f92f96 100644 --- a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-11-23_Day5_全文复筛API开发.md +++ b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-11-23_Day5_全文复筛API开发.md @@ -501,5 +501,6 @@ Failed to open file '\\tmp\\extraction_service\\temp_10000_test.pdf' + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_AI_Few-shot示例库.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_AI_Few-shot示例库.md index d6afb7ce..334b74e5 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_AI_Few-shot示例库.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_AI_Few-shot示例库.md @@ -567,5 +567,6 @@ df['creatinine'] = pd.to_numeric(df['creatinine'], errors='coerce') + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Bug修复总结_2025-12-08.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Bug修复总结_2025-12-08.md index 9f42cde7..c443293b 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Bug修复总结_2025-12-08.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Bug修复总结_2025-12-08.md @@ -405,5 +405,6 @@ npm run dev + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day3开发计划.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day3开发计划.md index 9fe2208e..1f784515 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day3开发计划.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day3开发计划.md @@ -982,5 +982,6 @@ export const aiController = new AIController(); + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day4-5前端开发计划.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day4-5前端开发计划.md index fdc72dbb..3fabc2d2 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day4-5前端开发计划.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day4-5前端开发计划.md @@ -1316,5 +1316,6 @@ npm install react-markdown + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Pivot列顺序优化总结.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Pivot列顺序优化总结.md index d5979808..23f18bfd 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Pivot列顺序优化总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Pivot列顺序优化总结.md @@ -224,5 +224,6 @@ FMA___基线 | FMA___1个月 | FMA___2个月 + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_方案B实施总结_2025-12-09.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_方案B实施总结_2025-12-09.md index 234da832..cceac4b1 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_方案B实施总结_2025-12-09.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_方案B实施总结_2025-12-09.md @@ -382,5 +382,6 @@ formula = "FMA总分(0-100) / 100" + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理_开发进度_2025-12-10.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理_开发进度_2025-12-10.md index 64008ada..6d9cfdbb 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理_开发进度_2025-12-10.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理_开发进度_2025-12-10.md @@ -216,5 +216,6 @@ async handleFillnaMice(request, reply) { + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能_更新说明.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能_更新说明.md index 818af24b..fed62f12 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能_更新说明.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能_更新说明.md @@ -188,5 +188,6 @@ method: 'mean' | 'median' | 'mode' | 'constant' | 'ffill' | 'bfill' + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md index 9a6ae016..6db4543c 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md @@ -338,5 +338,6 @@ Changes: + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day1开发完成总结.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day1开发完成总结.md index b10eccae..3183dcab 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day1开发完成总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day1开发完成总结.md @@ -410,5 +410,6 @@ cd path; command + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day2开发完成总结.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day2开发完成总结.md index db7e57d9..4b728135 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day2开发完成总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day2开发完成总结.md @@ -639,5 +639,6 @@ import { logger } from '../../../../common/logging/index.js'; + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_AI对话核心功能增强总结.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_AI对话核心功能增强总结.md index 210cb32f..bf2426a0 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_AI对话核心功能增强总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_AI对话核心功能增强总结.md @@ -643,5 +643,6 @@ Content-Length: 45234 + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Bug修复_DataGrid空数据防御.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Bug修复_DataGrid空数据防御.md index fbe7a153..2b43aa94 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Bug修复_DataGrid空数据防御.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Bug修复_DataGrid空数据防御.md @@ -295,5 +295,6 @@ Response: + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5_Ant-Design-X重构完成.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5_Ant-Design-X重构完成.md index d53cfa10..d26b4990 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5_Ant-Design-X重构完成.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5_Ant-Design-X重构完成.md @@ -448,5 +448,6 @@ Response: + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5最终总结.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5最终总结.md index 93f6b3d5..f0edc62b 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5最终总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5最终总结.md @@ -442,5 +442,6 @@ import { ChatContainer } from '@/shared/components/Chat'; + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_UI优化与Bug修复.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_UI优化与Bug修复.md index d7f86d89..ba52956d 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_UI优化与Bug修复.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_UI优化与Bug修复.md @@ -352,5 +352,6 @@ const initialMessages = defaultMessages.length > 0 ? defaultMessages : [{ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_后端API完整对接完成.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_后端API完整对接完成.md index ea4adec3..892fbe74 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_后端API完整对接完成.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_后端API完整对接完成.md @@ -392,5 +392,6 @@ python main.py + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_完整UI优化与功能增强.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_完整UI优化与功能增强.md index 9d9f866b..89864b29 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_完整UI优化与功能增强.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_完整UI优化与功能增强.md @@ -640,5 +640,6 @@ http://localhost:5173/data-cleaning/tool-c + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_工具C_Day4前端基础完成.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_工具C_Day4前端基础完成.md index 1b0000e6..f5ec2fd9 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_工具C_Day4前端基础完成.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_工具C_Day4前端基础完成.md @@ -250,5 +250,6 @@ Day 5 (6-8小时): + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md index a2f2e9ac..e2c9caca 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md @@ -428,5 +428,6 @@ Docs: docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建 + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md index a488dfbf..6599f089 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md @@ -403,5 +403,6 @@ const mockAssets: Asset[] = [ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase2-ToolB-Step1-2开发完成-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase2-ToolB-Step1-2开发完成-2025-12-03.md index 3abd6886..91fb094c 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase2-ToolB-Step1-2开发完成-2025-12-03.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase2-ToolB-Step1-2开发完成-2025-12-03.md @@ -387,5 +387,6 @@ frontend-v2/src/modules/dc/ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md index 1f80bc45..b91fb52f 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md @@ -347,5 +347,6 @@ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Tool-B-MVP完成总结-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Tool-B-MVP完成总结-2025-12-03.md index 910632a7..a639960a 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Tool-B-MVP完成总结-2025-12-03.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Tool-B-MVP完成总结-2025-12-03.md @@ -301,5 +301,6 @@ ConflictDetectionService // 冲突检测(字段级对比) + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md index 6032c950..3c4c88f1 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md @@ -350,5 +350,6 @@ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-Round2-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-Round2-2025-12-03.md index 85fab828..493b4cb6 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-Round2-2025-12-03.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-Round2-2025-12-03.md @@ -313,5 +313,6 @@ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md index 09f9aad1..1e534a90 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md @@ -377,5 +377,6 @@ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md index fcf7f7b4..8148a6fb 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md @@ -465,5 +465,6 @@ Tool B后端代码**100%复用**了平台通用能力层,无任何重复开发 + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md index 1bd2af2b..d806371c 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md @@ -311,5 +311,6 @@ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md index 1f2343c3..fcbd191f 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md @@ -242,5 +242,6 @@ $ node scripts/check-dc-tables.mjs + diff --git a/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md b/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md index 378c81f9..9c9efb6f 100644 --- a/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md +++ b/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md @@ -475,5 +475,6 @@ ${fields.map((f, i) => `${i + 1}. ${f.name}:${f.desc}`).join('\n')} + diff --git a/docs/03-业务模块/IIT Manager Agent/02-技术设计/IIT Manager Agent 技术路径与架构设计.md b/docs/03-业务模块/IIT Manager Agent/02-技术设计/IIT Manager Agent 技术路径与架构设计.md index 90fbbc37..1b380cb3 100644 --- a/docs/03-业务模块/IIT Manager Agent/02-技术设计/IIT Manager Agent 技术路径与架构设计.md +++ b/docs/03-业务模块/IIT Manager Agent/02-技术设计/IIT Manager Agent 技术路径与架构设计.md @@ -682,3 +682,4 @@ private async processMessageAsync(xmlData: any) { + diff --git a/docs/03-业务模块/IIT Manager Agent/04-开发计划/REDCap对接技术方案与实施指南.md b/docs/03-业务模块/IIT Manager Agent/04-开发计划/REDCap对接技术方案与实施指南.md index 4be32db6..5ce28572 100644 --- a/docs/03-业务模块/IIT Manager Agent/04-开发计划/REDCap对接技术方案与实施指南.md +++ b/docs/03-业务模块/IIT Manager Agent/04-开发计划/REDCap对接技术方案与实施指南.md @@ -1076,3 +1076,4 @@ async function testIntegration() { + diff --git a/docs/03-业务模块/IIT Manager Agent/04-开发计划/企业微信注册指南.md b/docs/03-业务模块/IIT Manager Agent/04-开发计划/企业微信注册指南.md index 461ba6cc..4b315ff1 100644 --- a/docs/03-业务模块/IIT Manager Agent/04-开发计划/企业微信注册指南.md +++ b/docs/03-业务模块/IIT Manager Agent/04-开发计划/企业微信注册指南.md @@ -217,3 +217,4 @@ Content-Type: application/json + diff --git a/docs/03-业务模块/IIT Manager Agent/06-开发记录/2026-01-04-Dify知识库集成开发记录.md b/docs/03-业务模块/IIT Manager Agent/06-开发记录/2026-01-04-Dify知识库集成开发记录.md index 19b3129e..50138611 100644 --- a/docs/03-业务模块/IIT Manager Agent/06-开发记录/2026-01-04-Dify知识库集成开发记录.md +++ b/docs/03-业务模块/IIT Manager Agent/06-开发记录/2026-01-04-Dify知识库集成开发记录.md @@ -637,3 +637,4 @@ REDCap API: exportRecords success { recordCount: 1 } + diff --git a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day2-REDCap实时集成开发完成记录.md b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day2-REDCap实时集成开发完成记录.md index 0609e006..819e6694 100644 --- a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day2-REDCap实时集成开发完成记录.md +++ b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day2-REDCap实时集成开发完成记录.md @@ -643,3 +643,4 @@ backend/src/modules/iit-manager/ + diff --git a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成与端到端测试完成记录.md b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成与端到端测试完成记录.md index 89af6746..1003abfd 100644 --- a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成与端到端测试完成记录.md +++ b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成与端到端测试完成记录.md @@ -793,3 +793,4 @@ CREATE TABLE iit_schema.wechat_tokens ( + diff --git a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成开发完成记录.md b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成开发完成记录.md index 64bfaa60..275a682b 100644 --- a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成开发完成记录.md +++ b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成开发完成记录.md @@ -550,3 +550,4 @@ Day 3 的开发工作虽然遇到了多个技术问题,但最终成功完成 + diff --git a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Phase1.5-AI对话集成REDCap完成记录.md b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Phase1.5-AI对话集成REDCap完成记录.md index feca4838..e871ddbc 100644 --- a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Phase1.5-AI对话集成REDCap完成记录.md +++ b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Phase1.5-AI对话集成REDCap完成记录.md @@ -317,3 +317,4 @@ AI: "出生日期:2017-01-04 + diff --git a/docs/03-业务模块/IIT Manager Agent/06-开发记录/V1.1更新完成报告.md b/docs/03-业务模块/IIT Manager Agent/06-开发记录/V1.1更新完成报告.md index 5e18c307..bb04b157 100644 --- a/docs/03-业务模块/IIT Manager Agent/06-开发记录/V1.1更新完成报告.md +++ b/docs/03-业务模块/IIT Manager Agent/06-开发记录/V1.1更新完成报告.md @@ -261,3 +261,4 @@ Day 4: REDCap EM(Webhook推送)← 作为增强,而非核心 + diff --git a/docs/03-业务模块/IIT Manager Agent/07-技术债务/IIT Manager Agent 技术债务清单.md b/docs/03-业务模块/IIT Manager Agent/07-技术债务/IIT Manager Agent 技术债务清单.md index 21203073..e4756e69 100644 --- a/docs/03-业务模块/IIT Manager Agent/07-技术债务/IIT Manager Agent 技术债务清单.md +++ b/docs/03-业务模块/IIT Manager Agent/07-技术债务/IIT Manager Agent 技术债务清单.md @@ -675,3 +675,4 @@ const answer = `根据研究方案[1]和CRF表格[2],纳入标准包括: + diff --git a/docs/03-业务模块/PKB-个人知识库/00-模块当前状态与开发指南.md b/docs/03-业务模块/PKB-个人知识库/00-模块当前状态与开发指南.md index 7a6e6995..d9511d34 100644 --- a/docs/03-业务模块/PKB-个人知识库/00-模块当前状态与开发指南.md +++ b/docs/03-业务模块/PKB-个人知识库/00-模块当前状态与开发指南.md @@ -1,10 +1,10 @@ # PKB个人知识库模块 - 当前状态与开发指南 -> **文档版本:** v1.0 +> **文档版本:** v2.0 > **创建日期:** 2026-01-07 > **维护者:** PKB模块开发团队 > **最后更新:** 2026-01-07 -> **重大进展:** 🎉 **PKB模块前端V3设计实现完成!** +> **重大进展:** 🎉 **PKB模块核心功能全部实现,具备生产可用性!** > **文档目的:** 反映模块真实状态,记录开发历程 --- @@ -36,14 +36,15 @@ PKB(Personal Knowledge Base)个人知识库模块提供: | 组件 | 状态 | 完成度 | 说明 | |------|------|--------|------| | **后端API** | ✅ 已完成 | 100% | v1 + v2双路由运行 | -| **前端Dashboard** | ✅ 已完成 | 90% | 基于V5原型实现 | -| **前端Workspace** | ✅ 已完成 | 85% | 基于V3原型实现 | -| **全文阅读模式** | ✅ 已完成 | 90% | Chat组件集成完成 | -| **逐篇精读模式** | ✅ 已完成 | 85% | 文档选择+对话 | -| **批处理模式** | 🔧 待调试 | 70% | UI完成,API待验证 | -| **RAG检索模式** | ❌ 待开发 | 0% | 后端待实现 | +| **前端Dashboard** | ✅ 已完成 | 95% | 基于V5原型实现 | +| **前端Workspace** | ✅ 已完成 | 95% | 基于V3原型实现 | +| **全文阅读模式** | ✅ 已完成 | 95% | Chat组件集成完成 | +| **逐篇精读模式** | ✅ 已完成 | 95% | 文档选择+对话 | +| **批处理模式** | ✅ 已完成 | 95% | 完整流程+结果导出 | +| **文档上传** | ✅ 已完成 | 100% | 拖拽+进度显示 | +| **RAG检索模式** | ⏸️ 暂缓 | 0% | 优先级调整 | -**整体完成度:约75%** +**整体完成度:约90%** 🎉 --- @@ -222,83 +223,69 @@ frontend-v2/src/modules/pkb/ ## ⚠️ 已知问题 -### 1. 批处理执行功能 🔴 高优先级 +### 1. RAG检索模式未实现 🟡 中优先级 **问题描述**: -- 批处理模式前端UI已完成 -- 后端API `/api/v1/batch-tasks` 执行需验证 -- 无法正常执行批量提取 +- RAG检索模式暂未实现 +- 当前优先全文阅读和逐篇精读模式 -**影响**:批处理功能不可用 +**影响**:工作模式选择有限 **解决方案**: -1. 验证后端API接口 -2. 检查请求参数格式 -3. 调试执行流程 +- v2.1版本实现RAG检索 +- 集成Dify知识库检索能力 -### 2. 知识资产页面导航 🟡 中优先级 +### 2. 批处理模板有限 🟢 低优先级 **问题描述**: -- 知识资产Tab页面缺少工具栏 -- 无法进行筛选、排序操作 +- 当前只支持1个模板(临床研究信息提取) +- 需要更多预设模板和自定义能力 -**影响**:用户操作不便 +**影响**:批处理应用场景有限 **解决方案**: -- 添加文档筛选工具栏 -- 添加排序功能 -- 添加批量操作 +- v2.2版本增加药物安全性、患者基线等模板 +- 支持用户自定义模板 -### 3. UI精细化 🟡 中优先级 +### 3. 文档预览功能缺失 🟢 低优先级 **问题描述**: -- 与原型图仍有差距 -- 部分样式需要调整 +- 暂不支持文档在线预览 +- 需下载后查看原文 -**影响**:视觉体验 +**影响**:用户体验 **解决方案**: -- 逐项对比原型图 -- 调整间距、字体、颜色 -- 完善动画效果 - -### 4. 引用格式化 🟢 低优先级 - -**问题描述**: -- AI回复中的引用格式不够美观 -- 需要自定义渲染 - -**影响**:阅读体验 - -**解决方案**: -- 实现customMessageRenderer -- 解析引用标记 -- 渲染为可点击的引用块 +- v3.0版本集成PDF预览功能 +- 支持文档标注和批注 --- ## 📝 下一步开发计划 -### 立即需要做的(紧急) +### v2.1 版本(短期) -1. **调试批处理API** 🔴 - - 验证 `/api/v1/batch-tasks` 接口 - - 检查请求参数 - - 测试完整流程 +1. **RAG检索模式** 🟡 + - 实现基于Dify的知识库检索 + - 添加工作模式选择器 + - 测试检索准确度 -2. **完善知识资产页面** 🔴 - - 添加工具栏导航 - - 实现筛选功能 +2. **性能优化** 🟡 + - 批处理并发优化 + - 文档加载缓存 + - API响应时间优化 -### 短期任务(本周) +### v2.2 版本(中期) -3. **UI精细化** - - 对比原型图优化 - - 调整样式细节 +3. **批处理增强** 🟢 + - 增加药物安全性模板 + - 增加患者基线特征模板 + - 支持自定义模板 -4. **错误处理** - - 完善错误提示 - - 添加重试机制 +4. **用户体验优化** 🟢 + - 文档筛选和排序 + - 批量操作 + - 快捷键支持 ### 中期任务(2周内) @@ -411,3 +398,4 @@ frontend-v2/src/modules/pkb/ **文档维护:** PKB模块开发团队 **联系方式:** 项目Issues + diff --git a/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07-前端迁移与批处理功能完善.md b/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07-前端迁移与批处理功能完善.md new file mode 100644 index 00000000..bdd66799 --- /dev/null +++ b/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07-前端迁移与批处理功能完善.md @@ -0,0 +1,358 @@ +# PKB个人知识库 - 前端迁移与批处理功能完善 + +**开发日期**:2026年1月7日 +**开发人员**:AI Assistant +**版本**:v2.0 + +--- + +## 一、开发目标 + +1. **前端架构迁移**:将PKB前端迁移到 `frontend-v2/modules/pkb` 新架构 +2. **工作模式实现**:实现全文阅读、逐篇精读、批处理三种工作模式 +3. **批处理功能**:完善批处理任务的执行、进度显示和结果导出 +4. **UI优化**:优化界面细节,提升用户体验 + +--- + +## 二、主要工作内容 + +### 1. 前端架构搭建 + +#### 目录结构创建 +``` +frontend-v2/src/modules/pkb/ +├── api/ # API客户端 +│ └── knowledgeBaseApi.ts +├── stores/ # 状态管理 +│ └── useKnowledgeBaseStore.ts +├── components/ # 通用组件 +│ ├── DocumentUpload.tsx +│ └── Workspace/ # 工作台组件 +│ ├── FullTextMode.tsx +│ ├── DeepReadMode.tsx +│ ├── BatchModeComplete.tsx +│ └── WorkModeSelector.tsx +├── pages/ # 页面组件 +│ ├── DashboardPage.tsx +│ └── WorkspacePage.tsx +├── hooks/ # 自定义Hooks +│ └── useWorkMode.ts +└── styles/ # 样式文件 + └── workspace.css +``` + +#### 核心文件创建 +- **DashboardPage.tsx**:知识库列表和创建入口 +- **WorkspacePage.tsx**:知识库工作台主页面 +- **三种工作模式组件**:全文阅读、逐篇精读、批处理 + +### 2. Chat组件集成 + +**技术选型**:Ant Design X +**特点**: +- 统一的对话组件,支持流式响应 +- 自定义消息渲染器 +- 自动滚动和输入框管理 + +**集成问题修复**: +- ✅ 输入框清除:使用受控模式 `value={inputValue}` +- ✅ 自动滚动:添加 `messagesEndRef` 锚点 +- ✅ 参考文献格式化:实现 `customMessageRenderer` + +### 3. 工作模式实现 + +#### 3.1 全文阅读模式 + +**功能**: +- 加载知识库全部文档(已完成状态) +- 使用 `fullTextDocumentIds` 参数传递完整文献 +- AI具备全知视角,可进行综合分析 + +**API调用**: +```typescript +body: JSON.stringify({ + content: message, + modelType: 'qwen-long', + knowledgeBaseIds: [kbId], + fullTextDocumentIds: completedDocIds, // 全文模式 +}) +``` + +**修复问题**: +- ❌ 初次加载显示"0篇文档" +- ✅ 将文档数量加入 `conversationKey`,强制重新渲染 + +#### 3.2 逐篇精读模式 + +**功能**: +- 选择1-5篇文档进行深度解读 +- 每篇文档独立对话上下文 +- 切换文档时清空对话历史 + +**技术实现**: +```typescript +const conversationKey = useMemo(() => { + return `kb-deepread-${kbId}-${selectedDoc.id}`; +}, [kbId, selectedDoc.id]); +``` + +**修复问题**: +- ❌ 切换文档报错:`TypeError: formattedContent.replace is not a function` +- ✅ 添加类型检查,正确处理 `MessageRenderParams` +- ❌ 输入框不清除、不自动滚动 +- ✅ 在ChatContainer添加受控输入和滚动锚点 + +#### 3.3 批处理模式 + +**功能**: +- 选择3-50篇文档批量提取信息 +- 支持临床研究信息提取模板(8个字段) +- 实时显示处理进度 +- 结果可导出为CSV + +**开发历程**: + +**问题1:选择数量翻倍** +- ❌ 原因:点击行和Checkbox都触发选择,导致重复添加 +- ✅ 解决:使用统一的 `toggle` 函数,Checkbox用 `onClick stopPropagation` + +**问题2:API 404错误** +- ❌ 路径错误:`/api/v1/batch-tasks` +- ✅ 正确路径:`/api/v2/pkb/batch-tasks/batch/execute` + +**问题3:API 500错误** +- ❌ 字段名不匹配:前端发送 `knowledgeBaseId`,后端期望 `kb_id` +- ✅ 修复请求体格式: +```typescript +{ + kb_id: kbId, // 后端格式 + document_ids: selectedDocs, + template_type: 'preset', + template_id: 'clinical_research', + model_type: 'qwen-long', +} +``` + +**问题4:模板ID不匹配** +- ❌ 前端:`clinicalResearch`(驼峰) +- ❌ 后端:`clinical_research`(下划线) +- ✅ 统一为 `clinical_research` + +**问题5:前端不显示结果** +- ❌ 后端返回 `status: "success"`,前端判断 `status === 'completed'` +- ✅ 修复状态判断: +```typescript +const isSuccess = docResult.status === 'success' || docResult.status === 'completed'; +``` + +**问题6:表格显示粗糙** +- ❌ 文件名过长,内容显示不全 +- ✅ 实现方案A: + - 文件名最多2行 + - 内容最多3行 (`-webkit-line-clamp: 3`) + - 悬停显示完整内容(Tooltip) + - 结果数据列更宽(280px) + +### 4. 文档上传功能 + +**问题**: +- ❌ "上传新文件"按钮无响应 +- ❌ 没有绑定 `onClick` 事件 + +**解决方案**: +1. 导入 `DocumentUpload` 组件和 `Modal` +2. 添加 `uploadModalVisible` 状态 +3. 为按钮绑定 `onClick={() => setUploadModalVisible(true)}` +4. 添加上传弹窗,集成 `DocumentUpload` 组件 +5. 修复导入路径:`../stores/useKnowledgeBaseStore` + +--- + +## 三、技术难点与解决方案 + +### 1. ChatContainer消息渲染 + +**问题**:自定义渲染器接收的参数格式复杂 +```typescript +interface MessageRenderParams { + id: string | number; + message: { + id: string | number; + role: string; + content: string; + status?: string; + }; + status: string; +} +``` + +**解决**:正确解析 `params.message.content` + +### 2. 批处理结果获取 + +**问题**:后端返回嵌套结构 `{ success: true, data: { results: [...] } }` + +**解决**: +```typescript +const resultsData = resultsJson.data?.results || []; +const newResults = resultsData.map((docResult: any) => ({ + documentId: docResult.document_id, + documentName: docResult.document_name, + result: docResult.data, // 提取数据在这里 +})); +``` + +### 3. React Key重复警告 + +**问题**:批处理结果列表使用 `documentId` 作为key,可能重复 + +**解决**: +- 在文档选择列表使用 `useMemo` 去重 +- 在结果映射时使用 `${documentId}-${index}` 确保唯一 + +### 4. 前后端字段映射 + +| 后端字段 | 前端显示 | +|---------|---------| +| `research_purpose` | 研究目的 | +| `research_design` | 研究设计 | +| `research_subjects` | 研究对象 | +| `sample_size` | 样本量 | +| `intervention_group` | 干预组 | +| `control_group` | 对照组 | +| `results_data` | 结果及数据 | +| `oxford_level` | 牛津评级 | + +--- + +## 四、API路由总结 + +### 新架构路由(v2) +| 功能 | 方法 | 路径 | +|------|------|------| +| 知识库列表 | GET | `/api/v2/pkb/knowledge-bases` | +| 创建知识库 | POST | `/api/v2/pkb/knowledge-bases` | +| 上传文档 | POST | `/api/v2/pkb/knowledge-bases/:id/documents` | +| 文档列表 | GET | `/api/v2/pkb/knowledge-bases/:id/documents` | +| 批处理执行 | POST | `/api/v2/pkb/batch-tasks/batch/execute` | +| 批处理状态 | GET | `/api/v2/pkb/batch-tasks/batch/tasks/:id` | +| 批处理结果 | GET | `/api/v2/pkb/batch-tasks/batch/tasks/:id/results` | + +### 对话路由(通用) +| 功能 | 方法 | 路径 | +|------|------|------| +| 流式对话 | POST | `/api/v1/chat/stream` | + +--- + +## 五、UI/UX优化细节 + +### 1. WorkspacePage布局 +- **单层Header**:整合返回、标题、Tab切换、设置、头像 +- **Header高度**:`h-14`(56px) +- **工作模式选择器**:紧凑的 `h-10` 栏 +- **Chat区域**:最大化剩余空间 + +### 2. 批处理结果表格 +- **固定表头**:背景 `#F9FAFB`,文字 `#6B7280` +- **文件名列**:220px,最多2行 +- **内容列**:180-280px,最多3行 +- **悬停提示**:最大宽度450px,最大高度300px + +### 3. 参考文献格式 +```typescript +// 卡片式显示 +
+ + {citation} +
+``` + +--- + +## 六、测试结果 + +### 功能测试 +| 功能模块 | 测试项 | 结果 | +|---------|--------|------| +| 知识库列表 | 创建/查看/删除 | ✅ | +| 文档上传 | 拖拽/点击上传 | ✅ | +| 全文阅读 | 加载文档/问答 | ✅ | +| 逐篇精读 | 文档切换/问答 | ✅ | +| 批处理 | 模板选择/执行/结果显示 | ✅ | +| 结果导出 | CSV导出 | ✅ | + +### 性能测试 +- **3篇文档批处理**:~17-28秒 +- **6篇文档全文加载**:~14k-15k tokens +- **文档上传**:进度实时显示,支持10MB以内 + +--- + +## 七、已知问题与改进方向 + +### 当前限制 +1. 批处理只支持1个模板(临床研究信息提取) +2. 批处理最少3篇文档(后端限制) +3. 逐篇精读最多5篇文档(前端限制) + +### 未来优化 +1. **增加模板**:药物安全性、患者基线特征等 +2. **自定义模板**:允许用户自定义提取字段 +3. **结果预览**:在表格中支持单元格展开 +4. **批处理恢复**:支持中断后继续执行 +5. **文档预览**:集成PDF预览功能 + +--- + +## 八、代码统计 + +### 新增文件 +- 前端页面:2个(Dashboard、Workspace) +- 前端组件:6个(3种工作模式 + 选择器 + 上传 + 文档列表) +- API客户端:1个 +- 状态管理:1个 +- 样式文件:1个 + +### 代码量估算 +- TypeScript:~2500行 +- CSS:~200行 +- 文档:~1000行 + +--- + +## 九、团队协作 + +### 参考旧版实现 +- 文档上传:`frontend/src/components/knowledge/DocumentUpload.tsx` +- 批处理:`frontend/src/components/chat/BatchMode.tsx` +- 文档选择:`frontend/src/components/chat/DocumentSelection.tsx` + +### Git提交 +- 遵循语义化提交规范 +- 中文使用UTF-8编码 +- 分多次提交,每次聚焦单一功能 + +--- + +## 十、总结 + +本次开发完成了PKB个人知识库模块从架构设计到核心功能的完整实现,特别是: + +1. ✅ **新架构迁移**:成功迁移到 `frontend-v2` 新架构 +2. ✅ **三种工作模式**:全文阅读、逐篇精读、批处理全部实现 +3. ✅ **批处理完整流程**:从模板选择到结果导出的完整链路 +4. ✅ **UI/UX优化**:参照原型图精细化实现,用户体验良好 +5. ✅ **问题解决能力**:快速定位并解决10+个技术问题 + +**里程碑意义**:PKB模块已具备生产环境可用性,为后续功能扩展奠定了坚实基础! + +--- + +**下一步建议**: +1. 进行完整的用户验收测试(UAT) +2. 优化批处理性能(并发、缓存) +3. 增加更多模板和自定义能力 +4. 完善错误处理和用户反馈 + diff --git a/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07_PKB模块前端V3设计实现.md b/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07_PKB模块前端V3设计实现.md index bda58829..84de9a98 100644 --- a/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07_PKB模块前端V3设计实现.md +++ b/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07_PKB模块前端V3设计实现.md @@ -228,3 +228,4 @@ const chatApi = axios.create({ **文档编写时间**:2026-01-07 **下次更新**:批处理功能调试完成后 + diff --git a/docs/03-业务模块/Redcap/01-部署与配置/10-REDCap_Docker部署操作手册.md b/docs/03-业务模块/Redcap/01-部署与配置/10-REDCap_Docker部署操作手册.md index 32527e84..c38dba51 100644 --- a/docs/03-业务模块/Redcap/01-部署与配置/10-REDCap_Docker部署操作手册.md +++ b/docs/03-业务模块/Redcap/01-部署与配置/10-REDCap_Docker部署操作手册.md @@ -765,3 +765,4 @@ docker exec redcap-apache php /tmp/create-redcap-password.php + diff --git a/docs/03-业务模块/Redcap/README.md b/docs/03-业务模块/Redcap/README.md index 061fd312..ffcf0846 100644 --- a/docs/03-业务模块/Redcap/README.md +++ b/docs/03-业务模块/Redcap/README.md @@ -147,3 +147,4 @@ AIclinicalresearch/redcap-docker-dev/ + diff --git a/docs/05-部署文档/02-SAE部署完全指南(产品经理版).md b/docs/05-部署文档/02-SAE部署完全指南(产品经理版).md index 2e74e677..591f7548 100644 --- a/docs/05-部署文档/02-SAE部署完全指南(产品经理版).md +++ b/docs/05-部署文档/02-SAE部署完全指南(产品经理版).md @@ -882,5 +882,6 @@ ACR镜像仓库: + diff --git a/docs/05-部署文档/07-前端Nginx-SAE部署操作手册.md b/docs/05-部署文档/07-前端Nginx-SAE部署操作手册.md index d37daca7..73834b0e 100644 --- a/docs/05-部署文档/07-前端Nginx-SAE部署操作手册.md +++ b/docs/05-部署文档/07-前端Nginx-SAE部署操作手册.md @@ -1369,5 +1369,6 @@ SAE应用配置: + diff --git a/docs/05-部署文档/08-PostgreSQL数据库部署操作手册.md b/docs/05-部署文档/08-PostgreSQL数据库部署操作手册.md index e5b1fc35..7402acd3 100644 --- a/docs/05-部署文档/08-PostgreSQL数据库部署操作手册.md +++ b/docs/05-部署文档/08-PostgreSQL数据库部署操作手册.md @@ -1185,5 +1185,6 @@ docker exec -e PGPASSWORD="密码" ai-clinical-postgres psql -h RDS地址 -U air + diff --git a/docs/05-部署文档/10-Node.js后端-Docker镜像构建手册.md b/docs/05-部署文档/10-Node.js后端-Docker镜像构建手册.md index b026f18b..75f87651 100644 --- a/docs/05-部署文档/10-Node.js后端-Docker镜像构建手册.md +++ b/docs/05-部署文档/10-Node.js后端-Docker镜像构建手册.md @@ -597,4 +597,5 @@ scripts/*.ts + diff --git a/docs/05-部署文档/11-Node.js后端-SAE部署配置清单.md b/docs/05-部署文档/11-Node.js后端-SAE部署配置清单.md index fa1db002..8b62aa1a 100644 --- a/docs/05-部署文档/11-Node.js后端-SAE部署配置清单.md +++ b/docs/05-部署文档/11-Node.js后端-SAE部署配置清单.md @@ -286,3 +286,4 @@ Node.js后端部署成功后: + diff --git a/docs/05-部署文档/12-Node.js后端-SAE部署操作手册.md b/docs/05-部署文档/12-Node.js后端-SAE部署操作手册.md index 568aff18..4f81c443 100644 --- a/docs/05-部署文档/12-Node.js后端-SAE部署操作手册.md +++ b/docs/05-部署文档/12-Node.js后端-SAE部署操作手册.md @@ -509,3 +509,4 @@ Node.js后端 (SAE) ← http://172.17.173.88:3001 + diff --git a/docs/05-部署文档/13-Node.js后端-镜像修复记录.md b/docs/05-部署文档/13-Node.js后端-镜像修复记录.md index a581de03..606503b1 100644 --- a/docs/05-部署文档/13-Node.js后端-镜像修复记录.md +++ b/docs/05-部署文档/13-Node.js后端-镜像修复记录.md @@ -224,3 +224,4 @@ curl http://localhost:3001/health + diff --git a/docs/05-部署文档/14-Node.js后端-pino-pretty问题修复.md b/docs/05-部署文档/14-Node.js后端-pino-pretty问题修复.md index 6e68da3a..bd261f9b 100644 --- a/docs/05-部署文档/14-Node.js后端-pino-pretty问题修复.md +++ b/docs/05-部署文档/14-Node.js后端-pino-pretty问题修复.md @@ -262,3 +262,4 @@ npm run dev + diff --git a/docs/05-部署文档/16-前端Nginx-部署成功总结.md b/docs/05-部署文档/16-前端Nginx-部署成功总结.md index 7e9b7cdd..60e1672d 100644 --- a/docs/05-部署文档/16-前端Nginx-部署成功总结.md +++ b/docs/05-部署文档/16-前端Nginx-部署成功总结.md @@ -486,3 +486,4 @@ pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432 + diff --git a/docs/05-部署文档/17-完整部署实战手册-2025版.md b/docs/05-部署文档/17-完整部署实战手册-2025版.md index 5d3d004e..ef8268ac 100644 --- a/docs/05-部署文档/17-完整部署实战手册-2025版.md +++ b/docs/05-部署文档/17-完整部署实战手册-2025版.md @@ -1814,3 +1814,4 @@ curl http://8.140.53.236/ + diff --git a/docs/05-部署文档/18-部署文档使用指南.md b/docs/05-部署文档/18-部署文档使用指南.md index af4f533f..e24852cf 100644 --- a/docs/05-部署文档/18-部署文档使用指南.md +++ b/docs/05-部署文档/18-部署文档使用指南.md @@ -362,3 +362,4 @@ crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-se + diff --git a/docs/05-部署文档/19-日常更新快速操作手册.md b/docs/05-部署文档/19-日常更新快速操作手册.md index f8ed21a4..16a9bd79 100644 --- a/docs/05-部署文档/19-日常更新快速操作手册.md +++ b/docs/05-部署文档/19-日常更新快速操作手册.md @@ -684,3 +684,4 @@ docker login --username=gofeng117@163.com \ + diff --git a/docs/05-部署文档/文档修正报告-20251214.md b/docs/05-部署文档/文档修正报告-20251214.md index c87f7258..6d557178 100644 --- a/docs/05-部署文档/文档修正报告-20251214.md +++ b/docs/05-部署文档/文档修正报告-20251214.md @@ -493,5 +493,6 @@ NAT网关成本¥100/月,对初创团队是一笔开销 + diff --git a/docs/07-运维文档/03-SAE环境变量配置指南.md b/docs/07-运维文档/03-SAE环境变量配置指南.md index 0ed898f5..56f0dde0 100644 --- a/docs/07-运维文档/03-SAE环境变量配置指南.md +++ b/docs/07-运维文档/03-SAE环境变量配置指南.md @@ -398,5 +398,6 @@ curl http://你的SAE地址:3001/health + diff --git a/docs/07-运维文档/05-Redis缓存与队列的区别说明.md b/docs/07-运维文档/05-Redis缓存与队列的区别说明.md index 8af0b996..134e632c 100644 --- a/docs/07-运维文档/05-Redis缓存与队列的区别说明.md +++ b/docs/07-运维文档/05-Redis缓存与队列的区别说明.md @@ -730,5 +730,6 @@ const job = await queue.getJob(jobId); + diff --git a/docs/07-运维文档/06-长时间任务可靠性分析.md b/docs/07-运维文档/06-长时间任务可靠性分析.md index 0d8c240a..45519e0e 100644 --- a/docs/07-运维文档/06-长时间任务可靠性分析.md +++ b/docs/07-运维文档/06-长时间任务可靠性分析.md @@ -497,5 +497,6 @@ processLiteraturesInBackground(task.id, projectId, testLiteratures); + diff --git a/docs/07-运维文档/07-Redis使用需求分析(按模块).md b/docs/07-运维文档/07-Redis使用需求分析(按模块).md index 058a92ac..36cb7f1b 100644 --- a/docs/07-运维文档/07-Redis使用需求分析(按模块).md +++ b/docs/07-运维文档/07-Redis使用需求分析(按模块).md @@ -974,5 +974,6 @@ ROI = (¥22,556 - ¥144) / ¥144 × 100% = 15,564% + diff --git a/docs/08-项目管理/03-每周计划/2025-12-13-Postgres-Only架构改造完成.md b/docs/08-项目管理/03-每周计划/2025-12-13-Postgres-Only架构改造完成.md index 8e2c84af..ec92ede6 100644 --- a/docs/08-项目管理/03-每周计划/2025-12-13-Postgres-Only架构改造完成.md +++ b/docs/08-项目管理/03-每周计划/2025-12-13-Postgres-Only架构改造完成.md @@ -1031,5 +1031,6 @@ Redis 实例:¥500/月 + diff --git a/docs/08-项目管理/05-技术债务/通用对话服务抽取计划.md b/docs/08-项目管理/05-技术债务/通用对话服务抽取计划.md index d9742325..f0d90bec 100644 --- a/docs/08-项目管理/05-技术债务/通用对话服务抽取计划.md +++ b/docs/08-项目管理/05-技术债务/通用对话服务抽取计划.md @@ -489,5 +489,6 @@ import { ChatContainer } from '@/shared/components/Chat'; + diff --git a/docs/08-项目管理/PKB前端问题修复报告.md b/docs/08-项目管理/PKB前端问题修复报告.md index 048f9f29..00a5481e 100644 --- a/docs/08-项目管理/PKB前端问题修复报告.md +++ b/docs/08-项目管理/PKB前端问题修复报告.md @@ -409,3 +409,4 @@ frontend-v2/src/modules/pkb/ + diff --git a/docs/08-项目管理/PKB前端验证指南.md b/docs/08-项目管理/PKB前端验证指南.md index 03491bb9..6b9d86e1 100644 --- a/docs/08-项目管理/PKB前端验证指南.md +++ b/docs/08-项目管理/PKB前端验证指南.md @@ -271,3 +271,4 @@ npm run dev + diff --git a/docs/08-项目管理/PKB功能审查报告-阶段0.md b/docs/08-项目管理/PKB功能审查报告-阶段0.md index c7339bb0..531a4479 100644 --- a/docs/08-项目管理/PKB功能审查报告-阶段0.md +++ b/docs/08-项目管理/PKB功能审查报告-阶段0.md @@ -786,3 +786,4 @@ AIA智能问答模块 + diff --git a/docs/08-项目管理/PKB和RVW功能迁移计划.md b/docs/08-项目管理/PKB和RVW功能迁移计划.md index 01b4707b..6019d628 100644 --- a/docs/08-项目管理/PKB和RVW功能迁移计划.md +++ b/docs/08-项目管理/PKB和RVW功能迁移计划.md @@ -931,3 +931,4 @@ CREATE INDEX idx_rvw_tasks_created_at ON rvw_schema.review_tasks(created_at); + diff --git a/docs/08-项目管理/PKB精细化优化报告.md b/docs/08-项目管理/PKB精细化优化报告.md index bf77b62a..31736a9b 100644 --- a/docs/08-项目管理/PKB精细化优化报告.md +++ b/docs/08-项目管理/PKB精细化优化报告.md @@ -584,3 +584,4 @@ const typography = { + diff --git a/docs/08-项目管理/PKB迁移-超级安全执行计划.md b/docs/08-项目管理/PKB迁移-超级安全执行计划.md index 7b33a110..380ba2a5 100644 --- a/docs/08-项目管理/PKB迁移-超级安全执行计划.md +++ b/docs/08-项目管理/PKB迁移-超级安全执行计划.md @@ -896,3 +896,4 @@ app.use('/api/v1/knowledge', (req, res) => { + diff --git a/docs/08-项目管理/PKB迁移-阶段1完成报告.md b/docs/08-项目管理/PKB迁移-阶段1完成报告.md index 9492e3ca..777f8c3f 100644 --- a/docs/08-项目管理/PKB迁移-阶段1完成报告.md +++ b/docs/08-项目管理/PKB迁移-阶段1完成报告.md @@ -210,3 +210,4 @@ rm -rf src/modules/pkb + diff --git a/docs/08-项目管理/PKB迁移-阶段2完成报告.md b/docs/08-项目管理/PKB迁移-阶段2完成报告.md index 3e5ab34c..cf7bddcb 100644 --- a/docs/08-项目管理/PKB迁移-阶段2完成报告.md +++ b/docs/08-项目管理/PKB迁移-阶段2完成报告.md @@ -385,3 +385,4 @@ GET /api/v2/pkb/batch-tasks/batch/templates + diff --git a/docs/08-项目管理/PKB迁移-阶段2进行中.md b/docs/08-项目管理/PKB迁移-阶段2进行中.md index 0546f5e5..47f23e3d 100644 --- a/docs/08-项目管理/PKB迁移-阶段2进行中.md +++ b/docs/08-项目管理/PKB迁移-阶段2进行中.md @@ -29,3 +29,4 @@ import pkbRoutes from './modules/pkb/routes/index.js'; + diff --git a/docs/08-项目管理/PKB迁移-阶段3完成报告.md b/docs/08-项目管理/PKB迁移-阶段3完成报告.md index 663916fd..dc143633 100644 --- a/docs/08-项目管理/PKB迁移-阶段3完成报告.md +++ b/docs/08-项目管理/PKB迁移-阶段3完成报告.md @@ -298,3 +298,4 @@ backend/ + diff --git a/docs/08-项目管理/PKB迁移-阶段4完成报告.md b/docs/08-项目管理/PKB迁移-阶段4完成报告.md index 71715e73..9552d177 100644 --- a/docs/08-项目管理/PKB迁移-阶段4完成报告.md +++ b/docs/08-项目管理/PKB迁移-阶段4完成报告.md @@ -509,3 +509,4 @@ const response = await fetch('/api/v2/pkb/batch-tasks/batch/execute', { + diff --git a/extraction_service/.dockerignore b/extraction_service/.dockerignore index a1f0ae68..6d5d34fb 100644 --- a/extraction_service/.dockerignore +++ b/extraction_service/.dockerignore @@ -64,5 +64,6 @@ models/ + diff --git a/extraction_service/operations/__init__.py b/extraction_service/operations/__init__.py index ab49d46e..c7930f04 100644 --- a/extraction_service/operations/__init__.py +++ b/extraction_service/operations/__init__.py @@ -52,5 +52,6 @@ __version__ = '1.0.0' + diff --git a/extraction_service/operations/dropna.py b/extraction_service/operations/dropna.py index 70511a14..5ca44696 100644 --- a/extraction_service/operations/dropna.py +++ b/extraction_service/operations/dropna.py @@ -185,5 +185,6 @@ def get_missing_summary(df: pd.DataFrame) -> dict: + diff --git a/extraction_service/operations/filter.py b/extraction_service/operations/filter.py index 1b22a277..153c73f0 100644 --- a/extraction_service/operations/filter.py +++ b/extraction_service/operations/filter.py @@ -145,5 +145,6 @@ def apply_filter( + diff --git a/extraction_service/operations/unpivot.py b/extraction_service/operations/unpivot.py index 06975245..9b2a3e7a 100644 --- a/extraction_service/operations/unpivot.py +++ b/extraction_service/operations/unpivot.py @@ -309,5 +309,6 @@ def get_unpivot_preview( + diff --git a/extraction_service/test_dc_api.py b/extraction_service/test_dc_api.py index 0580b8de..c8f5e1e6 100644 --- a/extraction_service/test_dc_api.py +++ b/extraction_service/test_dc_api.py @@ -319,5 +319,6 @@ if __name__ == "__main__": + diff --git a/extraction_service/test_execute_simple.py b/extraction_service/test_execute_simple.py index bb13e8f6..bc52dd40 100644 --- a/extraction_service/test_execute_simple.py +++ b/extraction_service/test_execute_simple.py @@ -85,5 +85,6 @@ except Exception as e: + diff --git a/extraction_service/test_module.py b/extraction_service/test_module.py index b59c93dc..96d180a9 100644 --- a/extraction_service/test_module.py +++ b/extraction_service/test_module.py @@ -65,5 +65,6 @@ except Exception as e: + diff --git a/frontend-v2/.dockerignore b/frontend-v2/.dockerignore index 4e2882d5..69905592 100644 --- a/frontend-v2/.dockerignore +++ b/frontend-v2/.dockerignore @@ -84,5 +84,6 @@ vite.config.*.timestamp-* + diff --git a/frontend-v2/docker-entrypoint.sh b/frontend-v2/docker-entrypoint.sh index 3a2b3cdc..f9a6f6ad 100644 --- a/frontend-v2/docker-entrypoint.sh +++ b/frontend-v2/docker-entrypoint.sh @@ -51,5 +51,6 @@ exec nginx -g 'daemon off;' + diff --git a/frontend-v2/nginx.conf b/frontend-v2/nginx.conf index c56d4213..2346abd1 100644 --- a/frontend-v2/nginx.conf +++ b/frontend-v2/nginx.conf @@ -207,5 +207,6 @@ http { + diff --git a/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx b/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx index 36dedb88..41bc3cc7 100644 --- a/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx +++ b/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx @@ -554,5 +554,6 @@ export default FulltextDetailDrawer; + diff --git a/frontend-v2/src/modules/dc/hooks/useAssets.ts b/frontend-v2/src/modules/dc/hooks/useAssets.ts index 858e2167..c35b796a 100644 --- a/frontend-v2/src/modules/dc/hooks/useAssets.ts +++ b/frontend-v2/src/modules/dc/hooks/useAssets.ts @@ -147,5 +147,6 @@ export const useAssets = (activeTab: AssetTabType) => { + diff --git a/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts b/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts index 5809fa01..f25cfc68 100644 --- a/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts +++ b/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts @@ -137,5 +137,6 @@ export const useRecentTasks = () => { + diff --git a/frontend-v2/src/modules/dc/pages/tool-c/components/DropnaDialog.tsx b/frontend-v2/src/modules/dc/pages/tool-c/components/DropnaDialog.tsx index 701965c8..a63cd36b 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/components/DropnaDialog.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/components/DropnaDialog.tsx @@ -336,5 +336,6 @@ export default DropnaDialog; + diff --git a/frontend-v2/src/modules/dc/pages/tool-c/components/MetricTimePanel.tsx b/frontend-v2/src/modules/dc/pages/tool-c/components/MetricTimePanel.tsx index 52d8f2fd..10e0539e 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/components/MetricTimePanel.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/components/MetricTimePanel.tsx @@ -421,5 +421,6 @@ export default MetricTimePanel; + diff --git a/frontend-v2/src/modules/dc/pages/tool-c/components/PivotPanel.tsx b/frontend-v2/src/modules/dc/pages/tool-c/components/PivotPanel.tsx index 3427bd20..62af1bdf 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/components/PivotPanel.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/components/PivotPanel.tsx @@ -307,5 +307,6 @@ export default PivotPanel; + diff --git a/frontend-v2/src/modules/dc/pages/tool-c/hooks/useSessionStatus.ts b/frontend-v2/src/modules/dc/pages/tool-c/hooks/useSessionStatus.ts index 61883850..b5b253c7 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/hooks/useSessionStatus.ts +++ b/frontend-v2/src/modules/dc/pages/tool-c/hooks/useSessionStatus.ts @@ -107,5 +107,6 @@ export function useSessionStatus({ + diff --git a/frontend-v2/src/modules/dc/pages/tool-c/types/index.ts b/frontend-v2/src/modules/dc/pages/tool-c/types/index.ts index 4d0e9c69..83d066e3 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/types/index.ts +++ b/frontend-v2/src/modules/dc/pages/tool-c/types/index.ts @@ -99,5 +99,6 @@ export interface DataStats { + diff --git a/frontend-v2/src/modules/dc/types/portal.ts b/frontend-v2/src/modules/dc/types/portal.ts index e2c346ad..0b1e3544 100644 --- a/frontend-v2/src/modules/dc/types/portal.ts +++ b/frontend-v2/src/modules/dc/types/portal.ts @@ -95,5 +95,6 @@ export type AssetTabType = 'all' | 'processed' | 'raw'; + diff --git a/frontend-v2/src/modules/pkb/api/knowledgeBaseApi.ts b/frontend-v2/src/modules/pkb/api/knowledgeBaseApi.ts index 1e219d65..365a73c4 100644 --- a/frontend-v2/src/modules/pkb/api/knowledgeBaseApi.ts +++ b/frontend-v2/src/modules/pkb/api/knowledgeBaseApi.ts @@ -216,3 +216,4 @@ export const documentSelectionApi = { + diff --git a/frontend-v2/src/modules/pkb/components/DocumentUpload.tsx b/frontend-v2/src/modules/pkb/components/DocumentUpload.tsx index b9d656bd..e51a1817 100644 --- a/frontend-v2/src/modules/pkb/components/DocumentUpload.tsx +++ b/frontend-v2/src/modules/pkb/components/DocumentUpload.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { Upload, message, Progress, Card } from 'antd'; import { InboxOutlined } from '@ant-design/icons'; import type { UploadProps } from 'antd'; -import { useKnowledgeBaseStore } from '../../stores/useKnowledgeBaseStore'; +import { useKnowledgeBaseStore } from '../stores/useKnowledgeBaseStore'; const { Dragger } = Upload; diff --git a/frontend-v2/src/modules/pkb/components/Workspace/BatchModeComplete.tsx b/frontend-v2/src/modules/pkb/components/Workspace/BatchModeComplete.tsx index 6ad4f4a4..869d3aa5 100644 --- a/frontend-v2/src/modules/pkb/components/Workspace/BatchModeComplete.tsx +++ b/frontend-v2/src/modules/pkb/components/Workspace/BatchModeComplete.tsx @@ -4,7 +4,7 @@ */ import React, { useState, useEffect } from 'react'; -import { Button, Table, Progress, Alert, message, Card, Steps, Checkbox, Radio } from 'antd'; +import { Button, Table, Progress, message, Card, Steps, Checkbox, Radio, Tooltip } from 'antd'; import { Play, Download, RotateCw, FileText, CheckCircle2, Zap } from 'lucide-react'; import type { KnowledgeBase, Document } from '../../api/knowledgeBaseApi'; @@ -31,42 +31,21 @@ interface BatchResult { error?: string; } +// 模板配置(ID必须与后端 PRESET_TEMPLATES 匹配) const TEMPLATES: BatchTemplate[] = [ { - id: 'clinicalResearch', + id: 'clinical_research', // ✅ 必须与后端模板ID匹配 name: '临床研究信息提取', - description: '提取研究目的、方法、样本量、结论等核心信息', + description: '提取研究目的、设计、对象、样本量、干预、对照、结果、证据等级', fields: [ - { key: 'title', label: '研究标题' }, - { key: 'purpose', label: '研究目的' }, - { key: 'method', label: '研究方法' }, - { key: 'sampleSize', label: '样本量' }, - { key: 'intervention', label: '干预措施' }, - { key: 'outcome', label: '主要结局' }, - { key: 'conclusion', label: '研究结论' }, - { key: 'limitation', label: '研究局限' }, - ], - }, - { - id: 'drug_safety', - name: '药物安全性分析', - description: '提取药物不良反应、禁忌症、注意事项等', - fields: [ - { key: 'drugName', label: '药物名称' }, - { key: 'adverseReactions', label: '不良反应' }, - { key: 'contraindications', label: '禁忌症' }, - { key: 'warnings', label: '警告事项' }, - ], - }, - { - id: 'patient_baseline', - name: '患者基线特征', - description: '提取患者年龄、性别、诊断、既往史等基线信息', - fields: [ - { key: 'age', label: '年龄' }, - { key: 'gender', label: '性别' }, - { key: 'diagnosis', label: '主要诊断' }, - { key: 'comorbidities', label: '合并症' }, + { key: 'research_purpose', label: '研究目的' }, + { key: 'research_design', label: '研究设计' }, + { key: 'research_subjects', label: '研究对象' }, + { key: 'sample_size', label: '样本量' }, + { key: 'intervention_group', label: '干预组' }, + { key: 'control_group', label: '对照组' }, + { key: 'results_data', label: '结果及数据' }, + { key: 'oxford_level', label: '牛津评级' }, ], }, ]; @@ -80,9 +59,19 @@ export const BatchModeComplete: React.FC = ({ const [selectedTemplate, setSelectedTemplate] = useState(TEMPLATES[0]); const [selectedDocs, setSelectedDocs] = useState([]); const [results, setResults] = useState([]); - const [, setIsExecuting] = useState(false); + const [isExecuting, setIsExecuting] = useState(false); - const completedDocs = documents.filter(doc => doc.status === 'completed'); + // 过滤出已完成解析的文档,并去重(确保唯一性) + const completedDocs = React.useMemo(() => { + const seen = new Set(); + return documents.filter(doc => { + if (doc.status === 'completed' && !seen.has(doc.id)) { + seen.add(doc.id); + return true; + } + return false; + }); + }, [documents]); useEffect(() => { // 初始化模板(如果有传入则使用,否则默认第一个) @@ -92,16 +81,18 @@ export const BatchModeComplete: React.FC = ({ } }, [initialTemplate]); - // 处理文档选择 - const handleDocSelect = (docId: string, checked: boolean) => { - if (checked) { + // 切换文档选择状态(toggle模式,参考旧版实现) + const handleToggleDocument = (docId: string) => { + if (selectedDocs.includes(docId)) { + // 已选中 -> 取消选择 + setSelectedDocs(prev => prev.filter(id => id !== docId)); + } else { + // 未选中 -> 添加选择 if (selectedDocs.length >= 50) { message.warning('最多选择50篇文档'); return; } setSelectedDocs(prev => [...prev, docId]); - } else { - setSelectedDocs(prev => prev.filter(id => id !== docId)); } }; @@ -130,11 +121,11 @@ export const BatchModeComplete: React.FC = ({ setStep(1); setIsExecuting(true); - // 初始化结果 - const initialResults: BatchResult[] = selectedDocs.map(docId => { - const doc = documents.find(d => d.id === docId); + // 初始化结果 - 使用唯一索引确保key唯一 + const initialResults: BatchResult[] = selectedDocs.map((docId, index) => { + const doc = completedDocs.find(d => d.id === docId); return { - documentId: docId, + documentId: `${docId}-${index}`, // 确保唯一性 documentName: doc?.filename || '未知文档', status: 'pending', progress: 0, @@ -143,81 +134,185 @@ export const BatchModeComplete: React.FC = ({ setResults(initialResults); try { - // 调用批处理API + // 调用批处理API(使用v2新版API) + // 完整路径: /api/v2/pkb/batch-tasks/batch/execute + // 请求体格式必须匹配后端 ExecuteBatchBody 接口 const response = await fetch('/api/v2/pkb/batch-tasks/batch/execute', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ - kb_id: kbId, - template_id: selectedTemplate.id, - document_ids: selectedDocs, + kb_id: kbId, // 后端期望 kb_id + document_ids: selectedDocs, // 后端期望 document_ids + template_type: 'preset', // 使用预设模板 + template_id: selectedTemplate.id, // 后端期望 template_id + model_type: 'qwen-long', // 使用qwen-long模型 + task_name: `${selectedTemplate.name}_${new Date().toLocaleString('zh-CN')}`, }), }); if (!response.ok) { - throw new Error('批处理执行失败'); + const errorData = await response.json().catch(() => ({})); + throw new Error(errorData.message || '批处理执行失败'); } - const data = await response.json(); - const taskId = data.task_id; + const responseData = await response.json(); + console.log('[BatchMode] API响应:', responseData); + + // 后端返回格式: { success: true, data: { task_id: xxx } } + const taskId = responseData.data?.task_id || responseData.taskId || responseData.task_id; + + if (!taskId) { + console.error('[BatchMode] 未获取到taskId:', responseData); + message.error('批处理任务创建失败:未获取到任务ID'); + setIsExecuting(false); + setStep(0); + return; + } + + console.log('[BatchMode] 任务已创建,开始轮询:', taskId); // 轮询任务状态 const pollInterval = setInterval(async () => { try { - const statusRes = await fetch(`/api/v2/pkb/batch-tasks/${taskId}`); - const statusData = await statusRes.json(); + const statusRes = await fetch(`/api/v2/pkb/batch-tasks/batch/tasks/${taskId}`); + if (!statusRes.ok) { + console.error('[BatchMode] 获取任务状态失败:', statusRes.status); + return; + } + const statusJson = await statusRes.json(); + const taskData = statusJson.data || statusJson; + + console.log('[BatchMode] 任务状态:', taskData); - // 更新进度 + // 计算进度 - 基于后端返回的completed_count + const completedCount = taskData.completed_count || 0; + const failedCount = taskData.failed_count || 0; + const processedCount = completedCount + failedCount; + + // 更新每个文档的状态(根据处理进度模拟) setResults(prev => prev.map((r, idx) => { - const docResult = statusData.results?.[idx]; - if (docResult) { - return { - ...r, - status: docResult.status, - progress: docResult.progress || 0, - result: docResult.result, - error: docResult.error, - }; + if (idx < completedCount) { + // 已完成 + return { ...r, status: 'completed' as const, progress: 100 }; + } else if (idx < processedCount) { + // 失败 + return { ...r, status: 'error' as const, progress: 100 }; + } else if (idx === processedCount && taskData.status === 'processing') { + // 正在处理 + return { ...r, status: 'processing' as const, progress: 50 }; } return r; })); // 检查是否全部完成 - if (statusData.status === 'completed' || statusData.status === 'failed') { + if (taskData.status === 'completed' || taskData.status === 'failed') { clearInterval(pollInterval); setIsExecuting(false); - setStep(2); - if (statusData.status === 'completed') { - message.success('批处理完成!'); + // 获取最终结果 + try { + const resultsRes = await fetch(`/api/v2/pkb/batch-tasks/batch/tasks/${taskId}/results`); + console.log('[BatchMode] 获取结果响应状态:', resultsRes.status); + + if (resultsRes.ok) { + const resultsJson = await resultsRes.json(); + console.log('[BatchMode] 结果数据:', JSON.stringify(resultsJson, null, 2)); + + const resultsData = resultsJson.data?.results || []; + console.log('[BatchMode] 解析到的结果数量:', resultsData.length); + + if (resultsData.length > 0) { + // 构建新的结果数组 - 后端返回的提取数据在 data 字段中 + const newResults: BatchResult[] = resultsData.map((docResult: any, idx: number) => { + console.log(`[BatchMode] 文档 ${idx}:`, { + id: docResult.document_id, + name: docResult.document_name, + status: docResult.status, + hasData: !!docResult.data, + dataKeys: docResult.data ? Object.keys(docResult.data) : [], + }); + + // 🔑 后端返回的状态是 "success" 或 "failed",需要映射为前端的 "completed" 或 "error" + const isSuccess = docResult.status === 'success' || docResult.status === 'completed'; + + return { + documentId: docResult.document_id || `doc-${idx}`, + documentName: docResult.document_name || `文档${idx + 1}`, + status: isSuccess ? 'completed' as const : 'error' as const, + progress: 100, + result: docResult.data, // 后端返回的提取数据 + error: docResult.error_message, + }; + }); + + console.log('[BatchMode] 更新结果:', newResults); + setResults(newResults); + } else { + console.warn('[BatchMode] 没有结果数据'); + } + } else { + console.error('[BatchMode] 获取结果失败,状态码:', resultsRes.status); + } + } catch (e) { + console.error('[BatchMode] 获取结果异常:', e); + } + + // 延迟设置step,确保状态更新完成 + setTimeout(() => { + setStep(2); + }, 100); + + if (taskData.status === 'completed') { + message.success(`批处理完成!成功 ${completedCount} 篇,失败 ${failedCount} 篇`); } else { - message.error('批处理失败'); + message.error('批处理失败: ' + (taskData.error || '未知错误')); } } } catch (error) { - console.error('轮询任务状态失败:', error); + console.error('[BatchMode] 轮询任务状态失败:', error); } }, 2000); + // 设置超时保护(5分钟) + setTimeout(() => { + clearInterval(pollInterval); + if (isExecuting) { + setIsExecuting(false); + setStep(2); + message.warning('任务执行超时,请稍后查看结果'); + } + }, 5 * 60 * 1000); + } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : '执行失败'; message.error(errorMessage); setIsExecuting(false); + setStep(0); // 返回配置步骤 } }; - // 导出Excel + // 导出Excel (CSV格式) const handleExport = () => { if (!selectedTemplate) return; - // 构建CSV数据 + const completedResults = results.filter(r => r.status === 'completed' && r.result); + + if (completedResults.length === 0) { + message.warning('没有可导出的结果'); + return; + } + + // 构建CSV数据 - 使用模板定义的字段 const headers = ['文档名称', ...selectedTemplate.fields.map(f => f.label)]; - const rows = results - .filter(r => r.status === 'completed' && r.result) - .map(r => [ - r.documentName, - ...selectedTemplate.fields.map(f => r.result?.[f.key] || '-'), - ]); + const rows = completedResults.map(r => [ + r.documentName, + ...selectedTemplate.fields.map(f => { + const value = r.result?.[f.key]; + if (!value) return '-'; + // 处理换行符和引号 + return String(value).replace(/"/g, '""').replace(/\n/g, ' '); + }), + ]); const csvContent = [ headers.join(','), @@ -228,8 +323,11 @@ export const BatchModeComplete: React.FC = ({ const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); - link.download = `批处理结果_${selectedTemplate.name}_${new Date().toISOString().split('T')[0]}.csv`; + const timestamp = new Date().toISOString().split('T')[0]; + link.download = `批处理结果_${selectedTemplate.name}_${timestamp}.csv`; link.click(); + + message.success(`已导出 ${completedResults.length} 条结果`); }; // 重置 @@ -247,9 +345,9 @@ export const BatchModeComplete: React.FC = ({ current={step} size="small" items={[ - { title: '配置任务', description: '选择模板和文档' }, - { title: '执行中', description: '正在处理文档' }, - { title: '查看结果', description: '导出数据' }, + { title: '配置任务', subTitle: '选择模板和文档' }, + { title: '执行中', subTitle: '正在处理文档' }, + { title: '查看结果', subTitle: '导出数据' }, ]} /> @@ -348,14 +446,12 @@ export const BatchModeComplete: React.FC = ({ ? 'bg-blue-50 border border-blue-200' : 'hover:bg-gray-50 border border-transparent' }`} - onClick={() => handleDocSelect(doc.id, !selectedDocs.includes(doc.id))} + onClick={() => handleToggleDocument(doc.id)} > { - e.stopPropagation(); - handleDocSelect(doc.id, e.target.checked); - }} + onChange={() => handleToggleDocument(doc.id)} + onClick={(e) => e.stopPropagation()} />
@@ -375,29 +471,32 @@ export const BatchModeComplete: React.FC = ({
- - 已选择 {selectedDocs.length} 篇文档 - {selectedDocs.length < 3 && (至少需要3篇)} - - } - type={selectedDocs.length >= 3 ? 'success' : 'warning'} - showIcon - /> +
= 3 + ? 'bg-green-50 border border-green-200' + : 'bg-yellow-50 border border-yellow-200' + }`}> + = 3 ? 'text-green-500' : 'text-yellow-500' + }`} /> + + 已选择 {selectedDocs.length} 篇文档 + {selectedDocs.length < 3 && (至少需要3篇)} + +
- {/* 开始按钮 */} + {/* 开始按钮 - 显示实际选择的文档数量 */} @@ -471,37 +570,84 @@ export const BatchModeComplete: React.FC = ({
- r.status === 'completed')} - rowKey="documentId" - pagination={false} - scroll={{ x: 'max-content', y: '100%' }} - size="small" - columns={[ - { - title: '文档名称', - dataIndex: 'documentName', - key: 'documentName', - fixed: 'left', - width: 200, - ellipsis: true, - render: (text) => ( -
- - {text} -
- ), - }, - ...selectedTemplate.fields.map(field => ({ - title: field.label, - dataIndex: ['result', field.key], - key: field.key, - width: 180, - ellipsis: true, - render: (text: string) => text || '-', - })), - ]} - /> + {results.filter(r => r.status === 'completed' && r.result).length === 0 ? ( +
+
+ +

暂无提取结果

+

请等待处理完成或检查是否有失败的文档

+
+
+ ) : ( +
r.status === 'completed' && r.result)} + rowKey="documentId" + pagination={false} + scroll={{ x: 1800, y: 'calc(100vh - 400px)' }} + size="small" + className="batch-results-table" + columns={[ + { + title: '文档名称', + dataIndex: 'documentName', + key: 'documentName', + fixed: 'left', + width: 220, + render: (text: string) => ( + +
+ + + {text} + +
+
+ ), + }, + ...selectedTemplate.fields.map(field => ({ + title: field.label, + key: field.key, + width: field.key === 'results_data' ? 280 : 180, // 结果数据列更宽 + render: (_: unknown, record: BatchResult) => { + const value = record.result?.[field.key]; + if (!value) return -; + + const textValue = String(value); + + return ( + {textValue}} + placement="topLeft" + overlayStyle={{ maxWidth: 450 }} + > +
+ {textValue} +
+
+ ); + }, + })), + ]} + /> + )} )} diff --git a/frontend-v2/src/modules/pkb/components/Workspace/DeepReadMode.tsx b/frontend-v2/src/modules/pkb/components/Workspace/DeepReadMode.tsx index 40cd0a6a..5ff037d1 100644 --- a/frontend-v2/src/modules/pkb/components/Workspace/DeepReadMode.tsx +++ b/frontend-v2/src/modules/pkb/components/Workspace/DeepReadMode.tsx @@ -1,10 +1,10 @@ /** * 逐篇精读模式组件 - ChatGPT风格全屏聊天 + * 修复:参考文献格式、文档切换对话独立 */ -import React from 'react'; -import { Empty } from 'antd'; -import { FileText } from 'lucide-react'; +import React, { useMemo } from 'react'; +import { FileText, BookOpen, ExternalLink } from 'lucide-react'; import { ChatContainer } from '@/shared/components/Chat'; import type { KnowledgeBase, Document } from '../../api/knowledgeBaseApi'; @@ -14,10 +14,92 @@ interface DeepReadModeProps { selectedDocuments: Document[]; } +// 消息渲染参数类型 +interface MessageRenderParams { + id: string | number; + message: { + id: string | number; + role: string; + content: string; + status?: string; + [key: string]: unknown; + }; + status: string; +} + +// 自定义消息渲染器 - 解析并格式化参考文献 +const renderMessageContent = (params: MessageRenderParams) => { + // 从params中提取消息内容 + const textContent = params?.message?.content; + + // 空内容处理 + if (!textContent || typeof textContent !== 'string' || textContent.trim() === '') { + return
加载中...
; + } + + // 处理参考文献格式 + let formattedContent = textContent; + + // 1. 移除HTML标签,转换为可读格式 + formattedContent = formattedContent.replace( + /]*id="citation-detail-(\d+)"[^>]*>\[(\d+)\]<\/span>\s*\*?\*?([^*\n]+)\*?\*?/g, + (_, _num, num2, title) => `\n📄 [${num2}] ${title.trim()}` + ); + + // 2. 处理其他HTML span标签 + formattedContent = formattedContent.replace(/]*>[^<]*<\/span>/g, ''); + + // 3. 处理Markdown加粗中的下划线(文件名) + formattedContent = formattedContent.replace( + /\*\*([^*]+\.pdf)\*\*/gi, + '📄 **$1**' + ); + + return ( +
+ {formattedContent.split('\n').map((line, idx) => { + // 检测是否是参考文献行 + if (line.startsWith('📄')) { + return ( +
+ + {line.replace('📄 ', '')} +
+ ); + } + + // 检测是否是"参考文献"标题 + if (line.includes('**参考文献**') || line.includes('📚 **参考文献**')) { + return ( +
+ + 参考文献 +
+ ); + } + + // 普通文本 + return line ?

{line}

: null; + })} +
+ ); +}; + export const DeepReadMode: React.FC = ({ kbId, selectedDocuments }) => { + // 使用useMemo确保文档切换时生成新的key + const conversationKey = useMemo(() => { + if (!selectedDocuments || selectedDocuments.length === 0) return ''; + return `kb-deepread-${kbId}-${selectedDocuments[0].id}-${Date.now()}`; + }, [kbId, selectedDocuments]); + + const selectedDocIds = useMemo(() => + selectedDocuments.map(d => d.id), + [selectedDocuments] + ); + if (!selectedDocuments || selectedDocuments.length === 0) { return (
@@ -35,15 +117,25 @@ export const DeepReadMode: React.FC = ({ } const selectedDoc = selectedDocuments[0]; - const selectedDocIds = selectedDocuments.map(d => d.id); return (
- {/* Chat组件 - 全屏展开 */} -
+ {/* 当前文档提示 */} +
+
+ + 当前精读: + + {selectedDoc.filename} + +
+
+ + {/* Chat组件 - 使用key强制重新渲染 */} +
= ({ providerConfig={{ apiEndpoint: '/api/v1/chat/stream', requestFn: async (message: string) => { + // 🔑 关键:传递 fullTextDocumentIds 而不是 documentIds + // fullTextDocumentIds 会触发全文加载模式,AI可以看到完整文献 + // documentIds 只是过滤RAG检索结果,AI只能看到片段 const response = await fetch('/api/v1/chat/stream', { method: 'POST', headers: { @@ -64,7 +159,7 @@ export const DeepReadMode: React.FC = ({ content: message, modelType: 'qwen-long', knowledgeBaseIds: [kbId], - documentIds: selectedDocIds, // 🌟 关键参数:限定文档范围 + fullTextDocumentIds: selectedDocIds, // ✅ 改用全文模式 }), }); @@ -72,7 +167,6 @@ export const DeepReadMode: React.FC = ({ throw new Error(`API请求失败: ${response.status}`); } - // 处理流式响应 const reader = response.body?.getReader(); const decoder = new TextDecoder(); let fullContent = ''; @@ -109,6 +203,7 @@ export const DeepReadMode: React.FC = ({ }; }, }} + customMessageRenderer={renderMessageContent} />
diff --git a/frontend-v2/src/modules/pkb/components/Workspace/FullTextMode.tsx b/frontend-v2/src/modules/pkb/components/Workspace/FullTextMode.tsx index d7319c5d..f2f296fd 100644 --- a/frontend-v2/src/modules/pkb/components/Workspace/FullTextMode.tsx +++ b/frontend-v2/src/modules/pkb/components/Workspace/FullTextMode.tsx @@ -3,6 +3,7 @@ */ import React from 'react'; +import { BookOpen, FileText } from 'lucide-react'; import { ChatContainer } from '@/shared/components/Chat'; import type { KnowledgeBase, Document } from '../../api/knowledgeBaseApi'; @@ -12,13 +13,87 @@ interface FullTextModeProps { documents: Document[]; } -export const FullTextMode: React.FC = ({ kbId, documents }) => { - // 准备全文文档ID - const fullTextDocumentIds = documents - .filter(doc => doc.status === 'completed') - .map(doc => doc.id); +// 消息渲染参数类型 +interface MessageRenderParams { + id: string | number; + message: { + id: string | number; + role: string; + content: string; + status?: string; + [key: string]: unknown; + }; + status: string; +} - const totalTokens = documents.reduce((sum, d) => sum + (d.tokensCount || 0), 0); +// 自定义消息渲染器 - 解析并格式化参考文献 +const renderMessageContent = (params: MessageRenderParams) => { + const textContent = params?.message?.content; + + if (!textContent || typeof textContent !== 'string' || textContent.trim() === '') { + return
加载中...
; + } + + // 处理参考文献格式 + let formattedContent = textContent; + + // 1. 移除HTML标签,转换为可读格式 + // 格式: [1] 📄 **文件名** - 第0段 (相关度100%) + formattedContent = formattedContent.replace( + /]*id="citation-detail-(\d+)"[^>]*>\[(\d+)\]<\/span>\s*📄?\s*\*?\*?([^*\n-]+)\*?\*?\s*-\s*第(\d+)段\s*\(相关度(\d+)%\)/g, + (_, _id, num, filename, position, score) => + `\n📖 [${num}] ${filename.trim()} - 第${position}段 (相关度${score}%)` + ); + + // 2. 处理其他HTML span标签 + formattedContent = formattedContent.replace(/]*>[^<]*<\/span>/g, ''); + + // 3. 清理多余的星号(Markdown加粗) + formattedContent = formattedContent.replace(/\*\*/g, ''); + + return ( +
+ {formattedContent.split('\n').map((line, idx) => { + // 检测是否是参考文献行 + if (line.startsWith('📖')) { + return ( +
+ + {line.replace('📖 ', '')} +
+ ); + } + + // 检测是否是"参考文献"标题 + if (line.includes('参考文献')) { + return ( +
+ + 📚 参考文献 +
+ ); + } + + // 分隔线 + if (line.trim() === '---') { + return
; + } + + // 普通文本 + return line.trim() ?

{line}

: null; + })} +
+ ); +}; + +export const FullTextMode: React.FC = ({ kbId, documents }) => { + // 准备全文文档ID(只选择已完成的文档) + const completedDocs = documents.filter(doc => doc.status === 'completed'); + const fullTextDocumentIds = completedDocs.map(doc => doc.id); + const totalTokens = completedDocs.reduce((sum, d) => sum + (d.tokensCount || 0), 0); + + // 🔑 将文档数量加入key,确保文档加载完成后重新渲染ChatContainer + const conversationKey = `kb-fulltext-${kbId}-${completedDocs.length}`; return (
@@ -26,26 +101,15 @@ export const FullTextMode: React.FC = ({ kbId, documents }) =
{ - const msg = msgInfo.message; - if (msg.role === 'assistant' && msg.content) { - // 处理参考文献格式 - const processedContent = msg.content.replace( - /\*\*参考文献\*\*/g, - '\n\n**📚 参考文献**\n' - ); - return
{processedContent}
; - } - return
{msg.content}
; - }} + customMessageRenderer={renderMessageContent} providerConfig={{ apiEndpoint: '/api/v1/chat/stream', requestFn: async (message: string) => { diff --git a/frontend-v2/src/modules/pkb/pages/KnowledgePage.tsx b/frontend-v2/src/modules/pkb/pages/KnowledgePage.tsx index 9b2bf0a3..cf61f2fa 100644 --- a/frontend-v2/src/modules/pkb/pages/KnowledgePage.tsx +++ b/frontend-v2/src/modules/pkb/pages/KnowledgePage.tsx @@ -284,3 +284,4 @@ export default KnowledgePage; + diff --git a/frontend-v2/src/modules/pkb/pages/WorkspacePage.tsx b/frontend-v2/src/modules/pkb/pages/WorkspacePage.tsx index cd06a71f..9cd1f0c8 100644 --- a/frontend-v2/src/modules/pkb/pages/WorkspacePage.tsx +++ b/frontend-v2/src/modules/pkb/pages/WorkspacePage.tsx @@ -8,8 +8,9 @@ import React, { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; -import { Table, Button, message, Progress, Dropdown } from 'antd'; +import { Table, Button, message, Progress, Dropdown, Modal } from 'antd'; import type { MenuProps } from 'antd'; +import DocumentUpload from '../components/DocumentUpload'; import { MessageSquare, FileText, Database, Settings, ChevronLeft, Trash2, CheckCircle2, @@ -49,6 +50,7 @@ const WorkspacePage: React.FC = ({ standalone = false }) => const [activeTab, setActiveTab] = useState('chat'); const [isPdfOpen, setIsPdfOpen] = useState(false); + const [uploadModalVisible, setUploadModalVisible] = useState(false); useEffect(() => { if (kbId) { @@ -211,7 +213,7 @@ const WorkspacePage: React.FC = ({ standalone = false }) =>
{/* 中间:Tab切换(精致胶囊按钮) */} -
+
-
+
DL
@@ -397,33 +399,50 @@ const WorkspacePage: React.FC = ({ standalone = false }) => -
- {/* 文档表格 */} + {/* 文档表格 - 参考原型图精细化设计 */}
(
-
- +
+
- {text} + + {text} +
), }, @@ -431,8 +450,10 @@ const WorkspacePage: React.FC = ({ standalone = false }) => title: '解析状态 (MinerU Pipeline)', dataIndex: 'status', key: 'status', + width: 200, + align: 'center', render: (status, record) => ( -
+
{getStatusBadge(status)} {status !== 'completed' && status !== 'error' && ( = ({ standalone = false }) => size="small" strokeColor="#3b82f6" trailColor="#e5e7eb" + style={{ width: 120 }} /> )}
@@ -449,9 +471,11 @@ const WorkspacePage: React.FC = ({ standalone = false }) => title: '文件大小', dataIndex: 'fileSizeBytes', key: 'fileSizeBytes', + width: 100, + align: 'center', render: (size) => ( - - {(size / 1024 / 1024).toFixed(1)} MB + + {size ? `${(size / 1024 / 1024).toFixed(1)} MB` : '-'} ), }, @@ -459,8 +483,10 @@ const WorkspacePage: React.FC = ({ standalone = false }) => title: 'Tokens', dataIndex: 'tokensCount', key: 'tokensCount', + width: 80, + align: 'center', render: (tokens) => ( - + {tokens ? `${(tokens / 1000).toFixed(0)}k` : '-'} ), @@ -469,20 +495,30 @@ const WorkspacePage: React.FC = ({ standalone = false }) => title: '上传时间', dataIndex: 'uploadedAt', key: 'uploadedAt', + width: 160, + align: 'center', render: (date) => ( - - {new Date(date).toLocaleString('zh-CN')} + + {date ? new Date(date).toLocaleString('zh-CN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit' + }) : '-'} ), }, { title: '操作', key: 'action', - align: 'right', + width: 80, + align: 'center', render: (_, record) => ( @@ -505,6 +541,26 @@ const WorkspacePage: React.FC = ({ standalone = false }) => background-position: 0 0, 10px 10px; } `} + + {/* 上传文档弹窗 */} + setUploadModalVisible(false)} + footer={null} + width={600} + > + { + fetchDocuments(kbId!); + setUploadModalVisible(false); + message.success('文档上传成功!'); + }} + maxDocuments={50} + currentDocumentCount={documents.length} + /> +
); }; diff --git a/frontend-v2/src/modules/pkb/stores/useKnowledgeBaseStore.ts b/frontend-v2/src/modules/pkb/stores/useKnowledgeBaseStore.ts index 6a38e49a..e7245ffd 100644 --- a/frontend-v2/src/modules/pkb/stores/useKnowledgeBaseStore.ts +++ b/frontend-v2/src/modules/pkb/stores/useKnowledgeBaseStore.ts @@ -222,3 +222,4 @@ export const useKnowledgeBaseStore = create((set, get) => ({ + diff --git a/frontend-v2/src/modules/pkb/styles/workspace.css b/frontend-v2/src/modules/pkb/styles/workspace.css index 81562cf3..0585f0e2 100644 --- a/frontend-v2/src/modules/pkb/styles/workspace.css +++ b/frontend-v2/src/modules/pkb/styles/workspace.css @@ -1,39 +1,154 @@ /** * PKB Workspace 样式优化 - * 根据差距文档进行精细化调整 + * 根据原型图进行精细化调整 */ -/* 1. 全局字体和排版优化 */ +/* ======================================== + 1. 文档资产表格 - 参考原型图精细化设计 + ======================================== */ + .pkb-document-table .ant-table { font-size: 14px; line-height: 1.5; } +/* 表头样式 - 浅灰背景,深灰文字 */ .pkb-document-table .ant-table-thead > tr > th { - background-color: #f9fafb; - color: #6b7280; - font-weight: 600; - font-size: 13px; - padding: 14px 16px; - border-bottom: 1px solid #e5e7eb; + background-color: #fafafa !important; + color: #374151 !important; + font-weight: 600 !important; + font-size: 13px !important; + padding: 16px 20px !important; + border-bottom: 1px solid #e5e7eb !important; + white-space: nowrap; } +/* 表头首列(复选框)特殊处理 */ +.pkb-document-table .ant-table-thead > tr > th.ant-table-selection-column { + padding-left: 24px !important; +} + +/* 表体单元格样式 */ .pkb-document-table .ant-table-tbody > tr > td { - padding: 16px; - border-bottom: 1px solid #f3f4f6; + padding: 16px 20px !important; + border-bottom: 1px solid #f3f4f6 !important; + vertical-align: middle; } +/* 表体首列(复选框)特殊处理 */ +.pkb-document-table .ant-table-tbody > tr > td.ant-table-selection-column { + padding-left: 24px !important; +} + +/* 行悬停效果 */ .pkb-document-table .ant-table-tbody > tr:hover > td { - background-color: #f9fafb; - transition: background-color 0.2s ease; + background-color: #f9fafb !important; + transition: background-color 0.15s ease; } -/* 2. 圆角统一 */ +/* 选中行背景 */ +.pkb-document-table .ant-table-tbody > tr.ant-table-row-selected > td { + background-color: #eff6ff !important; +} + +/* 选中行悬停 */ +.pkb-document-table .ant-table-tbody > tr.ant-table-row-selected:hover > td { + background-color: #dbeafe !important; +} + +/* 行过渡动画 */ +.pkb-document-table .ant-table-tbody > tr { + transition: all 0.15s ease; +} + +/* 最后一行去掉底部边框 */ +.pkb-document-table .ant-table-tbody > tr:last-child > td { + border-bottom: none !important; +} + +/* ======================================== + 2. 复选框样式优化 + ======================================== */ + +.pkb-document-table .ant-checkbox-wrapper { + display: flex; + align-items: center; + justify-content: center; +} + +.pkb-document-table .ant-checkbox-inner { + width: 18px; + height: 18px; + border-radius: 4px; + border-color: #d1d5db; +} + +.pkb-document-table .ant-checkbox-checked .ant-checkbox-inner { + background-color: #3b82f6; + border-color: #3b82f6; +} + +/* ======================================== + 3. 表格容器圆角 + ======================================== */ + .pkb-document-table .ant-table-container { - border-radius: 8px; + border-radius: 12px; + overflow: hidden; } -/* 3. 动画优化 */ +.pkb-document-table .ant-table-content { + border-radius: 0; +} + +/* ======================================== + 4. 滚动条样式 + ======================================== */ + +.pkb-document-table .ant-table-body::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +.pkb-document-table .ant-table-body::-webkit-scrollbar-track { + background: #f1f5f9; + border-radius: 4px; +} + +.pkb-document-table .ant-table-body::-webkit-scrollbar-thumb { + background: #cbd5e1; + border-radius: 4px; +} + +.pkb-document-table .ant-table-body::-webkit-scrollbar-thumb:hover { + background: #94a3b8; +} + +/* ======================================== + 5. 空数据状态 + ======================================== */ + +.pkb-document-table .ant-table-placeholder { + padding: 60px 20px; +} + +.pkb-document-table .ant-empty-description { + color: #9ca3af; + font-size: 14px; +} + +/* ======================================== + 6. 加载状态 + ======================================== */ + +.pkb-document-table .ant-spin-container { + transition: opacity 0.2s ease; +} + +/* ======================================== + 7. 动画效果 + ======================================== */ + @keyframes fadeIn { from { opacity: 0; @@ -49,7 +164,89 @@ animation: fadeIn 0.3s ease-out; } -/* 4. 表格行悬停优化 */ -.pkb-document-table .ant-table-tbody > tr { - transition: all 0.2s ease; +@keyframes slideInRight { + from { + opacity: 0; + transform: translateX(20px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.animate-slide-in-right { + animation: slideInRight 0.25s ease-out; +} + +/* ======================================== + 8. 文件名链接样式 + ======================================== */ + +.pkb-document-table .filename-link { + color: #2563eb; + font-weight: 500; + cursor: pointer; + transition: color 0.15s ease; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + display: block; + max-width: 100%; +} + +.pkb-document-table .filename-link:hover { + color: #1d4ed8; + text-decoration: underline; +} + +/* ======================================== + 9. 状态徽章优化 + ======================================== */ + +.pkb-status-badge { + display: inline-flex; + align-items: center; + padding: 4px 10px; + border-radius: 6px; + font-size: 12px; + font-weight: 500; + gap: 6px; +} + +.pkb-status-badge.completed { + background-color: #ecfdf5; + color: #059669; + border: 1px solid #a7f3d0; +} + +.pkb-status-badge.processing { + background-color: #eff6ff; + color: #2563eb; + border: 1px solid #bfdbfe; +} + +.pkb-status-badge.error { + background-color: #fef2f2; + color: #dc2626; + border: 1px solid #fecaca; +} + +/* ======================================== + 10. 响应式调整 + ======================================== */ + +@media (max-width: 1280px) { + .pkb-document-table .ant-table-thead > tr > th, + .pkb-document-table .ant-table-tbody > tr > td { + padding: 12px 16px !important; + } +} + +@media (max-width: 1024px) { + .pkb-document-table .ant-table-thead > tr > th, + .pkb-document-table .ant-table-tbody > tr > td { + padding: 10px 12px !important; + font-size: 13px !important; + } } diff --git a/frontend-v2/src/modules/pkb/types/workspace.ts b/frontend-v2/src/modules/pkb/types/workspace.ts index f22ebda7..314429af 100644 --- a/frontend-v2/src/modules/pkb/types/workspace.ts +++ b/frontend-v2/src/modules/pkb/types/workspace.ts @@ -39,3 +39,4 @@ export interface BatchTemplate { + diff --git a/frontend-v2/src/shared/components/Chat/ChatContainer.tsx b/frontend-v2/src/shared/components/Chat/ChatContainer.tsx index 8f5dd679..2343aad7 100644 --- a/frontend-v2/src/shared/components/Chat/ChatContainer.tsx +++ b/frontend-v2/src/shared/components/Chat/ChatContainer.tsx @@ -8,7 +8,7 @@ * 直接管理消息状态,不使用 useXChat Hook */ -import React, { useState, useCallback } from 'react'; +import React, { useState, useCallback, useRef, useEffect } from 'react'; import { Bubble, Sender } from '@ant-design/x'; import type { ChatContainerProps, ChatMessage } from './types'; import type { BubbleItemType } from '@ant-design/x/es/bubble/interface'; @@ -40,11 +40,28 @@ export const ChatContainer: React.FC = ({ const [messages, setMessages] = useState(initialMessages); const [isLoading, setIsLoading] = useState(false); + const [inputValue, setInputValue] = useState(''); // 受控输入框 + const messagesEndRef = useRef(null); // 用于滚动到底部 + + // 滚动到底部 + const scrollToBottom = useCallback(() => { + setTimeout(() => { + messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); + }, 100); + }, []); + + // 消息变化时自动滚动 + useEffect(() => { + scrollToBottom(); + }, [messages, scrollToBottom]); // 处理消息发送 const handleSend = useCallback(async (messageContent: string) => { if (!messageContent.trim()) return; // 防止发送空消息 + // 🔑 立即清除输入框 + setInputValue(''); + // 1. 添加用户消息 const userMessage: ChatMessage = { id: Date.now(), @@ -144,13 +161,17 @@ export const ChatContainer: React.FC = ({ items={bubbleItems} autoScroll={true} /> + {/* 滚动锚点 */} +
- {/* 输入框 */} + {/* 输入框(受控模式) */}
diff --git a/frontend-v2/src/shared/components/index.ts b/frontend-v2/src/shared/components/index.ts index 2e73aba3..a4763ab0 100644 --- a/frontend-v2/src/shared/components/index.ts +++ b/frontend-v2/src/shared/components/index.ts @@ -50,5 +50,6 @@ export { default as Placeholder } from './Placeholder'; + diff --git a/frontend-v2/src/vite-env.d.ts b/frontend-v2/src/vite-env.d.ts index 52592af0..baf820b4 100644 --- a/frontend-v2/src/vite-env.d.ts +++ b/frontend-v2/src/vite-env.d.ts @@ -30,5 +30,6 @@ interface ImportMeta { + diff --git a/git-cleanup-redcap.ps1 b/git-cleanup-redcap.ps1 index f7944b92..6ed3040e 100644 --- a/git-cleanup-redcap.ps1 +++ b/git-cleanup-redcap.ps1 @@ -25,3 +25,4 @@ Write-Host "Next step: Run the commit command" -ForegroundColor Cyan + diff --git a/git-commit-day1.ps1 b/git-commit-day1.ps1 index e50b7661..1f901b22 100644 --- a/git-commit-day1.ps1 +++ b/git-commit-day1.ps1 @@ -81,3 +81,4 @@ Write-Host "Git commit and push completed!" -ForegroundColor Green + diff --git a/git-fix-lock.ps1 b/git-fix-lock.ps1 index 8aeb8c64..d81aa008 100644 --- a/git-fix-lock.ps1 +++ b/git-fix-lock.ps1 @@ -29,3 +29,4 @@ Write-Host "Now you can run git commands again." -ForegroundColor Cyan + diff --git a/python-microservice/operations/__init__.py b/python-microservice/operations/__init__.py index ab49d46e..c7930f04 100644 --- a/python-microservice/operations/__init__.py +++ b/python-microservice/operations/__init__.py @@ -52,5 +52,6 @@ __version__ = '1.0.0' + diff --git a/python-microservice/operations/binning.py b/python-microservice/operations/binning.py index b0861423..5ce3ea70 100644 --- a/python-microservice/operations/binning.py +++ b/python-microservice/operations/binning.py @@ -159,5 +159,6 @@ def apply_binning( + diff --git a/python-microservice/operations/filter.py b/python-microservice/operations/filter.py index 1b22a277..153c73f0 100644 --- a/python-microservice/operations/filter.py +++ b/python-microservice/operations/filter.py @@ -145,5 +145,6 @@ def apply_filter( + diff --git a/python-microservice/operations/recode.py b/python-microservice/operations/recode.py index c675ded5..1850f062 100644 --- a/python-microservice/operations/recode.py +++ b/python-microservice/operations/recode.py @@ -115,5 +115,6 @@ def apply_recode( + diff --git a/recover_dc_code.py b/recover_dc_code.py index 202f1c9d..42f9148c 100644 --- a/recover_dc_code.py +++ b/recover_dc_code.py @@ -259,5 +259,6 @@ if __name__ == "__main__": + diff --git a/redcap-docker-dev/.gitattributes b/redcap-docker-dev/.gitattributes index 2ed9b11d..6dcd0a96 100644 --- a/redcap-docker-dev/.gitattributes +++ b/redcap-docker-dev/.gitattributes @@ -41,3 +41,4 @@ + diff --git a/redcap-docker-dev/.gitignore b/redcap-docker-dev/.gitignore index c4f541b6..f2a55302 100644 --- a/redcap-docker-dev/.gitignore +++ b/redcap-docker-dev/.gitignore @@ -72,3 +72,4 @@ Desktop.ini + diff --git a/redcap-docker-dev/README.md b/redcap-docker-dev/README.md index bb664eb8..2386dd5f 100644 --- a/redcap-docker-dev/README.md +++ b/redcap-docker-dev/README.md @@ -373,3 +373,4 @@ docker-compose -f docker-compose.prod.yml up -d + diff --git a/redcap-docker-dev/docker-compose.prod.yml b/redcap-docker-dev/docker-compose.prod.yml index a038e48b..80b96d23 100644 --- a/redcap-docker-dev/docker-compose.prod.yml +++ b/redcap-docker-dev/docker-compose.prod.yml @@ -134,3 +134,4 @@ volumes: + diff --git a/redcap-docker-dev/docker-compose.yml b/redcap-docker-dev/docker-compose.yml index 502f78ed..b358f950 100644 --- a/redcap-docker-dev/docker-compose.yml +++ b/redcap-docker-dev/docker-compose.yml @@ -132,3 +132,4 @@ volumes: + diff --git a/redcap-docker-dev/env.template b/redcap-docker-dev/env.template index 7681895d..24a85c7a 100644 --- a/redcap-docker-dev/env.template +++ b/redcap-docker-dev/env.template @@ -68,3 +68,4 @@ PMA_UPLOAD_LIMIT=50M + diff --git a/redcap-docker-dev/scripts/clean-redcap.ps1 b/redcap-docker-dev/scripts/clean-redcap.ps1 index 916565b3..d9c57de8 100644 --- a/redcap-docker-dev/scripts/clean-redcap.ps1 +++ b/redcap-docker-dev/scripts/clean-redcap.ps1 @@ -76,3 +76,4 @@ Write-Host "" + diff --git a/redcap-docker-dev/scripts/create-redcap-password.php b/redcap-docker-dev/scripts/create-redcap-password.php index 1f8f14af..96559117 100644 --- a/redcap-docker-dev/scripts/create-redcap-password.php +++ b/redcap-docker-dev/scripts/create-redcap-password.php @@ -54,3 +54,4 @@ try { + diff --git a/redcap-docker-dev/scripts/logs-redcap.ps1 b/redcap-docker-dev/scripts/logs-redcap.ps1 index 99b9a728..7c478e78 100644 --- a/redcap-docker-dev/scripts/logs-redcap.ps1 +++ b/redcap-docker-dev/scripts/logs-redcap.ps1 @@ -67,3 +67,4 @@ Write-Host "" + diff --git a/redcap-docker-dev/scripts/reset-admin-password.php b/redcap-docker-dev/scripts/reset-admin-password.php index edcc0393..97b78957 100644 --- a/redcap-docker-dev/scripts/reset-admin-password.php +++ b/redcap-docker-dev/scripts/reset-admin-password.php @@ -30,3 +30,4 @@ if ($result) { + diff --git a/redcap-docker-dev/scripts/start-redcap.ps1 b/redcap-docker-dev/scripts/start-redcap.ps1 index b03d6b65..64d155fd 100644 --- a/redcap-docker-dev/scripts/start-redcap.ps1 +++ b/redcap-docker-dev/scripts/start-redcap.ps1 @@ -52,3 +52,4 @@ if ($LASTEXITCODE -eq 0) { + diff --git a/redcap-docker-dev/scripts/stop-redcap.ps1 b/redcap-docker-dev/scripts/stop-redcap.ps1 index 9f22fcae..3449601b 100644 --- a/redcap-docker-dev/scripts/stop-redcap.ps1 +++ b/redcap-docker-dev/scripts/stop-redcap.ps1 @@ -38,3 +38,4 @@ if ($LASTEXITCODE -eq 0) { + diff --git a/run_recovery.ps1 b/run_recovery.ps1 index d2e2f5b9..d207b586 100644 --- a/run_recovery.ps1 +++ b/run_recovery.ps1 @@ -83,5 +83,6 @@ Write-Host "==================================================================== + diff --git a/tests/QUICKSTART_快速开始.md b/tests/QUICKSTART_快速开始.md index 5dc4a5ed..f7a03e86 100644 --- a/tests/QUICKSTART_快速开始.md +++ b/tests/QUICKSTART_快速开始.md @@ -130,5 +130,6 @@ INFO: Uvicorn running on http://0.0.0.0:8001 + diff --git a/tests/README_测试说明.md b/tests/README_测试说明.md index 83080e9d..7d8c9008 100644 --- a/tests/README_测试说明.md +++ b/tests/README_测试说明.md @@ -286,5 +286,6 @@ df_numeric.to_excel('test_data/numeric_test.xlsx', index=False) + diff --git a/tests/run_tests.bat b/tests/run_tests.bat index bb615ec5..f966ceae 100644 --- a/tests/run_tests.bat +++ b/tests/run_tests.bat @@ -81,5 +81,6 @@ pause + diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 9ba00b56..51120318 100644 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -77,5 +77,6 @@ echo "========================================" + diff --git a/快速部署到SAE.md b/快速部署到SAE.md index 07bc9514..63ee4d02 100644 --- a/快速部署到SAE.md +++ b/快速部署到SAE.md @@ -342,5 +342,6 @@ OSS AccessKeySecret:_______________ + diff --git a/部署检查清单.md b/部署检查清单.md index 88d85c67..48373b29 100644 --- a/部署检查清单.md +++ b/部署检查清单.md @@ -378,5 +378,6 @@ OSS配置: +