feat: 增加管理端多语言与风控/报表/奖池操作能力
This commit is contained in:
73
src/components/admin/admin-language-switcher.tsx
Normal file
73
src/components/admin/admin-language-switcher.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
"use client";
|
||||
|
||||
import { CheckIcon, GlobeIcon } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import {
|
||||
ADMIN_API_LOCALES,
|
||||
ADMIN_LOCALE_LABELS,
|
||||
applyAdminUiLocale,
|
||||
getAdminRequestLocale,
|
||||
type AdminApiLocale,
|
||||
} from "@/lib/admin-locale";
|
||||
|
||||
export function AdminLanguageSwitcher() {
|
||||
const { i18n, t } = useTranslation("common");
|
||||
const [locale, setLocale] = useState<AdminApiLocale>(() =>
|
||||
typeof document !== "undefined" ? getAdminRequestLocale() : "en",
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
queueMicrotask(() => {
|
||||
setLocale(getAdminRequestLocale());
|
||||
});
|
||||
}, []);
|
||||
|
||||
async function onSelectLocale(next: AdminApiLocale) {
|
||||
applyAdminUiLocale(next);
|
||||
await i18n.changeLanguage(next);
|
||||
setLocale(next);
|
||||
toast.success(`${t("language.changed", { defaultValue: "语言已切换" })}: ${ADMIN_LOCALE_LABELS[next]}`);
|
||||
}
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger className="inline-flex h-9 items-center gap-2 rounded-lg border border-border bg-background px-3 text-sm text-muted-foreground outline-none hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring">
|
||||
<GlobeIcon className="size-4 stroke-[1.75]" aria-hidden />
|
||||
<span className="font-medium uppercase">{locale}</span>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="min-w-[12rem]">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel className="text-xs text-muted-foreground">
|
||||
{t("language.title", { defaultValue: "界面语言" })}
|
||||
</DropdownMenuLabel>
|
||||
{ADMIN_API_LOCALES.map((code) => (
|
||||
<DropdownMenuItem
|
||||
key={code}
|
||||
className="gap-2"
|
||||
onClick={() => void onSelectLocale(code)}
|
||||
>
|
||||
{locale === code ? (
|
||||
<CheckIcon className="size-4 opacity-100" />
|
||||
) : (
|
||||
<span className="size-4 shrink-0" aria-hidden />
|
||||
)}
|
||||
<span className="flex-1">{ADMIN_LOCALE_LABELS[code]}</span>
|
||||
<span className="text-xs text-muted-foreground uppercase">{code}</span>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
@@ -2,16 +2,14 @@
|
||||
|
||||
import {
|
||||
BellIcon,
|
||||
CheckIcon,
|
||||
ChevronDownIcon,
|
||||
GlobeIcon,
|
||||
LogOutIcon,
|
||||
UserRoundIcon,
|
||||
} from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { AdminLanguageSwitcher } from "@/components/admin/admin-language-switcher";
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
@@ -24,13 +22,6 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import {
|
||||
ADMIN_API_LOCALES,
|
||||
ADMIN_LOCALE_LABELS,
|
||||
applyAdminUiLocale,
|
||||
getAdminRequestLocale,
|
||||
type AdminApiLocale,
|
||||
} from "@/lib/admin-locale";
|
||||
import {
|
||||
useAdminProfile,
|
||||
useAdminSessionStore,
|
||||
@@ -76,17 +67,6 @@ export function ShellToolbar() {
|
||||
const router = useRouter();
|
||||
const adminProfile = useAdminProfile();
|
||||
const clearSession = useAdminSessionStore((s) => s.clearSession);
|
||||
const [locale, setLocale] = useState<AdminApiLocale>(() =>
|
||||
typeof document !== "undefined"
|
||||
? getAdminRequestLocale()
|
||||
: "zh",
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
queueMicrotask(() => {
|
||||
setLocale(getAdminRequestLocale());
|
||||
});
|
||||
}, []);
|
||||
|
||||
const displayName =
|
||||
adminProfile?.nickname?.trim() ||
|
||||
@@ -100,13 +80,6 @@ export function ShellToolbar() {
|
||||
router.refresh();
|
||||
}
|
||||
|
||||
function onSelectLocale(next: AdminApiLocale) {
|
||||
applyAdminUiLocale(next);
|
||||
setLocale(next);
|
||||
toast.success(`语言:${ADMIN_LOCALE_LABELS[next]}`);
|
||||
router.refresh();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2 sm:gap-3">
|
||||
<Button
|
||||
@@ -128,36 +101,7 @@ export function ShellToolbar() {
|
||||
|
||||
<Separator orientation="vertical" className="mx-0.5 h-7" />
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger className="inline-flex size-8 shrink-0 items-center justify-center rounded-lg text-muted-foreground outline-none hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring">
|
||||
<GlobeIcon className="size-5 stroke-[1.75]" aria-hidden />
|
||||
<span className="sr-only">语言</span>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="min-w-[10rem]">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel className="text-xs text-muted-foreground">
|
||||
界面语言 / Language
|
||||
</DropdownMenuLabel>
|
||||
{ADMIN_API_LOCALES.map((code) => (
|
||||
<DropdownMenuItem
|
||||
key={code}
|
||||
className="gap-2"
|
||||
onClick={() => onSelectLocale(code)}
|
||||
>
|
||||
{locale === code ? (
|
||||
<CheckIcon className="size-4 opacity-100" />
|
||||
) : (
|
||||
<span className="size-4 shrink-0" aria-hidden />
|
||||
)}
|
||||
<span className="flex-1">{ADMIN_LOCALE_LABELS[code]}</span>
|
||||
<span className="text-xs text-muted-foreground uppercase">
|
||||
{code}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<AdminLanguageSwitcher />
|
||||
|
||||
<Separator orientation="vertical" className="mx-0.5 h-7" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user