feat(dc): Add multi-metric transformation feature (direction 1+2)

Summary:
- Implement intelligent multi-metric grouping detection algorithm
- Add direction 1: timepoint-as-row, metric-as-column (analysis format)
- Add direction 2: timepoint-as-column, metric-as-row (display format)
- Fix column name pattern detection (FMA___ issue)
- Maintain original Record ID order in output
- Add full-select/clear buttons in UI
- Integrate into TransformDialog with Radio selection
- Update 3 documentation files

Technical Details:
- Python: detect_metric_groups(), apply_multi_metric_to_long(), apply_multi_metric_to_matrix()
- Backend: 3 new methods in QuickActionService
- Frontend: MultiMetricPanel.tsx (531 lines)
- Total: ~1460 lines of new code

Status: Fully tested and verified, ready for production
This commit is contained in:
2025-12-21 15:06:15 +08:00
parent 8be8cdcf53
commit 9b81aef9a7
123 changed files with 4781 additions and 150 deletions

View File

@@ -93,7 +93,7 @@ npm --version
- [ ] **RDS PostgreSQL 15** 实例已创建并运行
- 数据库名称:`ai_clinical`(或自定义)
- 用户名和密码已准备
- 内网地址已获取(如 `rm-xxxxx.pg.rds.aliyuncs.com:5432`
- 内网地址已获取(如 `pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432`
- 白名单已配置(允许 SAE VPC 访问)
- [ ] **阿里云容器镜像服务 ACR** 已开通
@@ -104,8 +104,8 @@ npm --version
- VPC 和交换机已选择(与 RDS 在同一 VPC
- [ ] **依赖服务的内网地址已获取**
- Python 微服务SAE`http://172.16.0.10:8000`
- Dify 服务ECS`http://172.16.0.20:80`
- Python 微服务SAE`http://172.17.x.x:8000`
- Dify 服务ECS`http://172.17.x.x:80`
#### 敏感信息准备
@@ -113,7 +113,7 @@ npm --version
```bash
# 数据库
DATABASE_URL=postgresql://username:password@rm-xxxxx.pg.rds.aliyuncs.com:5432/ai_clinical?connection_limit=18&pool_timeout=10
DATABASE_URL=postgresql://username:password@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical?connection_limit=18&pool_timeout=10
# LLM API Keys至少配置一个
DEEPSEEK_API_KEY=sk-xxxxx
@@ -122,10 +122,10 @@ CLOSEAI_API_KEY=sk-xxxxx
# Dify
DIFY_API_KEY=app-xxxxx
DIFY_API_URL=http://172.16.0.20:80/v1
DIFY_API_URL=http://172.17.x.x:80/v1
# 阿里云 OSS
OSS_REGION=oss-cn-hangzhou
OSS_REGION=oss-cn-beijing
OSS_BUCKET=clinical-research-files
OSS_ACCESS_KEY_ID=LTAI5t...
OSS_ACCESS_KEY_SECRET=xxx...
@@ -157,10 +157,10 @@ Node.js 后端SAE
├──→ RDS PostgreSQL 15数据库
├──→ Python 微服务SAE - 文档提取
│ └─ http://172.16.0.10:8000
│ └─ http://172.17.x.x:8000
├──→ Dify 服务ECS - RAG 知识库
│ └─ http://172.16.0.20:80/v1
│ └─ http://172.17.x.x:80/v1
└──→ 阿里云 OSS - 文件存储
└─ clinical-research-files
@@ -247,7 +247,7 @@ cp backend/.env backend/.env.backup
# 2. 创建临时 RDS 连接配置
cat > backend/.env.rds <<EOF
DATABASE_URL="postgresql://username:password@rm-xxxxx.pg.rds.aliyuncs.com:5432/ai_clinical?connection_limit=18&pool_timeout=10"
DATABASE_URL="postgresql://username:password@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical?connection_limit=18&pool_timeout=10"
EOF
# 3. 使用 RDS 配置
@@ -263,7 +263,7 @@ npx prisma db pull
# 输出示例:
# Prisma schema loaded from prisma/schema.prisma
# Datasource "db": PostgreSQL database "ai_clinical" at "rm-xxxxx.pg.rds.aliyuncs.com:5432"
# Datasource "db": PostgreSQL database "ai_clinical" at "pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432"
#
# Introspecting based on datasource defined in prisma/schema.prisma …
#
@@ -348,7 +348,7 @@ git push
```bash
# 错误信息:
Error: P1001: Can't reach database server at `rm-xxxxx.pg.rds.aliyuncs.com:5432`
Error: P1001: Can't reach database server at `pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432`
```
**解决方法**
@@ -359,7 +359,7 @@ Error: P1001: Can't reach database server at `rm-xxxxx.pg.rds.aliyuncs.com:5432`
# 添加你的本地公网 IP查询curl ipinfo.io
# 2. 测试连接
psql "postgresql://username:password@rm-xxxxx.pg.rds.aliyuncs.com:5432/ai_clinical"
psql "postgresql://username:password@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical"
# 如果能连上,再执行 npx prisma db pull
```
@@ -885,7 +885,7 @@ SERVICE_NAME=backend-service
```bash
# ⚠️ 使用 RDS 内网地址
DATABASE_URL=postgresql://username:password@rm-xxxxx.pg.rds.aliyuncs.com:5432/ai_clinical?connection_limit=18&pool_timeout=10
DATABASE_URL=postgresql://username:password@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical?connection_limit=18&pool_timeout=10
# 连接池配置(根据 RDS 规格调整)
DB_MAX_CONNECTIONS=400
@@ -903,7 +903,7 @@ MAX_INSTANCES=20
```bash
# 使用阿里云 OSS
STORAGE_TYPE=oss
OSS_REGION=oss-cn-hangzhou
OSS_REGION=oss-cn-beijing
OSS_BUCKET=clinical-research-files
OSS_ACCESS_KEY_ID=LTAI5t...
OSS_ACCESS_KEY_SECRET=xxx...
@@ -939,7 +939,7 @@ CLOSEAI_CLAUDE_BASE_URL=https://api.openai-proxy.org/anthropic
```bash
# ⚠️ 使用 ECS 内网 IP不要使用公网域名
DIFY_API_URL=http://172.16.0.20:80/v1
DIFY_API_URL=http://172.17.x.x:80/v1
DIFY_API_KEY=app-xxxxx
```
@@ -1079,7 +1079,7 @@ ls -lh ai_clinical_backup_*.sql
```bash
# 连接到 RDS 并导入
psql "postgresql://username:password@rm-xxxxx.pg.rds.aliyuncs.com:5432/ai_clinical" \
psql "postgresql://username:password@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical" \
< ai_clinical_backup_20251213.sql
# 输出示例:
@@ -1101,7 +1101,7 @@ psql "postgresql://username:password@rm-xxxxx.pg.rds.aliyuncs.com:5432/ai_clinic
```bash
# 连接到 RDS
psql "postgresql://username:password@rm-xxxxx.pg.rds.aliyuncs.com:5432/ai_clinical"
psql "postgresql://username:password@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical"
# 查看所有 Schema
\dn
@@ -1160,7 +1160,7 @@ ls -l prisma/schema.prisma
```bash
# 1. 连接到 RDS
export DATABASE_URL="postgresql://username:password@rm-xxxxx.pg.rds.aliyuncs.com:5432/ai_clinical"
export DATABASE_URL="postgresql://username:password@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical"
# 2. 执行迁移
cd backend
@@ -1319,7 +1319,7 @@ curl -X POST https://backend-service-xxxxx.cn-hangzhou.sae.aliyuncs.com/api/asl/
# 查看后端日志SAE 控制台 → 应用详情 → 日志)
# 应该看到:
# [INFO] Calling extraction service: http://172.16.0.10:8000/extract/pdf
# [INFO] Calling extraction service: http://172.17.x.x:8000/extract/pdf
# [INFO] Extraction completed in 3.2s
```
@@ -1337,7 +1337,7 @@ curl -X POST https://backend-service-xxxxx.cn-hangzhou.sae.aliyuncs.com/api/know
# 查看后端日志
# 应该看到:
# [INFO] Calling Dify API: http://172.16.0.20:80/v1/chat-messages
# [INFO] Calling Dify API: http://172.17.x.x:80/v1/chat-messages
# [INFO] Dify response received in 2.5s
```
@@ -1512,14 +1512,14 @@ SAE 控制台显示:实例启动中 → 健康检查失败 → 实例停止
# 解决:检查 SAE 环境变量配置,补充缺失的变量
# 错误 B数据库连接失败
# 日志:❌ 数据库连接失败: getaddrinfo ENOTFOUND rm-xxxxx.pg.rds.aliyuncs.com
# 日志:❌ 数据库连接失败: getaddrinfo ENOTFOUND pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com
# 解决:
# - 检查 DATABASE_URL 是否正确
# - 检查 RDS 白名单是否允许 SAE VPC 访问
# - 检查 RDS 内网地址是否可达
# 错误 CPrisma 迁移未执行
# 日志Error: P1001: Can't reach database server at `rm-xxxxx.pg.rds.aliyuncs.com`
# 日志Error: P1001: Can't reach database server at `pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com`
# 解决:先执行数据库迁移(参见第 8 节)
# 错误 D端口冲突
@@ -1607,7 +1607,7 @@ DATABASE_URL=postgresql://...?connection_limit=10&pool_timeout=10
```
[ERROR] Failed to connect to Python service: ECONNREFUSED
[ERROR] connect ETIMEDOUT 172.16.0.10:8000
[ERROR] connect ETIMEDOUT 172.17.x.x:8000
```
**排查步骤**
@@ -1622,7 +1622,7 @@ DATABASE_URL=postgresql://...?connection_limit=10&pool_timeout=10
# 3. 测试内网连通性
# 在后端应用的 Webshell 中执行:
curl -v http://172.16.0.10:8000/health
curl -v http://172.17.x.x:8000/health
# 4. 检查安全组规则
# SAE 控制台 → extraction-service 应用 → 网络配置
@@ -1666,7 +1666,7 @@ curl http://localhost/v1/info
# 3. 从 SAE 测试连通性
# 在后端应用的 Webshell 中执行:
curl -v http://172.16.0.20:80/v1/info
curl -v http://172.17.x.x:80/v1/info
```
**解决方法**
@@ -1700,7 +1700,7 @@ DIFY_API_URL=http://<ECS内网IP>:80/v1
# 1. 检查环境变量
# SAE 控制台 → 应用详情 → 环境变量
# 确认以下变量正确:
OSS_REGION=oss-cn-hangzhou
OSS_REGION=oss-cn-beijing
OSS_BUCKET=clinical-research-files
OSS_ACCESS_KEY_ID=LTAI5t...
OSS_ACCESS_KEY_SECRET=xxx...
@@ -1825,7 +1825,7 @@ PrismaClientKnownRequestError: column "phone" does not exist
```bash
# 1. 在本地开发环境,连接到 RDS
export DATABASE_URL="postgresql://username:password@rm-xxxxx.pg.rds.aliyuncs.com:5432/ai_clinical"
export DATABASE_URL="postgresql://username:password@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical"
# 2. 反向同步 Schema
npx prisma db pull
@@ -2006,7 +2006,7 @@ pg_dump → 导入 RDS → prisma db pull同步→ 构建镜像 → 部署
```typescript
// ❌ 错误示例
const dbUrl = 'postgresql://admin:P@ssw0rd@rm-xxxxx.pg.rds.aliyuncs.com:5432/ai_clinical';
const dbUrl = 'postgresql://admin:P@ssw0rd@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical';
// ✅ 正确做法
const dbUrl = process.env.DATABASE_URL;