feat(access-logs): 重构访问日志为概览与明细双 Tab

新增访问日志概览 API 与前端页面:汇总请求量/访问量/带宽趋势与 Top 排行,
明细列表保留检索;排行榜改为紧凑列表样式。
This commit is contained in:
ryan
2026-07-18 20:58:03 +08:00
parent 4c0c389122
commit 177578ef4e
24 changed files with 1546 additions and 1419 deletions
@@ -1,4 +1,4 @@
export type AccessLogTab = 'list' | 'folds' | 'ip-summary' | 'ip-trend';
export type AccessLogTab = 'overview' | 'list';
export type SearchDraft = {
nodeId: string;
@@ -7,8 +7,20 @@ export type SearchDraft = {
path: string;
};
export type OverviewRangeHours = 24 | 168 | 360 | 720;
export const PAGE_SIZE_OPTIONS = [20, 50, 100, 200];
export const OVERVIEW_RANGE_OPTIONS: {
value: OverviewRangeHours;
label: string;
}[] = [
{ value: 24, label: '24 小时' },
{ value: 168, label: '7 天' },
{ value: 360, label: '15 天' },
{ value: 720, label: '30 天' },
];
export const DETAIL_SORT_OPTIONS = [
{ value: 'logged_at:desc', label: '时间从新到旧' },
{ value: 'logged_at:asc', label: '时间从旧到新' },
@@ -18,20 +30,6 @@ export const DETAIL_SORT_OPTIONS = [
{ value: 'remote_addr:desc', label: 'IP 倒序' },
];
export const FOLD_SORT_OPTIONS = [
{ value: 'bucket_started_at:desc', label: '时间桶从新到旧' },
{ value: 'bucket_started_at:asc', label: '时间桶从旧到新' },
{ value: 'request_count:desc', label: '访问次数从高到低' },
{ value: 'request_count:asc', label: '访问次数从低到高' },
];
export const IP_SORT_OPTIONS = [
{ value: 'total_requests:desc', label: '总访问次数从高到低' },
{ value: 'total_requests:asc', label: '总访问次数从低到高' },
{ value: 'recent_requests:desc', label: '3 小时访问次数从高到低' },
{ value: 'last_seen_at:desc', label: '最后访问时间从新到旧' },
];
export function parseSortValue(value: string) {
const [sortBy = 'logged_at', sortOrder = 'desc'] = value.split(':');
return {
@@ -46,3 +44,23 @@ export function formatCompactNumber(value: number) {
maximumFractionDigits: 1,
}).format(value);
}
export function formatOverviewRangeHint(hours: number) {
if (hours <= 24) return '近 24 小时';
if (hours % 24 === 0) return `近 ${hours / 24} 天`;
return `近 ${hours} 小时`;
}
export function formatOverviewTrendLabel(value: string, hours: number) {
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
return '—';
}
const month = `${date.getMonth() + 1}`.padStart(2, '0');
const day = `${date.getDate()}`.padStart(2, '0');
const hour = `${date.getHours()}`.padStart(2, '0');
if (hours <= 24) {
return `${hour}:00`;
}
return `${month}/${day} ${hour}:00`;
}