fix(frontend): keep browser API on same-origin rewrites in dev

Document that NEXT_PUBLIC_WAVELET_BACKEND_URL must stay unset for local
next dev so axios hits /api/* and Next rewrites proxy to the backend.
This commit is contained in:
ryan
2026-07-24 16:37:24 +08:00
parent a4588b05e0
commit 9f15f42b47
75 changed files with 5971 additions and 2450 deletions
@@ -28,6 +28,7 @@ import {
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts';
import services from '@/lib/services';
import { useTranslations } from 'next-intl';
import { ErrorInline } from '@/components/layout/error';
import { LoadingStateWithBorder } from '@/components/layout/loading';
import { EmptyStateWithBorder } from '@/components/layout/empty';
@@ -83,6 +84,7 @@ function formatDateLabel(dateStr: string) {
}
export function AccessAnalytics() {
const t = useTranslations('admin.logs.analytics');
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
const [clickhouseDisabled, setClickhouseDisabled] = useState(false);
@@ -135,11 +137,9 @@ export function AccessAnalytics() {
return (
<div className='flex flex-col items-center justify-center p-8 border border-dashed rounded-lg bg-card text-center my-6 min-h-[300px]'>
<XCircle className='size-10 text-muted-foreground mb-3' />
<h3 className='text-base font-semibold'>ClickHouse 未启用</h3>
<h3 className='text-base font-semibold'>{t('clickhouseDisabled')}</h3>
<p className='text-sm text-muted-foreground mt-1 max-w-[400px] mb-4'>
当前系统配置未启用 ClickHouse
存储,系统不会收集用户访问日志。如需使用此功能,请在后端 `config.yaml`
配置文件中配置并启用 ClickHouse。
{t('clickhouseDisabledDesc')}
</p>
</div>
);
@@ -153,7 +153,7 @@ export function AccessAnalytics() {
return (
<LoadingStateWithBorder
icon={BarChart3}
description='加载访问统计指标中...'
description={t('loadingAnalytics')}
/>
);
}
@@ -165,7 +165,7 @@ export function AccessAnalytics() {
<Card className='bg-card/25 border-border/40'>
<CardHeader className='flex flex-row items-center justify-between pb-2 space-y-0'>
<CardTitle className='text-sm font-semibold tracking-tight'>
近 7 天总请求数
{t('totalRequests7d')}
</CardTitle>
<TrendingUp className='size-4 text-muted-foreground' />
</CardHeader>
@@ -174,14 +174,14 @@ export function AccessAnalytics() {
{totalTrendRequests.toLocaleString()}
</div>
<p className='text-[10px] text-muted-foreground mt-1'>
系统记录的所有成功认证的访问总频次
{t('totalRequests7dDesc')}
</p>
</CardContent>
</Card>
<Card className='bg-card/25 border-border/40'>
<CardHeader className='flex flex-row items-center justify-between pb-2 space-y-0'>
<CardTitle className='text-sm font-semibold tracking-tight'>
活跃终端分类数
{t('activeBrowserTypes')}
</CardTitle>
<Globe className='size-4 text-muted-foreground' />
</CardHeader>
@@ -190,14 +190,14 @@ export function AccessAnalytics() {
{browsers.length}
</div>
<p className='text-[10px] text-muted-foreground mt-1'>
在一周内发起请求的浏览器代理大类统计
{t('activeBrowserTypesDesc')}
</p>
</CardContent>
</Card>
<Card className='bg-card/25 border-border/40 sm:col-span-2 lg:col-span-1'>
<CardHeader className='flex flex-row items-center justify-between pb-2 space-y-0'>
<CardTitle className='text-sm font-semibold tracking-tight'>
活跃独立用户数
{t('activeUsers')}
</CardTitle>
<Users className='size-4 text-muted-foreground' />
</CardHeader>
@@ -206,7 +206,7 @@ export function AccessAnalytics() {
{topUsers.length}
</div>
<p className='text-[10px] text-muted-foreground mt-1'>
一周内累计发起高频请求的注册账户总量
{t('activeUsersDesc')}
</p>
</CardContent>
</Card>
@@ -217,10 +217,10 @@ export function AccessAnalytics() {
<CardHeader className='flex flex-row items-center justify-between'>
<div>
<CardTitle className='text-base font-bold'>
一周访问量趋势
{t('weeklyAccessTrend')}
</CardTitle>
<CardDescription className='text-xs'>
展现系统最近 7 天内的每日 API 请求曲线
{t('weeklyAccessTrendDesc')}
</CardDescription>
</div>
<Button
@@ -241,7 +241,7 @@ export function AccessAnalytics() {
{trend.length === 0 ? (
<EmptyStateWithBorder
icon={TrendingUp}
description='暂无趋势数据'
description={t('noTrendData')}
/>
) : (
<div className='h-[280px] w-full'>
@@ -305,17 +305,17 @@ export function AccessAnalytics() {
<CardHeader>
<CardTitle className='text-base font-bold flex items-center gap-1.5'>
<Globe className='size-4.5 text-muted-foreground' />
使用的浏览器排行
{t('browserRanking')}
</CardTitle>
<CardDescription className='text-xs'>
基于请求头 User-Agent 智能分类的一周占比统计
{t('browserRankingDesc')}
</CardDescription>
</CardHeader>
<CardContent className='flex-1'>
{browsers.length === 0 ? (
<EmptyStateWithBorder
icon={Globe}
description='暂无浏览器排行数据'
description={t('noBrowserData')}
/>
) : (
<div className='space-y-4'>
@@ -360,17 +360,17 @@ export function AccessAnalytics() {
<CardHeader>
<CardTitle className='text-base font-bold flex items-center gap-1.5'>
<Users className='size-4.5 text-muted-foreground' />
最活跃的用户排行 (Top 10)
{t('topActiveUsers')}
</CardTitle>
<CardDescription className='text-xs'>
统计最近一周发起接口访问请求数量最多的账户
{t('topActiveUsersDesc')}
</CardDescription>
</CardHeader>
<CardContent className='flex-1'>
{topUsers.length === 0 ? (
<EmptyStateWithBorder
icon={Users}
description='暂无活跃用户数据'
description={t('noActiveUsersData')}
/>
) : (
<div className='divide-y divide-border/40'>
@@ -385,11 +385,13 @@ export function AccessAnalytics() {
</div>
<div className='truncate max-w-[180px] sm:max-w-xs'>
<div className='text-xs font-bold leading-tight truncate'>
{user.username || '未知'}
{user.username || t('unknown')}
</div>
<div className='text-[10px] text-muted-foreground leading-normal truncate'>
{user.nickname ? `(${user.nickname})` : '(无昵称)'} |
ID: {user.user_id}
{user.nickname
? `(${user.nickname})`
: t('noNickname')}{' '}
| ID: {user.user_id}
</div>
</div>
</div>
@@ -398,7 +400,7 @@ export function AccessAnalytics() {
{user.count.toLocaleString()}
</div>
<div className='text-[9px] text-muted-foreground uppercase font-bold tracking-wider'>
次请求
{t('requests')}
</div>
</div>
</div>