充值弹窗

This commit is contained in:
zhx 2026-06-16 17:58:35 +08:00
parent f5d06e1e52
commit 97915b5980
2 changed files with 249 additions and 136 deletions

View File

@ -7,7 +7,6 @@ import Tabs from "@mui/material/Tabs";
import TextField from "@mui/material/TextField"; import TextField from "@mui/material/TextField";
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { useRechargeProductsPage } from "@/features/payment/hooks/useRechargeProductsPage.js"; import { useRechargeProductsPage } from "@/features/payment/hooks/useRechargeProductsPage.js";
import { ThirdPartyPaymentContent } from "@/features/payment/pages/ThirdPartyPaymentPage.jsx";
import styles from "@/features/payment/payment.module.css"; import styles from "@/features/payment/payment.module.css";
import { Button } from "@/shared/ui/Button.jsx"; import { Button } from "@/shared/ui/Button.jsx";
import { import {
@ -51,10 +50,25 @@ const audienceOptions = [
["coin_seller", "币商"], ["coin_seller", "币商"],
]; ];
const productTabConfigs = {
google: {
createLabel: "新增 Google 商品",
dialogEditTitle: "编辑 Google 商品",
dialogCreateTitle: "新增 Google 商品",
platform: "android",
},
third_party: {
createLabel: "新增三方商品",
dialogEditTitle: "编辑三方商品",
dialogCreateTitle: "新增三方商品",
platform: "web",
},
};
export function RechargeProductConfigPage() { export function RechargeProductConfigPage() {
const page = useRechargeProductsPage(); const page = useRechargeProductsPage();
const [activeProductTab, setActiveProductTab] = useState("google"); const [activeProductTab, setActiveProductTab] = useState("google");
const googleProductPlatform = "android"; const activeProductConfig = productTabConfigs[activeProductTab] || productTabConfigs.google;
const { platform, setPlatform } = page; const { platform, setPlatform } = page;
const items = page.data?.items || []; const items = page.data?.items || [];
const regionLabels = useMemo(() => regionLabelMap(page.regionOptions), [page.regionOptions]); const regionLabels = useMemo(() => regionLabelMap(page.regionOptions), [page.regionOptions]);
@ -64,14 +78,15 @@ export function RechargeProductConfigPage() {
const canSubmit = page.editingItem ? page.abilities.canUpdateProduct : page.abilities.canCreateProduct; const canSubmit = page.editingItem ? page.abilities.canUpdateProduct : page.abilities.canCreateProduct;
const openCreate = () => { const openCreate = () => {
page.openCreate(); page.openCreate();
page.setForm({ platform: googleProductPlatform }); page.setForm({ platform: activeProductConfig.platform });
}; };
useEffect(() => { useEffect(() => {
if (activeProductTab === "google" && platform !== googleProductPlatform) { // platform Google / tab
setPlatform(googleProductPlatform); if (platform !== activeProductConfig.platform) {
setPlatform(activeProductConfig.platform);
} }
}, [activeProductTab, googleProductPlatform, platform, setPlatform]); }, [activeProductConfig.platform, platform, setPlatform]);
return ( return (
<AdminListPage> <AdminListPage>
@ -81,17 +96,11 @@ export function RechargeProductConfigPage() {
<Tab label="三方" value="third_party" /> <Tab label="三方" value="third_party" />
</Tabs> </Tabs>
</div> </div>
{activeProductTab === "google" ? (
<>
<AdminListToolbar <AdminListToolbar
actions={ actions={
page.abilities.canCreateProduct ? ( page.abilities.canCreateProduct ? (
<Button <Button startIcon={<AddOutlined fontSize="small" />} variant="primary" onClick={openCreate}>
startIcon={<AddOutlined fontSize="small" />} {activeProductConfig.createLabel}
variant="primary"
onClick={openCreate}
>
新增 Google 商品
</Button> </Button>
) : null ) : null
} }
@ -112,18 +121,12 @@ export function RechargeProductConfigPage() {
/> />
</AdminListBody> </AdminListBody>
</DataState> </DataState>
</>
) : (
<ThirdPartyPaymentContent embedded />
)}
{activeProductTab === "google" ? (
<AdminFormDialog <AdminFormDialog
loading={saving} loading={saving}
open={Boolean(page.activeAction)} open={Boolean(page.activeAction)}
size="compact" size="compact"
submitDisabled={!canSubmit || saving} submitDisabled={!canSubmit || saving}
title={page.editingItem ? "编辑 Google 商品" : "新增 Google 商品"} title={page.editingItem ? activeProductConfig.dialogEditTitle : activeProductConfig.dialogCreateTitle}
onClose={page.closeDialog} onClose={page.closeDialog}
onSubmit={page.submitProduct} onSubmit={page.submitProduct}
> >
@ -214,7 +217,6 @@ export function RechargeProductConfigPage() {
/> />
</AdminFormSection> </AdminFormSection>
</AdminFormDialog> </AdminFormDialog>
) : null}
</AdminListPage> </AdminListPage>
); );
} }

View File

@ -0,0 +1,111 @@
import { fireEvent, render, screen } from "@testing-library/react";
import { afterEach, expect, test, vi } from "vitest";
import { RechargeProductConfigPage } from "@/features/payment/pages/RechargeProductConfigPage.jsx";
import { useRechargeProductsPage } from "@/features/payment/hooks/useRechargeProductsPage.js";
vi.mock("@/features/payment/hooks/useRechargeProductsPage.js", () => ({
useRechargeProductsPage: vi.fn(),
}));
afterEach(() => {
vi.clearAllMocks();
});
test("recharge product page defaults to google product list", () => {
vi.mocked(useRechargeProductsPage).mockReturnValue(pageFixture());
render(<RechargeProductConfigPage />);
expect(screen.getByRole("tab", { name: "Google", selected: true })).toBeInTheDocument();
expect(screen.getByRole("button", { name: "新增 Google 商品" })).toBeInTheDocument();
expect(screen.getAllByText("coins_480000").length).toBeGreaterThan(0);
expect(screen.queryByText("支付汇率全球同步")).not.toBeInTheDocument();
});
test("third-party tab reuses product dialog and locks create platform to web", () => {
const page = pageFixture();
vi.mocked(useRechargeProductsPage).mockReturnValue(page);
render(<RechargeProductConfigPage />);
fireEvent.click(screen.getByRole("tab", { name: "三方" }));
expect(screen.getByRole("tab", { name: "三方", selected: true })).toBeInTheDocument();
expect(screen.getByRole("button", { name: "新增三方商品" })).toBeInTheDocument();
expect(screen.queryByText("支付汇率全球同步")).not.toBeInTheDocument();
fireEvent.click(screen.getByRole("button", { name: "新增三方商品" }));
expect(page.openCreate).toHaveBeenCalledTimes(1);
expect(page.setForm).toHaveBeenCalledWith({ platform: "web" });
});
function pageFixture() {
return {
abilities: {
canCreateProduct: true,
canDeleteProduct: true,
canUpdateProduct: true,
},
activeAction: "",
audienceType: "",
closeDialog: vi.fn(),
data: {
items: [
{
amountUsdt: "5.99",
audienceType: "normal",
coinAmount: 480000,
description: "480,000 coins",
enabled: true,
platform: "android",
productCode: "coins_480000",
productId: 1,
productName: "coins_480000",
regionIds: [1, 2],
updatedAtMs: 1760000000000,
},
],
total: 1,
},
editingItem: null,
error: null,
form: {
amountUsdt: "",
audienceType: "normal",
coinAmount: "",
description: "",
enabled: true,
platform: "android",
productName: "",
regionIds: [],
},
keyword: "",
loading: false,
loadingAction: "",
loadingRegions: false,
openCreate: vi.fn(),
openEdit: vi.fn(),
page: 1,
pageSize: 50,
platform: "android",
regionId: "",
regionOptions: [
{ label: "中东 · ME · 1", name: "中东", value: "1" },
{ label: "欧洲美区 · EU · 2", name: "欧洲美区", value: "2" },
],
reload: vi.fn(),
removeProduct: vi.fn(),
resetFilters: vi.fn(),
setAudienceType: vi.fn(),
setForm: vi.fn(),
setKeyword: vi.fn(),
setPage: vi.fn(),
setPlatform: vi.fn(),
setRegionId: vi.fn(),
setStatus: vi.fn(),
status: "",
submitProduct: vi.fn(),
toggleProductEnabled: vi.fn(),
};
}