fix: 管理会话自动恢复与访问来源统计优化

- 新增 AdminSessionRecover:后台离线/后端重启时自动重试恢复会话,明确失效才回跳登录
- 认证 cookie 契约调整(SameSite=Lax 与刷新轮转适配),路由与守卫适配
- 访问来源统计查询优化与测试、管理端 analytics sources 页面适配
- 移动端布局修正:覆盖 body min-h-screen 避免内容区高度异常
This commit is contained in:
2026-09-28 03:33:52 +08:00
parent 0c3b3a710c
commit 3e0689fe98
15 changed files with 548 additions and 85 deletions

View File

@@ -38,6 +38,11 @@ import { useUrlStyle } from "./SiteBrandProvider";
import { leaderboardPath } from "@/lib/urlStyle";
import type { BrandLogoFit, BrandLogoSize, BrandMark } from "@/lib/brand";
// 搜索关键词长度上限(与后端 handler maxSearchKeywordRunes 一致);
// 接近上限时输入框内显示 n/100 计数帮助用户感知
const SEARCH_MAX_LEN = 100;
const SEARCH_COUNT_FROM = 80;
export default function Header({
initialUser,
initialUnread = 0,
@@ -280,18 +285,30 @@ export default function Header({
ref={searchInputRef}
type="text"
value={searchQuery}
maxLength={SEARCH_MAX_LEN}
onChange={(e) => setSearchQuery(e.target.value)}
onKeyDown={onSearchKeyDown}
placeholder="搜索帖子..."
aria-label="搜索帖子"
className="j13-search-field w-full pl-10 pr-10 py-2.5 text-sm rounded-full"
className={`j13-search-field w-full pl-10 py-2.5 text-sm rounded-full ${
searchQuery.length >= SEARCH_COUNT_FROM ? "pr-16" : "pr-10"
}`}
/>
<kbd
className="absolute right-3.5 top-1/2 -translate-y-1/2 text-[11px] w-5 h-5 flex items-center justify-center rounded-md pointer-events-none"
style={{ color: "var(--ink-3)", border: "1px solid var(--line-2)", background: "var(--bg)" }}
>
/
</kbd>
{searchQuery.length >= SEARCH_COUNT_FROM ? (
<span
className="absolute right-3.5 top-1/2 -translate-y-1/2 text-[11px] tabular-nums pointer-events-none"
style={{ color: searchQuery.length >= SEARCH_MAX_LEN ? "var(--danger)" : "var(--ink-3)" }}
>
{searchQuery.length}/{SEARCH_MAX_LEN}
</span>
) : (
<kbd
className="absolute right-3.5 top-1/2 -translate-y-1/2 text-[11px] w-5 h-5 flex items-center justify-center rounded-md pointer-events-none"
style={{ color: "var(--ink-3)", border: "1px solid var(--line-2)", background: "var(--bg)" }}
>
/
</kbd>
)}
</div>
</form>
<ThemeToggle initialTheme={initialTheme} className={iconBtn} style={iconBtnStyle} />
@@ -365,6 +382,7 @@ export default function Header({
autoFocus
type="text"
value={searchQuery}
maxLength={SEARCH_MAX_LEN}
onChange={(e) => setSearchQuery(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Escape") {
@@ -374,8 +392,18 @@ export default function Header({
}}
aria-label="搜索帖子"
placeholder="搜索帖子..."
className="j13-search-field w-full pl-10 pr-4 py-3 rounded-full text-sm"
className={`j13-search-field w-full pl-10 py-3 rounded-full text-sm ${
searchQuery.length >= SEARCH_COUNT_FROM ? "pr-16" : "pr-4"
}`}
/>
{searchQuery.length >= SEARCH_COUNT_FROM && (
<span
className="absolute right-4 top-1/2 -translate-y-1/2 text-[11px] tabular-nums pointer-events-none"
style={{ color: searchQuery.length >= SEARCH_MAX_LEN ? "var(--danger)" : "var(--ink-3)" }}
>
{searchQuery.length}/{SEARCH_MAX_LEN}
</span>
)}
</form>
</div>
)}