70 lines
3.1 KiB
TypeScript
70 lines
3.1 KiB
TypeScript
"use client";
|
|
|
|
import { GeoData } from '../../api/types';
|
|
|
|
interface GeoAnalyticsProps {
|
|
data: GeoData[];
|
|
}
|
|
|
|
export default function GeoAnalytics({ data }: GeoAnalyticsProps) {
|
|
// 安全地格式化数字
|
|
const formatNumber = (value: any): string => {
|
|
if (value === undefined || value === null) return '0';
|
|
return typeof value === 'number' ? value.toLocaleString() : String(value);
|
|
};
|
|
|
|
// 安全地格式化百分比
|
|
const formatPercent = (value: any): string => {
|
|
if (value === undefined || value === null) return '0';
|
|
return typeof value === 'number' ? value.toFixed(2) : String(value);
|
|
};
|
|
|
|
return (
|
|
<div className="overflow-x-auto">
|
|
<table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
<thead className="bg-gray-50 dark:bg-gray-800">
|
|
<tr>
|
|
<th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
Location
|
|
</th>
|
|
<th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
Visits
|
|
</th>
|
|
<th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
Unique Visitors
|
|
</th>
|
|
<th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
Percentage
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700">
|
|
{data.map((item, index) => (
|
|
<tr key={index} className={index % 2 === 0 ? 'bg-white dark:bg-gray-900' : 'bg-gray-50 dark:bg-gray-800'}>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
|
|
{item.city ? `${item.city}, ${item.region}, ${item.country}` : item.region ? `${item.region}, ${item.country}` : item.country || item.location || 'Unknown'}
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
|
|
{formatNumber(item.visits)}
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
|
|
{formatNumber(item.uniqueVisitors || item.visitors)}
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
|
|
<div className="flex items-center">
|
|
<span className="mr-2">{formatPercent(item.percentage)}%</span>
|
|
<div className="w-24 bg-gray-200 dark:bg-gray-700 rounded-full h-2">
|
|
<div
|
|
className="bg-blue-500 h-2 rounded-full"
|
|
style={{ width: `${item.percentage || 0}%` }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
);
|
|
}
|