diff --git a/contracts/admin-openapi.json b/contracts/admin-openapi.json index 4363abe..b6edec9 100644 --- a/contracts/admin-openapi.json +++ b/contracts/admin-openapi.json @@ -4153,181 +4153,6 @@ "x-permissions": ["finance:view"] } }, - "/admin/finance/applications": { - "get": { - "operationId": "listFinanceApplications", - "parameters": [ - { - "in": "query", - "name": "app_code", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "operation", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "status", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "keyword", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "page", - "schema": { - "type": "integer" - } - }, - { - "in": "query", - "name": "page_size", - "schema": { - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/FinanceApplicationPageResponse" - } - }, - "x-permission": "finance-application:audit", - "x-permissions": ["finance-application:audit"] - }, - "post": { - "operationId": "createFinanceApplication", - "requestBody": { - "$ref": "#/components/requestBodies/FinanceApplicationRequest" - }, - "responses": { - "201": { - "$ref": "#/components/responses/FinanceApplicationResponse" - } - }, - "x-permission": "finance-application:create", - "x-permissions": ["finance-application:create"] - } - }, - "/admin/finance/applications/mine": { - "get": { - "operationId": "listMyFinanceApplications", - "parameters": [ - { - "in": "query", - "name": "app_code", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "operation", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "status", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "keyword", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "page", - "schema": { - "type": "integer" - } - }, - { - "in": "query", - "name": "page_size", - "schema": { - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/FinanceApplicationPageResponse" - } - }, - "x-permission": "finance-application:create", - "x-permissions": ["finance-application:create"] - } - }, - "/admin/finance/applications/{application_id}/approve": { - "post": { - "operationId": "approveFinanceApplication", - "parameters": [ - { - "in": "path", - "name": "application_id", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "$ref": "#/components/requestBodies/FinanceApplicationAuditRequest" - }, - "responses": { - "200": { - "$ref": "#/components/responses/FinanceApplicationResponse" - } - }, - "x-permission": "finance-application:audit", - "x-permissions": ["finance-application:audit"] - } - }, - "/admin/finance/applications/{application_id}/reject": { - "post": { - "operationId": "rejectFinanceApplication", - "parameters": [ - { - "in": "path", - "name": "application_id", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "$ref": "#/components/requestBodies/FinanceApplicationAuditRequest" - }, - "responses": { - "200": { - "$ref": "#/components/responses/FinanceApplicationResponse" - } - }, - "x-permission": "finance-application:audit", - "x-permissions": ["finance-application:audit"] - } - }, "/admin/finance/withdrawal-applications": { "get": { "operationId": "listFinanceWithdrawalApplications", @@ -4367,7 +4192,7 @@ } }, "x-permission": "finance-withdrawal:view", - "x-permissions": ["finance-withdrawal:view", "finance-withdrawal:audit", "finance-application:audit"] + "x-permissions": ["finance-withdrawal:view", "finance-withdrawal:audit"] } }, "/admin/finance/withdrawal-applications/{application_id}/approve": { @@ -4384,7 +4209,7 @@ } ], "requestBody": { - "$ref": "#/components/requestBodies/FinanceApplicationAuditRequest" + "$ref": "#/components/requestBodies/FinanceWithdrawalAuditRequest" }, "responses": { "200": { @@ -4392,7 +4217,7 @@ } }, "x-permission": "finance-withdrawal:audit", - "x-permissions": ["finance-withdrawal:audit", "finance-application:audit"] + "x-permissions": ["finance-withdrawal:audit"] } }, "/admin/finance/withdrawal-applications/{application_id}/reject": { @@ -4409,7 +4234,7 @@ } ], "requestBody": { - "$ref": "#/components/requestBodies/FinanceApplicationAuditRequest" + "$ref": "#/components/requestBodies/FinanceWithdrawalAuditRequest" }, "responses": { "200": { @@ -4417,7 +4242,7 @@ } }, "x-permission": "finance-withdrawal:audit", - "x-permissions": ["finance-withdrawal:audit", "finance-application:audit"] + "x-permissions": ["finance-withdrawal:audit"] } }, "/admin/finance/orders/coin-seller-recharges": { @@ -7419,15 +7244,6 @@ } } }, - "FinanceApplicationRequest": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FinanceApplicationInput" - } - } - } - }, "FinanceCoinSellerRechargeOrderRequest": { "content": { "application/json": { @@ -7464,7 +7280,7 @@ } } }, - "FinanceApplicationAuditRequest": { + "FinanceWithdrawalAuditRequest": { "content": { "application/json": { "schema": { @@ -7952,26 +7768,6 @@ } } }, - "FinanceApplicationPageResponse": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiResponseFinanceApplicationPage" - } - } - } - }, - "FinanceApplicationResponse": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiResponseFinanceApplication" - } - } - } - }, "FinanceCoinSellerRechargeOrderPageResponse": { "description": "OK", "content": { @@ -9395,27 +9191,6 @@ } } }, - "ApiPageFinanceApplication": { - "type": "object", - "required": ["items", "page", "pageSize", "total"], - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FinanceApplication" - } - }, - "page": { - "type": "integer" - }, - "pageSize": { - "type": "integer" - }, - "total": { - "type": "integer" - } - } - }, "ApiPageFinanceCoinSellerRechargeOrder": { "type": "object", "required": ["items", "page", "pageSize", "total"], @@ -10004,36 +9779,6 @@ "region_id": { "type": "integer", "format": "int64" } } }, - "ApiResponseFinanceApplication": { - "allOf": [ - { - "$ref": "#/components/schemas/Envelope" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/components/schemas/FinanceApplication" - } - } - } - ] - }, - "ApiResponseFinanceApplicationPage": { - "allOf": [ - { - "$ref": "#/components/schemas/Envelope" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/components/schemas/ApiPageFinanceApplication" - } - } - } - ] - }, "ApiResponseFinanceCoinSellerRechargeOrder": { "allOf": [ { @@ -12057,94 +11802,6 @@ } } }, - "FinanceApplication": { - "type": "object", - "required": [ - "id", - "appCode", - "operation", - "targetUserId", - "coinAmount", - "rechargeAmount", - "applicantUserId", - "status", - "createdAtMs", - "updatedAtMs" - ], - "properties": { - "id": { - "type": "integer" - }, - "appCode": { - "type": "string" - }, - "appName": { - "type": "string" - }, - "operation": { - "type": "string", - "enum": [ - "user_coin_credit", - "user_coin_debit", - "user_wallet_debit", - "user_wallet_credit", - "coin_seller_coin_credit", - "coin_seller_coin_debit" - ] - }, - "walletIdentity": { - "type": "string" - }, - "targetUserId": { - "type": "string" - }, - "coinAmount": { - "type": "integer" - }, - "rechargeAmount": { - "type": "string" - }, - "credentialImageUrl": { - "type": "string" - }, - "credentialText": { - "type": "string" - }, - "applicantUserId": { - "type": "integer" - }, - "applicantName": { - "type": "string" - }, - "auditorUserId": { - "nullable": true, - "type": "integer" - }, - "auditorName": { - "type": "string" - }, - "status": { - "type": "string", - "enum": ["pending", "approved", "rejected"] - }, - "auditRemark": { - "type": "string" - }, - "auditedAtMs": { - "nullable": true, - "type": "integer" - }, - "createdAtMs": { - "type": "integer" - }, - "updatedAtMs": { - "type": "integer" - }, - "dingTalkNotified": { - "type": "boolean" - } - } - }, "FinanceCoinSellerRechargeOrder": { "type": "object", "required": [ @@ -12347,47 +12004,6 @@ } } }, - "FinanceApplicationInput": { - "type": "object", - "required": ["appCode", "operation", "targetUserId", "coinAmount", "rechargeAmount"], - "properties": { - "appCode": { - "type": "string" - }, - "operation": { - "type": "string", - "enum": [ - "user_coin_credit", - "user_coin_debit", - "user_wallet_debit", - "user_wallet_credit", - "coin_seller_coin_credit", - "coin_seller_coin_debit" - ] - }, - "walletIdentity": { - "type": "string", - "enum": ["host", "agency", "bd"] - }, - "targetUserId": { - "type": "string" - }, - "coinAmount": { - "type": "number", - "minimum": 0 - }, - "rechargeAmount": { - "type": "number", - "minimum": 0 - }, - "credentialImageUrl": { - "type": "string" - }, - "credentialText": { - "type": "string" - } - } - }, "FinanceCoinSellerRechargeOrderInput": { "type": "object", "required": ["appCode", "targetUserId", "usdAmount", "providerCode", "externalOrderNo"], diff --git a/finance/src/FinanceApp.jsx b/finance/src/FinanceApp.jsx index 391b309..eae89de 100644 --- a/finance/src/FinanceApp.jsx +++ b/finance/src/FinanceApp.jsx @@ -1,59 +1,41 @@ import { useCallback, useEffect, useMemo, useState } from "react"; -import Dialog from "@mui/material/Dialog"; -import DialogContent from "@mui/material/DialogContent"; -import DialogTitle from "@mui/material/DialogTitle"; import { - approveFinanceApplication, approveFinanceWithdrawalApplication, - createFinanceApplication, createFinanceCoinSellerRechargeOrder, exportFinanceRechargeBills, - fetchFinanceApplicationOptions, + fetchFinanceOptions, fetchFinanceRechargeApps, fetchFinanceRechargeOverview, fetchFinanceRechargeSummaries, fetchFinanceSession, - filterOperationsByPermissions, grantFinanceCoinSellerRechargeOrder, getFinanceCoinSellerRechargeExchangeRate, - listFinanceApplications, listFinanceCoinSellerRechargeOrders, listFinanceRechargeDetails, listFinanceRechargeRegions, - listMyFinanceApplications, listFinanceWithdrawalApplications, refreshFinanceGoogleRechargePaid, replaceFinanceCoinSellerRechargeExchangeRate, - rejectFinanceApplication, rejectFinanceWithdrawalApplication, quoteFinanceCoinSellerRechargeOrder, verifyFinanceCoinSellerRechargeReceipt, verifyFinanceCoinSellerRechargeOrder, } from "./api.js"; -import { FinanceApplicationForm } from "./components/FinanceApplicationForm.jsx"; -import { FinanceApplicationList } from "./components/FinanceApplicationList.jsx"; import { FinanceAuditDialog } from "./components/FinanceAuditDialog.jsx"; import { FinanceCoinSellerRechargeOrderList } from "./components/FinanceCoinSellerRechargeOrderList.jsx"; -import { FinanceMyApplicationList } from "./components/FinanceMyApplicationList.jsx"; import { FinanceOverview } from "./components/FinanceOverview.jsx"; import { FinanceReconciliation } from "./components/FinanceReconciliation.jsx"; import { FinanceRechargeDetailList } from "./components/FinanceRechargeDetailList.jsx"; import { FinanceShell } from "./components/FinanceShell.jsx"; import { FinanceWithdrawalApplicationList } from "./components/FinanceWithdrawalApplicationList.jsx"; -import { DEFAULT_APPLICATION_FORM } from "./constants.js"; -import { - EMPTY_RECHARGE_OVERVIEW, - EMPTY_RECHARGE_SUMMARY, - buildApplicationPayload, - validateApplicationPayload, -} from "./format.js"; +import { EMPTY_RECHARGE_OVERVIEW, EMPTY_RECHARGE_SUMMARY } from "./format.js"; import { downloadCsv } from "@/shared/api/download"; import { buildLoginRedirectPath } from "@/features/auth/loginRedirect.js"; import { AppIdentity } from "@/shared/ui/AppIdentity.jsx"; import { TimeRangeFilter } from "@/shared/ui/TimeRangeFilter.jsx"; import { useToast } from "@/shared/ui/ToastProvider.jsx"; -const emptyOptions = { apps: [], operations: [], walletIdentities: [] }; +const emptyOptions = { apps: [] }; const pageSize = 50; const DAY_MS = 86_400_000; const CHINA_OFFSET_MS = 8 * 3_600_000; @@ -123,16 +105,6 @@ export function FinanceApp() { overview: EMPTY_RECHARGE_OVERVIEW, summary: EMPTY_RECHARGE_SUMMARY, }); - const [myApplicationsState, setMyApplicationsState] = useState({ - data: { items: [], page: 1, pageSize, total: 0 }, - error: "", - loading: false, - }); - const [applicationsState, setApplicationsState] = useState({ - data: { items: [], page: 1, pageSize, total: 0 }, - error: "", - loading: false, - }); const [withdrawalsState, setWithdrawalsState] = useState({ data: { items: [], page: 1, pageSize, total: 0 }, error: "", @@ -144,7 +116,7 @@ export function FinanceApp() { loading: false, }); const [coinSellerRechargeOrderActionLoading, setCoinSellerRechargeOrderActionLoading] = useState(""); - const [activeView, setActiveView] = useState("create"); + const [activeView, setActiveView] = useState("overview"); const [rechargeDetailFilters, setRechargeDetailFilters] = useState(() => ({ appCode: "", currency: "usd", @@ -156,8 +128,6 @@ export function FinanceApp() { timeRange: timePresets().find((preset) => preset.key === "yesterday").range, })); const [rechargeExporting, setRechargeExporting] = useState(false); - const [myFilters, setMyFilters] = useState({ appCode: "", keyword: "", operation: "", page: 1, status: "" }); - const [filters, setFilters] = useState({ appCode: "", keyword: "", operation: "", page: 1, status: "pending" }); const [withdrawalFilters, setWithdrawalFilters] = useState({ appCode: "", keyword: "", page: 1 }); const [coinSellerRechargeOrderFilters, setCoinSellerRechargeOrderFilters] = useState({ appCode: "", @@ -168,11 +138,6 @@ export function FinanceApp() { status: "", verifyStatus: "", }); - const [form, setForm] = useState(DEFAULT_APPLICATION_FORM); - const [createDialogOpen, setCreateDialogOpen] = useState(false); - const [submitting, setSubmitting] = useState(false); - const [auditTarget, setAuditTarget] = useState(null); - const [auditLoading, setAuditLoading] = useState(false); const [withdrawalAuditTarget, setWithdrawalAuditTarget] = useState(null); const [withdrawalAuditLoading, setWithdrawalAuditLoading] = useState(false); @@ -189,11 +154,7 @@ export function FinanceApp() { ? "overview" : session.canViewCoinSellerRechargeOrders ? "coinSellerRechargeOrders" - : session.canAuditApplication - ? "applications" - : session.canCreateApplication - ? "create" - : "withdrawals", + : "withdrawals", ); }) .catch((err) => { @@ -233,28 +194,6 @@ export function FinanceApp() { }), [rechargeBaseQuery, rechargeDetailFilters.page, rechargeDetailFilters.paidState], ); - const myApplicationQuery = useMemo( - () => ({ - app_code: myFilters.appCode, - keyword: myFilters.keyword, - operation: myFilters.operation, - page: myFilters.page, - page_size: pageSize, - status: myFilters.status, - }), - [myFilters], - ); - const applicationQuery = useMemo( - () => ({ - app_code: filters.appCode, - keyword: filters.keyword, - operation: filters.operation, - page: filters.page, - page_size: pageSize, - status: filters.status, - }), - [filters], - ); const withdrawalQuery = useMemo( () => ({ app_code: withdrawalFilters.appCode, @@ -284,30 +223,13 @@ export function FinanceApp() { } setOptionsState((current) => ({ ...current, error: "", loading: true })); try { - const data = await fetchFinanceApplicationOptions(); + const data = await fetchFinanceOptions(); setOptionsState({ data, error: "", loading: false }); } catch (err) { setOptionsState({ data: emptyOptions, error: err.message || "加载财务选项失败", loading: false }); } }, [canLoadOptions]); - const loadMyApplications = useCallback(async () => { - if (!session?.canCreateApplication) { - return; - } - setMyApplicationsState((current) => ({ ...current, error: "", loading: true })); - try { - const data = await listMyFinanceApplications(myApplicationQuery); - setMyApplicationsState({ data, error: "", loading: false }); - } catch (err) { - setMyApplicationsState((current) => ({ - ...current, - error: err.message || "加载我的申请列表失败", - loading: false, - })); - } - }, [myApplicationQuery, session?.canCreateApplication]); - // 充值详情的 App 目录来自 recharge-apps(含 Yumi/Aslan 等 legacy 外部账单源);接口未就绪时回退到财务通用 App 列表。 const rechargeApps = useMemo( () => @@ -474,23 +396,6 @@ export function FinanceApp() { } }, [rechargeAppCode, rechargeDetailQuery, rechargeExporting, showToast]); - const loadApplications = useCallback(async () => { - if (!session?.canAuditApplication) { - return; - } - setApplicationsState((current) => ({ ...current, error: "", loading: true })); - try { - const data = await listFinanceApplications(applicationQuery); - setApplicationsState({ data, error: "", loading: false }); - } catch (err) { - setApplicationsState((current) => ({ - ...current, - error: err.message || "加载申请列表失败", - loading: false, - })); - } - }, [applicationQuery, session?.canAuditApplication]); - const loadWithdrawals = useCallback(async () => { if (!session?.canViewWithdrawalApplications) { return; @@ -529,10 +434,6 @@ export function FinanceApp() { loadOptions(); }, [loadOptions]); - useEffect(() => { - loadMyApplications(); - }, [loadMyApplications]); - useEffect(() => { loadRechargeApps(); }, [loadRechargeApps]); @@ -557,10 +458,6 @@ export function FinanceApp() { loadRechargeRegions(); }, [loadRechargeRegions]); - useEffect(() => { - loadApplications(); - }, [loadApplications]); - useEffect(() => { loadWithdrawals(); }, [loadWithdrawals]); @@ -569,63 +466,6 @@ export function FinanceApp() { loadCoinSellerRechargeOrders(); }, [loadCoinSellerRechargeOrders]); - const operationOptions = useMemo( - () => filterOperationsByPermissions(optionsState.data.operations, session?.permissions || []), - [optionsState.data.operations, session?.permissions], - ); - - const submitApplication = async (event) => { - event.preventDefault(); - if (!session?.canCreateApplication) { - showToast("无发起财务申请权限", "error"); - return; - } - - const payload = buildApplicationPayload(form); - const validationMessage = validateApplicationPayload(payload); - if (validationMessage) { - showToast(validationMessage, "warning"); - return; - } - - setSubmitting(true); - try { - const result = await createFinanceApplication(cleanPayload(payload)); - setForm({ ...DEFAULT_APPLICATION_FORM, appCode: payload.appCode }); - setCreateDialogOpen(false); - showToast( - result?.dingTalkNotified === false ? "申请已提交,钉钉通知未确认" : "申请已提交并通知财务", - "success", - ); - await loadMyApplications(); - if (session.canAuditApplication) { - await loadApplications(); - } - } catch (err) { - showToast(err.message || "发起申请失败", "error"); - } finally { - setSubmitting(false); - } - }; - - const submitAudit = async ({ decision, remark }) => { - if (!auditTarget?.id || !session?.canAuditApplication) { - return; - } - setAuditLoading(true); - try { - const submitter = decision === "approved" ? approveFinanceApplication : rejectFinanceApplication; - await submitter(auditTarget.id, { auditRemark: remark }); - showToast(decision === "approved" ? "申请已通过" : "申请已拒绝", "success"); - setAuditTarget(null); - await loadApplications(); - } catch (err) { - showToast(err.message || "审核失败", "error"); - } finally { - setAuditLoading(false); - } - }; - const submitWithdrawalAudit = async ({ auditImageUrl, decision, remark }) => { if (!withdrawalAuditTarget?.id || !session?.canAuditWithdrawalApplications) { return; @@ -730,18 +570,10 @@ export function FinanceApp() { } }; - const updateFilters = (nextFilters) => { - setFilters((current) => ({ ...current, ...nextFilters, page: nextFilters.page || 1 })); - }; - const updateRechargeDetailFilters = (nextFilters) => { setRechargeDetailFilters((current) => ({ ...current, ...nextFilters, page: nextFilters.page || 1 })); }; - const updateMyFilters = (nextFilters) => { - setMyFilters((current) => ({ ...current, ...nextFilters, page: nextFilters.page || 1 })); - }; - const updateWithdrawalFilters = (nextFilters) => { setWithdrawalFilters((current) => ({ ...current, ...nextFilters, page: nextFilters.page || 1 })); }; @@ -750,13 +582,6 @@ export function FinanceApp() { setCoinSellerRechargeOrderFilters((current) => ({ ...current, ...nextFilters, page: nextFilters.page || 1 })); }; - const closeCreateDialog = (_, reason) => { - if (submitting || reason === "backdropClick") { - return; - } - setCreateDialogOpen(false); - }; - if (sessionState.loading) { return ; } @@ -853,16 +678,12 @@ export function FinanceApp() { - ) : activeView === "applications" && session.canAuditApplication ? ( - ) : activeView === "withdrawals" && session.canViewWithdrawalApplications ? ( - ) : ( - setCreateDialogOpen(true)} - onFiltersChange={updateMyFilters} - onReload={loadMyApplications} - /> - )} - - 发起申请 - - - - - setAuditTarget(null)} - onSubmit={submitAudit} - /> + ) : null} ({ - approveFinanceApplication: vi.fn(), approveFinanceWithdrawalApplication: vi.fn(), - createFinanceApplication: vi.fn(), createFinanceCoinSellerRechargeOrder: vi.fn(), exportFinanceRechargeBills: vi.fn(), - fetchFinanceApplicationOptions: vi.fn(), + fetchFinanceOptions: vi.fn(), fetchFinanceRechargeApps: vi.fn(), fetchFinanceRechargeOverview: vi.fn(), fetchFinanceRechargeSummaries: vi.fn(), fetchFinanceSession: vi.fn(), - filterOperationsByPermissions: vi.fn((operations, permissions) => operations.filter((item) => permissions.includes(item.permissionCode))), grantFinanceCoinSellerRechargeOrder: vi.fn(), getFinanceCoinSellerRechargeExchangeRate: vi.fn(), - listFinanceApplications: vi.fn(), listFinanceCoinSellerRechargeOrders: vi.fn(), listFinanceRechargeDetails: vi.fn(), listFinanceRechargeRegions: vi.fn(), listFinanceWithdrawalApplications: vi.fn(), - listMyFinanceApplications: vi.fn(), - rejectFinanceApplication: vi.fn(), rejectFinanceWithdrawalApplication: vi.fn(), refreshFinanceGoogleRechargePaid: vi.fn(), replaceFinanceCoinSellerRechargeExchangeRate: vi.fn(), @@ -48,35 +40,28 @@ vi.mock("./api.js", () => ({ const defaultSession = { canAccessFinance: true, - canAuditApplication: false, + canAuditWithdrawalApplications: false, canConfigureCoinSellerRechargeExchangeRate: false, - canCreateApplication: true, canCreateCoinSellerRechargeOrder: false, canGrantCoinSellerRechargeOrder: false, canVerifyCoinSellerRechargeOrder: false, canViewAppRechargeDetails: false, canViewCoinSellerRechargeOrders: false, - canViewWithdrawalApplications: false, - permissions: ["finance-application:create", "finance-operation:user-coin-credit"], + canViewWithdrawalApplications: true, + permissions: ["finance-withdrawal:view"], user: { account: "admin", name: "admin" } }; beforeEach(() => { - vi.mocked(fetchFinanceApplicationOptions).mockResolvedValue({ - apps: [{ appCode: "lalu", appName: "lalu" }], - operations: [{ label: "增加用户金币", permissionCode: "finance-operation:user-coin-credit", value: "user_coin_credit" }], - walletIdentities: [] - }); + vi.mocked(fetchFinanceOptions).mockResolvedValue({ apps: [{ appCode: "lalu", appName: "lalu" }] }); vi.mocked(fetchFinanceRechargeApps).mockResolvedValue([{ appCode: "lalu", appName: "Lalu" }]); vi.mocked(fetchFinanceRechargeOverview).mockResolvedValue(EMPTY_RECHARGE_OVERVIEW); vi.mocked(fetchFinanceRechargeSummaries).mockResolvedValue({ merged: EMPTY_RECHARGE_SUMMARY, perApp: [] }); vi.mocked(fetchFinanceSession).mockResolvedValue(defaultSession); - vi.mocked(listFinanceApplications).mockResolvedValue({ items: [], page: 1, pageSize: 50, total: 0 }); vi.mocked(listFinanceCoinSellerRechargeOrders).mockResolvedValue({ items: [], page: 1, pageSize: 50, total: 0 }); vi.mocked(listFinanceRechargeDetails).mockResolvedValue({ items: [], page: 1, pageSize: 50, total: 0 }); vi.mocked(listFinanceRechargeRegions).mockResolvedValue([]); vi.mocked(listFinanceWithdrawalApplications).mockResolvedValue({ items: [], page: 1, pageSize: 50, total: 0 }); - vi.mocked(listMyFinanceApplications).mockResolvedValue({ items: [], page: 1, pageSize: 50, total: 0 }); }); afterEach(() => { @@ -105,7 +90,6 @@ test("defaults recharge finance views to yesterday in China timezone", async () vi.spyOn(Date, "now").mockReturnValue(Date.UTC(2026, 6, 8, 4)); vi.mocked(fetchFinanceSession).mockResolvedValue({ ...defaultSession, - canCreateApplication: false, canViewAppRechargeDetails: true, permissions: ["finance-recharge-detail:view"] }); @@ -125,26 +109,3 @@ test("defaults recharge finance views to yesterday in China timezone", async () expect(query.start_at_ms).toBe(Date.UTC(2026, 6, 6, 16)); expect(query.end_at_ms).toBe(Date.UTC(2026, 6, 7, 16)); }); - -test("keeps create application dialog open when backdrop is clicked", async () => { - render( - - - - ); - - await screen.findByRole("button", { name: "添加" }); - expect(document.querySelector(".finance-header")).toBeNull(); - - fireEvent.click(screen.getByRole("button", { name: "添加" })); - expect(within(screen.getByRole("dialog")).getByRole("heading", { name: "发起申请" })).toBeInTheDocument(); - - const backdrop = document.querySelector(".MuiBackdrop-root"); - expect(backdrop).toBeTruthy(); - fireEvent.mouseDown(backdrop); - fireEvent.click(backdrop); - expect(screen.getByRole("dialog")).toBeInTheDocument(); - - fireEvent.click(screen.getByRole("button", { name: "取消" })); - await waitFor(() => expect(screen.queryByRole("dialog")).not.toBeInTheDocument()); -}); diff --git a/finance/src/api.js b/finance/src/api.js index 9dc630a..ec4303e 100644 --- a/finance/src/api.js +++ b/finance/src/api.js @@ -1,11 +1,10 @@ import { getMe, refreshSession } from "@/features/auth/api"; import { API_ENDPOINTS, API_OPERATIONS, apiEndpointPath } from "@/shared/api/generated/endpoints"; import { apiRequest, getAccessToken } from "@/shared/api/request"; -import { FINANCE_OPERATIONS, FINANCE_PERMISSIONS, WALLET_IDENTITIES } from "./constants.js"; +import { FINANCE_PERMISSIONS } from "./constants.js"; import { mergeRechargeOverviews, mergeRechargeSummaries, - normalizeApplicationPage, normalizeCoinSellerRechargeOrder, normalizeCoinSellerRechargeOrderPage, normalizeRechargeBillPage, @@ -20,10 +19,7 @@ const appCodeHeader = "X-App-Code"; export async function fetchFinanceSession() { const session = await currentSession(); const permissions = Array.isArray(session.permissions) ? session.permissions : []; - const canCreateApplication = permissions.includes(FINANCE_PERMISSIONS.createApplication); - const canAuditApplication = permissions.includes(FINANCE_PERMISSIONS.auditApplication); - const canAuditWithdrawalApplications = - permissions.includes(FINANCE_PERMISSIONS.auditWithdrawalApplications) || permissions.includes(FINANCE_PERMISSIONS.auditApplication); + const canAuditWithdrawalApplications = permissions.includes(FINANCE_PERMISSIONS.auditWithdrawalApplications); const canViewWithdrawalApplications = permissions.includes(FINANCE_PERMISSIONS.viewWithdrawalApplications) || canAuditWithdrawalApplications; const canViewAppRechargeDetails = permissions.includes(FINANCE_PERMISSIONS.viewAppRechargeDetails); const canViewCoinSellerRechargeOrders = permissions.includes(FINANCE_PERMISSIONS.viewCoinSellerRechargeOrders); @@ -35,15 +31,11 @@ export async function fetchFinanceSession() { return { ...session, canAccessFinance: - canCreateApplication || - canAuditApplication || canViewWithdrawalApplications || canViewAppRechargeDetails || canViewCoinSellerRechargeOrders, - canAuditApplication, canAuditWithdrawalApplications, canConfigureCoinSellerRechargeExchangeRate, - canCreateApplication, canCreateCoinSellerRechargeOrder, canGrantCoinSellerRechargeOrder, canVerifyCoinSellerRechargeOrder, @@ -54,7 +46,7 @@ export async function fetchFinanceSession() { }; } -export async function fetchFinanceApplicationOptions() { +export async function fetchFinanceOptions() { const endpoint = API_ENDPOINTS.listApps; const data = await apiRequest(apiEndpointPath(API_OPERATIONS.listApps), { method: endpoint.method @@ -71,24 +63,6 @@ export async function fetchFinanceRechargeApps() { return normalizeApps(data); } -export async function listFinanceApplications(query = {}) { - const endpoint = API_ENDPOINTS.listFinanceApplications; - const data = await apiRequest(apiEndpointPath(API_OPERATIONS.listFinanceApplications), { - method: endpoint.method, - query - }); - return normalizeApplicationPage(data); -} - -export async function listMyFinanceApplications(query = {}) { - const endpoint = API_ENDPOINTS.listMyFinanceApplications; - const data = await apiRequest(apiEndpointPath(API_OPERATIONS.listMyFinanceApplications), { - method: endpoint.method, - query - }); - return normalizeApplicationPage(data); -} - export async function listFinanceWithdrawalApplications(query = {}) { const endpoint = API_ENDPOINTS.listFinanceWithdrawalApplications; const data = await apiRequest(apiEndpointPath(API_OPERATIONS.listFinanceWithdrawalApplications), { @@ -277,30 +251,6 @@ export async function refreshFinanceGoogleRechargePaid(appCode, transactionIds) return Array.isArray(data?.items) ? data.items : []; } -export async function createFinanceApplication(payload) { - const endpoint = API_ENDPOINTS.createFinanceApplication; - return apiRequest(apiEndpointPath(API_OPERATIONS.createFinanceApplication), { - body: payload, - method: endpoint.method - }); -} - -export async function approveFinanceApplication(applicationId, payload) { - const endpoint = API_ENDPOINTS.approveFinanceApplication; - return apiRequest(apiEndpointPath(API_OPERATIONS.approveFinanceApplication, { application_id: applicationId }), { - body: payload, - method: endpoint.method - }); -} - -export async function rejectFinanceApplication(applicationId, payload) { - const endpoint = API_ENDPOINTS.rejectFinanceApplication; - return apiRequest(apiEndpointPath(API_OPERATIONS.rejectFinanceApplication, { application_id: applicationId }), { - body: payload, - method: endpoint.method - }); -} - export async function approveFinanceWithdrawalApplication(applicationId, payload) { const endpoint = API_ENDPOINTS.approveFinanceWithdrawalApplication; return apiRequest(apiEndpointPath(API_OPERATIONS.approveFinanceWithdrawalApplication, { application_id: applicationId }), { @@ -317,11 +267,6 @@ export async function rejectFinanceWithdrawalApplication(applicationId, payload) }); } -export function filterOperationsByPermissions(operations, permissions) { - const allowed = new Set(permissions || []); - return (operations || []).filter((operation) => !operation.permissionCode || allowed.has(operation.permissionCode)); -} - async function currentSession() { try { return await refreshSession(); @@ -365,9 +310,7 @@ async function listRechargeBillsForApp(appCode, query = {}) { function normalizeOptions(data = {}) { return { - apps: normalizeApps(data.apps), - operations: FINANCE_OPERATIONS, - walletIdentities: WALLET_IDENTITIES + apps: normalizeApps(data.apps) }; } diff --git a/finance/src/api.test.js b/finance/src/api.test.js index c05d8e1..816be65 100644 --- a/finance/src/api.test.js +++ b/finance/src/api.test.js @@ -1,34 +1,53 @@ import { afterEach, expect, test, vi } from "vitest"; import { setAccessToken } from "@/shared/api/request"; import { - approveFinanceApplication, approveFinanceWithdrawalApplication, - createFinanceApplication, createFinanceCoinSellerRechargeOrder, - fetchFinanceApplicationOptions, + fetchFinanceOptions, + fetchFinanceSession, getFinanceCoinSellerRechargeExchangeRate, - filterOperationsByPermissions, grantFinanceCoinSellerRechargeOrder, - listFinanceApplications, listFinanceCoinSellerRechargeOrders, listFinanceRechargeDetails, - listMyFinanceApplications, listFinanceWithdrawalApplications, - rejectFinanceApplication, rejectFinanceWithdrawalApplication, quoteFinanceCoinSellerRechargeOrder, replaceFinanceCoinSellerRechargeExchangeRate, verifyFinanceCoinSellerRechargeReceipt, verifyFinanceCoinSellerRechargeOrder } from "./api.js"; -import { FINANCE_OPERATIONS } from "./constants.js"; afterEach(() => { setAccessToken(""); vi.unstubAllGlobals(); }); -test("finance application APIs use generated endpoint paths", async () => { +test("finance session no longer treats removed application permissions as withdrawal access", async () => { + vi.stubGlobal( + "fetch", + vi.fn(async () => + new Response( + JSON.stringify({ + code: 0, + data: { + permissions: ["finance-application:audit"], + user: { account: "legacy-finance" } + } + }) + ) + ) + ); + + const session = await fetchFinanceSession(); + + expect(session.canAccessFinance).toBe(false); + expect(session.canAuditWithdrawalApplications).toBe(false); + expect(session.canViewWithdrawalApplications).toBe(false); + expect(session).not.toHaveProperty("canAuditApplication"); + expect(session).not.toHaveProperty("canCreateApplication"); +}); + +test("finance options and withdrawal APIs use generated endpoint paths", async () => { vi.stubGlobal( "fetch", vi.fn(async (url) => { @@ -41,12 +60,6 @@ test("finance application APIs use generated endpoint paths", async () => { } })); } - if (String(url).includes("/applications?")) { - return new Response(JSON.stringify({ code: 0, data: { items: [], page: 1, pageSize: 50, total: 0 } })); - } - if (String(url).includes("/applications/mine?")) { - return new Response(JSON.stringify({ code: 0, data: { items: [], page: 1, pageSize: 50, total: 0 } })); - } if (String(url).includes("/withdrawal-applications?")) { return new Response(JSON.stringify({ code: 0, data: { items: [], page: 1, pageSize: 50, total: 0 } })); } @@ -54,19 +67,8 @@ test("finance application APIs use generated endpoint paths", async () => { }) ); - const options = await fetchFinanceApplicationOptions(); - await listFinanceApplications({ page: 1, page_size: 50, status: "pending" }); - await listMyFinanceApplications({ page: 1, page_size: 50 }); + const options = await fetchFinanceOptions(); await listFinanceWithdrawalApplications({ page: 1, page_size: 50 }); - await createFinanceApplication({ - appCode: "lalu", - coinAmount: 100, - operation: "coin_seller_coin_credit", - rechargeAmount: 10, - targetUserId: "10001" - }); - await approveFinanceApplication(12, { auditRemark: "ok" }); - await rejectFinanceApplication(13, { auditRemark: "bad" }); await approveFinanceWithdrawalApplication(14, { auditImageUrl: "https://cdn.example.com/pay.png", auditRemark: "ok" }); await rejectFinanceWithdrawalApplication(15, { auditRemark: "bad" }); @@ -74,38 +76,16 @@ test("finance application APIs use generated endpoint paths", async () => { expect(options.apps).toEqual([ { appCode: "lalu", appName: "Lalu", logoUrl: "https://media.example.com/lalu.png" } ]); - expect(options.operations.map((item) => item.label)).toEqual([ - "增加用户金币", - "减少用户金币", - "用户钱包扣减", - "用户钱包增加", - "增加币商金币", - "减少币商金币" - ]); expect(String(calls[0][0])).toContain("/api/v1/admin/apps"); expect(calls[0][1]?.method).toBe("GET"); - expect(String(calls[1][0])).toContain("/api/v1/admin/finance/applications?"); - expect(String(calls[1][0])).toContain("status=pending"); + expect(String(calls[1][0])).toContain("/api/v1/admin/finance/withdrawal-applications?"); expect(calls[1][1]?.method).toBe("GET"); - expect(String(calls[2][0])).toContain("/api/v1/admin/finance/applications/mine?"); - expect(calls[2][1]?.method).toBe("GET"); - expect(String(calls[3][0])).toContain("/api/v1/admin/finance/withdrawal-applications?"); - expect(calls[3][1]?.method).toBe("GET"); - expect(String(calls[4][0])).toContain("/api/v1/admin/finance/applications"); - expect(calls[4][1]?.method).toBe("POST"); - expect(JSON.parse(String(calls[4][1]?.body))).toMatchObject({ appCode: "lalu", operation: "coin_seller_coin_credit" }); - expect(String(calls[5][0])).toContain("/api/v1/admin/finance/applications/12/approve"); - expect(calls[5][1]?.method).toBe("POST"); - expect(JSON.parse(String(calls[5][1]?.body))).toEqual({ auditRemark: "ok" }); - expect(String(calls[6][0])).toContain("/api/v1/admin/finance/applications/13/reject"); - expect(calls[6][1]?.method).toBe("POST"); - expect(JSON.parse(String(calls[6][1]?.body))).toEqual({ auditRemark: "bad" }); - expect(String(calls[7][0])).toContain("/api/v1/admin/finance/withdrawal-applications/14/approve"); - expect(calls[7][1]?.method).toBe("POST"); - expect(JSON.parse(String(calls[7][1]?.body))).toEqual({ auditImageUrl: "https://cdn.example.com/pay.png", auditRemark: "ok" }); - expect(String(calls[8][0])).toContain("/api/v1/admin/finance/withdrawal-applications/15/reject"); - expect(calls[8][1]?.method).toBe("POST"); - expect(JSON.parse(String(calls[8][1]?.body))).toEqual({ auditRemark: "bad" }); + expect(String(calls[2][0])).toContain("/api/v1/admin/finance/withdrawal-applications/14/approve"); + expect(calls[2][1]?.method).toBe("POST"); + expect(JSON.parse(String(calls[2][1]?.body))).toEqual({ auditImageUrl: "https://cdn.example.com/pay.png", auditRemark: "ok" }); + expect(String(calls[3][0])).toContain("/api/v1/admin/finance/withdrawal-applications/15/reject"); + expect(calls[3][1]?.method).toBe("POST"); + expect(JSON.parse(String(calls[3][1]?.body))).toEqual({ auditRemark: "bad" }); }); test("finance coin seller recharge order APIs use generated endpoint paths", async () => { @@ -194,15 +174,6 @@ test("finance coin seller quote and exchange rate APIs use generated endpoint pa expect(calls[2][1]?.method).toBe("PUT"); }); -test("filters operation options by backend-configured permissions", () => { - const allowed = filterOperationsByPermissions(FINANCE_OPERATIONS, [ - "finance-operation:user-coin-credit", - "finance-operation:coin-seller-coin-debit" - ]); - - expect(allowed.map((item) => item.value)).toEqual(["user_coin_credit", "coin_seller_coin_debit"]); -}); - test("finance recharge details query every app with app header and merge by recharge time", async () => { vi.stubGlobal( "fetch", diff --git a/finance/src/components/FinanceApplicationForm.jsx b/finance/src/components/FinanceApplicationForm.jsx deleted file mode 100644 index cca1463..0000000 --- a/finance/src/components/FinanceApplicationForm.jsx +++ /dev/null @@ -1,143 +0,0 @@ -import SendOutlined from "@mui/icons-material/SendOutlined"; -import Alert from "@mui/material/Alert"; -import Button from "@mui/material/Button"; -import InputAdornment from "@mui/material/InputAdornment"; -import MenuItem from "@mui/material/MenuItem"; -import TextField from "@mui/material/TextField"; -import { AppIdentity } from "@/shared/ui/AppIdentity.jsx"; -import { UploadField } from "@/shared/ui/UploadField.jsx"; - -export function FinanceApplicationForm({ - apps, - disabled, - error, - form, - loading, - operations, - walletIdentities, - onChange, - onCancel, - onSubmit -}) { - const selectedOperation = operations.find((operation) => operation.value === form.operation); - const needsWalletIdentity = Boolean(selectedOperation?.requiresWalletIdentity); - const canSubmit = !disabled && !loading && apps.length > 0 && operations.length > 0; - - const updateField = (key, value) => { - if (key === "operation") { - const nextOperation = operations.find((operation) => operation.value === value); - onChange({ ...form, operation: value, walletIdentity: nextOperation?.requiresWalletIdentity ? form.walletIdentity : "" }); - return; - } - onChange({ ...form, [key]: value }); - }; - - return ( -
- {error ? {error} : null} - {disabled ? 无发起财务申请权限 : null} - {!loading && !disabled && (!apps.length || !operations.length) ? 暂无可用 APP 或操作权限 : null} -
- updateField("appCode", event.target.value)} - > - {apps.map((app) => ( - - - - ))} - - updateField("operation", event.target.value)} - > - {operations.map((operation) => ( - - {operation.label} - - ))} - - {needsWalletIdentity ? ( - updateField("walletIdentity", event.target.value)} - > - {walletIdentities.map(([value, label]) => ( - - {label} - - ))} - - ) : null} - updateField("targetUserId", event.target.value)} - /> - updateField("coinAmount", event.target.value)} - /> - USD }} - inputProps={{ min: 0, step: "0.01" }} - label="充值金额" - required - type="number" - value={form.rechargeAmount} - onChange={(event) => updateField("rechargeAmount", event.target.value)} - /> -
-
- updateField("credentialImageUrl", value)} - /> - updateField("credentialText", event.target.value)} - /> -
-
- {onCancel ? ( - - ) : null} - -
-
- ); -} diff --git a/finance/src/components/FinanceApplicationList.jsx b/finance/src/components/FinanceApplicationList.jsx deleted file mode 100644 index 96ed6d6..0000000 --- a/finance/src/components/FinanceApplicationList.jsx +++ /dev/null @@ -1,201 +0,0 @@ -import CheckCircleOutlineOutlined from "@mui/icons-material/CheckCircleOutlineOutlined"; -import CloseOutlined from "@mui/icons-material/CloseOutlined"; -import RefreshOutlined from "@mui/icons-material/RefreshOutlined"; -import Button from "@mui/material/Button"; -import IconButton from "@mui/material/IconButton"; -import MenuItem from "@mui/material/MenuItem"; -import Table from "@mui/material/Table"; -import TableBody from "@mui/material/TableBody"; -import TableCell from "@mui/material/TableCell"; -import TableContainer from "@mui/material/TableContainer"; -import TableHead from "@mui/material/TableHead"; -import TableRow from "@mui/material/TableRow"; -import TextField from "@mui/material/TextField"; -import { AppIdentity } from "@/shared/ui/AppIdentity.jsx"; -import Tooltip from "@mui/material/Tooltip"; -import { APPLICATION_STATUS } from "../constants.js"; -import { formatAmount, formatTime, operationLabel, statusLabel, walletIdentityLabel } from "../format.js"; - -export function FinanceApplicationList({ applications, error, filters, loading, onAudit, onFiltersChange, onReload, operations, options }) { - const items = applications.items || []; - const page = Number(applications.page || filters.page || 1); - const pageSize = Number(applications.pageSize || 50); - const total = Number(applications.total || 0); - const hasNextPage = page * pageSize < total; - - return ( -
-
- onFiltersChange({ appCode: event.target.value })} - > - 全部 APP - {options.apps.map((app) => ( - - - - ))} - - onFiltersChange({ operation: event.target.value })} - > - 全部操作 - {operations.map((operation) => ( - - {operation.label} - - ))} - - onFiltersChange({ status: event.target.value })}> - 全部状态 - {APPLICATION_STATUS.map(([value, label]) => ( - - {label} - - ))} - - onFiltersChange({ keyword: event.target.value })} - /> - -
- {error ?
{error}
: null} - {loading && !items.length ?
: null} - {!loading || items.length ? ( - - - - - APP - 操作 - 目标用户 - 金币数量 - 充值金额 - 凭证 - 申请人 - 发起申请时间 - 审批人 - 审核时间 - 状态 - 审核 - - - - {items.length ? ( - items.map((item) => ( - - - app.appCode === item.appCode)} - appCode={item.appCode} - appName={item.appName} - size="small" - /> - - - - - {item.targetUserId || "-"} - {formatAmount(item.coinAmount)} - {formatAmount(item.rechargeAmount)} - - - - - - - {formatTime(item.createdAtMs)} - - - - {formatTime(item.auditedAtMs)} - - - - - {item.status === "pending" ? ( - - - onAudit({ ...item, decision: "approved" })}> - - - - - onAudit({ ...item, decision: "rejected" })}> - - - - - ) : ( - "-" - )} - - - )) - ) : ( - - - 当前无数据 - - - )} - -
-
- ) : null} - {total > pageSize ? ( -
- - - 第 {page} 页 / 共 {total} 条 - - -
- ) : null} -
- ); -} - -function Evidence({ item }) { - if (!item.credentialImageUrl && !item.credentialText) { - return "-"; - } - return ( - - {item.credentialImageUrl ? ( - - 图片 - - ) : null} - {item.credentialText ? {item.credentialText} : null} - - ); -} - -function Stacked({ primary, secondary }) { - return ( - - {primary || "-"} - {secondary || ""} - - ); -} - -function StatusBadge({ status }) { - const tone = status === "approved" ? "success" : status === "rejected" ? "danger" : "warning"; - return {statusLabel(status)}; -} diff --git a/finance/src/components/FinanceApplicationList.test.jsx b/finance/src/components/FinanceApplicationList.test.jsx deleted file mode 100644 index 0b0cc76..0000000 --- a/finance/src/components/FinanceApplicationList.test.jsx +++ /dev/null @@ -1,67 +0,0 @@ -import { render, screen } from "@testing-library/react"; -import { expect, test, vi } from "vitest"; -import { FinanceApplicationList } from "./FinanceApplicationList.jsx"; - -const baseProps = { - applications: { - items: [], - page: 1, - pageSize: 50, - total: 0 - }, - error: "", - filters: { - appCode: "", - keyword: "", - operation: "", - page: 1, - status: "" - }, - loading: false, - onAudit: vi.fn(), - onFiltersChange: vi.fn(), - onReload: vi.fn(), - operations: [{ label: "增加币商金币", value: "coin_seller_coin_credit" }], - options: { apps: [] } -}; - -test("renders finance audit table with explicit applicant and audit time columns", () => { - render( - - ); - - expect(screen.getByRole("columnheader", { name: "发起申请时间" })).toBeInTheDocument(); - expect(screen.getByRole("columnheader", { name: "审批人" })).toBeInTheDocument(); - expect(screen.getByRole("columnheader", { name: "审核时间" })).toBeInTheDocument(); - expect(screen.getByText("王财务")).toBeInTheDocument(); - expect(screen.getByText("99")).toBeInTheDocument(); -}); - -test("keeps empty finance audit table colspan aligned with visible columns", () => { - const { container } = render(); - - expect(container.querySelector("tbody td")?.colSpan).toBe(12); - expect(screen.getByText("当前无数据")).toBeInTheDocument(); -}); diff --git a/finance/src/components/FinanceAuditDialog.jsx b/finance/src/components/FinanceAuditDialog.jsx index 07ccb6f..3f2e9a4 100644 --- a/finance/src/components/FinanceAuditDialog.jsx +++ b/finance/src/components/FinanceAuditDialog.jsx @@ -7,9 +7,8 @@ import TextField from "@mui/material/TextField"; import { useEffect, useState } from "react"; import { AppIdentity } from "@/shared/ui/AppIdentity.jsx"; import { UploadField } from "@/shared/ui/UploadField.jsx"; -import { operationLabel } from "../format.js"; -export function FinanceAuditDialog({ application, apps = [], loading, onClose, onSubmit, open, operations, requireApprovalImage = false, requireRejectRemark = false }) { +export function FinanceAuditDialog({ application, apps = [], loading, onClose, onSubmit, open, requireApprovalImage = false, requireRejectRemark = false }) { const [remark, setRemark] = useState(""); const [auditImageUrl, setAuditImageUrl] = useState(""); const decision = application?.decision || "approved"; @@ -39,8 +38,8 @@ export function FinanceAuditDialog({ application, apps = [], loading, onClose, o appName={application?.appName} size="small" /> - {operationLabel(application?.operation, operations)} - {application?.targetUserId || "-"} + {application?.withdrawMethod || "用户提现"} + {application?.userId || "-"} -
- onFiltersChange({ appCode: event.target.value })}> - 全部 APP - {options.apps.map((app) => ( - - - - ))} - - onFiltersChange({ operation: event.target.value })}> - 全部操作 - {operations.map((operation) => ( - - {operation.label} - - ))} - - onFiltersChange({ status: event.target.value })}> - 全部状态 - {APPLICATION_STATUS.map(([value, label]) => ( - - {label} - - ))} - - onFiltersChange({ keyword: event.target.value })} /> - - -
- {error ?
{error}
: null} - {loading && !items.length ?
: null} - {!loading || items.length ? ( - - - - - APP - 操作 - 目标用户 - 金币数量 - 充值金额 - 凭证 - 状态 - 发起申请时间 - 审批人 - 审核时间 - - - - {items.length ? ( - items.map((item) => ( - - - app.appCode === item.appCode)} - appCode={item.appCode} - appName={item.appName} - size="small" - /> - - - - - {item.targetUserId || "-"} - {formatAmount(item.coinAmount)} - {formatAmount(item.rechargeAmount)} - - - - - - - {formatTime(item.createdAtMs)} - - - - {formatTime(item.auditedAtMs)} - - )) - ) : ( - - - 当前无数据 - - - )} - -
-
- ) : null} - {total > pageSize ? ( -
- - - 第 {page} 页 / 共 {total} 条 - - -
- ) : null} - - ); -} - -function Evidence({ item }) { - if (!item.credentialImageUrl && !item.credentialText) { - return "-"; - } - return ( - - {item.credentialImageUrl ? ( - - 图片 - - ) : null} - {item.credentialText ? {item.credentialText} : null} - - ); -} - -function Stacked({ primary, secondary }) { - return ( - - {primary || "-"} - {secondary || ""} - - ); -} - -function StatusBadge({ status }) { - const tone = status === "approved" ? "success" : status === "rejected" ? "danger" : "warning"; - return {statusLabel(status)}; -} diff --git a/finance/src/components/FinanceMyApplicationList.test.jsx b/finance/src/components/FinanceMyApplicationList.test.jsx deleted file mode 100644 index 3ee06d6..0000000 --- a/finance/src/components/FinanceMyApplicationList.test.jsx +++ /dev/null @@ -1,81 +0,0 @@ -import { fireEvent, render, screen } from "@testing-library/react"; -import { expect, test, vi } from "vitest"; -import { FinanceMyApplicationList } from "./FinanceMyApplicationList.jsx"; - -const baseProps = { - applications: { - items: [], - page: 1, - pageSize: 50, - total: 0 - }, - error: "", - filters: { - appCode: "", - keyword: "", - operation: "", - page: 1, - status: "" - }, - loading: false, - onCreate: vi.fn(), - onFiltersChange: vi.fn(), - onReload: vi.fn(), - operations: [{ label: "增加用户金币", value: "user_coin_credit" }], - options: { apps: [] } -}; - -test("renders my finance application list and create action", () => { - const onCreate = vi.fn(); - render( - - ); - - expect(screen.getByRole("columnheader", { name: "APP" })).toBeInTheDocument(); - expect(screen.getByRole("columnheader", { name: "操作" })).toBeInTheDocument(); - expect(screen.getByRole("columnheader", { name: "目标用户" })).toBeInTheDocument(); - expect(screen.getByRole("columnheader", { name: "金币数量" })).toBeInTheDocument(); - expect(screen.getByRole("columnheader", { name: "充值金额" })).toBeInTheDocument(); - expect(screen.getByRole("columnheader", { name: "凭证" })).toBeInTheDocument(); - expect(screen.getByRole("columnheader", { name: "状态" })).toBeInTheDocument(); - expect(screen.getByRole("columnheader", { name: "发起申请时间" })).toBeInTheDocument(); - expect(screen.getByRole("columnheader", { name: "审批人" })).toBeInTheDocument(); - expect(screen.getByRole("columnheader", { name: "审核时间" })).toBeInTheDocument(); - expect(screen.getByText("lalu")).toBeInTheDocument(); - expect(screen.getByText("增加用户金币")).toBeInTheDocument(); - expect(screen.getByText("10001")).toBeInTheDocument(); - expect(screen.getByText("已通过")).toBeInTheDocument(); - - fireEvent.click(screen.getByRole("button", { name: "添加" })); - expect(onCreate).toHaveBeenCalledTimes(1); -}); - -test("keeps empty my finance application table colspan aligned with visible columns", () => { - const { container } = render(); - - expect(container.querySelector("tbody td")?.colSpan).toBe(10); - expect(screen.getByText("当前无数据")).toBeInTheDocument(); -}); diff --git a/finance/src/components/FinanceShell.jsx b/finance/src/components/FinanceShell.jsx index 9c395ab..f2ea994 100644 --- a/finance/src/components/FinanceShell.jsx +++ b/finance/src/components/FinanceShell.jsx @@ -1,5 +1,3 @@ -import AssignmentOutlined from "@mui/icons-material/AssignmentOutlined"; -import FactCheckOutlined from "@mui/icons-material/FactCheckOutlined"; import InsightsOutlined from "@mui/icons-material/InsightsOutlined"; import PaymentsOutlined from "@mui/icons-material/PaymentsOutlined"; import ReceiptLongOutlined from "@mui/icons-material/ReceiptLongOutlined"; @@ -21,18 +19,12 @@ const NAV_GROUPS = [ }, { label: "审批", - views: [ - { icon: AssignmentOutlined, id: "create", label: "发起申请" }, - { icon: FactCheckOutlined, id: "applications", label: "申请审核" }, - { icon: PaymentsOutlined, id: "withdrawals", label: "用户提现申请" }, - ], + views: [{ icon: PaymentsOutlined, id: "withdrawals", label: "用户提现申请" }], }, ]; const VIEW_TITLES = { - applications: "申请审核", coinSellerRechargeOrders: "币商充值", - create: "发起申请", overview: "财务概览", recon: "渠道对账", rechargeDetails: "充值流水", @@ -42,8 +34,6 @@ const VIEW_TITLES = { export function FinanceShell({ activeView, appBar, - canAudit, - canCreate, canViewCoinSellerRechargeOrders, canViewRechargeDetails, canViewWithdrawals, @@ -61,13 +51,10 @@ export function FinanceShell({ if (viewId === "coinSellerRechargeOrders") { return canViewCoinSellerRechargeOrders; } - if (viewId === "applications") { - return canAudit; - } if (viewId === "withdrawals") { return canViewWithdrawals; } - return canCreate; + return false; }; return (
diff --git a/finance/src/constants.js b/finance/src/constants.js index 880b042..f837a32 100644 --- a/finance/src/constants.js +++ b/finance/src/constants.js @@ -1,8 +1,6 @@ export const FINANCE_PERMISSIONS = { - auditApplication: "finance-application:audit", auditWithdrawalApplications: "finance-withdrawal:audit", configureCoinSellerRechargeExchangeRate: "coin-seller:exchange-rate", - createApplication: "finance-application:create", createCoinSellerRechargeOrder: "finance-order:coin-seller-recharge:create", grantCoinSellerRechargeOrder: "finance-order:coin-seller-recharge:grant", verifyCoinSellerRechargeOrder: "finance-order:coin-seller-recharge:verify", @@ -11,50 +9,7 @@ export const FINANCE_PERMISSIONS = { viewWithdrawalApplications: "finance-withdrawal:view", }; -export const FINANCE_OPERATIONS = [ - { - allowsZeroRechargeAmount: true, - label: "增加用户金币", - permissionCode: "finance-operation:user-coin-credit", - value: "user_coin_credit", - }, - { - allowsZeroRechargeAmount: true, - label: "减少用户金币", - permissionCode: "finance-operation:user-coin-debit", - value: "user_coin_debit", - }, - { - label: "用户钱包扣减", - permissionCode: "finance-operation:user-wallet-debit", - requiresWalletIdentity: true, - value: "user_wallet_debit", - }, - { - label: "用户钱包增加", - permissionCode: "finance-operation:user-wallet-credit", - requiresWalletIdentity: true, - value: "user_wallet_credit", - }, - { - label: "增加币商金币", - permissionCode: "finance-operation:coin-seller-coin-credit", - value: "coin_seller_coin_credit", - }, - { - label: "减少币商金币", - permissionCode: "finance-operation:coin-seller-coin-debit", - value: "coin_seller_coin_debit", - }, -]; - -export const WALLET_IDENTITIES = [ - ["host", "Host 钱包"], - ["agency", "Agency 钱包"], - ["bd", "BD 钱包"], -]; - -export const APPLICATION_STATUS = [ +export const WITHDRAWAL_STATUS = [ ["pending", "待审核"], ["approved", "已通过"], ["rejected", "已拒绝"], @@ -96,17 +51,6 @@ export const COIN_SELLER_RECHARGE_GRANT_STATUS = [ ["failed", "发放失败"], ]; -export const DEFAULT_APPLICATION_FORM = { - appCode: "", - coinAmount: "", - credentialImageUrl: "", - credentialText: "", - operation: "", - rechargeAmount: "", - targetUserId: "", - walletIdentity: "", -}; - export const DEFAULT_COIN_SELLER_RECHARGE_ORDER_FORM = { appCode: "", chain: "", @@ -121,11 +65,3 @@ export const DEFAULT_COIN_SELLER_RECHARGE_ORDER_FORM = { targetUserId: "", usdAmount: "", }; - -export function operationRequiresWalletIdentity(operation) { - return FINANCE_OPERATIONS.some((item) => item.value === operation && item.requiresWalletIdentity); -} - -export function operationAllowsZeroRechargeAmount(operation) { - return FINANCE_OPERATIONS.some((item) => item.value === operation && item.allowsZeroRechargeAmount); -} diff --git a/finance/src/format.js b/finance/src/format.js index 81f5123..230a6a3 100644 --- a/finance/src/format.js +++ b/finance/src/format.js @@ -1,96 +1,12 @@ import { - APPLICATION_STATUS, COIN_SELLER_RECHARGE_CHAINS, COIN_SELLER_RECHARGE_GRANT_STATUS, COIN_SELLER_RECHARGE_PROVIDERS, COIN_SELLER_RECHARGE_STATUS, COIN_SELLER_RECHARGE_VERIFY_STATUS, - FINANCE_OPERATIONS, - WALLET_IDENTITIES, - operationAllowsZeroRechargeAmount, + WITHDRAWAL_STATUS, } from "./constants.js"; -export function buildApplicationPayload(form) { - const operation = stringValue(form.operation); - const payload = { - appCode: stringValue(form.appCode), - coinAmount: numberValue(form.coinAmount), - credentialImageUrl: stringValue(form.credentialImageUrl), - credentialText: stringValue(form.credentialText), - operation, - rechargeAmount: numberValue(form.rechargeAmount), - targetUserId: stringValue(form.targetUserId), - walletIdentity: requiresWalletIdentity(operation) ? stringValue(form.walletIdentity) : "", - }; - - return payload; -} - -export function validateApplicationPayload(payload) { - if (!payload.appCode) { - return "请选择 APP"; - } - if (!payload.operation) { - return "请选择操作内容"; - } - if (!payload.targetUserId) { - return "请填写目标用户 ID"; - } - if (!Number.isFinite(payload.coinAmount) || payload.coinAmount <= 0) { - return "请填写大于 0 的金币数量"; - } - const allowsZeroRechargeAmount = operationAllowsZeroRechargeAmount(payload.operation); - if ( - !Number.isFinite(payload.rechargeAmount) || - payload.rechargeAmount < 0 || - (!allowsZeroRechargeAmount && payload.rechargeAmount <= 0) - ) { - return allowsZeroRechargeAmount ? "请填写不小于 0 的充值金额" : "请填写大于 0 的充值金额"; - } - if (requiresWalletIdentity(payload.operation) && !payload.walletIdentity) { - return "请选择钱包身份"; - } - if (!payload.credentialImageUrl && !payload.credentialText) { - return "请上传凭证图片或填写凭证文字"; - } - return ""; -} - -export function normalizeApplication(item = {}) { - return { - appCode: stringValue(item.appCode ?? item.app_code), - appName: stringValue(item.appName ?? item.app_name), - applicantName: stringValue( - item.applicantName ?? item.applicant_name ?? item.applicantAccount ?? item.applicant_account, - ), - applicantUserId: item.applicantUserId ?? item.applicant_user_id, - auditedAtMs: numberOrNull(item.auditedAtMs ?? item.audited_at_ms), - auditorName: stringValue(item.auditorName ?? item.auditor_name ?? item.auditorAccount ?? item.auditor_account), - auditorUserId: item.auditorUserId ?? item.auditor_user_id, - auditRemark: stringValue(item.auditRemark ?? item.audit_remark), - coinAmount: numberValue(item.coinAmount ?? item.coin_amount), - createdAtMs: numberOrNull(item.createdAtMs ?? item.created_at_ms), - credentialImageUrl: stringValue(item.credentialImageUrl ?? item.credential_image_url), - credentialText: stringValue(item.credentialText ?? item.credential_text), - id: item.id ?? item.applicationId ?? item.application_id, - operation: stringValue(item.operation), - rechargeAmount: numberValue(item.rechargeAmount ?? item.recharge_amount), - status: stringValue(item.status) || "pending", - targetUserId: stringValue(item.targetUserId ?? item.target_user_id), - walletIdentity: stringValue(item.walletIdentity ?? item.wallet_identity), - }; -} - -export function normalizeApplicationPage(data = {}) { - const items = Array.isArray(data.items) ? data.items : []; - return { - items: items.map(normalizeApplication), - page: Number(data.page || 1), - pageSize: Number(data.pageSize ?? data.page_size ?? items.length), - total: Number(data.total ?? items.length), - }; -} - export function normalizeWithdrawalApplication(item = {}) { return { appCode: stringValue(item.appCode ?? item.app_code), @@ -538,10 +454,6 @@ export function normalizeRechargeRegions(data = {}) { .filter(Boolean); } -export function operationLabel(value, operations = FINANCE_OPERATIONS) { - return operations.find((item) => item.value === value)?.label || value || "-"; -} - export function rechargeTypeLabel(value) { if (value === "coin_seller_transfer") { return "币商充值"; @@ -595,7 +507,7 @@ export function rechargeSourceTone(rechargeType) { } export function statusLabel(value) { - return APPLICATION_STATUS.find(([status]) => status === value)?.[1] || value || "-"; + return WITHDRAWAL_STATUS.find(([status]) => status === value)?.[1] || value || "-"; } export function coinSellerRechargeProviderLabel(value) { @@ -642,10 +554,6 @@ export function isCoinSellerRechargeGranted(order) { ); } -export function walletIdentityLabel(value) { - return WALLET_IDENTITIES.find(([identity]) => identity === value)?.[1] || value || "-"; -} - export function formatAmount(value) { const number = Number(value); if (!Number.isFinite(number)) { @@ -701,10 +609,6 @@ export function formatPercent(value) { return `${percent.toLocaleString("zh-CN", { maximumFractionDigits: 4 })}%`; } -export function requiresWalletIdentity(operation) { - return FINANCE_OPERATIONS.some((item) => item.value === operation && item.requiresWalletIdentity); -} - function numberValue(value) { if (value === "" || value === null || value === undefined) { return Number.NaN; diff --git a/finance/src/format.test.js b/finance/src/format.test.js index 63ef80f..cc8f372 100644 --- a/finance/src/format.test.js +++ b/finance/src/format.test.js @@ -1,120 +1,18 @@ import { expect, test } from "vitest"; import { - buildApplicationPayload, buildCoinSellerRechargeReceiptPayload, buildCoinSellerRechargeExchangeRatePayload, buildCoinSellerRechargeOrderPayload, buildCoinSellerRechargeQuotePayload, coinSellerRechargeProviderLabel, - normalizeApplicationPage, normalizeCoinSellerRechargeOrderPage, normalizeRechargeBillPage, normalizeWithdrawalApplicationPage, - operationLabel, rechargeTypeLabel, - statusLabel, - validateApplicationPayload, validateCoinSellerRechargeOrderPayload, validateCoinSellerRechargeExchangeRatePayload, - walletIdentityLabel, } from "./format.js"; -test("builds and validates finance application payload", () => { - const payload = buildApplicationPayload({ - appCode: " lalu ", - coinAmount: "3000", - credentialImageUrl: "", - credentialText: "bank receipt", - operation: "user_wallet_credit", - rechargeAmount: "15.5", - targetUserId: " 10001 ", - walletIdentity: "agency", - }); - - expect(payload).toEqual({ - appCode: "lalu", - coinAmount: 3000, - credentialImageUrl: "", - credentialText: "bank receipt", - operation: "user_wallet_credit", - rechargeAmount: 15.5, - targetUserId: "10001", - walletIdentity: "agency", - }); - expect(validateApplicationPayload(payload)).toBe(""); -}); - -test("requires wallet identity and credential for wallet operations", () => { - const payload = buildApplicationPayload({ - appCode: "lalu", - coinAmount: "100", - operation: "user_wallet_debit", - rechargeAmount: "1", - targetUserId: "10001", - }); - - expect(validateApplicationPayload(payload)).toBe("请选择钱包身份"); - expect(validateApplicationPayload({ ...payload, walletIdentity: "host" })).toBe("请上传凭证图片或填写凭证文字"); -}); - -test("allows zero recharge amount only for user coin operations", () => { - const payload = buildApplicationPayload({ - appCode: "lalu", - coinAmount: "1111", - credentialText: "测试", - operation: "user_coin_credit", - rechargeAmount: "0", - targetUserId: "163185", - }); - - expect(validateApplicationPayload(payload)).toBe(""); - expect(validateApplicationPayload({ ...payload, operation: "user_wallet_credit", walletIdentity: "agency" })).toBe( - "请填写大于 0 的充值金额", - ); - expect(validateApplicationPayload({ ...payload, operation: "coin_seller_coin_credit" })).toBe( - "请填写大于 0 的充值金额", - ); -}); - -test("normalizes finance application list rows", () => { - const page = normalizeApplicationPage({ - items: [ - { - app_code: "lalu", - applicant_name: "张三", - audited_at_ms: 1760003600000, - auditor_name: "李四", - auditor_user_id: 99, - coin_amount: 200, - created_at_ms: 1760000000000, - id: 9, - operation: "coin_seller_coin_credit", - recharge_amount: 20, - status: "pending", - target_user_id: 88, - }, - ], - page: 1, - page_size: 50, - total: 1, - }); - - expect(page.items[0]).toMatchObject({ - appCode: "lalu", - applicantName: "张三", - auditedAtMs: 1760003600000, - auditorName: "李四", - auditorUserId: 99, - coinAmount: 200, - operation: "coin_seller_coin_credit", - targetUserId: "88", - }); - expect(page.pageSize).toBe(50); - expect(operationLabel("coin_seller_coin_credit")).toBe("增加币商金币"); - expect(statusLabel("pending")).toBe("待审核"); - expect(walletIdentityLabel("bd")).toBe("BD 钱包"); -}); - test("normalizes finance withdrawal application list rows", () => { const page = normalizeWithdrawalApplicationPage({ items: [ diff --git a/src/app/permissions.ts b/src/app/permissions.ts index 0f4686b..7e4f8c3 100644 --- a/src/app/permissions.ts +++ b/src/app/permissions.ts @@ -49,20 +49,12 @@ export const PERMISSIONS = { pointWithdrawalConfigView: "point-withdrawal-config:view", pointWithdrawalConfigUpdate: "point-withdrawal-config:update", financeView: "finance:view", - financeApplicationCreate: "finance-application:create", - financeApplicationAudit: "finance-application:audit", financeWithdrawalView: "finance-withdrawal:view", financeWithdrawalAudit: "finance-withdrawal:audit", financeOrderCoinSellerRechargeView: "finance-order:coin-seller-recharge:view", financeOrderCoinSellerRechargeCreate: "finance-order:coin-seller-recharge:create", financeOrderCoinSellerRechargeVerify: "finance-order:coin-seller-recharge:verify", financeOrderCoinSellerRechargeGrant: "finance-order:coin-seller-recharge:grant", - financeOperationUserCoinCredit: "finance-operation:user-coin-credit", - financeOperationUserCoinDebit: "finance-operation:user-coin-debit", - financeOperationUserWalletCredit: "finance-operation:user-wallet-credit", - financeOperationUserWalletDebit: "finance-operation:user-wallet-debit", - financeOperationCoinSellerCoinCredit: "finance-operation:coin-seller-coin-credit", - financeOperationCoinSellerCoinDebit: "finance-operation:coin-seller-coin-debit", coinLedgerView: "coin-ledger:view", coinSellerLedgerView: "coin-seller-ledger:view", coinAdjustmentView: "coin-adjustment:view", diff --git a/src/features/level-config/pages/LevelConfigPage.jsx b/src/features/level-config/pages/LevelConfigPage.jsx index e5a15d8..2b57738 100644 --- a/src/features/level-config/pages/LevelConfigPage.jsx +++ b/src/features/level-config/pages/LevelConfigPage.jsx @@ -21,6 +21,7 @@ import { ResourceGroupSelectField } from "@/shared/ui/ResourceGroupSelectDrawer. import { formatMillis } from "@/shared/utils/time.js"; import { levelStatusLabels, levelTrackLabels, levelTrackOptions } from "@/features/level-config/constants.js"; import { useLevelConfigPage } from "@/features/level-config/hooks/useLevelConfigPage.js"; +import { ResourceSelectField } from "@/features/resources/components/ResourceSelectDrawer.jsx"; import styles from "@/features/level-config/level-config.module.css"; export function LevelConfigPage() { @@ -467,32 +468,58 @@ function RuleFormDialog({ page }) { - + page.setRuleForm((current) => ({ ...current, longBadgeResourceId: value })) + } /> - + page.setRuleForm((current) => ({ ...current, avatarFrameResourceId: value })) + } /> - + page.setRuleForm((current) => ({ ...current, shortBadgeResourceId: value })) + } /> page.setRuleForm((current) => ({ ...current, rewardResourceGroupId: value })) @@ -548,6 +575,7 @@ function TierFormDialog({ page }) { page.setTierForm((current) => ({ ...current, displayAvatarFrameResourceId: "", + displayBadgeResourceId: "", track: event.target.value, })) } @@ -584,25 +612,43 @@ function TierFormDialog({ page }) { - + page.setTierForm((current) => ({ ...current, displayAvatarFrameResourceId: value })) + } /> - + page.setTierForm((current) => ({ ...current, displayBadgeResourceId: value })) + } /> page.setTierForm((current) => ({ ...current, rewardResourceGroupId: value })) @@ -668,20 +714,6 @@ function TrackFormDialog({ page }) { ); } -function ResourceSelect({ disabled, label, onChange, resources, value }) { - const options = withSelectedResource(resources, value); - return ( - - 不配置 - {options.map((resource) => ( - - {resource.name || resource.resourceCode || resource.resourceId} - - ))} - - ); -} - function ResourceLabel({ id, resources }) { if (!id) { return 未配置; diff --git a/src/shared/api/generated/endpoints.ts b/src/shared/api/generated/endpoints.ts index 523f146..b218174 100644 --- a/src/shared/api/generated/endpoints.ts +++ b/src/shared/api/generated/endpoints.ts @@ -25,7 +25,6 @@ export const API_OPERATIONS = { appListUserLoginLogs: "appListUserLoginLogs", appListUsers: "appListUsers", approveCoinSellerSubApplication: "approveCoinSellerSubApplication", - approveFinanceApplication: "approveFinanceApplication", approveFinanceWithdrawalApplication: "approveFinanceWithdrawalApplication", appSetPassword: "appSetPassword", appUnbanUser: "appUnbanUser", @@ -49,7 +48,6 @@ export const API_OPERATIONS = { createCountry: "createCountry", createEmojiPack: "createEmojiPack", createExploreTab: "createExploreTab", - createFinanceApplication: "createFinanceApplication", createFinanceCoinSellerRechargeOrder: "createFinanceCoinSellerRechargeOrder", createFullServerNoticeFanout: "createFullServerNoticeFanout", createGift: "createGift", @@ -196,7 +194,6 @@ export const API_OPERATIONS = { listEmojiPackCategories: "listEmojiPackCategories", listEmojiPacks: "listEmojiPacks", listExploreTabs: "listExploreTabs", - listFinanceApplications: "listFinanceApplications", listFinanceCoinSellerRechargeOrders: "listFinanceCoinSellerRechargeOrders", listFinanceWithdrawalApplications: "listFinanceWithdrawalApplications", listFirstRechargeRewardClaims: "listFirstRechargeRewardClaims", @@ -214,7 +211,6 @@ export const API_OPERATIONS = { listLuckyGiftConfigs: "listLuckyGiftConfigs", listLuckyGiftDraws: "listLuckyGiftDraws", listManagers: "listManagers", - listMyFinanceApplications: "listMyFinanceApplications", listOperationLogs: "listOperationLogs", listPermissions: "listPermissions", listPlatformGrantRecords: "listPlatformGrantRecords", @@ -275,7 +271,6 @@ export const API_OPERATIONS = { refresh: "refresh", refreshGoogleRechargePaid: "refreshGoogleRechargePaid", rejectCoinSellerSubApplication: "rejectCoinSellerSubApplication", - rejectFinanceApplication: "rejectFinanceApplication", rejectFinanceWithdrawalApplication: "rejectFinanceWithdrawalApplication", renameCountryCode: "renameCountryCode", replaceCoinSellerSalaryRates: "replaceCoinSellerSalaryRates", @@ -464,19 +459,12 @@ export const API_ENDPOINTS: Record = { permission: "coin-seller-sub-application:audit", permissions: ["coin-seller-sub-application:audit"] }, - approveFinanceApplication: { - method: "POST", - operationId: API_OPERATIONS.approveFinanceApplication, - path: "/v1/admin/finance/applications/{application_id}/approve", - permission: "finance-application:audit", - permissions: ["finance-application:audit"] - }, approveFinanceWithdrawalApplication: { method: "POST", operationId: API_OPERATIONS.approveFinanceWithdrawalApplication, path: "/v1/admin/finance/withdrawal-applications/{application_id}/approve", permission: "finance-withdrawal:audit", - permissions: ["finance-withdrawal:audit","finance-application:audit"] + permissions: ["finance-withdrawal:audit"] }, appSetPassword: { method: "POST", @@ -630,13 +618,6 @@ export const API_ENDPOINTS: Record = { permission: "app-config:update", permissions: ["app-config:update"] }, - createFinanceApplication: { - method: "POST", - operationId: API_OPERATIONS.createFinanceApplication, - path: "/v1/admin/finance/applications", - permission: "finance-application:create", - permissions: ["finance-application:create"] - }, createFinanceCoinSellerRechargeOrder: { method: "POST", operationId: API_OPERATIONS.createFinanceCoinSellerRechargeOrder, @@ -1657,13 +1638,6 @@ export const API_ENDPOINTS: Record = { permission: "app-config:view", permissions: ["app-config:view"] }, - listFinanceApplications: { - method: "GET", - operationId: API_OPERATIONS.listFinanceApplications, - path: "/v1/admin/finance/applications", - permission: "finance-application:audit", - permissions: ["finance-application:audit"] - }, listFinanceCoinSellerRechargeOrders: { method: "GET", operationId: API_OPERATIONS.listFinanceCoinSellerRechargeOrders, @@ -1676,7 +1650,7 @@ export const API_ENDPOINTS: Record = { operationId: API_OPERATIONS.listFinanceWithdrawalApplications, path: "/v1/admin/finance/withdrawal-applications", permission: "finance-withdrawal:view", - permissions: ["finance-withdrawal:view","finance-withdrawal:audit","finance-application:audit"] + permissions: ["finance-withdrawal:view","finance-withdrawal:audit"] }, listFirstRechargeRewardClaims: { method: "GET", @@ -1783,13 +1757,6 @@ export const API_ENDPOINTS: Record = { permission: "bd:view", permissions: ["bd:view"] }, - listMyFinanceApplications: { - method: "GET", - operationId: API_OPERATIONS.listMyFinanceApplications, - path: "/v1/admin/finance/applications/mine", - permission: "finance-application:create", - permissions: ["finance-application:create"] - }, listOperationLogs: { method: "GET", operationId: API_OPERATIONS.listOperationLogs, @@ -2200,19 +2167,12 @@ export const API_ENDPOINTS: Record = { permission: "coin-seller-sub-application:audit", permissions: ["coin-seller-sub-application:audit"] }, - rejectFinanceApplication: { - method: "POST", - operationId: API_OPERATIONS.rejectFinanceApplication, - path: "/v1/admin/finance/applications/{application_id}/reject", - permission: "finance-application:audit", - permissions: ["finance-application:audit"] - }, rejectFinanceWithdrawalApplication: { method: "POST", operationId: API_OPERATIONS.rejectFinanceWithdrawalApplication, path: "/v1/admin/finance/withdrawal-applications/{application_id}/reject", permission: "finance-withdrawal:audit", - permissions: ["finance-withdrawal:audit","finance-application:audit"] + permissions: ["finance-withdrawal:audit"] }, renameCountryCode: { method: "POST", diff --git a/src/shared/api/generated/schema.d.ts b/src/shared/api/generated/schema.d.ts index c430c29..3e49a93 100644 --- a/src/shared/api/generated/schema.d.ts +++ b/src/shared/api/generated/schema.d.ts @@ -2380,70 +2380,6 @@ export interface paths { patch?: never; trace?: never; }; - "/admin/finance/applications": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get: operations["listFinanceApplications"]; - put?: never; - post: operations["createFinanceApplication"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/admin/finance/applications/mine": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get: operations["listMyFinanceApplications"]; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/admin/finance/applications/{application_id}/approve": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - post: operations["approveFinanceApplication"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/admin/finance/applications/{application_id}/reject": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - post: operations["rejectFinanceApplication"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; "/admin/finance/withdrawal-applications": { parameters: { query?: never; @@ -4863,12 +4799,6 @@ export interface components { pageSize: number; total: number; }; - ApiPageFinanceApplication: { - items: components["schemas"]["FinanceApplication"][]; - page: number; - pageSize: number; - total: number; - }; ApiPageFinanceCoinSellerRechargeOrder: { items: components["schemas"]["FinanceCoinSellerRechargeOrder"][]; page: number; @@ -5095,12 +5025,6 @@ export interface components { /** Format: int64 */ region_id?: number; }; - ApiResponseFinanceApplication: components["schemas"]["Envelope"] & { - data?: components["schemas"]["FinanceApplication"]; - }; - ApiResponseFinanceApplicationPage: components["schemas"]["Envelope"] & { - data?: components["schemas"]["ApiPageFinanceApplication"]; - }; ApiResponseFinanceCoinSellerRechargeOrder: components["schemas"]["Envelope"] & { data?: components["schemas"]["FinanceCoinSellerRechargeOrder"]; }; @@ -5736,30 +5660,6 @@ export interface components { countryName?: string; countryDisplayName?: string; }; - FinanceApplication: { - id: number; - appCode: string; - appName?: string; - /** @enum {string} */ - operation: "user_coin_credit" | "user_coin_debit" | "user_wallet_debit" | "user_wallet_credit" | "coin_seller_coin_credit" | "coin_seller_coin_debit"; - walletIdentity?: string; - targetUserId: string; - coinAmount: number; - rechargeAmount: string; - credentialImageUrl?: string; - credentialText?: string; - applicantUserId: number; - applicantName?: string; - auditorUserId?: number | null; - auditorName?: string; - /** @enum {string} */ - status: "pending" | "approved" | "rejected"; - auditRemark?: string; - auditedAtMs?: number | null; - createdAtMs: number; - updatedAtMs: number; - dingTalkNotified?: boolean; - }; FinanceCoinSellerRechargeOrder: { id: string; appCode: string; @@ -5824,18 +5724,6 @@ export interface components { createdAtMs: number; updatedAtMs?: number; }; - FinanceApplicationInput: { - appCode: string; - /** @enum {string} */ - operation: "user_coin_credit" | "user_coin_debit" | "user_wallet_debit" | "user_wallet_credit" | "coin_seller_coin_credit" | "coin_seller_coin_debit"; - /** @enum {string} */ - walletIdentity?: "host" | "agency" | "bd"; - targetUserId: string; - coinAmount: number; - rechargeAmount: number; - credentialImageUrl?: string; - credentialText?: string; - }; FinanceCoinSellerRechargeOrderInput: { appCode: string; targetUserId: string; @@ -6236,24 +6124,6 @@ export interface components { }; }; /** @description OK */ - FinanceApplicationPageResponse: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ApiResponseFinanceApplicationPage"]; - }; - }; - /** @description OK */ - FinanceApplicationResponse: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ApiResponseFinanceApplication"]; - }; - }; - /** @description OK */ FinanceCoinSellerRechargeOrderPageResponse: { headers: { [name: string]: unknown; @@ -6576,11 +6446,6 @@ export interface components { }; }; }; - FinanceApplicationRequest: { - content: { - "application/json": components["schemas"]["FinanceApplicationInput"]; - }; - }; FinanceCoinSellerRechargeOrderRequest: { content: { "application/json": components["schemas"]["FinanceCoinSellerRechargeOrderInput"]; @@ -6601,7 +6466,7 @@ export interface components { "application/json": components["schemas"]["FinanceCoinSellerRechargeReceiptVerificationInput"]; }; }; - FinanceApplicationAuditRequest: { + FinanceWithdrawalAuditRequest: { content: { "application/json": { auditRemark?: string; @@ -9686,84 +9551,6 @@ export interface operations { 200: components["responses"]["FinanceScopeCatalogResponse"]; }; }; - listFinanceApplications: { - parameters: { - query?: { - app_code?: string; - operation?: string; - status?: string; - keyword?: string; - page?: number; - page_size?: number; - }; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - 200: components["responses"]["FinanceApplicationPageResponse"]; - }; - }; - createFinanceApplication: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: components["requestBodies"]["FinanceApplicationRequest"]; - responses: { - 201: components["responses"]["FinanceApplicationResponse"]; - }; - }; - listMyFinanceApplications: { - parameters: { - query?: { - app_code?: string; - operation?: string; - status?: string; - keyword?: string; - page?: number; - page_size?: number; - }; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - 200: components["responses"]["FinanceApplicationPageResponse"]; - }; - }; - approveFinanceApplication: { - parameters: { - query?: never; - header?: never; - path: { - application_id: number; - }; - cookie?: never; - }; - requestBody?: components["requestBodies"]["FinanceApplicationAuditRequest"]; - responses: { - 200: components["responses"]["FinanceApplicationResponse"]; - }; - }; - rejectFinanceApplication: { - parameters: { - query?: never; - header?: never; - path: { - application_id: number; - }; - cookie?: never; - }; - requestBody?: components["requestBodies"]["FinanceApplicationAuditRequest"]; - responses: { - 200: components["responses"]["FinanceApplicationResponse"]; - }; - }; listFinanceWithdrawalApplications: { parameters: { query?: { @@ -9790,7 +9577,7 @@ export interface operations { }; cookie?: never; }; - requestBody?: components["requestBodies"]["FinanceApplicationAuditRequest"]; + requestBody?: components["requestBodies"]["FinanceWithdrawalAuditRequest"]; responses: { 200: components["responses"]["FinanceWithdrawalApplicationResponse"]; }; @@ -9804,7 +9591,7 @@ export interface operations { }; cookie?: never; }; - requestBody?: components["requestBodies"]["FinanceApplicationAuditRequest"]; + requestBody?: components["requestBodies"]["FinanceWithdrawalAuditRequest"]; responses: { 200: components["responses"]["FinanceWithdrawalApplicationResponse"]; };