import { NextRequest, NextResponse } from 'next/server'; import clickhouse from '@/lib/clickhouse'; import type { ApiResponse } from '@/lib/types'; interface UtmData { utm_value: string; clicks: number; visitors: number; avg_time_spent: number; bounces: number; conversions: number; } // 格式化日期时间字符串为ClickHouse支持的格式 const formatDateTime = (dateStr: string): string => { return dateStr.replace('T', ' ').replace('Z', ''); }; export async function GET(request: NextRequest) { try { const searchParams = request.nextUrl.searchParams; // 获取过滤参数 const startTime = searchParams.get('startTime'); const endTime = searchParams.get('endTime'); const linkId = searchParams.get('linkId'); // 获取UTM类型参数 const utmType = searchParams.get('utmType') || 'source'; // 构建WHERE子句 let whereClause = ''; const conditions = []; if (startTime) { conditions.push(`event_time >= toDateTime('${formatDateTime(startTime)}')`); } if (endTime) { conditions.push(`event_time <= toDateTime('${formatDateTime(endTime)}')`); } if (linkId) { conditions.push(`link_id = '${linkId}'`); } if (conditions.length > 0) { whereClause = `WHERE ${conditions.join(' AND ')}`; } // 确定要分组的UTM字段 let utmField; switch (utmType) { case 'source': utmField = 'utm_source'; break; case 'medium': utmField = 'utm_medium'; break; case 'campaign': utmField = 'utm_campaign'; break; case 'term': utmField = 'utm_term'; break; case 'content': utmField = 'utm_content'; break; default: utmField = 'utm_source'; } // 构建SQL查询 const query = ` SELECT ${utmField} AS utm_value, COUNT(*) AS clicks, uniqExact(visitor_id) AS visitors, round(AVG(time_spent_sec), 2) AS avg_time_spent, countIf(is_bounce = 1) AS bounces, countIf(conversion_type IN ('visit', 'stay', 'interact', 'signup', 'subscription', 'purchase')) AS conversions FROM shorturl_analytics.events ${whereClause} ${whereClause ? 'AND' : 'WHERE'} ${utmField} != '' GROUP BY utm_value ORDER BY clicks DESC LIMIT 100 `; // 执行查询 const result = await clickhouse.query({ query, format: 'JSONEachRow', }); // 获取查询结果 const rows = await result.json(); const data = rows as UtmData[]; // 返回数据 const response: ApiResponse = { success: true, data }; return NextResponse.json(response); } catch (error) { console.error('Error fetching UTM data:', error); const response: ApiResponse = { success: false, error: error instanceof Error ? error.message : 'Unknown error occurred' }; return NextResponse.json(response, { status: 500 }); } }