feat(router): wrap public routes in ErrorLayout with ErrorBoundary

This commit is contained in:
xfy 2026-07-09 17:29:47 +08:00
parent b5a64f8dcf
commit 37e8f51fac

View File

@ -29,7 +29,8 @@ use crate::theme::{use_theme_provider, ThemePreload};
#[derive(Clone, Routable, Debug, PartialEq)]
#[rustfmt::skip]
pub enum Route {
// 前台页面共享布局
// 前台页面共享布局,最外层嵌套错误边界布局以拦截报错
#[layout(ErrorLayout)]
#[layout(FrontendLayout)]
/// 首页
#[route("/")]
@ -59,6 +60,7 @@ pub enum Route {
#[route("/:..segments")]
NotFound { segments: Vec<String> },
#[end_layout]
#[end_layout]
// 后台管理路由嵌套在 `/admin` 下
#[nest("/admin")]
@ -131,3 +133,48 @@ pub fn AppRouter() -> Element {
}
}
}
#[component]
fn ErrorLayout() -> Element {
rsx! {
ErrorBoundary {
handle_error: move |err: ErrorContext| {
// Commit the status code on the server side
#[cfg(feature = "server")]
{
if let Some(captured_error) = err.error() {
let _ = dioxus::fullstack::FullstackContext::commit_error_status(captured_error);
}
}
// Parse the captured error to detect 404 vs 500
let mut is_404 = false;
if let Some(captured_error) = err.error() {
let err_str = format!("{:?}", captured_error);
if err_str.contains("NotFound") || err_str.contains("404") || err_str.contains("not found") {
is_404 = true;
}
}
if is_404 {
rsx! {
NotFound { segments: vec![] }
}
} else {
rsx! {
div { class: "flex flex-col items-center justify-center text-center min-h-[50vh] px-6",
h1 { class: "text-2xl font-bold text-red-500 mb-4", "加载失败" }
p { class: "text-paper-secondary mb-6", "抱歉,加载页面时出现了一些错误,请稍后再试。" }
dioxus::router::components::Link {
class: "px-5 py-2.5 bg-paper-entry border border-paper-border rounded-lg text-sm font-medium text-paper-primary hover:border-paper-secondary transition-all",
to: Route::Home {},
"返回首页"
}
}
}
}
},
Outlet::<Route> {}
}
}
}