init ana page with apis
This commit is contained in:
28
app/api/analytics/device-analysis/route.ts
Normal file
28
app/api/analytics/device-analysis/route.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getDeviceAnalysis } from '@/lib/analytics';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
// 获取请求参数
|
||||
const { searchParams } = new URL(request.url);
|
||||
const linkId = searchParams.get('linkId') || undefined;
|
||||
const startDate = searchParams.get('startDate') || undefined;
|
||||
const endDate = searchParams.get('endDate') || undefined;
|
||||
|
||||
// 获取设备分析详情
|
||||
const analysisData = await getDeviceAnalysis(
|
||||
startDate,
|
||||
endDate,
|
||||
linkId
|
||||
);
|
||||
|
||||
// 返回数据
|
||||
return NextResponse.json(analysisData);
|
||||
} catch (error) {
|
||||
console.error('Error in device-analysis API:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch device analysis data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
36
app/api/analytics/funnel/route.ts
Normal file
36
app/api/analytics/funnel/route.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getConversionFunnel } from '@/lib/analytics';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
// 获取请求参数
|
||||
const { searchParams } = new URL(request.url);
|
||||
const linkId = searchParams.get('linkId');
|
||||
const startDate = searchParams.get('startDate') || undefined;
|
||||
const endDate = searchParams.get('endDate') || undefined;
|
||||
|
||||
// 验证必要参数
|
||||
if (!linkId) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Missing required parameter: linkId' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// 获取转化漏斗数据
|
||||
const funnelData = await getConversionFunnel(
|
||||
linkId,
|
||||
startDate || undefined,
|
||||
endDate || undefined
|
||||
);
|
||||
|
||||
// 返回数据
|
||||
return NextResponse.json(funnelData);
|
||||
} catch (error) {
|
||||
console.error('Error in funnel API:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch funnel data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
36
app/api/analytics/link-performance/route.ts
Normal file
36
app/api/analytics/link-performance/route.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getLinkPerformance } from '@/lib/analytics';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
// 获取请求参数
|
||||
const { searchParams } = new URL(request.url);
|
||||
const linkId = searchParams.get('linkId');
|
||||
const startDate = searchParams.get('startDate') || undefined;
|
||||
const endDate = searchParams.get('endDate') || undefined;
|
||||
|
||||
// 验证必要参数
|
||||
if (!linkId) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Missing required parameter: linkId' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// 获取链接表现数据
|
||||
const performanceData = await getLinkPerformance(
|
||||
linkId,
|
||||
startDate || undefined,
|
||||
endDate || undefined
|
||||
);
|
||||
|
||||
// 返回数据
|
||||
return NextResponse.json(performanceData);
|
||||
} catch (error) {
|
||||
console.error('Error in link-performance API:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch link performance data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
28
app/api/analytics/link-status-distribution/route.ts
Normal file
28
app/api/analytics/link-status-distribution/route.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getLinkStatusDistribution } from '@/lib/analytics';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
// 获取请求参数
|
||||
const { searchParams } = new URL(request.url);
|
||||
const projectId = searchParams.get('projectId') || undefined;
|
||||
const startDate = searchParams.get('startDate') || undefined;
|
||||
const endDate = searchParams.get('endDate') || undefined;
|
||||
|
||||
// 获取链接状态分布数据
|
||||
const distributionData = await getLinkStatusDistribution(
|
||||
startDate,
|
||||
endDate,
|
||||
projectId
|
||||
);
|
||||
|
||||
// 返回数据
|
||||
return NextResponse.json(distributionData);
|
||||
} catch (error) {
|
||||
console.error('Error in link-status-distribution API:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch link status distribution data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
28
app/api/analytics/overview-cards/route.ts
Normal file
28
app/api/analytics/overview-cards/route.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getOverviewCards } from '@/lib/analytics';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
// 获取请求参数
|
||||
const { searchParams } = new URL(request.url);
|
||||
const projectId = searchParams.get('projectId') || undefined;
|
||||
const startDate = searchParams.get('startDate') || undefined;
|
||||
const endDate = searchParams.get('endDate') || undefined;
|
||||
|
||||
// 获取概览卡片数据
|
||||
const cardsData = await getOverviewCards(
|
||||
startDate,
|
||||
endDate,
|
||||
projectId
|
||||
);
|
||||
|
||||
// 返回数据
|
||||
return NextResponse.json(cardsData);
|
||||
} catch (error) {
|
||||
console.error('Error in overview-cards API:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch overview cards data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
36
app/api/analytics/overview/route.ts
Normal file
36
app/api/analytics/overview/route.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getLinkOverview } from '@/lib/analytics';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
// 获取请求参数
|
||||
const { searchParams } = new URL(request.url);
|
||||
const linkId = searchParams.get('linkId');
|
||||
const startDate = searchParams.get('startDate') || undefined;
|
||||
const endDate = searchParams.get('endDate') || undefined;
|
||||
|
||||
// 验证必要参数
|
||||
if (!linkId) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Missing required parameter: linkId' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// 获取链接概览数据
|
||||
const overviewData = await getLinkOverview(
|
||||
linkId,
|
||||
startDate || undefined,
|
||||
endDate || undefined
|
||||
);
|
||||
|
||||
// 返回数据
|
||||
return NextResponse.json(overviewData);
|
||||
} catch (error) {
|
||||
console.error('Error in overview API:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch overview data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
28
app/api/analytics/platform-distribution/route.ts
Normal file
28
app/api/analytics/platform-distribution/route.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getPlatformDistribution } from '@/lib/analytics';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
// 获取请求参数
|
||||
const { searchParams } = new URL(request.url);
|
||||
const linkId = searchParams.get('linkId') || undefined;
|
||||
const startDate = searchParams.get('startDate') || undefined;
|
||||
const endDate = searchParams.get('endDate') || undefined;
|
||||
|
||||
// 获取平台分布数据
|
||||
const distributionData = await getPlatformDistribution(
|
||||
startDate,
|
||||
endDate,
|
||||
linkId
|
||||
);
|
||||
|
||||
// 返回数据
|
||||
return NextResponse.json(distributionData);
|
||||
} catch (error) {
|
||||
console.error('Error in platform-distribution API:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch platform distribution data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
32
app/api/analytics/popular-links/route.ts
Normal file
32
app/api/analytics/popular-links/route.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getPopularLinks } from '@/lib/analytics';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
// 获取请求参数
|
||||
const { searchParams } = new URL(request.url);
|
||||
const projectId = searchParams.get('projectId') || undefined;
|
||||
const startDate = searchParams.get('startDate') || undefined;
|
||||
const endDate = searchParams.get('endDate') || undefined;
|
||||
const sortBy = searchParams.get('sortBy') as 'visits' | 'uniqueVisitors' | 'conversionRate' || 'visits';
|
||||
const limit = searchParams.get('limit') ? parseInt(searchParams.get('limit') as string, 10) : 10;
|
||||
|
||||
// 获取热门链接数据
|
||||
const linksData = await getPopularLinks(
|
||||
startDate,
|
||||
endDate,
|
||||
projectId,
|
||||
sortBy,
|
||||
limit
|
||||
);
|
||||
|
||||
// 返回数据
|
||||
return NextResponse.json(linksData);
|
||||
} catch (error) {
|
||||
console.error('Error in popular-links API:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch popular links data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
32
app/api/analytics/popular-referrers/route.ts
Normal file
32
app/api/analytics/popular-referrers/route.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getPopularReferrers } from '@/lib/analytics';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
// 获取请求参数
|
||||
const { searchParams } = new URL(request.url);
|
||||
const linkId = searchParams.get('linkId') || undefined;
|
||||
const startDate = searchParams.get('startDate') || undefined;
|
||||
const endDate = searchParams.get('endDate') || undefined;
|
||||
const type = searchParams.get('type') as 'domain' | 'full' || 'domain';
|
||||
const limit = searchParams.get('limit') ? parseInt(searchParams.get('limit') as string, 10) : 10;
|
||||
|
||||
// 获取热门引荐来源数据
|
||||
const referrersData = await getPopularReferrers(
|
||||
startDate,
|
||||
endDate,
|
||||
linkId,
|
||||
type,
|
||||
limit
|
||||
);
|
||||
|
||||
// 返回数据
|
||||
return NextResponse.json(referrersData);
|
||||
} catch (error) {
|
||||
console.error('Error in popular-referrers API:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch popular referrers data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
30
app/api/analytics/qr-code-analysis/route.ts
Normal file
30
app/api/analytics/qr-code-analysis/route.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getQrCodeAnalysis } from '@/lib/analytics';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
// 获取请求参数
|
||||
const { searchParams } = new URL(request.url);
|
||||
const linkId = searchParams.get('linkId') || undefined;
|
||||
const qrCodeId = searchParams.get('qrCodeId') || undefined;
|
||||
const startDate = searchParams.get('startDate') || undefined;
|
||||
const endDate = searchParams.get('endDate') || undefined;
|
||||
|
||||
// 获取QR码分析数据
|
||||
const analysisData = await getQrCodeAnalysis(
|
||||
startDate,
|
||||
endDate,
|
||||
linkId,
|
||||
qrCodeId
|
||||
);
|
||||
|
||||
// 返回数据
|
||||
return NextResponse.json(analysisData);
|
||||
} catch (error) {
|
||||
console.error('Error in qr-code-analysis API:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch QR code analysis data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
68
app/api/analytics/track/route.ts
Normal file
68
app/api/analytics/track/route.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { trackEvent, EventType, ConversionType } from '@/lib/analytics';
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
// 解析请求体
|
||||
const body = await request.json();
|
||||
|
||||
// 验证必要字段
|
||||
if (!body.linkId) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Missing required field: linkId' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (!body.eventType || !Object.values(EventType).includes(body.eventType)) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Invalid or missing eventType',
|
||||
validValues: Object.values(EventType)
|
||||
},
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// 验证转化类型(如果提供)
|
||||
if (
|
||||
body.conversionType &&
|
||||
!Object.values(ConversionType).includes(body.conversionType)
|
||||
) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Invalid conversionType',
|
||||
validValues: Object.values(ConversionType)
|
||||
},
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// 添加客户端IP
|
||||
const clientIp = request.headers.get('x-forwarded-for') ||
|
||||
request.headers.get('x-real-ip') ||
|
||||
'0.0.0.0';
|
||||
|
||||
// 添加用户代理
|
||||
const userAgent = request.headers.get('user-agent') || '';
|
||||
|
||||
// 合并数据
|
||||
const eventData = {
|
||||
...body,
|
||||
ipAddress: body.ipAddress || clientIp,
|
||||
userAgent: body.userAgent || userAgent,
|
||||
};
|
||||
|
||||
// 追踪事件
|
||||
const result = await trackEvent(eventData);
|
||||
|
||||
// 返回结果
|
||||
return NextResponse.json(result);
|
||||
} catch (error) {
|
||||
console.error('Error in track API:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to track event' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
50
app/api/analytics/trends/route.ts
Normal file
50
app/api/analytics/trends/route.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getVisitTrends, TimeGranularity } from '@/lib/analytics';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
// 获取请求参数
|
||||
const { searchParams } = new URL(request.url);
|
||||
const linkId = searchParams.get('linkId');
|
||||
const startDate = searchParams.get('startDate') || undefined;
|
||||
const endDate = searchParams.get('endDate') || undefined;
|
||||
const granularity = searchParams.get('granularity') as TimeGranularity || TimeGranularity.DAY;
|
||||
|
||||
// 验证必要参数
|
||||
if (!linkId) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Missing required parameter: linkId' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// 验证粒度参数
|
||||
const validGranularities = Object.values(TimeGranularity);
|
||||
if (granularity && !validGranularities.includes(granularity)) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Invalid granularity value',
|
||||
validValues: validGranularities
|
||||
},
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// 获取访问趋势数据
|
||||
const trendsData = await getVisitTrends(
|
||||
linkId,
|
||||
startDate || undefined,
|
||||
endDate || undefined,
|
||||
granularity
|
||||
);
|
||||
|
||||
// 返回数据
|
||||
return NextResponse.json(trendsData);
|
||||
} catch (error) {
|
||||
console.error('Error in trends API:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch trends data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user