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'); const subpath = searchParams.get('subpath'); // 获取团队、项目和标签筛选参数 const teamIds = searchParams.getAll('teamId'); const projectIds = searchParams.getAll('projectId'); const tagIds = searchParams.getAll('tagId'); const tagNames = searchParams.getAll('tagName'); // 获取UTM类型参数 const utmType = searchParams.get('utmType') || 'source'; // 添加调试日志 console.log('UTM API received parameters:', { startTime, endTime, linkId, subpath, teamIds, projectIds, tagIds, tagNames, utmType, url: request.url }); // 构建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 (subpath) { conditions.push(`positionCaseInsensitive(url, '/${subpath}') > 0`); } // 添加团队筛选 if (teamIds && teamIds.length > 0) { // 如果只有一个团队ID if (teamIds.length === 1) { conditions.push(`team_id = '${teamIds[0]}'`); } else { // 多个团队ID conditions.push(`team_id IN ('${teamIds.join("','")}')`); } } // 添加项目筛选 if (projectIds && projectIds.length > 0) { // 如果只有一个项目ID if (projectIds.length === 1) { conditions.push(`project_id = '${projectIds[0]}'`); } else { // 多个项目ID conditions.push(`project_id IN ('${projectIds.join("','")}')`); } } // 添加标签筛选 if ((tagIds && tagIds.length > 0) || (tagNames && tagNames.length > 0)) { // 优先使用tagNames,如果有的话 const tagsToUse = tagNames.length > 0 ? tagNames : tagIds; // 使用与buildFilter函数相同的处理方式 const tagConditions = tagsToUse.map(tag => `link_tags LIKE '%${tag}%'` ); conditions.push(`(${tagConditions.join(' OR ')})`); } 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 }); } }