refactor: 合并多语言支持的显示名称字段,优化奖池手动爆发功能的返回数据结构,增强管理端权限控制

This commit is contained in:
2026-05-25 14:31:24 +08:00
parent 7d01e5c47e
commit ddedef824e
101 changed files with 3033 additions and 641 deletions

View File

@@ -38,9 +38,11 @@ import {
import { getAdminRiskPoolDetail, getAdminRiskPools } from "@/api/admin-risk";
import { getAdminUsers } from "@/api/admin-users";
import { getAdminTransferOrders } from "@/api/admin-wallet";
import { adminHasAnyPermission } from "@/lib/admin-permissions";
import { PRD_REPORT_EXPORT, PRD_REPORT_VIEW } from "@/lib/admin-prd";
import { useAdminProfile } from "@/stores/admin-session";
import { AdminDateRangeField } from "@/components/admin/admin-date-range-field";
import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
@@ -365,6 +367,9 @@ function resultRowCount(result: ReportResult | null): number {
export function ReportsConsole() {
const { t, i18n } = useTranslation(["reports", "common"]);
const profile = useAdminProfile();
const canViewReports = adminHasAnyPermission(profile?.permissions, [PRD_REPORT_VIEW]);
const canExportReports = adminHasAnyPermission(profile?.permissions, [PRD_REPORT_EXPORT]);
useAdminCurrencyCatalog();
useAdminPlayTypeCatalog();
const playCodeLabel = useAdminPlayCodeLabel();
@@ -446,6 +451,9 @@ export function ReportsConsole() {
}, [search.open, search.query, loadSearchOptions]);
const queryReport = useCallback(async () => {
if (!canViewReports) {
return;
}
setLoading(true);
setError(null);
try {
@@ -739,7 +747,7 @@ export function ReportsConsole() {
} finally {
setLoading(false);
}
}, [filters, page, perPage, selectedReport, t]);
}, [canViewReports, filters, page, perPage, selectedReport, t]);
useEffect(() => {
setResult(null);
@@ -766,6 +774,9 @@ export function ReportsConsole() {
}
function exportReport(format: ExportFormat): void {
if (!canExportReports) {
return;
}
if (!result || result.rows.length === 0) {
toast.info(t("empty"));
return;
@@ -1173,15 +1184,6 @@ export function ReportsConsole() {
return (
<div className="mx-auto flex w-full max-w-7xl flex-col gap-5">
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="min-w-0">
<h1 className="text-lg font-semibold tracking-tight text-[#13315f]">{t("title")}</h1>
</div>
<Badge variant="outline" className="h-7 px-3">
{resultRowCount(result)} {t("preview.exportableRows")}
</Badge>
</div>
<div className="grid gap-5 lg:grid-cols-[18rem_minmax(0,1fr)]">
<Card className="admin-list-card self-start">
<CardHeader className="admin-list-header pb-4">
@@ -1233,7 +1235,7 @@ export function ReportsConsole() {
</Button>
<Button
type="button"
disabled={!selectedReport.connected || loading}
disabled={!canViewReports || !selectedReport.connected || loading}
onClick={() => {
setPage(1);
void queryReport();
@@ -1267,11 +1269,20 @@ export function ReportsConsole() {
<CardTitle className="admin-list-title">{t("preview.title")}</CardTitle>
</div>
<div className="flex shrink-0 gap-2">
<Button type="button" variant="outline" disabled={!result || exporting !== null} onClick={() => exportReport("csv")}>
<Button
type="button"
variant="outline"
disabled={!canExportReports || !result || exporting !== null}
onClick={() => exportReport("csv")}
>
<FileDown data-icon="inline-start" />
{t("formats.csv")}
</Button>
<Button type="button" disabled={!result || exporting !== null} onClick={() => exportReport("excel")}>
<Button
type="button"
disabled={!canExportReports || !result || exporting !== null}
onClick={() => exportReport("excel")}
>
<FileSpreadsheet data-icon="inline-start" />
{t("formats.excel")}
</Button>