主播提现列表
This commit is contained in:
parent
8fe2efb344
commit
18ad13563b
@ -1650,6 +1650,71 @@
|
|||||||
"x-permissions": ["coin-seller:exchange-rate"]
|
"x-permissions": ["coin-seller:exchange-rate"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/admin/host-withdrawals": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "listHostWithdrawals",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/parameters/Page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/parameters/PageSize"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "app_code",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "record_type",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["salary_transfer", "withdrawal"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "identity",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["host", "agency", "bd", "bd_leader_admin"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/parameters/Status"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/parameters/Keyword"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "start_at_ms",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "end_at_ms",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"$ref": "#/components/responses/HostWithdrawalPageResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-permission": "host-withdrawal:view",
|
||||||
|
"x-permissions": ["host-withdrawal:view"]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/admin/countries": {
|
"/admin/countries": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "listCountries",
|
"operationId": "listCountries",
|
||||||
@ -5819,6 +5884,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"HostWithdrawalPageResponse": {
|
||||||
|
"description": "OK",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ApiResponseHostWithdrawalPage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"HostProfilePageResponse": {
|
"HostProfilePageResponse": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"content": {
|
"content": {
|
||||||
@ -6159,6 +6234,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ApiPageHostWithdrawal": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["items", "page", "pageSize", "total"],
|
||||||
|
"properties": {
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/HostWithdrawal"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"pageSize": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"ApiPageRechargeBill": {
|
"ApiPageRechargeBill": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["items", "page", "pageSize", "total"],
|
"required": ["items", "page", "pageSize", "total"],
|
||||||
@ -6349,6 +6445,21 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"ApiResponseHostWithdrawalPage": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Envelope"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"$ref": "#/components/schemas/ApiPageHostWithdrawal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"ApiResponseRechargeBillPage": {
|
"ApiResponseRechargeBillPage": {
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{
|
{
|
||||||
@ -6852,6 +6963,114 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"HostWithdrawalUser": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"userId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"displayUserId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"avatar": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"HostWithdrawal": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"recordType",
|
||||||
|
"identity",
|
||||||
|
"salaryAssetType",
|
||||||
|
"usdMinorAmount",
|
||||||
|
"coinAmount",
|
||||||
|
"status",
|
||||||
|
"createdAtMs",
|
||||||
|
"updatedAtMs"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"recordType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["salary_transfer", "withdrawal"]
|
||||||
|
},
|
||||||
|
"identity": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"salaryAssetType": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sourceUserId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sourceUser": {
|
||||||
|
"$ref": "#/components/schemas/HostWithdrawalUser"
|
||||||
|
},
|
||||||
|
"sellerUserId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sellerUser": {
|
||||||
|
"$ref": "#/components/schemas/HostWithdrawalUser"
|
||||||
|
},
|
||||||
|
"usdMinorAmount": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"coinAmount": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"transactionId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"commandId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"applicationId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"freezeTransactionId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"auditTransactionId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"withdrawMethod": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"withdrawAddress": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"auditRemark": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"auditImageUrl": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"createdAtMs": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"updatedAtMs": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"HumanRoomRobotCountryRule": {
|
"HumanRoomRobotCountryRule": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["countryCode", "maxRoomCount"],
|
"required": ["countryCode", "maxRoomCount"],
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { API_OPERATIONS, apiEndpointPath } from "../../src/shared/api/generated/endpoints.ts";
|
import { API_OPERATIONS, apiEndpointPath } from "../../src/shared/api/generated/endpoints.ts";
|
||||||
|
import { API_BASE_URL } from "../../src/shared/config/env.js";
|
||||||
import { countryFlag, stripCountryFlagPrefix } from "./data/countryMeta.js";
|
import { countryFlag, stripCountryFlagPrefix } from "./data/countryMeta.js";
|
||||||
|
|
||||||
const API_BASE_URL = import.meta.env?.VITE_API_BASE_URL || "/api";
|
|
||||||
const TOKEN_KEY = "hyapp-admin.access-token";
|
const TOKEN_KEY = "hyapp-admin.access-token";
|
||||||
const APP_CODE_KEY = "hyapp-admin.app-code";
|
const APP_CODE_KEY = "hyapp-admin.app-code";
|
||||||
const APP_CODE_HEADER = "X-App-Code";
|
const APP_CODE_HEADER = "X-App-Code";
|
||||||
|
|||||||
@ -134,6 +134,7 @@ export const fallbackNavigation = [
|
|||||||
routeNavItem("host-agency-policy", { icon: WalletOutlined }),
|
routeNavItem("host-agency-policy", { icon: WalletOutlined }),
|
||||||
routeNavItem("host-salary-settlement", { icon: ReceiptLongOutlined }),
|
routeNavItem("host-salary-settlement", { icon: ReceiptLongOutlined }),
|
||||||
routeNavItem("host-org-coin-sellers", { icon: WalletOutlined }),
|
routeNavItem("host-org-coin-sellers", { icon: WalletOutlined }),
|
||||||
|
routeNavItem("host-withdrawals", { icon: ReceiptLongOutlined }),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -41,6 +41,7 @@ export const PERMISSIONS = {
|
|||||||
coinSellerUpdate: "coin-seller:update",
|
coinSellerUpdate: "coin-seller:update",
|
||||||
coinSellerStockCredit: "coin-seller:stock-credit",
|
coinSellerStockCredit: "coin-seller:stock-credit",
|
||||||
coinSellerExchangeRate: "coin-seller:exchange-rate",
|
coinSellerExchangeRate: "coin-seller:exchange-rate",
|
||||||
|
hostWithdrawalView: "host-withdrawal:view",
|
||||||
financeView: "finance:view",
|
financeView: "finance:view",
|
||||||
financeApplicationCreate: "finance-application:create",
|
financeApplicationCreate: "finance-application:create",
|
||||||
financeApplicationAudit: "finance-application:audit",
|
financeApplicationAudit: "finance-application:audit",
|
||||||
@ -272,6 +273,7 @@ export const MENU_CODES = {
|
|||||||
hostAgencyPolicy: "host-agency-policy",
|
hostAgencyPolicy: "host-agency-policy",
|
||||||
hostSalarySettlement: "host-salary-settlement",
|
hostSalarySettlement: "host-salary-settlement",
|
||||||
hostOrgCoinSellers: "host-org-coin-sellers",
|
hostOrgCoinSellers: "host-org-coin-sellers",
|
||||||
|
hostWithdrawals: "host-withdrawals",
|
||||||
payment: "payment",
|
payment: "payment",
|
||||||
paymentBillList: "payment-bill-list",
|
paymentBillList: "payment-bill-list",
|
||||||
paymentRechargeProducts: "payment-recharge-products",
|
paymentRechargeProducts: "payment-recharge-products",
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import type {
|
|||||||
CreateManagerPayload,
|
CreateManagerPayload,
|
||||||
EntityId,
|
EntityId,
|
||||||
HostCommandPayload,
|
HostCommandPayload,
|
||||||
|
HostWithdrawalDto,
|
||||||
HostProfileDto,
|
HostProfileDto,
|
||||||
ManagerDto,
|
ManagerDto,
|
||||||
PageQuery,
|
PageQuery,
|
||||||
@ -212,6 +213,14 @@ export function listCoinSellers(query: PageQuery = {}): Promise<ApiPage<CoinSell
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function listHostWithdrawals(query: PageQuery = {}): Promise<ApiPage<HostWithdrawalDto>> {
|
||||||
|
const endpoint = API_ENDPOINTS.listHostWithdrawals;
|
||||||
|
return apiRequest<ApiPage<HostWithdrawalDto>>(apiEndpointPath(API_OPERATIONS.listHostWithdrawals), {
|
||||||
|
method: endpoint.method,
|
||||||
|
query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function listSalaryWalletHistory(query: PageQuery = {}): Promise<ApiPage<SalaryWalletHistoryDto>> {
|
export function listSalaryWalletHistory(query: PageQuery = {}): Promise<ApiPage<SalaryWalletHistoryDto>> {
|
||||||
return apiRequest<ApiPage<SalaryWalletHistoryDto>>("/v1/admin/host-org/salary-wallets/history", {
|
return apiRequest<ApiPage<SalaryWalletHistoryDto>>("/v1/admin/host-org/salary-wallets/history", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
|||||||
90
src/features/host-org/hooks/useHostWithdrawalsPage.js
Normal file
90
src/features/host-org/hooks/useHostWithdrawalsPage.js
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { useMemo, useState } from "react";
|
||||||
|
import { listHostWithdrawals } from "@/features/host-org/api";
|
||||||
|
import { useHostWithdrawalAbilities } from "@/features/host-org/permissions.js";
|
||||||
|
import { usePaginatedQuery } from "@/shared/hooks/usePaginatedQuery.js";
|
||||||
|
|
||||||
|
const pageSize = 50;
|
||||||
|
const emptyData = { items: [], page: 1, pageSize, total: 0 };
|
||||||
|
const emptyTimeRange = { endMs: "", startMs: "" };
|
||||||
|
|
||||||
|
export function useHostWithdrawalsPage() {
|
||||||
|
const abilities = useHostWithdrawalAbilities();
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
const [recordType, setRecordType] = useState("");
|
||||||
|
const [identity, setIdentity] = useState("");
|
||||||
|
const [status, setStatus] = useState("");
|
||||||
|
const [keyword, setKeyword] = useState("");
|
||||||
|
const [timeRange, setTimeRange] = useState(emptyTimeRange);
|
||||||
|
const filters = useMemo(
|
||||||
|
() => ({
|
||||||
|
end_at_ms: timeRange.endMs || "",
|
||||||
|
identity,
|
||||||
|
keyword,
|
||||||
|
record_type: recordType,
|
||||||
|
start_at_ms: timeRange.startMs || "",
|
||||||
|
status,
|
||||||
|
}),
|
||||||
|
[identity, keyword, recordType, status, timeRange.endMs, timeRange.startMs],
|
||||||
|
);
|
||||||
|
const query = usePaginatedQuery({
|
||||||
|
errorMessage: "加载主播提现列表失败",
|
||||||
|
fetcher: listHostWithdrawals,
|
||||||
|
filters,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
queryKey: ["host-org", "host-withdrawals", filters, page],
|
||||||
|
});
|
||||||
|
const data = query.data || emptyData;
|
||||||
|
const hasActiveFilters = Boolean(recordType || identity || status || keyword || timeRange.startMs || timeRange.endMs);
|
||||||
|
|
||||||
|
const changeRecordType = (value) => {
|
||||||
|
setRecordType(value);
|
||||||
|
setPage(1);
|
||||||
|
};
|
||||||
|
const changeIdentity = (value) => {
|
||||||
|
setIdentity(value);
|
||||||
|
setPage(1);
|
||||||
|
};
|
||||||
|
const changeStatus = (value) => {
|
||||||
|
setStatus(value);
|
||||||
|
setPage(1);
|
||||||
|
};
|
||||||
|
const changeKeyword = (value) => {
|
||||||
|
setKeyword(value);
|
||||||
|
setPage(1);
|
||||||
|
};
|
||||||
|
const changeTimeRange = (nextRange) => {
|
||||||
|
setTimeRange(nextRange);
|
||||||
|
setPage(1);
|
||||||
|
};
|
||||||
|
const resetFilters = () => {
|
||||||
|
setRecordType("");
|
||||||
|
setIdentity("");
|
||||||
|
setStatus("");
|
||||||
|
setKeyword("");
|
||||||
|
setTimeRange(emptyTimeRange);
|
||||||
|
setPage(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
abilities,
|
||||||
|
changeIdentity,
|
||||||
|
changeKeyword,
|
||||||
|
changeRecordType,
|
||||||
|
changeStatus,
|
||||||
|
changeTimeRange,
|
||||||
|
data,
|
||||||
|
error: query.error,
|
||||||
|
hasActiveFilters,
|
||||||
|
identity,
|
||||||
|
keyword,
|
||||||
|
loading: query.loading,
|
||||||
|
page,
|
||||||
|
recordType,
|
||||||
|
reload: query.reload,
|
||||||
|
resetFilters,
|
||||||
|
setPage,
|
||||||
|
status,
|
||||||
|
timeRange,
|
||||||
|
};
|
||||||
|
}
|
||||||
276
src/features/host-org/pages/HostWithdrawalsPage.jsx
Normal file
276
src/features/host-org/pages/HostWithdrawalsPage.jsx
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
import {
|
||||||
|
AdminFilterResetButton,
|
||||||
|
AdminListBody,
|
||||||
|
AdminListPage,
|
||||||
|
AdminListToolbar,
|
||||||
|
} from "@/shared/ui/AdminListLayout.jsx";
|
||||||
|
import { AdminUserIdentity } from "@/shared/ui/AdminUserIdentity.jsx";
|
||||||
|
import { DataState } from "@/shared/ui/DataState.jsx";
|
||||||
|
import { DataTable } from "@/shared/ui/DataTable.jsx";
|
||||||
|
import { TimeRangeFilter } from "@/shared/ui/TimeRangeFilter.jsx";
|
||||||
|
import { createOptionsColumnFilter, createTextColumnFilter } from "@/shared/ui/tableFilters.js";
|
||||||
|
import { formatMillis } from "@/shared/utils/time.js";
|
||||||
|
import { useHostWithdrawalsPage } from "@/features/host-org/hooks/useHostWithdrawalsPage.js";
|
||||||
|
import styles from "@/features/operations/operations.module.css";
|
||||||
|
|
||||||
|
const recordTypeOptions = [
|
||||||
|
["", "全部"],
|
||||||
|
["salary_transfer", "工资转币商"],
|
||||||
|
["withdrawal", "提现申请"],
|
||||||
|
];
|
||||||
|
|
||||||
|
const identityOptions = [
|
||||||
|
["", "全部"],
|
||||||
|
["host", "Host"],
|
||||||
|
["agency", "Agency"],
|
||||||
|
["bd", "BD"],
|
||||||
|
["bd_leader_admin", "BD Leader/Admin"],
|
||||||
|
];
|
||||||
|
|
||||||
|
const statusOptions = [
|
||||||
|
["", "全部"],
|
||||||
|
["completed", "已完成"],
|
||||||
|
["pending", "待审核"],
|
||||||
|
["approved", "已通过"],
|
||||||
|
["rejected", "已拒绝"],
|
||||||
|
];
|
||||||
|
|
||||||
|
const recordTypeLabels = Object.fromEntries(recordTypeOptions.filter(([value]) => value));
|
||||||
|
const identityLabels = Object.fromEntries(identityOptions.filter(([value]) => value));
|
||||||
|
const statusLabels = Object.fromEntries(statusOptions.filter(([value]) => value));
|
||||||
|
|
||||||
|
const baseColumns = [
|
||||||
|
{
|
||||||
|
key: "createdAtMs",
|
||||||
|
label: "时间",
|
||||||
|
render: (item) => formatMillis(item.createdAtMs),
|
||||||
|
width: "minmax(170px, 0.8fr)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "recordType",
|
||||||
|
label: "类型",
|
||||||
|
render: (item) => recordTypeLabel(item.recordType),
|
||||||
|
width: "minmax(130px, 0.6fr)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "identity",
|
||||||
|
label: "身份",
|
||||||
|
render: (item) => identityLabel(item.identity, item.salaryAssetType),
|
||||||
|
width: "minmax(150px, 0.65fr)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "sourceUser",
|
||||||
|
label: "发起用户",
|
||||||
|
render: (item) => <AdminUserIdentity openInAppUserDetail user={item.sourceUser} userId={item.sourceUserId} />,
|
||||||
|
width: "minmax(230px, 1fr)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "receiver",
|
||||||
|
label: "币商/收款",
|
||||||
|
render: (item) => <ReceiverCell item={item} />,
|
||||||
|
width: "minmax(240px, 1.05fr)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "usdMinorAmount",
|
||||||
|
label: "USD金额",
|
||||||
|
render: (item) => <AmountText value={`$${formatUSDMinor(item.usdMinorAmount)}`} />,
|
||||||
|
width: "minmax(120px, 0.55fr)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "coinAmount",
|
||||||
|
label: "币商金币",
|
||||||
|
render: (item) => formatCoinAmount(item),
|
||||||
|
width: "minmax(130px, 0.6fr)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "status",
|
||||||
|
label: "状态",
|
||||||
|
render: (item) => <StatusBadge status={item.status} />,
|
||||||
|
width: "minmax(110px, 0.55fr)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "recordId",
|
||||||
|
label: "交易/申请ID",
|
||||||
|
render: (item) => <RecordIdCell item={item} />,
|
||||||
|
width: "minmax(260px, 1.1fr)",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function HostWithdrawalsPage() {
|
||||||
|
const page = useHostWithdrawalsPage();
|
||||||
|
const data = page.data || { items: [], page: 1, pageSize: 50, total: 0 };
|
||||||
|
const items = data.items || [];
|
||||||
|
const total = Number(data.total || 0);
|
||||||
|
const tableColumns = baseColumns.map((column) => {
|
||||||
|
if (column.key === "recordType") {
|
||||||
|
return {
|
||||||
|
...column,
|
||||||
|
filter: createOptionsColumnFilter({
|
||||||
|
emptyLabel: "全部",
|
||||||
|
options: recordTypeOptions,
|
||||||
|
placeholder: "类型",
|
||||||
|
value: page.recordType,
|
||||||
|
onChange: page.changeRecordType,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (column.key === "identity") {
|
||||||
|
return {
|
||||||
|
...column,
|
||||||
|
filter: createOptionsColumnFilter({
|
||||||
|
emptyLabel: "全部",
|
||||||
|
options: identityOptions,
|
||||||
|
placeholder: "身份",
|
||||||
|
value: page.identity,
|
||||||
|
onChange: page.changeIdentity,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (column.key === "sourceUser") {
|
||||||
|
return {
|
||||||
|
...column,
|
||||||
|
filter: createTextColumnFilter({
|
||||||
|
activeLabel: page.keyword ? `用户 ${page.keyword}` : "",
|
||||||
|
placeholder: "用户/交易/地址",
|
||||||
|
value: page.keyword,
|
||||||
|
onChange: page.changeKeyword,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (column.key === "status") {
|
||||||
|
return {
|
||||||
|
...column,
|
||||||
|
filter: createOptionsColumnFilter({
|
||||||
|
emptyLabel: "全部",
|
||||||
|
options: statusOptions,
|
||||||
|
placeholder: "状态",
|
||||||
|
value: page.status,
|
||||||
|
onChange: page.changeStatus,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return column;
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AdminListPage>
|
||||||
|
<AdminListToolbar
|
||||||
|
filters={
|
||||||
|
<>
|
||||||
|
<TimeRangeFilter value={page.timeRange} onChange={page.changeTimeRange} />
|
||||||
|
<AdminFilterResetButton disabled={!page.hasActiveFilters} onClick={page.resetFilters} />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<DataState error={page.error} loading={page.loading} onRetry={page.reload}>
|
||||||
|
<AdminListBody>
|
||||||
|
<DataTable
|
||||||
|
columns={tableColumns}
|
||||||
|
emptyLabel="当前无主播提现记录"
|
||||||
|
items={items}
|
||||||
|
minWidth="1510px"
|
||||||
|
pagination={
|
||||||
|
total > 0
|
||||||
|
? {
|
||||||
|
page: page.page,
|
||||||
|
pageSize: data.pageSize || 50,
|
||||||
|
total,
|
||||||
|
onPageChange: page.setPage,
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
rowKey={(item) => item.id}
|
||||||
|
/>
|
||||||
|
</AdminListBody>
|
||||||
|
</DataState>
|
||||||
|
</AdminListPage>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ReceiverCell({ item }) {
|
||||||
|
if (item.recordType === "salary_transfer") {
|
||||||
|
return <AdminUserIdentity openInAppUserDetail user={item.sellerUser} userId={item.sellerUserId} />;
|
||||||
|
}
|
||||||
|
const method = String(item.withdrawMethod || "").trim();
|
||||||
|
const address = String(item.withdrawAddress || "").trim();
|
||||||
|
if (!method && !address) {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<span className={styles.identityText}>
|
||||||
|
<span className={styles.primaryText}>{method || "-"}</span>
|
||||||
|
{address ? <span className={styles.meta}>{address}</span> : null}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function RecordIdCell({ item }) {
|
||||||
|
const primary = item.transactionId || item.applicationId || item.id || "-";
|
||||||
|
const secondary = item.commandId || item.freezeTransactionId || item.auditTransactionId || "";
|
||||||
|
return (
|
||||||
|
<span className={styles.identityText}>
|
||||||
|
<span className={styles.primaryText}>{primary}</span>
|
||||||
|
{secondary ? <span className={styles.meta}>{secondary}</span> : null}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function StatusBadge({ status }) {
|
||||||
|
const normalized = String(status || "").trim();
|
||||||
|
return (
|
||||||
|
<span className={`status-badge status-badge--${statusTone(normalized)}`}>
|
||||||
|
<span className="status-point" />
|
||||||
|
{statusLabel(normalized)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AmountText({ value }) {
|
||||||
|
return <span className={styles.amount}>{value}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function recordTypeLabel(value) {
|
||||||
|
return recordTypeLabels[value] || value || "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
function identityLabel(identity, salaryAssetType) {
|
||||||
|
return identityLabels[identity] || salaryAssetLabel(salaryAssetType) || identity || "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
function salaryAssetLabel(assetType) {
|
||||||
|
const labels = {
|
||||||
|
AGENCY_SALARY_USD: "Agency",
|
||||||
|
ADMIN_SALARY_USD: "BD Leader/Admin",
|
||||||
|
BD_SALARY_USD: "BD",
|
||||||
|
HOST_SALARY_USD: "Host",
|
||||||
|
};
|
||||||
|
return labels[assetType] || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function statusLabel(status) {
|
||||||
|
return statusLabels[status] || status || "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
function statusTone(status) {
|
||||||
|
if (status === "completed" || status === "approved") {
|
||||||
|
return "succeeded";
|
||||||
|
}
|
||||||
|
if (status === "pending") {
|
||||||
|
return "warning";
|
||||||
|
}
|
||||||
|
if (status === "rejected") {
|
||||||
|
return "danger";
|
||||||
|
}
|
||||||
|
return "stopped";
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatCoinAmount(item) {
|
||||||
|
if (item.recordType !== "salary_transfer") {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
return Number(item.coinAmount || 0).toLocaleString("zh-CN");
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatUSDMinor(value) {
|
||||||
|
return (Number(value || 0) / 100).toFixed(2);
|
||||||
|
}
|
||||||
175
src/features/host-org/pages/HostWithdrawalsPage.test.jsx
Normal file
175
src/features/host-org/pages/HostWithdrawalsPage.test.jsx
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
import { fireEvent, render, screen } from "@testing-library/react";
|
||||||
|
import { afterEach, expect, test, vi } from "vitest";
|
||||||
|
import { HostWithdrawalsPage } from "./HostWithdrawalsPage.jsx";
|
||||||
|
import { useHostWithdrawalsPage } from "@/features/host-org/hooks/useHostWithdrawalsPage.js";
|
||||||
|
|
||||||
|
const mocks = vi.hoisted(() => ({
|
||||||
|
changeIdentity: vi.fn(),
|
||||||
|
changeKeyword: vi.fn(),
|
||||||
|
changeRecordType: vi.fn(),
|
||||||
|
changeStatus: vi.fn(),
|
||||||
|
changeTimeRange: vi.fn(),
|
||||||
|
dataTable: vi.fn(),
|
||||||
|
resetFilters: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/features/host-org/hooks/useHostWithdrawalsPage.js", () => ({
|
||||||
|
useHostWithdrawalsPage: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/shared/ui/DataTable.jsx", () => ({
|
||||||
|
DataTable: (props) => {
|
||||||
|
mocks.dataTable(props);
|
||||||
|
return (
|
||||||
|
<div data-testid="host-withdrawals-table">
|
||||||
|
{props.columns.map((column) => (
|
||||||
|
<div data-testid={`column-${column.key}`} key={column.key}>
|
||||||
|
{column.label}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{props.items.map((item) => (
|
||||||
|
<div data-testid={`row-${item.id}`} key={item.id}>
|
||||||
|
{props.columns.map((column) => (
|
||||||
|
<div key={column.key}>{column.render ? column.render(item) : item[column.key]}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/shared/ui/TimeRangeFilter.jsx", () => ({
|
||||||
|
TimeRangeFilter: ({ onChange }) => (
|
||||||
|
<button type="button" onClick={() => onChange({ endMs: "2000", startMs: "1000" })}>
|
||||||
|
时间
|
||||||
|
</button>
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("host withdrawals page renders salary transfer and withdrawal records", () => {
|
||||||
|
vi.mocked(useHostWithdrawalsPage).mockReturnValue(pageFixture());
|
||||||
|
|
||||||
|
render(<HostWithdrawalsPage />);
|
||||||
|
|
||||||
|
expect(screen.getByText("工资转币商")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("提现申请")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("Host")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("BD Leader/Admin")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("$123.45")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("1,112")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("已完成")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("待审核")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("USDT-TRC20")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("TRON9ADDRESS")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("tx-salary-1")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("9")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("host withdrawals filters are wired to the page hook", () => {
|
||||||
|
vi.mocked(useHostWithdrawalsPage).mockReturnValue(pageFixture({ hasActiveFilters: true }));
|
||||||
|
|
||||||
|
render(<HostWithdrawalsPage />);
|
||||||
|
|
||||||
|
const props = mocks.dataTable.mock.calls.at(-1)?.[0];
|
||||||
|
props.columns.find((column) => column.key === "recordType").filter.onChange("withdrawal");
|
||||||
|
props.columns.find((column) => column.key === "identity").filter.onChange("bd_leader_admin");
|
||||||
|
props.columns.find((column) => column.key === "sourceUser").filter.onChange("168557");
|
||||||
|
props.columns.find((column) => column.key === "status").filter.onChange("approved");
|
||||||
|
fireEvent.click(screen.getByRole("button", { name: "时间" }));
|
||||||
|
fireEvent.click(screen.getByRole("button", { name: "重置" }));
|
||||||
|
|
||||||
|
expect(mocks.changeRecordType).toHaveBeenCalledWith("withdrawal");
|
||||||
|
expect(mocks.changeIdentity).toHaveBeenCalledWith("bd_leader_admin");
|
||||||
|
expect(mocks.changeKeyword).toHaveBeenCalledWith("168557");
|
||||||
|
expect(mocks.changeStatus).toHaveBeenCalledWith("approved");
|
||||||
|
expect(mocks.changeTimeRange).toHaveBeenCalledWith({ endMs: "2000", startMs: "1000" });
|
||||||
|
expect(mocks.resetFilters).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
function pageFixture(patch = {}) {
|
||||||
|
return {
|
||||||
|
abilities: { canView: true },
|
||||||
|
changeIdentity: mocks.changeIdentity,
|
||||||
|
changeKeyword: mocks.changeKeyword,
|
||||||
|
changeRecordType: mocks.changeRecordType,
|
||||||
|
changeStatus: mocks.changeStatus,
|
||||||
|
changeTimeRange: mocks.changeTimeRange,
|
||||||
|
data: {
|
||||||
|
items: [salaryTransferFixture(), withdrawalFixture()],
|
||||||
|
page: 1,
|
||||||
|
pageSize: 50,
|
||||||
|
total: 2,
|
||||||
|
},
|
||||||
|
error: null,
|
||||||
|
hasActiveFilters: false,
|
||||||
|
identity: "",
|
||||||
|
keyword: "",
|
||||||
|
loading: false,
|
||||||
|
page: 1,
|
||||||
|
recordType: "",
|
||||||
|
reload: vi.fn(),
|
||||||
|
resetFilters: mocks.resetFilters,
|
||||||
|
setPage: vi.fn(),
|
||||||
|
status: "",
|
||||||
|
timeRange: { endMs: "", startMs: "" },
|
||||||
|
...patch,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function salaryTransferFixture() {
|
||||||
|
return {
|
||||||
|
coinAmount: 1112,
|
||||||
|
commandId: "cmd-salary-1",
|
||||||
|
createdAtMs: 1780000000000,
|
||||||
|
id: "salary_transfer:101",
|
||||||
|
identity: "host",
|
||||||
|
recordType: "salary_transfer",
|
||||||
|
salaryAssetType: "HOST_SALARY_USD",
|
||||||
|
sellerUser: {
|
||||||
|
displayUserId: "168556",
|
||||||
|
userId: "3001",
|
||||||
|
username: "Coin Seller",
|
||||||
|
},
|
||||||
|
sellerUserId: "3001",
|
||||||
|
sourceUser: {
|
||||||
|
displayUserId: "168577",
|
||||||
|
userId: "1001",
|
||||||
|
username: "Raj",
|
||||||
|
},
|
||||||
|
sourceUserId: "1001",
|
||||||
|
status: "completed",
|
||||||
|
transactionId: "tx-salary-1",
|
||||||
|
updatedAtMs: 1780000000000,
|
||||||
|
usdMinorAmount: 12345,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function withdrawalFixture() {
|
||||||
|
return {
|
||||||
|
applicationId: "9",
|
||||||
|
coinAmount: 0,
|
||||||
|
commandId: "freeze-cmd-9",
|
||||||
|
createdAtMs: 1780000001000,
|
||||||
|
freezeTransactionId: "freeze-tx-9",
|
||||||
|
id: "withdrawal:9",
|
||||||
|
identity: "bd_leader_admin",
|
||||||
|
recordType: "withdrawal",
|
||||||
|
salaryAssetType: "ADMIN_SALARY_USD",
|
||||||
|
sourceUser: {
|
||||||
|
displayUserId: "481479",
|
||||||
|
userId: "2002",
|
||||||
|
username: "Mao",
|
||||||
|
},
|
||||||
|
sourceUserId: "2002",
|
||||||
|
status: "pending",
|
||||||
|
updatedAtMs: 1780000001000,
|
||||||
|
usdMinorAmount: 5000,
|
||||||
|
withdrawAddress: "TRON9ADDRESS",
|
||||||
|
withdrawMethod: "USDT-TRC20",
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -67,3 +67,11 @@ export function useCoinSellerAbilities() {
|
|||||||
canView: can(PERMISSIONS.coinSellerView),
|
canView: can(PERMISSIONS.coinSellerView),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useHostWithdrawalAbilities() {
|
||||||
|
const { can } = useAuth();
|
||||||
|
|
||||||
|
return {
|
||||||
|
canView: can(PERMISSIONS.hostWithdrawalView),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -65,4 +65,12 @@ export const hostOrgRoutes = [
|
|||||||
path: "/host/coin-sellers",
|
path: "/host/coin-sellers",
|
||||||
permission: PERMISSIONS.coinSellerView,
|
permission: PERMISSIONS.coinSellerView,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "主播提现",
|
||||||
|
loader: () => import("./pages/HostWithdrawalsPage.jsx").then((module) => module.HostWithdrawalsPage),
|
||||||
|
menuCode: MENU_CODES.hostWithdrawals,
|
||||||
|
pageKey: "host-withdrawals",
|
||||||
|
path: "/host/withdrawals",
|
||||||
|
permission: PERMISSIONS.hostWithdrawalView,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -175,6 +175,7 @@ export const API_OPERATIONS = {
|
|||||||
listHostAgencyPolicies: "listHostAgencyPolicies",
|
listHostAgencyPolicies: "listHostAgencyPolicies",
|
||||||
listHosts: "listHosts",
|
listHosts: "listHosts",
|
||||||
listHostSalarySettlements: "listHostSalarySettlements",
|
listHostSalarySettlements: "listHostSalarySettlements",
|
||||||
|
listHostWithdrawals: "listHostWithdrawals",
|
||||||
listInviteActivityRewardClaims: "listInviteActivityRewardClaims",
|
listInviteActivityRewardClaims: "listInviteActivityRewardClaims",
|
||||||
listLevelConfig: "listLevelConfig",
|
listLevelConfig: "listLevelConfig",
|
||||||
listLoginLogs: "listLoginLogs",
|
listLoginLogs: "listLoginLogs",
|
||||||
@ -1460,6 +1461,13 @@ export const API_ENDPOINTS: Record<ApiOperationId, ApiEndpoint> = {
|
|||||||
permission: "host-salary-settlement:view",
|
permission: "host-salary-settlement:view",
|
||||||
permissions: ["host-salary-settlement:view"]
|
permissions: ["host-salary-settlement:view"]
|
||||||
},
|
},
|
||||||
|
listHostWithdrawals: {
|
||||||
|
method: "GET",
|
||||||
|
operationId: API_OPERATIONS.listHostWithdrawals,
|
||||||
|
path: "/v1/admin/host-withdrawals",
|
||||||
|
permission: "host-withdrawal:view",
|
||||||
|
permissions: ["host-withdrawal:view"]
|
||||||
|
},
|
||||||
listInviteActivityRewardClaims: {
|
listInviteActivityRewardClaims: {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
operationId: API_OPERATIONS.listInviteActivityRewardClaims,
|
operationId: API_OPERATIONS.listInviteActivityRewardClaims,
|
||||||
|
|||||||
94
src/shared/api/generated/schema.d.ts
vendored
94
src/shared/api/generated/schema.d.ts
vendored
@ -1140,6 +1140,22 @@ export interface paths {
|
|||||||
patch?: never;
|
patch?: never;
|
||||||
trace?: never;
|
trace?: never;
|
||||||
};
|
};
|
||||||
|
"/admin/host-withdrawals": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get: operations["listHostWithdrawals"];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
"/admin/countries": {
|
"/admin/countries": {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: never;
|
query?: never;
|
||||||
@ -3672,6 +3688,12 @@ export interface components {
|
|||||||
pageSize: number;
|
pageSize: number;
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
|
ApiPageHostWithdrawal: {
|
||||||
|
items: components["schemas"]["HostWithdrawal"][];
|
||||||
|
page: number;
|
||||||
|
pageSize: number;
|
||||||
|
total: number;
|
||||||
|
};
|
||||||
ApiPageRechargeBill: {
|
ApiPageRechargeBill: {
|
||||||
items: components["schemas"]["RechargeBill"][];
|
items: components["schemas"]["RechargeBill"][];
|
||||||
page: number;
|
page: number;
|
||||||
@ -3714,6 +3736,9 @@ export interface components {
|
|||||||
ApiResponseFinanceWithdrawalApplicationPage: components["schemas"]["Envelope"] & {
|
ApiResponseFinanceWithdrawalApplicationPage: components["schemas"]["Envelope"] & {
|
||||||
data?: components["schemas"]["ApiPageFinanceWithdrawalApplication"];
|
data?: components["schemas"]["ApiPageFinanceWithdrawalApplication"];
|
||||||
};
|
};
|
||||||
|
ApiResponseHostWithdrawalPage: components["schemas"]["Envelope"] & {
|
||||||
|
data?: components["schemas"]["ApiPageHostWithdrawal"];
|
||||||
|
};
|
||||||
ApiResponseRechargeBillPage: components["schemas"]["Envelope"] & {
|
ApiResponseRechargeBillPage: components["schemas"]["Envelope"] & {
|
||||||
data?: components["schemas"]["ApiPageRechargeBill"];
|
data?: components["schemas"]["ApiPageRechargeBill"];
|
||||||
};
|
};
|
||||||
@ -3845,6 +3870,44 @@ export interface components {
|
|||||||
updatedAtMs?: number;
|
updatedAtMs?: number;
|
||||||
userId: string;
|
userId: string;
|
||||||
};
|
};
|
||||||
|
HostWithdrawalUser: {
|
||||||
|
userId?: string;
|
||||||
|
displayUserId?: string;
|
||||||
|
username?: string;
|
||||||
|
avatar?: string;
|
||||||
|
};
|
||||||
|
HostWithdrawal: {
|
||||||
|
id: string;
|
||||||
|
/** @enum {string} */
|
||||||
|
recordType: "salary_transfer" | "withdrawal";
|
||||||
|
identity: string;
|
||||||
|
salaryAssetType: string;
|
||||||
|
sourceUserId?: string;
|
||||||
|
sourceUser?: components["schemas"]["HostWithdrawalUser"];
|
||||||
|
sellerUserId?: string;
|
||||||
|
sellerUser?: components["schemas"]["HostWithdrawalUser"];
|
||||||
|
/** Format: int64 */
|
||||||
|
usdMinorAmount: number;
|
||||||
|
/** Format: int64 */
|
||||||
|
coinAmount: number;
|
||||||
|
status: string;
|
||||||
|
transactionId?: string;
|
||||||
|
commandId?: string;
|
||||||
|
applicationId?: string;
|
||||||
|
freezeTransactionId?: string;
|
||||||
|
auditTransactionId?: string;
|
||||||
|
withdrawMethod?: string;
|
||||||
|
withdrawAddress?: string;
|
||||||
|
auditRemark?: string;
|
||||||
|
auditImageUrl?: string;
|
||||||
|
metadata?: {
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
/** Format: int64 */
|
||||||
|
createdAtMs: number;
|
||||||
|
/** Format: int64 */
|
||||||
|
updatedAtMs: number;
|
||||||
|
};
|
||||||
HumanRoomRobotCountryRule: {
|
HumanRoomRobotCountryRule: {
|
||||||
allowedOwnerIds?: string[];
|
allowedOwnerIds?: string[];
|
||||||
countryCode: string;
|
countryCode: string;
|
||||||
@ -4137,6 +4200,15 @@ export interface components {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
/** @description OK */
|
/** @description OK */
|
||||||
|
HostWithdrawalPageResponse: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["ApiResponseHostWithdrawalPage"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description OK */
|
||||||
HostProfilePageResponse: {
|
HostProfilePageResponse: {
|
||||||
headers: {
|
headers: {
|
||||||
[name: string]: unknown;
|
[name: string]: unknown;
|
||||||
@ -5802,6 +5874,28 @@ export interface operations {
|
|||||||
200: components["responses"]["EmptyResponse"];
|
200: components["responses"]["EmptyResponse"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
listHostWithdrawals: {
|
||||||
|
parameters: {
|
||||||
|
query?: {
|
||||||
|
page?: components["parameters"]["Page"];
|
||||||
|
page_size?: components["parameters"]["PageSize"];
|
||||||
|
app_code?: string;
|
||||||
|
record_type?: "salary_transfer" | "withdrawal";
|
||||||
|
identity?: "host" | "agency" | "bd" | "bd_leader_admin";
|
||||||
|
status?: components["parameters"]["Status"];
|
||||||
|
keyword?: components["parameters"]["Keyword"];
|
||||||
|
start_at_ms?: number;
|
||||||
|
end_at_ms?: number;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
200: components["responses"]["HostWithdrawalPageResponse"];
|
||||||
|
};
|
||||||
|
};
|
||||||
listCountries: {
|
listCountries: {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: never;
|
query?: never;
|
||||||
|
|||||||
@ -273,6 +273,32 @@ export interface CoinSellerLedgerDto {
|
|||||||
transferUsdMinor?: number;
|
transferUsdMinor?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface HostWithdrawalDto {
|
||||||
|
applicationId?: string;
|
||||||
|
auditImageUrl?: string;
|
||||||
|
auditRemark?: string;
|
||||||
|
auditTransactionId?: string;
|
||||||
|
coinAmount: number;
|
||||||
|
commandId?: string;
|
||||||
|
createdAtMs?: number;
|
||||||
|
freezeTransactionId?: string;
|
||||||
|
id: string;
|
||||||
|
identity: string;
|
||||||
|
metadata?: Record<string, unknown>;
|
||||||
|
recordType: string;
|
||||||
|
salaryAssetType: string;
|
||||||
|
sellerUser?: CoinLedgerUserDto;
|
||||||
|
sellerUserId?: string;
|
||||||
|
sourceUser?: CoinLedgerUserDto;
|
||||||
|
sourceUserId?: string;
|
||||||
|
status: string;
|
||||||
|
transactionId?: string;
|
||||||
|
updatedAtMs?: number;
|
||||||
|
usdMinorAmount: number;
|
||||||
|
withdrawAddress?: string;
|
||||||
|
withdrawMethod?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface CoinAdjustmentOperatorDto {
|
export interface CoinAdjustmentOperatorDto {
|
||||||
adminId?: string;
|
adminId?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user