feat(ui): enhance table and admin components with improved layout and status display

- Updated global CSS to center-align table headers and cells, ensuring a consistent layout.
- Modified admin table components to replace switches with status badges for better clarity.
- Enhanced internationalization support by adding new strings for version actions and validation messages in multiple locales.
- Refactored configuration document screens to include version selection and improved user feedback on status changes.
This commit is contained in:
2026-05-26 11:13:16 +08:00
parent 05fa0cbeec
commit 4080f0b601
38 changed files with 788 additions and 608 deletions

View File

@@ -2,6 +2,7 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import { useConfirmAction } from "@/hooks/use-confirm-action";
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
import { useExportLabels } from "@/hooks/use-export-labels";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
@@ -16,8 +17,10 @@ import {
} from "@/api/admin-player";
import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer";
import { AdminTableExportButton } from "@/components/admin/admin-table-export-button";
import { AdminStatusBadge } from "@/components/admin/admin-status-badge";
import { ConfirmableSwitch } from "@/components/admin/confirmable-switch";
import { resolvePlayerStatusTone } from "@/lib/admin-status-tone";
import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
Dialog,
@@ -66,7 +69,8 @@ const PLAYER_STATUS_OPTIONS = [
export function PlayersConsole(): React.ReactElement {
const { t } = useTranslation(["players", "common"]);
const { request: requestConfirm, ConfirmDialog } = useConfirmAction();
const { request: requestConfirm, ConfirmDialog, busy: confirmBusy } = useConfirmAction();
const formatDt = useAdminDateTimeFormatter();
const exportLabels = useExportLabels("players");
const profile = useAdminProfile();
useAdminCurrencyCatalog();
@@ -338,8 +342,8 @@ export function PlayersConsole(): React.ReactElement {
<TableHead>{t("username")}</TableHead>
<TableHead>{t("nickname")}</TableHead>
<TableHead className="whitespace-nowrap">{t("currency")}</TableHead>
<TableHead className="whitespace-nowrap text-right">{t("balance")}</TableHead>
<TableHead className="whitespace-nowrap text-right">{t("available")}</TableHead>
<TableHead className="whitespace-nowrap text-center">{t("balance")}</TableHead>
<TableHead className="whitespace-nowrap text-center">{t("available")}</TableHead>
<TableHead className="w-20 whitespace-nowrap">{t("status")}</TableHead>
<TableHead className="whitespace-nowrap">{t("lastLogin")}</TableHead>
<TableHead className="min-w-[10rem]">{t("actions")}</TableHead>
@@ -365,21 +369,28 @@ export function PlayersConsole(): React.ReactElement {
<TableCell>{row.username ?? "—"}</TableCell>
<TableCell>{row.nickname ?? "—"}</TableCell>
<TableCell>{row.default_currency}</TableCell>
<TableCell className="whitespace-nowrap text-right tabular-nums text-xs">
<TableCell className="whitespace-nowrap text-center tabular-nums text-xs">
{row.wallets.length > 0
? formatAdminMinorUnits(row.wallets[0].balance, row.wallets[0].currency_code)
: "—"}
</TableCell>
<TableCell className="whitespace-nowrap text-right tabular-nums text-xs">
<TableCell className="whitespace-nowrap text-center tabular-nums text-xs">
{row.wallets.length > 0
? formatAdminMinorUnits(row.wallets[0].available_balance, row.wallets[0].currency_code)
: "—"}
</TableCell>
<TableCell>
{canFreezePlayers ? (
{row.status === 2 ? (
<div className="flex justify-center">
<Switch
<AdminStatusBadge status={row.status} tone={resolvePlayerStatusTone(row.status)}>
{playerStatusLabelT(row.status, t)}
</AdminStatusBadge>
</div>
) : canFreezePlayers ? (
<div className="flex justify-center">
<ConfirmableSwitch
checked={row.status === 0}
confirmBusy={confirmBusy}
disabled={freezeBusyId === row.id}
aria-label={t("status")}
onCheckedChange={(checked) => {
@@ -407,15 +418,7 @@ export function PlayersConsole(): React.ReactElement {
)}
</TableCell>
<TableCell className="whitespace-nowrap text-xs text-muted-foreground">
{row.last_login_at
? new Date(row.last_login_at).toLocaleString("zh-CN", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
})
: "—"}
{row.last_login_at ? formatDt(row.last_login_at) : "—"}
</TableCell>
<TableCell>
{canManagePlayers || canFreezePlayers ? (