diff --git a/app/(app)/analytics/page.tsx b/app/(app)/analytics/page.tsx index cfec1bc..d6dc856 100644 --- a/app/(app)/analytics/page.tsx +++ b/app/(app)/analytics/page.tsx @@ -112,9 +112,9 @@ export default function AnalyticsPage() { Tag Analytics ({selectedTagIds.length} selected)
- {selectedTagIds.map((tagId) => ( -
-

Tag ID: {tagId}

+ {selectedTagIds.map((tagName) => ( +
+

Tag: {tagName}

Tag analytics will appear here

))} diff --git a/app/api/events/route.ts b/app/api/events/route.ts index 6a43d03..b1a1013 100644 --- a/app/api/events/route.ts +++ b/app/api/events/route.ts @@ -1,50 +1,70 @@ import { NextRequest, NextResponse } from 'next/server'; -import type { ApiResponse, EventsQueryParams, EventType } from '@/lib/types'; -import { - getEvents, - getEventsSummary, - getTimeSeriesData, - getGeoAnalytics, - getDeviceAnalytics -} from '@/lib/analytics'; +import { getEvents, EventsQueryParams } from '@/lib/analytics'; +import { ApiResponse } from '@/lib/types'; // 获取事件列表 export async function GET(request: NextRequest) { try { - const searchParams = request.nextUrl.searchParams; + const { searchParams } = new URL(request.url); + // 获取查询参数 + const page = parseInt(searchParams.get('page') || '1'); + const pageSize = parseInt(searchParams.get('pageSize') || '20'); + const eventType = searchParams.get('eventType') || undefined; + const linkId = searchParams.get('linkId') || undefined; + const linkSlug = searchParams.get('linkSlug') || undefined; + const userId = searchParams.get('userId') || undefined; + + // 获取可能存在的多个团队、项目和标签ID + const teamIds = searchParams.getAll('teamId'); + const projectIds = searchParams.getAll('projectId'); + const tagIds = searchParams.getAll('tagId'); + + const startTime = searchParams.get('startTime') || undefined; + const endTime = searchParams.get('endTime') || undefined; + const sortBy = searchParams.get('sortBy') || undefined; + const sortOrder = (searchParams.get('sortOrder') as 'asc' | 'desc') || undefined; + + console.log("API接收到的tagIds:", tagIds); // 添加日志便于调试 + + // 获取事件列表 const params: EventsQueryParams = { - startTime: searchParams.get('startTime') || undefined, - endTime: searchParams.get('endTime') || undefined, - eventType: searchParams.get('eventType') as EventType || undefined, - linkId: searchParams.get('linkId') || undefined, - linkSlug: searchParams.get('linkSlug') || undefined, - userId: searchParams.get('userId') || undefined, - teamId: searchParams.get('teamId') || undefined, - projectId: searchParams.get('projectId') || undefined, - page: searchParams.has('page') ? parseInt(searchParams.get('page')!, 10) : 1, - pageSize: searchParams.has('pageSize') ? parseInt(searchParams.get('pageSize')!, 10) : 20, - sortBy: searchParams.get('sortBy') || undefined, - sortOrder: (searchParams.get('sortOrder') as 'asc' | 'desc') || undefined + page, + pageSize, + eventType, + linkId, + linkSlug, + userId, + teamId: teamIds.length > 0 ? teamIds[0] : undefined, + teamIds: teamIds.length > 1 ? teamIds : undefined, + projectId: projectIds.length > 0 ? projectIds[0] : undefined, + projectIds: projectIds.length > 1 ? projectIds : undefined, + tagIds: tagIds.length > 0 ? tagIds : undefined, + startTime, + endTime, + sortBy, + sortOrder }; - - const { events, total } = await getEvents(params); - - const response: ApiResponse = { + + const result = await getEvents(params); + + const response: ApiResponse = { success: true, - data: events, + data: result.events, meta: { - total, - page: params.page, - pageSize: params.pageSize + total: result.total, + page, + pageSize } }; - + return NextResponse.json(response); } catch (error) { + console.error('获取事件列表失败:', error); const response: ApiResponse = { success: false, - error: error instanceof Error ? error.message : 'Unknown error occurred' + data: null, + error: error instanceof Error ? error.message : '获取事件列表失败' }; return NextResponse.json(response, { status: 500 }); } diff --git a/app/components/ui/TagSelector.tsx b/app/components/ui/TagSelector.tsx index bc95d3b..754a1bc 100644 --- a/app/components/ui/TagSelector.tsx +++ b/app/components/ui/TagSelector.tsx @@ -46,18 +46,47 @@ export function TagSelector({ const [isOpen, setIsOpen] = useState(false); const selectorRef = useRef(null); - // Initialize selected tags based on value prop - useEffect(() => { - if (value) { - if (Array.isArray(value)) { - setSelectedIds(value); - } else { - setSelectedIds(value ? [value] : []); - } - } else { - setSelectedIds([]); + // 标签名称与ID的映射函数 + const getTagIdByName = (name: string): string | undefined => { + const tag = tags.find(t => t.name === name); + return tag?.id; + }; + + const getTagNameById = (id: string): string | undefined => { + const tag = tags.find(t => t.id === id); + return tag?.name; + }; + + // 从标签名称转换为标签ID + const nameToId = (nameOrNames: string | string[] | undefined): string[] => { + if (!nameOrNames) return []; + if (Array.isArray(nameOrNames)) { + return nameOrNames + .map(name => getTagIdByName(name)) + .filter((id): id is string => !!id); } - }, [value]); + const id = getTagIdByName(nameOrNames); + return id ? [id] : []; + }; + + // 从标签ID转换为标签名称 + const idToName = (idOrIds: string | string[] | undefined): string[] => { + if (!idOrIds) return []; + if (Array.isArray(idOrIds)) { + return idOrIds + .map(id => getTagNameById(id)) + .filter((name): name is string => !!name); + } + const name = getTagNameById(idOrIds); + return name ? [name] : []; + }; + + // 初始化已选择的标签 - 从传入的名称转换为ID + useEffect(() => { + if (tags.length > 0 && value) { + setSelectedIds(nameToId(value)); + } + }, [value, tags]); // Add click outside listener to close dropdown useEffect(() => { @@ -167,8 +196,10 @@ export function TagSelector({ setSelectedIds(newSelected); + // 传递标签名称而不是ID if (onChange) { - onChange(multiple ? newSelected : newSelected[0] || ''); + const tagNames = idToName(newSelected); + onChange(multiple ? tagNames : tagNames[0] || ''); } }; @@ -176,8 +207,11 @@ export function TagSelector({ e.stopPropagation(); const newSelected = selectedIds.filter(id => id !== tagId); setSelectedIds(newSelected); + + // 传递标签名称而不是ID if (onChange) { - onChange(multiple ? newSelected : newSelected[0] || ''); + const tagNames = idToName(newSelected); + onChange(multiple ? tagNames : tagNames[0] || ''); } }; @@ -214,6 +248,7 @@ export function TagSelector({ ); } + // 根据已选择的ID筛选出已选择的标签 const selectedTags = tags.filter(tag => selectedIds.includes(tag.id)); return ( diff --git a/app/page.tsx b/app/page.tsx index feb94e5..9c69539 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -322,11 +322,11 @@ export default function HomePage() { {selectedTagIds.length === 1 ? 'Tag filter:' : 'Tags filter:'}
- {selectedTagIds.map(tagId => ( - - {tagId} + {selectedTagIds.map(tagName => ( + + {tagName}