From a138f428e1a5e99c312fb8b9578c4de3e9715f44 Mon Sep 17 00:00:00 2001 From: freefire Date: Wed, 16 Sep 2026 00:39:54 +0800 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20=E7=BB=9F=E4=B8=80=E5=85=A8?= =?UTF-8?q?=E7=AB=99=20Modal=20=E5=A3=B3=E5=B9=B6=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E4=BF=9D=E5=AD=98=E6=8C=89=E9=92=AE=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- frontend/app/admin/users/UsersAdmin.tsx | 599 +++++++++++------------- frontend/app/chat/ChatShell.tsx | 181 ++++--- frontend/components/AccountGuard.tsx | 72 +-- frontend/components/AvatarCropModal.tsx | 55 +-- frontend/components/ConfirmDialog.tsx | 61 +-- frontend/components/Modal.tsx | 145 ++++++ frontend/components/PostActions.tsx | 65 +-- 7 files changed, 584 insertions(+), 594 deletions(-) create mode 100644 frontend/components/Modal.tsx diff --git a/frontend/app/admin/users/UsersAdmin.tsx b/frontend/app/admin/users/UsersAdmin.tsx index e9ba07e..17a4398 100644 --- a/frontend/app/admin/users/UsersAdmin.tsx +++ b/frontend/app/admin/users/UsersAdmin.tsx @@ -38,6 +38,7 @@ import { toast } from "@/lib/toast"; import { realtime } from "@/lib/realtime"; import Avatar from "@/components/Avatar"; import RoleBadge from "@/components/RoleBadge"; +import Modal from "@/components/Modal"; export type UserFilter = "all" | "staff" | "banned"; @@ -848,15 +849,6 @@ function RoleAssignDialog({ } }, [target]); - useEffect(() => { - if (!target) return; - const onKey = (e: KeyboardEvent) => { - if (e.key === "Escape" && !acting) onClose(); - }; - window.addEventListener("keydown", onKey); - return () => window.removeEventListener("keydown", onKey); - }, [target, acting, onClose]); - if (!target) return null; const toggleBoard = (id: number) => { @@ -904,217 +896,198 @@ function RoleAssignDialog({ const saveLabel = willBan ? "保存并封禁" : willUnban ? "保存并解封" : "保存"; return ( -
!acting && onClose()} - > -
e.stopPropagation()} - role="dialog" - aria-modal="true" - aria-label="角色与账号" - > -
-
-

- 角色与账号 -

-

- @{target.username}({target.nickname}) -

-
- -
- -

- 角色决定后台入口与前台管理能力;封禁立即强制下线。登录历史、站长内容档案仍走列表其他入口。 -

- -

- 管理角色 -

-
- {options.map((o) => { - const active = role === o.value; - return ( - - ); - })} -
- - {role === ROLES.BOARD_ADMIN && ( -
-

- 授权板块 * -

- {boards.length === 0 ? ( -

板块加载中…

- ) : ( -
- {boards.map((b) => { - const checked = boardIds.includes(b.id); - return ( - - ); - })} -
- )} - {err && ( -

- {err} -

- )} -
- )} - -
-

- 账号状态 -

-
- - -
- {willBan && ( -

- 封禁后立即强制下线,无法登录、发帖与回复;已发布内容保留。角色变更与封禁将一并保存。 -

- )} -
- -
+ + + @{target.username}({target.nickname}) + + + 角色决定后台入口与前台管理能力;封禁立即强制下线。登录历史、站长内容档案仍走列表其他入口。 + + + } + onClose={onClose} + busy={acting} + maxWidthClass="max-w-[500px]" + panelClassName="p-6 max-h-[88vh] overflow-y-auto" + ariaLabel="角色与账号" + footer={ + <> -
+ + } + > +

+ 管理角色 +

+
+ {options.map((o) => { + const active = role === o.value; + return ( + + ); + })}
-
+ + {role === ROLES.BOARD_ADMIN && ( +
+

+ 授权板块 * +

+ {boards.length === 0 ? ( +

板块加载中…

+ ) : ( +
+ {boards.map((b) => { + const checked = boardIds.includes(b.id); + return ( + + ); + })} +
+ )} + {err && ( +

+ {err} +

+ )} +
+ )} + +
+

+ 账号状态 +

+
+ + +
+ {willBan && ( +

+ 封禁后立即强制下线,无法登录、发帖与回复;已发布内容保留。角色变更与封禁将一并保存。 +

+ )} +
+ ); } @@ -1154,133 +1127,107 @@ function LoginLogsDialog({ target, onClose }: { target: AdminUser | null; onClos if (target) setPage(1); }, [target]); - useEffect(() => { - if (!target) return; - const onKey = (e: KeyboardEvent) => { - if (e.key === "Escape") onClose(); - }; - window.addEventListener("keydown", onKey); - return () => window.removeEventListener("keydown", onKey); - }, [target, onClose]); - if (!target) return null; const pageSize = 15; const totalPages = Math.max(1, Math.ceil(total / pageSize)); return ( -
-
e.stopPropagation()} - role="dialog" - aria-modal="true" - aria-label="登录历史" - > -
-
-

- - 登录历史 -

-

- @{target.username} · 共 {total} 条记录(含失败尝试) -

-
- -
- -
- {loading ? ( -
- 加载中… -
- ) : err ? ( -

{err}

- ) : logs.length === 0 ? ( -
- -

暂无登录记录

-
- ) : ( -
    - {logs.map((log) => ( -
  • - -
    -

    - {log.ip || "未知 IP"} - - {log.success ? "成功" : "失败"} - -

    -

    - {log.user_agent || "未知设备"} -

    -
    - - {formatDate(log.created_at)} {new Date(log.created_at).toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" })} - -
  • - ))} -
- )} -
- - {total > pageSize && ( -
- + + + 登录历史 + + } + description={`@${target.username} · 共 ${total} 条记录(含失败尝试)`} + onClose={onClose} + dismissOnOverlay + maxWidthClass="max-w-[520px]" + panelClassName="p-6 max-h-[88vh] flex flex-col" + ariaLabel="登录历史" + footer={ + total > pageSize ? ( + <> + 第 {page} / {totalPages} 页 -
- - -
+ + + + ) : undefined + } + > +
+ {loading ? ( +
+ 加载中…
+ ) : err ? ( +

{err}

+ ) : logs.length === 0 ? ( +
+ +

暂无登录记录

+
+ ) : ( +
    + {logs.map((log) => ( +
  • + +
    +

    + {log.ip || "未知 IP"} + + {log.success ? "成功" : "失败"} + +

    +

    + {log.user_agent || "未知设备"} +

    +
    + + {formatDate(log.created_at)}{" "} + {new Date(log.created_at).toLocaleTimeString("zh-CN", { + hour: "2-digit", + minute: "2-digit", + })} + +
  • + ))} +
)}
-
+ ); } diff --git a/frontend/app/chat/ChatShell.tsx b/frontend/app/chat/ChatShell.tsx index 4c20aac..ceaff56 100644 --- a/frontend/app/chat/ChatShell.tsx +++ b/frontend/app/chat/ChatShell.tsx @@ -26,6 +26,7 @@ import { onDocumentVisible } from "@/lib/visibilityReconcile"; import { toast } from "@/lib/toast"; import Avatar from "@/components/Avatar"; import ContextMenu, { type CtxMenuItem } from "@/components/ContextMenu"; +import Modal from "@/components/Modal"; function roomTitle(room: ChatRoomView) { if (room.room_type === "direct") { @@ -600,115 +601,99 @@ function CreateGroupModal({ }; return ( -
-
e.stopPropagation()} - > -
-

- 新建群聊 -

- + + + } + > +
+
+ + setName(e.target.value)} + maxLength={32} + placeholder="2-32 个字符" + className="w-full px-3.5 h-10 rounded-lg outline-none" + style={{ background: "var(--bg)", border: "1px solid var(--line)", color: "var(--ink)" }} + />
-
+
+ +