import { NextRequest, NextResponse } from 'next/server' import { getMongoClient } from '@/lib/mongodb' // 获取所有数据库结构 async function getDatabaseStructure() { const client = await getMongoClient() const admin = client.db().admin() // 获取数据库列表 const dbList = await admin.listDatabases() const krDatabases = dbList.databases.filter(db => db.name.startsWith('KR')) const structure = [] for (const dbInfo of krDatabases.slice(0, 10)) { // 限制前10个 try { const db = client.db(dbInfo.name) const collections = await db.listCollections().toArray() // 获取每个集合的字段示例 const collectionDetails = [] for (const col of collections.slice(0, 5)) { // 每个库最多5个集合 try { const sample = await db.collection(col.name).findOne() const fields = sample ? Object.keys(sample).filter(k => k !== '_id').slice(0, 10) : [] const count = await db.collection(col.name).estimatedDocumentCount() collectionDetails.push({ name: col.name, fields, count }) } catch { // 忽略错误 } } structure.push({ database: dbInfo.name, sizeGB: (dbInfo.sizeOnDisk / 1024 / 1024 / 1024).toFixed(2), collections: collectionDetails }) } catch { // 忽略错误 } } return structure } // 生成血缘节点 function generateLineageNodes(structure: any[]) { const nodes: any[] = [] const connections: any[] = [] let yOffset = 50 // 数据源节点 (左侧) const colors = [ 'from-blue-400 to-blue-600', 'from-orange-400 to-orange-600', 'from-green-400 to-green-600', 'from-red-400 to-red-600', 'from-purple-400 to-purple-600', ] structure.forEach((db, i) => { const mainCol = db.collections[0] if (!mainCol) return nodes.push({ id: `source_${db.database}`, type: 'source', name: db.database.replace('KR_', ''), database: db.database, collection: mainCol.name, fields: mainCol.fields.slice(0, 5), x: 50, y: yOffset, color: colors[i % colors.length], count: mainCol.count, sizeGB: db.sizeGB }) yOffset += 140 }) // AI引擎节点 (中间) nodes.push({ id: 'transform_ai', type: 'transform', name: 'AI标签引擎', fields: ['phone_norm', 'qq_norm', 'rfm_score', 'user_level', 'tags'], x: 400, y: 150, color: 'from-violet-400 to-violet-600' }) nodes.push({ id: 'transform_clean', type: 'transform', name: '数据清洗', fields: ['unique_id', 'merged_data', 'quality'], x: 400, y: 350, color: 'from-yellow-400 to-yellow-600' }) // 目标节点 (右侧) nodes.push({ id: 'target_valuation', type: 'target', name: '用户估值', database: 'KR', collection: '用户估值', fields: ['phone', 'qq', 'rfm_score', 'user_level', 'tags'], x: 750, y: 200, color: 'from-emerald-400 to-emerald-600' }) nodes.push({ id: 'target_portrait', type: 'target', name: '用户画像', database: 'KR', collection: '用户画像', fields: ['user_id', 'portrait', 'behavior'], x: 750, y: 400, color: 'from-cyan-400 to-cyan-600' }) // 自动生成连接 structure.forEach(db => { const sourceId = `source_${db.database}` const mainCol = db.collections[0] if (!mainCol) return // 连接到AI引擎 if (mainCol.fields.includes('phone') || mainCol.fields.includes('手机')) { connections.push({ id: `conn_${sourceId}_phone`, sourceNode: sourceId, sourceField: mainCol.fields.includes('phone') ? 'phone' : '手机', targetNode: 'transform_ai', targetField: 'phone_norm' }) } if (mainCol.fields.includes('qq') || mainCol.fields.includes('QQ')) { connections.push({ id: `conn_${sourceId}_qq`, sourceNode: sourceId, sourceField: mainCol.fields.includes('qq') ? 'qq' : 'QQ', targetNode: 'transform_ai', targetField: 'qq_norm' }) } }) // AI引擎到目标 connections.push({ id: 'conn_ai_valuation', sourceNode: 'transform_ai', sourceField: 'rfm_score', targetNode: 'target_valuation', targetField: 'rfm_score' }) connections.push({ id: 'conn_clean_portrait', sourceNode: 'transform_clean', sourceField: 'merged_data', targetNode: 'target_portrait', targetField: 'portrait' }) return { nodes, connections } } export async function GET(request: NextRequest) { const { searchParams } = new URL(request.url) const action = searchParams.get('action') || 'structure' try { const structure = await getDatabaseStructure() if (action === 'lineage') { const lineage = generateLineageNodes(structure) return NextResponse.json({ success: true, ...lineage }) } return NextResponse.json({ success: true, databases: structure }) } catch (error) { console.error('数据库结构查询失败:', error) return NextResponse.json({ error: '查询失败' }, { status: 500 }) } }