yggdrasil/src/router.rs
xfy d72495c002 refactor(admin): merge trash into /admin/posts as a URL-driven tab
回收站从独立路由 /admin/trash 合并为 /admin/posts 下的一个 tab,
消除「回收站」导航项,让文章管理(列表 + 回收站 + 自动清理配置)集中在
同一页面,符合「相关功能就近聚合」的组织原则。

路由(router.rs)
- 删除 Route::Trash / Route::TrashPage
- 新增 Route::PostsTrash (/posts/trash) 与 PostsTrashPage (/posts/trash/:page)
- 静态段声明在 :page 之前::page 为 i32 类型,天然排斥 'trash' 文本,
  路由匹配安全且遵循文件内 static-first 约定

导航(admin_layout.rs)
- 移除「回收站」导航项
- 「管理文章」高亮覆盖其下所有子路由(列表/分页/回收站 tab),
  顺带修掉原 PostsPage 分页不高亮的小 bug

页面(posts.rs / posts_trash.rs)
- 新增 PostsTabs:URL 驱动的 tab 栏(Link 切换路由,非本地 signal),
  回收站 tab 带 get_post_stats().trash 数量角标,>0 用主题强调色提醒
- trash.rs → posts_trash.rs:TrashPage 重命名为 PostsTrashPage,
  分页路由改指向 PostsTrash/PostsTrashPage,内容(列表/批量操作/
  清空回收站/AutoPurgeSettings)原样迁移;include_str 测试同步更新
- posts.rs 的 PostsPage 渲染 PostsTabs,列表逻辑不变

无后端契约变更:所有 server function(list/delete/restore/purge/
batch/empty_trash/get_trash_settings)签名不变,Pagination 组件
接收具体 Route 变体,给 trash tab 传 PostsTrash 即可,无需改组件。
2026-07-08 16:52:02 +08:00

134 lines
4.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 全站路由配置
//!
//! 使用 Dioxus Router 定义前端路由层级,包含前台布局、后台管理布局、
//! 独立的登录与注册页面。`Route` 枚举上的 `#[route("/path")]` 属性
//! 既用于生成 URL 匹配规则,也用于组件导航。
use dioxus::prelude::*;
use std::sync::Arc;
use crate::components::admin_layout::AdminLayout;
use crate::components::frontend_layout::FrontendLayout;
use crate::context::UserContext;
use crate::pages::about::About;
use crate::pages::admin::{
Admin, AdminComments, AdminCommentsPage, Posts, PostsPage, PostsTrash, PostsTrashPage, Runner,
System, Write, WriteEdit,
};
use crate::pages::archives::Archives;
use crate::pages::home::{Home, HomePage};
use crate::pages::login::Login;
use crate::pages::not_found::NotFound;
use crate::pages::post_detail::PostDetail;
use crate::pages::register::Register;
use crate::pages::search::Search;
use crate::pages::tags::{TagDetail, Tags};
use crate::theme::{use_theme_provider, ThemePreload};
/// 全站路由枚举,每个变体对应一个页面路径
#[derive(Clone, Routable, Debug, PartialEq)]
#[rustfmt::skip]
pub enum Route {
// 前台页面共享布局
#[layout(FrontendLayout)]
/// 首页
#[route("/")]
Home {},
/// 首页分页
#[route("/page/:page")]
HomePage { page: i32 },
/// 文章归档页
#[route("/archives")]
Archives {},
/// 标签列表页
#[route("/tags")]
Tags {},
/// 单个标签下的文章列表
#[route("/tags/:tag")]
TagDetail { tag: String },
/// 文章详情页,按 slug 匹配
#[route("/post/:slug")]
PostDetail { slug: String },
/// 搜索页
#[route("/search")]
Search {},
/// 关于页面
#[route("/about")]
About {},
/// 404 兜底路由,匹配所有未命中路径
#[route("/:..segments")]
NotFound { segments: Vec<String> },
#[end_layout]
// 后台管理路由嵌套在 `/admin` 下
#[nest("/admin")]
// 后台页面共享管理布局
#[layout(AdminLayout)]
/// 后台仪表盘
#[route("/")]
Admin {},
/// 写文章页
#[route("/write")]
Write {},
/// 编辑文章页
#[route("/write/:id")]
WriteEdit { id: i32 },
/// 文章管理列表
#[route("/posts")]
Posts {},
/// 回收站(文章管理下的 tab静态段优先于 :page
#[route("/posts/trash")]
PostsTrash {},
/// 回收站分页
#[route("/posts/trash/:page")]
PostsTrashPage { page: i32 },
/// 文章管理列表分页
#[route("/posts/:page")]
PostsPage { page: i32 },
/// 评论管理
#[route("/comments")]
AdminComments {},
/// 评论管理分页
#[route("/comments/:page")]
AdminCommentsPage { page: i32 },
/// 系统管理(数据库 + 服务器状态 + SQL 控制台 + 导出 + 备份)
#[route("/system")]
System {},
/// 代码试运行沙箱(作者预览可运行代码块输出)
#[route("/runner")]
Runner {},
#[end_layout]
#[end_nest]
/// 登录页面
#[route("/login")]
Login {},
/// 注册页面
#[route("/register")]
Register {},
}
/// 应用路由器组件
///
/// 初始化主题提供者、全局用户上下文,并挂载样式表与 `Router`。
#[component]
pub fn AppRouter() -> Element {
let _theme = use_theme_provider();
// 提供全局用户上下文,供登录状态与路由守卫使用
let user = use_signal(|| None::<Arc<crate::models::user::PublicUser>>);
let checked = use_signal(|| false);
use_context_provider(|| UserContext { user, checked });
rsx! {
document::Stylesheet { href: "/style.css" }
document::Stylesheet { href: "/highlight.css" }
document::Title { "Yggdrasil Blog" }
document::Link { rel: "icon", href: "/favicon.ico" }
div {
ThemePreload {}
Router::<Route> {}
}
}
}