Files
jiang13-bbs/frontend/components/AccountGuard.tsx
freefire 6da4309453 feat: 新增管理员用户管理功能与账号封禁体系
此提交完成了全站管理员后台核心功能开发:
1.  新增AdminUserService与管理接口,支持用户列表查询、角色变更与封禁解封
2.  重构认证链路,统一账号封禁错误码与处理逻辑
3.  新增全局强制下线机制,账号被封禁时自动弹出告知弹窗并清理登录态
4.  重构管理员后台路由与布局,统一权限校验逻辑
5.  优化通知轮询逻辑,页面切回前台时立即刷新未读计数
6.  合并原公告、外观管理页到统一后台面板
2026-09-15 02:52:26 +08:00

75 lines
2.4 KiB
TypeScript
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.
"use client";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { Ban } from "lucide-react";
import { onForceLogout } from "@/lib/userEvents";
/**
* 账号安全守卫:监听全局强制下线事件,被封禁时弹出不可误关的告知模态。
*
* 登录态清理(cookie/Header 游客化/router.refresh)由 Header 复用统一
* 登出链路完成;本组件只负责"告知"这一职责,故不处理任何凭据逻辑。
* 挂载于 root layout,覆盖任意页面(含后台)。
*/
export default function AccountGuard() {
const router = useRouter();
const [banned, setBanned] = useState(false);
useEffect(
() =>
onForceLogout((reason) => {
if (reason === "banned") setBanned(true);
}),
[]
);
if (!banned) return null;
return (
<div
className="fixed inset-0 z-[1000] flex items-center justify-center p-4"
style={{ background: "color-mix(in srgb, var(--ink) 60%, transparent)" }}
role="alertdialog"
aria-modal="true"
aria-labelledby="banned-dialog-title"
aria-describedby="banned-dialog-desc"
>
<div
className="j13-toast-in panel w-full max-w-[400px] rounded-2xl p-6 text-center"
style={{ boxShadow: "var(--shadow-lg)" }}
>
<span
className="mx-auto w-14 h-14 rounded-full flex items-center justify-center"
style={{ background: "var(--danger-soft)", color: "var(--danger)" }}
>
<Ban size={26} />
</span>
<h2
id="banned-dialog-title"
className="mt-4 text-[18px] font-extrabold tracking-tight"
style={{ color: "var(--ink)" }}
>
账号已被封禁
</h2>
<p id="banned-dialog-desc" className="meta mt-2 text-[13px] leading-relaxed">
你的账号因违反社区规则已被管理员封禁,当前登录状态已失效,无法继续发布内容与互动。
如对处理结果有异议,请联系管理员核实。
</p>
<button
type="button"
onClick={() => {
setBanned(false);
// 回到首页展示游客视图(若当前停留在受保护页面)
router.push("/");
}}
className="btn btn-primary w-full mt-5"
autoFocus
>
我知道了
</button>
</div>
</div>
);
}