From 51fbc1828e760422d33f0438b289da99debef054 Mon Sep 17 00:00:00 2001 From: WorkBuddy Date: Tue, 22 Sep 2026 15:35:59 +0800 Subject: [PATCH] =?UTF-8?q?fix(admin):=20=E6=97=A5=E5=BF=97=E9=A1=B5?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=AE=9A=E4=BD=8D=E5=88=B0=E6=9C=80=E6=96=B0?= =?UTF-8?q?=E8=80=8C=E9=9D=9E=E6=9C=80=E6=97=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 渲染顺序(最新在前)与滚动逻辑假设(正序+贴底=最新)相互矛盾: 自动刷新(默认开启)每 10s 强制贴底,而底部恰好是最早的日志, 用户打开页面被钉在最旧的一条上。 改为渲染时间正序(旧→新),与贴底滚动/上滚暂停跟随的 tail -f 行为一致:打开页面即定位最新。 --- frontend/src/admin/pages/Logs.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/admin/pages/Logs.tsx b/frontend/src/admin/pages/Logs.tsx index 513ac30..28768e6 100644 --- a/frontend/src/admin/pages/Logs.tsx +++ b/frontend/src/admin/pages/Logs.tsx @@ -7,7 +7,7 @@ * - 缓冲上限 2000 条,进程重启后清零 */ -import { useEffect, useState, useCallback, useRef } from 'react' +import { useEffect, useState, useCallback, useRef, useMemo } from 'react' import { fetchLogs } from '../dal' import type { LogEntry } from '../types' import { Card, CardBody, CardHeader, Badge, SectionHeader, Alert, Spinner, SkeletonBlock } from '../components' @@ -63,6 +63,10 @@ export default function LogsPage() { userScrolledUp.current = !atBottom } + // 后端返回最新在前;渲染转为时间正序(旧→新),配合「自动贴底」滚动: + // 打开页面/自动刷新默认定位到最新日志,用户上滚回看时暂停跟随 + const ordered = useMemo(() => [...entries].reverse(), [entries]) + // 加载后自动滚动到底部(仅当用户未向上滚动时) useEffect(() => { if (autoRefresh && !userScrolledUp.current && scrollRef.current) { @@ -142,7 +146,7 @@ export default function LogsPage() {

暂无匹配的日志

) : (
- {entries.map((e, i) => { + {ordered.map((e, i) => { const badge = LEVEL_BADGE[e.level] ?? { status: 'info' as const, text: e.level } return (