From 97915b59803dce8edfb5aca1ee3bb823824aa0ba Mon Sep 17 00:00:00 2001 From: zhx Date: Tue, 16 Jun 2026 17:58:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=85=E5=80=BC=E5=BC=B9=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/RechargeProductConfigPage.jsx | 274 +++++++++--------- .../pages/RechargeProductConfigPage.test.jsx | 111 +++++++ 2 files changed, 249 insertions(+), 136 deletions(-) create mode 100644 src/features/payment/pages/RechargeProductConfigPage.test.jsx diff --git a/src/features/payment/pages/RechargeProductConfigPage.jsx b/src/features/payment/pages/RechargeProductConfigPage.jsx index e5bde54..7fc774d 100644 --- a/src/features/payment/pages/RechargeProductConfigPage.jsx +++ b/src/features/payment/pages/RechargeProductConfigPage.jsx @@ -7,7 +7,6 @@ import Tabs from "@mui/material/Tabs"; import TextField from "@mui/material/TextField"; import { useEffect, useMemo, useState } from "react"; 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 { Button } from "@/shared/ui/Button.jsx"; import { @@ -51,10 +50,25 @@ const audienceOptions = [ ["coin_seller", "币商"], ]; +const productTabConfigs = { + google: { + createLabel: "新增 Google 商品", + dialogEditTitle: "编辑 Google 商品", + dialogCreateTitle: "新增 Google 商品", + platform: "android", + }, + third_party: { + createLabel: "新增三方商品", + dialogEditTitle: "编辑三方商品", + dialogCreateTitle: "新增三方商品", + platform: "web", + }, +}; + export function RechargeProductConfigPage() { const page = useRechargeProductsPage(); const [activeProductTab, setActiveProductTab] = useState("google"); - const googleProductPlatform = "android"; + const activeProductConfig = productTabConfigs[activeProductTab] || productTabConfigs.google; const { platform, setPlatform } = page; const items = page.data?.items || []; 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 openCreate = () => { page.openCreate(); - page.setForm({ platform: googleProductPlatform }); + page.setForm({ platform: activeProductConfig.platform }); }; useEffect(() => { - if (activeProductTab === "google" && platform !== googleProductPlatform) { - setPlatform(googleProductPlatform); + // 商品接口已经支持按 platform 区分 Google / 三方档位;tab 只负责把查询和新建表单固定到对应平台。 + if (platform !== activeProductConfig.platform) { + setPlatform(activeProductConfig.platform); } - }, [activeProductTab, googleProductPlatform, platform, setPlatform]); + }, [activeProductConfig.platform, platform, setPlatform]); return ( @@ -81,140 +96,127 @@ export function RechargeProductConfigPage() { - {activeProductTab === "google" ? ( - <> - } - variant="primary" - onClick={openCreate} - > - 新增 Google 商品 - - ) : null - } + } variant="primary" onClick={openCreate}> + {activeProductConfig.createLabel} + + ) : null + } + /> + + + item.productId} /> - - - item.productId} - /> - - - - ) : ( - - )} - - {activeProductTab === "google" ? ( - - - - page.setForm({ productName: event.target.value })} - /> - page.setForm({ platform: event.target.value })} - > - Web - Android - iOS - - page.setForm({ audienceType: event.target.value })} - > - 普通用户 - 币商 - - - - - - page.setForm({ amountUsdt: event.target.value })} - /> - page.setForm({ coinAmount: event.target.value })} - /> - - - - page.setForm({ regionIds })} - /> - page.setForm({ enabled: checked })} - /> - - + + + + + page.setForm({ description: event.target.value })} + label="产品名称" + required + value={page.form.productName} + onChange={(event) => page.setForm({ productName: event.target.value })} /> - - - ) : null} + page.setForm({ platform: event.target.value })} + > + Web + Android + iOS + + page.setForm({ audienceType: event.target.value })} + > + 普通用户 + 币商 + + + + + + page.setForm({ amountUsdt: event.target.value })} + /> + page.setForm({ coinAmount: event.target.value })} + /> + + + + page.setForm({ regionIds })} + /> + page.setForm({ enabled: checked })} + /> + + + page.setForm({ description: event.target.value })} + /> + + ); } diff --git a/src/features/payment/pages/RechargeProductConfigPage.test.jsx b/src/features/payment/pages/RechargeProductConfigPage.test.jsx new file mode 100644 index 0000000..c280b08 --- /dev/null +++ b/src/features/payment/pages/RechargeProductConfigPage.test.jsx @@ -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(); + + 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(); + + 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(), + }; +}