fix: 修复主题切换后首页状态重置 + 首页 UX 优化 + 文档同步

## 根因
  设置页 `navigate('/settings')` 导致 React Router `/*` 的 index
  路由不匹配,HomePage 被卸载重挂载,所有 useState 回到默认值。

  ## 修复(6 文件)
  - event-bus.ts: 新增 OPEN_SETTINGS 事件
  - nav-config.ts: 设置按钮 action: 'navigate' → 'button',去路由化
  - NavBar.tsx: button case 中 emit(OPEN_SETTINGS)
  - SettingsPage.tsx: 去路由化,改为 Modal 居中叠加 + open/onClose props,
    使用 antd 6.x 正确 API destroyOnHidden(非废弃的 destroyOnClose),
    mask={{ closable: false }} + keyboard={false} 仅允许 X 按钮关闭
  - router/index.tsx: 移除 SettingsPage 渲染
  - App.tsx: 添加 SettingsPage Modal,事件驱动(与 LoginPage 模式一致)

  ## UX 优化(2 文件)
  - HomeContent.tsx: 右侧分隔条移除多余 marginLeft,左右视觉对称
  - BannerCarousel.tsx: 新增关闭按钮,session 级别 useState 隐藏,
    不做 localStorage 持久化,确保每次启动重新展示

  ## 架构原则
  确立 QT 多窗口模型 → Web 映射:叠加层走 Modal/Drawer + 事件总线,
  主页面不卸载;真正的视图切换才用 React Router。

  ## 文档同步
  - TODO.md: 移除已完成项详细记录,精简为未完成待办
  - WORKLOG.md: 追加 2026-06-07 完整工作日志
  - PROJECT.md: 更新路由/叠加层架构说明
  - CHANGELOG.md: 追加 v0.0.13 条目
  - ARCHITECTURE.md: 更新日期 + 新增叠加层模式章节
This commit is contained in:
2026-06-05 21:03:14 +08:00
parent a8ace232a4
commit 72ec1a5459
15 changed files with 192 additions and 164 deletions

View File

@@ -1,10 +1,16 @@
// ============================================================
// BannerCarousel — 首页顶部轮播图
// 使用 useBannerList() Hook 获取数据,组件仅负责渲染
//
// 关闭行为:
// - 关闭后当前会话不再显示(组件内 useState 驱动)
// - 刷新/重启应用 → state 重置 → 重新展示
// - 不做 localStorage 持久化,确保每次启动都可见
// ============================================================
import { useRef, useMemo } from 'react';
import { Carousel, Skeleton } from 'antd';
import { useRef, useMemo, useState } from 'react';
import { Carousel, Skeleton, Button } from 'antd';
import { CloseOutlined } from '@ant-design/icons';
import type { CarouselRef } from 'antd/es/carousel';
import { useBannerList } from '@/hooks/use-api';
@@ -22,6 +28,9 @@ export function BannerCarousel({ className }: BannerCarouselProps) {
const carouselRef = useRef<CarouselRef>(null);
const { data: rawBanners, loading } = useBannerList();
/** 当前会话是否已关闭轮播图(组件卸载即重置,下次启动重新展示) */
const [dismissed, setDismissed] = useState(false);
// 过滤 + 排序(纯计算,无副作用)
const banners = useMemo<Banner[]>(() => {
if (!rawBanners) return [];
@@ -31,8 +40,8 @@ export function BannerCarousel({ className }: BannerCarouselProps) {
.sort((a, b) => a.sort_order - b.sort_order);
}, [rawBanners]);
// 无数据时不渲染
if (!loading && banners.length === 0) {
// 用户已关闭或加载完成但无数据 → 不渲染
if (dismissed || (!loading && banners.length === 0)) {
return null;
}
@@ -69,6 +78,35 @@ export function BannerCarousel({ className }: BannerCarouselProps) {
</div>
))}
</Carousel>
{/* 关闭按钮 — 右上角悬浮半透明底色hover 加深 */}
<Button
type="text"
size="small"
icon={<CloseOutlined />}
onClick={() => setDismissed(true)}
title="关闭轮播图"
style={{
position: 'absolute',
top: 8,
right: 8,
zIndex: 10,
color: '#fff',
background: 'rgba(0, 0, 0, 0.35)',
borderRadius: 4,
width: 24,
height: 24,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
onMouseEnter={(e) => {
(e.currentTarget as HTMLButtonElement).style.background = 'rgba(0, 0, 0, 0.55)';
}}
onMouseLeave={(e) => {
(e.currentTarget as HTMLButtonElement).style.background = 'rgba(0, 0, 0, 0.35)';
}}
/>
</div>
);
}