From b8cd3716c47ed2e0c2e99e29f6a25192d8f449aa Mon Sep 17 00:00:00 2001 From: William Tso Date: Thu, 10 Apr 2025 18:07:10 +0800 Subject: [PATCH] click subpath --- app/analytics/page.tsx | 16 ++++++++++-- app/api/events/route.ts | 6 +++++ app/api/events/utm/route.ts | 29 ++++++++++++++++++---- app/components/analytics/PathAnalytics.tsx | 6 +++++ lib/clickhouse.ts | 21 +++++++++++++--- 5 files changed, 68 insertions(+), 10 deletions(-) diff --git a/app/analytics/page.tsx b/app/analytics/page.tsx index b8f90fe..e791a51 100644 --- a/app/analytics/page.tsx +++ b/app/analytics/page.tsx @@ -481,8 +481,20 @@ function AnalyticsContent() { // 处理子路径点击 const handlePathClick = (path: string) => { - console.log('Path clicked:', path); - setSelectedSubpath(path); + console.log('====== ANALYTICS PAGE PATH DEBUG ======'); + console.log('Original path:', path); + + // 从路径中提取 subpath 部分,移除前导斜杠 + // 示例:如果路径是 "/slug/subpath",我们需要提取 "subpath" 部分 + // 或者直接使用原始路径,取决于您的路径结构 + const pathParts = path.split('/').filter(Boolean); + // 如果路径包含多个部分,获取第二部分(subpath) + const subpath = pathParts.length > 1 ? pathParts[1] : path; + + console.log('Extracted subpath:', subpath); + console.log('====================================='); + + setSelectedSubpath(subpath); // 重置到第一页 setCurrentPage(1); }; diff --git a/app/api/events/route.ts b/app/api/events/route.ts index cee45d4..d9ded44 100644 --- a/app/api/events/route.ts +++ b/app/api/events/route.ts @@ -14,6 +14,7 @@ export async function GET(request: NextRequest) { const linkId = searchParams.get('linkId') || undefined; const linkSlug = searchParams.get('linkSlug') || undefined; const userId = searchParams.get('userId') || undefined; + const subpath = searchParams.get('subpath') || undefined; // 获取可能存在的多个团队、项目和标签ID const teamIds = searchParams.getAll('teamId'); @@ -26,6 +27,7 @@ export async function GET(request: NextRequest) { const sortOrder = (searchParams.get('sortOrder') as 'asc' | 'desc') || undefined; console.log("API接收到的tagIds:", tagIds); // 添加日志便于调试 + console.log("API接收到的subpath:", subpath); // 添加日志便于调试 // 获取事件列表 const params: EventsQueryParams = { @@ -35,6 +37,7 @@ export async function GET(request: NextRequest) { linkId, linkSlug, userId, + subpath, teamIds: teamIds.length > 0 ? teamIds : undefined, projectIds: projectIds.length > 0 ? projectIds : undefined, tagIds: tagIds.length > 0 ? tagIds : undefined, @@ -44,6 +47,9 @@ export async function GET(request: NextRequest) { sortOrder }; + // 记录完整的参数用于调试 + console.log("完整请求参数:", JSON.stringify(params)); + const result = await getEvents(params); const response: ApiResponse = { diff --git a/app/api/events/utm/route.ts b/app/api/events/utm/route.ts index daa0faf..aa1cd51 100644 --- a/app/api/events/utm/route.ts +++ b/app/api/events/utm/route.ts @@ -11,10 +11,11 @@ interface UtmData { conversions: number; } -// 格式化日期时间字符串为ClickHouse支持的格式 -const formatDateTime = (dateStr: string): string => { - return dateStr.replace('T', ' ').replace('Z', ''); -}; +// 辅助函数,将日期格式化为标准格式 +function formatDateTime(dateString: string): string { + const date = new Date(dateString); + return date.toISOString().split('.')[0]; +} export async function GET(request: NextRequest) { try { @@ -67,7 +68,25 @@ export async function GET(request: NextRequest) { // 添加子路径筛选 if (subpath) { - conditions.push(`positionCaseInsensitive(url, '/${subpath}') > 0`); + console.log('====== UTM API SUBPATH DEBUG ======'); + console.log('Raw subpath param:', subpath); + console.log('Subpath type:', typeof subpath); + console.log('Subpath length:', subpath.length); + console.log('Subpath chars:', Array.from(subpath).map(c => c.charCodeAt(0))); + + // 确保没有前导斜杠,避免双斜杠问题 + const cleanSubpath = subpath.startsWith('/') + ? subpath.substring(1) + : subpath; + + console.log('Cleaned subpath:', cleanSubpath); + + // 在event_attributes JSON的full_url字段中查找subpath + const condition = `JSONExtractString(event_attributes, 'full_url') LIKE '%${cleanSubpath}%'`; + console.log('Final SQL condition:', condition); + console.log('=================================='); + + conditions.push(condition); } // 添加团队筛选 diff --git a/app/components/analytics/PathAnalytics.tsx b/app/components/analytics/PathAnalytics.tsx index 379fc38..23ac39b 100644 --- a/app/components/analytics/PathAnalytics.tsx +++ b/app/components/analytics/PathAnalytics.tsx @@ -86,6 +86,12 @@ const PathAnalytics: React.FC = ({ startTime, endTime, linkI const handlePathClick = (path: string, e: React.MouseEvent) => { e.preventDefault(); + console.log('====== PATH CLICK DEBUG ======'); + console.log('Path value:', path); + console.log('Path type:', typeof path); + console.log('Path length:', path.length); + console.log('Path chars:', Array.from(path).map(c => c.charCodeAt(0))); + console.log('=============================='); if (onPathClick) { onPathClick(path); } diff --git a/lib/clickhouse.ts b/lib/clickhouse.ts index c057d08..1ff5e1b 100644 --- a/lib/clickhouse.ts +++ b/lib/clickhouse.ts @@ -60,9 +60,24 @@ export function buildFilter(params: Partial): string { // 添加子路径过滤条件 if (params.subpath) { - console.log('Adding subpath filter:', params.subpath); - // 使用 url 字段和字符串函数替代不存在的 path 字段 - filters.push(`positionCaseInsensitive(url, '/${params.subpath}') > 0`); + console.log('====== SUBPATH DEBUG ======'); + console.log('Raw subpath param:', params.subpath); + console.log('Subpath type:', typeof params.subpath); + console.log('Subpath length:', params.subpath.length); + + // 确保子路径没有前导斜杠,避免双斜杠问题 + const cleanSubpath = params.subpath.startsWith('/') + ? params.subpath.substring(1) + : params.subpath; + + console.log('Cleaned subpath:', cleanSubpath); + + // 在event_attributes JSON的full_url字段中查找subpath + const condition = `JSONExtractString(event_attributes, 'full_url') LIKE '%${cleanSubpath}%'`; + console.log('Final SQL condition:', condition); + console.log('=========================='); + + filters.push(condition); } // 添加团队ID过滤条件