front
This commit is contained in:
120
lib/analytics.ts
120
lib/analytics.ts
@@ -91,57 +91,71 @@ export async function getEventsSummary(params: {
|
||||
ORDER BY count DESC
|
||||
`;
|
||||
|
||||
const [baseResult, browserResults, osResults] = await Promise.all([
|
||||
executeQuerySingle<{
|
||||
totalEvents: number;
|
||||
uniqueVisitors: number;
|
||||
totalConversions: number;
|
||||
averageTimeSpent: number;
|
||||
mobileCount: number;
|
||||
desktopCount: number;
|
||||
tabletCount: number;
|
||||
otherCount: number;
|
||||
}>(baseQuery),
|
||||
executeQuery<{ name: string; count: number }>(browserQuery),
|
||||
executeQuery<{ name: string; count: number }>(osQuery)
|
||||
]);
|
||||
|
||||
if (!baseResult) {
|
||||
throw new Error('Failed to get events summary');
|
||||
try {
|
||||
const [baseResult, browserResults, osResults] = await Promise.all([
|
||||
executeQuerySingle<{
|
||||
totalEvents: number;
|
||||
uniqueVisitors: number;
|
||||
totalConversions: number;
|
||||
averageTimeSpent: number;
|
||||
mobileCount: number;
|
||||
desktopCount: number;
|
||||
tabletCount: number;
|
||||
otherCount: number;
|
||||
}>(baseQuery),
|
||||
executeQuery<{ name: string; count: number }>(browserQuery),
|
||||
executeQuery<{ name: string; count: number }>(osQuery)
|
||||
]);
|
||||
|
||||
if (!baseResult) {
|
||||
throw new Error('Failed to get events summary');
|
||||
}
|
||||
|
||||
// 安全转换数字类型
|
||||
const safeNumber = (value: any): number => {
|
||||
if (value === null || value === undefined) return 0;
|
||||
const num = Number(value);
|
||||
return isNaN(num) ? 0 : num;
|
||||
};
|
||||
|
||||
// 计算百分比
|
||||
const calculatePercentage = (count: number, total: number) => {
|
||||
if (!total) return 0; // 防止除以零
|
||||
return Number(((count / total) * 100).toFixed(2));
|
||||
};
|
||||
|
||||
// 处理浏览器数据
|
||||
const browsers = browserResults.map(item => ({
|
||||
name: item.name || 'Unknown',
|
||||
count: safeNumber(item.count),
|
||||
percentage: calculatePercentage(safeNumber(item.count), safeNumber(baseResult.totalEvents))
|
||||
}));
|
||||
|
||||
// 处理操作系统数据
|
||||
const operatingSystems = osResults.map(item => ({
|
||||
name: item.name || 'Unknown',
|
||||
count: safeNumber(item.count),
|
||||
percentage: calculatePercentage(safeNumber(item.count), safeNumber(baseResult.totalEvents))
|
||||
}));
|
||||
|
||||
return {
|
||||
totalEvents: safeNumber(baseResult.totalEvents),
|
||||
uniqueVisitors: safeNumber(baseResult.uniqueVisitors),
|
||||
totalConversions: safeNumber(baseResult.totalConversions),
|
||||
averageTimeSpent: baseResult.averageTimeSpent ? Number(baseResult.averageTimeSpent.toFixed(2)) : 0,
|
||||
deviceTypes: {
|
||||
mobile: safeNumber(baseResult.mobileCount),
|
||||
desktop: safeNumber(baseResult.desktopCount),
|
||||
tablet: safeNumber(baseResult.tabletCount),
|
||||
other: safeNumber(baseResult.otherCount)
|
||||
},
|
||||
browsers,
|
||||
operatingSystems
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error in getEventsSummary:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
// 计算百分比
|
||||
const calculatePercentage = (count: number, total: number) =>
|
||||
Number(((count / total) * 100).toFixed(2));
|
||||
|
||||
// 处理浏览器数据
|
||||
const browsers = browserResults.map(item => ({
|
||||
name: item.name,
|
||||
count: item.count,
|
||||
percentage: calculatePercentage(item.count, baseResult.totalEvents)
|
||||
}));
|
||||
|
||||
// 处理操作系统数据
|
||||
const operatingSystems = osResults.map(item => ({
|
||||
name: item.name,
|
||||
count: item.count,
|
||||
percentage: calculatePercentage(item.count, baseResult.totalEvents)
|
||||
}));
|
||||
|
||||
return {
|
||||
totalEvents: baseResult.totalEvents,
|
||||
uniqueVisitors: baseResult.uniqueVisitors,
|
||||
totalConversions: baseResult.totalConversions,
|
||||
averageTimeSpent: Number(baseResult.averageTimeSpent.toFixed(2)),
|
||||
deviceTypes: {
|
||||
mobile: baseResult.mobileCount,
|
||||
desktop: baseResult.desktopCount,
|
||||
tablet: baseResult.tabletCount,
|
||||
other: baseResult.otherCount
|
||||
},
|
||||
browsers,
|
||||
operatingSystems
|
||||
};
|
||||
}
|
||||
|
||||
// 获取时间序列数据
|
||||
@@ -263,8 +277,10 @@ export async function getDeviceAnalytics(params: {
|
||||
}
|
||||
|
||||
// 计算百分比
|
||||
const calculatePercentage = (count: number) =>
|
||||
Number(((count / totalResult.total) * 100).toFixed(2));
|
||||
const calculatePercentage = (count: number) => {
|
||||
if (!totalResult || totalResult.total === 0) return 0;
|
||||
return Number(((count / totalResult.total) * 100).toFixed(2));
|
||||
};
|
||||
|
||||
return {
|
||||
deviceTypes: deviceTypes.map(item => ({
|
||||
|
||||
@@ -3,10 +3,10 @@ import type { EventsQueryParams } from './types';
|
||||
|
||||
// ClickHouse 客户端配置
|
||||
const clickhouse = createClient({
|
||||
url: process.env.CLICKHOUSE_URL || 'http://localhost:8123',
|
||||
username: process.env.CLICKHOUSE_USER || 'admin',
|
||||
password: process.env.CLICKHOUSE_PASSWORD || 'your_secure_password',
|
||||
database: process.env.CLICKHOUSE_DB || 'shorturl_analytics'
|
||||
url: process.env.CLICKHOUSE_URL,
|
||||
username: process.env.CLICKHOUSE_USER ,
|
||||
password: process.env.CLICKHOUSE_PASSWORD ,
|
||||
database: process.env.CLICKHOUSE_DATABASE
|
||||
});
|
||||
|
||||
// 构建日期过滤条件
|
||||
|
||||
Reference in New Issue
Block a user