feat: 增加角色管理与奖池配置迁移,优化管理端权限与样式

This commit is contained in:
2026-05-19 14:40:04 +08:00
parent d625c59393
commit a1fb163f1b
45 changed files with 1080 additions and 518 deletions

View File

@@ -23,6 +23,8 @@ import {
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { adminHasAnyPermission } from "@/lib/admin-permissions";
import { useAdminProfile } from "@/stores/admin-session";
import {
Select,
SelectContent,
@@ -70,6 +72,8 @@ const PLAYER_STATUS_OPTIONS = [
export function PlayersConsole(): React.ReactElement {
const { t } = useTranslation(["players", "common"]);
const profile = useAdminProfile();
const canManagePlayers = adminHasAnyPermission(profile?.permissions, ["prd.users.manage"]);
const [page, setPage] = useState(1);
const [perPage, setPerPage] = useState(25);
const [keyword, setKeyword] = useState("");
@@ -249,9 +253,11 @@ export function PlayersConsole(): React.ReactElement {
<CardHeader className="flex flex-row flex-wrap items-end justify-between gap-4">
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3">
<CardTitle>{t("listTitle")}</CardTitle>
<Button type="button" size="sm" onClick={() => openCreateAccount()}>
{t("createPlayer")}
</Button>
{canManagePlayers ? (
<Button type="button" size="sm" onClick={() => openCreateAccount()}>
{t("createPlayer")}
</Button>
) : null}
</div>
<div className="flex w-full max-w-lg gap-2">
<Input
@@ -348,26 +354,30 @@ export function PlayersConsole(): React.ReactElement {
: "—"}
</TableCell>
<TableCell>
<div className="flex flex-wrap gap-1">
<Button
type="button"
size="sm"
variant={
accountOpen && editingAccountId === row.id ? "secondary" : "outline"
}
onClick={() => openEditAccount(row)}
>
{t("edit")}
</Button>
<Button
type="button"
size="sm"
variant="destructive"
onClick={() => setDeleteTarget(row)}
>
{t("delete")}
</Button>
</div>
{canManagePlayers ? (
<div className="flex flex-wrap gap-1">
<Button
type="button"
size="sm"
variant={
accountOpen && editingAccountId === row.id ? "secondary" : "outline"
}
onClick={() => openEditAccount(row)}
>
{t("edit")}
</Button>
<Button
type="button"
size="sm"
variant="destructive"
onClick={() => setDeleteTarget(row)}
>
{t("delete")}
</Button>
</div>
) : (
<span className="text-xs text-muted-foreground"></span>
)}
</TableCell>
</TableRow>
))