- 在 API 类型定义中添加订单状态字段及其枚举值 - 更新桌面端财务记录表格界面,增加状态列并调整列宽布局 - 实现移动端财务记录表格的状态列显示和样式适配 - 添加财务记录状态的颜色标识和标签显示逻辑 - 在多语言文件中添加状态相关的翻译内容 - 修复充值组件中的金额字段引用错误 - 重构提现功能中的汇率计算逻辑,提高准确性
456 lines
13 KiB
TypeScript
456 lines
13 KiB
TypeScript
import {
|
|
API_SUCCESS_CODE,
|
|
DEFAULT_LIST_PAGE_SIZE,
|
|
FINANCE_API_ENDPOINTS,
|
|
} from '@/constants'
|
|
import { api } from '@/lib/api/api-client'
|
|
import { ApiError } from '@/lib/api/api-error'
|
|
import type {
|
|
ApiResponse,
|
|
DepositCreateRequestDto,
|
|
DepositCreateResponseDto,
|
|
DepositTierItem,
|
|
DepositTierItemDto,
|
|
DepositWithdrawConfig,
|
|
DepositWithdrawConfigDto,
|
|
FinanceCurrencyConfigDto,
|
|
FinanceDepositConfigDto,
|
|
FinanceDepositFieldsDto,
|
|
FinanceDepositMethodDto,
|
|
FinanceOrderItemDto,
|
|
FinanceOrderList,
|
|
FinanceOrderListDto,
|
|
FinancePayChannelDto,
|
|
FinanceRateConfigDto,
|
|
FinanceWithdrawBankDto,
|
|
FinanceWithdrawConfigDto,
|
|
WalletRecordItemDto,
|
|
WalletRecordList,
|
|
WalletRecordListDto,
|
|
WalletRecordType,
|
|
WithdrawCreateRequestDto,
|
|
WithdrawCreateResponseDto,
|
|
} from '@/type'
|
|
|
|
function unwrapFinanceEnvelope<T>(
|
|
response: ApiResponse<T>,
|
|
fallbackMessage = 'Finance request failed',
|
|
) {
|
|
if (response.code === API_SUCCESS_CODE) {
|
|
return response.data
|
|
}
|
|
|
|
const responseMessage =
|
|
typeof response.message === 'string' && response.message.length > 0
|
|
? response.message
|
|
: typeof response.msg === 'string' && response.msg.length > 0
|
|
? response.msg
|
|
: fallbackMessage
|
|
|
|
throw new ApiError({
|
|
data: response,
|
|
message: responseMessage,
|
|
})
|
|
}
|
|
|
|
function toFiniteNumber(value: string | number | null | undefined) {
|
|
const numericValue = Number(value)
|
|
|
|
return Number.isFinite(numericValue) ? numericValue : 0
|
|
}
|
|
|
|
function normalizeCurrency(dto: FinanceCurrencyConfigDto) {
|
|
return {
|
|
code: dto.code,
|
|
depositCoinsPerFiat: dto.deposit_coins_per_fiat,
|
|
depositCoinsPerFiatValue: toFiniteNumber(dto.deposit_coins_per_fiat),
|
|
label: dto.label,
|
|
withdrawCoinsPerFiat: dto.withdraw_coins_per_fiat,
|
|
withdrawCoinsPerFiatValue: toFiniteNumber(dto.withdraw_coins_per_fiat),
|
|
}
|
|
}
|
|
|
|
function normalizeRate(dto: FinanceRateConfigDto) {
|
|
return {
|
|
currency: dto.currency,
|
|
diamondsPerFiatUnit: dto.diamonds_per_fiat_unit,
|
|
diamondsPerFiatUnitValue: toFiniteNumber(dto.diamonds_per_fiat_unit),
|
|
}
|
|
}
|
|
|
|
function normalizePayChannel(dto: FinancePayChannelDto) {
|
|
return {
|
|
code: dto.code,
|
|
currencyCodes: Array.isArray(dto.currency_codes) ? dto.currency_codes : [],
|
|
depositBanks: (dto.deposit_banks ?? []).map(normalizeWithdrawBank),
|
|
name: dto.name,
|
|
sort: Number.isFinite(dto.sort) ? dto.sort : 0,
|
|
status: typeof dto.status === 'number' ? dto.status : 1,
|
|
tierIds: Array.isArray(dto.tier_ids) ? dto.tier_ids : [],
|
|
}
|
|
}
|
|
|
|
function normalizeWithdrawBank(dto: FinanceWithdrawBankDto, index: number) {
|
|
const code = dto.code ?? dto.id ?? dto.name ?? `bank-${index + 1}`
|
|
const label = dto.label ?? dto.name ?? code
|
|
|
|
return {
|
|
code,
|
|
currencyCode: dto.currency_code ?? null,
|
|
gatewayCode: dto.gateway_code ?? null,
|
|
label,
|
|
sort:
|
|
typeof dto.sort === 'number' && Number.isFinite(dto.sort)
|
|
? dto.sort
|
|
: index,
|
|
status: typeof dto.status === 'number' ? dto.status : 1,
|
|
}
|
|
}
|
|
|
|
function normalizeDepositMethod(dto: FinanceDepositMethodDto) {
|
|
return {
|
|
code: dto.code,
|
|
currencyCode: dto.currency_code,
|
|
gatewayCode: dto.gateway_code,
|
|
name: dto.name,
|
|
requiresBank: dto.requires_bank,
|
|
requiresBankAccount: dto.requires_bank_account,
|
|
requiresDepositorName: dto.requires_depositor_name,
|
|
requiresFromAddress: dto.requires_from_address,
|
|
}
|
|
}
|
|
|
|
function normalizeDepositFields(dto: FinanceDepositFieldsDto | undefined = {}) {
|
|
return {
|
|
depositBankAccountParam:
|
|
dto.deposit_bank_account_param ?? 'deposit_bank_account',
|
|
depositBankParam: dto.deposit_bank_param ?? 'deposit_bank',
|
|
depositFromAddressParam:
|
|
dto.deposit_from_address_param ?? 'deposit_from_address',
|
|
depositNameServerSide: dto.deposit_name_server_side ?? false,
|
|
paymentTypeParam: dto.payment_type_param ?? 'payment_type',
|
|
requireChannelCode: dto.require_channel_code ?? true,
|
|
requireIdempotencyKey: dto.require_idempotency_key ?? true,
|
|
requirePaymentType: dto.require_payment_type ?? false,
|
|
}
|
|
}
|
|
|
|
function normalizeDepositConfig(
|
|
dto: FinanceDepositConfigDto | undefined,
|
|
fallbackPayChannels: FinancePayChannelDto[] = [],
|
|
) {
|
|
const payChannels =
|
|
dto?.pay_channels && dto.pay_channels.length > 0
|
|
? dto.pay_channels
|
|
: fallbackPayChannels
|
|
|
|
return {
|
|
banks: (dto?.banks ?? []).map(normalizeWithdrawBank),
|
|
defaultChannelCode: dto?.default_channel_code ?? '',
|
|
defaultChannelByCurrency: dto?.default_channel_by_currency ?? {},
|
|
fields: normalizeDepositFields(dto?.fields),
|
|
methods: (dto?.methods ?? []).map(normalizeDepositMethod),
|
|
payChannels: payChannels.map(normalizePayChannel),
|
|
}
|
|
}
|
|
|
|
function normalizeWithdrawFields(dto: FinanceWithdrawConfigDto['fields'] = {}) {
|
|
return {
|
|
receiveTypeBankOnly: dto.receive_type_bank_only ?? true,
|
|
requireBankBranch: dto.require_bank_branch ?? false,
|
|
requireBankCode: dto.require_bank_code ?? true,
|
|
requireChannelCode: dto.require_channel_code ?? true,
|
|
requireReceiveAccount: dto.require_receive_account ?? true,
|
|
requireReceiverEmail: dto.require_receiver_email ?? true,
|
|
requireReceiverMobile: dto.require_receiver_mobile ?? true,
|
|
requireReceiverName: dto.require_receiver_name ?? true,
|
|
}
|
|
}
|
|
|
|
function normalizeWithdrawConfig(dto: FinanceWithdrawConfigDto) {
|
|
return {
|
|
banks: (dto.banks ?? []).map(normalizeWithdrawBank),
|
|
feeNote: dto.fee_note,
|
|
fields: normalizeWithdrawFields(dto.fields),
|
|
minBank: dto.min_bank,
|
|
minEwallet: dto.min_ewallet,
|
|
payChannels: (dto.pay_channels ?? []).map(normalizePayChannel),
|
|
processingNote: dto.processing_note,
|
|
rateHint: dto.rate_hint,
|
|
rateMode: dto.rate_mode,
|
|
reviewThresholdCoin: dto.review_threshold_coin ?? '0',
|
|
}
|
|
}
|
|
|
|
function normalizeDepositWithdrawConfig(
|
|
dto: DepositWithdrawConfigDto,
|
|
): DepositWithdrawConfig {
|
|
return {
|
|
currencies: (dto.currencies ?? []).map(normalizeCurrency),
|
|
defaultDepositChannelCode: dto.default_deposit_channel_code ?? '',
|
|
deposit: normalizeDepositConfig(dto.deposit, dto.pay_channels ?? []),
|
|
payChannels: (dto.pay_channels ?? []).map(normalizePayChannel),
|
|
platformCoinLabel: dto.platform_coin_label,
|
|
rates: (dto.rates ?? []).map(normalizeRate),
|
|
withdraw: normalizeWithdrawConfig(dto.withdraw),
|
|
}
|
|
}
|
|
|
|
function normalizeDepositTierItem(
|
|
dto: DepositTierItemDto,
|
|
index: number,
|
|
): DepositTierItem {
|
|
const id = String(dto.id ?? dto.tier_id ?? `tier-${index + 1}`)
|
|
const amount = toFiniteNumber(dto.amount)
|
|
const bonusAmount = toFiniteNumber(dto.bonus_amount ?? dto.bonus_coins)
|
|
const payAmount = toFiniteNumber(dto.pay_amount ?? dto.amount)
|
|
const totalAmount = toFiniteNumber(
|
|
dto.total_amount ?? dto.coins ?? amount + bonusAmount,
|
|
)
|
|
const coins = totalAmount
|
|
const currency =
|
|
typeof dto.currency === 'string' && dto.currency.length > 0
|
|
? dto.currency
|
|
: null
|
|
const payChannelCode =
|
|
typeof dto.pay_channel_code === 'string' && dto.pay_channel_code.length > 0
|
|
? dto.pay_channel_code
|
|
: null
|
|
const channelCode =
|
|
typeof dto.channel_code === 'string' && dto.channel_code.length > 0
|
|
? dto.channel_code
|
|
: (payChannelCode ?? null)
|
|
const sort = toFiniteNumber(dto.sort ?? dto.pay_amount ?? dto.amount)
|
|
const status = toFiniteNumber(dto.status ?? 1)
|
|
const channels = (dto.channels ?? [])
|
|
.map((channel, channelIndex) => ({
|
|
code: channel.code ?? `channel-${channelIndex + 1}`,
|
|
name: channel.name ?? channel.code ?? '--',
|
|
sort: toFiniteNumber(channel.sort ?? channelIndex),
|
|
}))
|
|
.sort((left, right) => left.sort - right.sort)
|
|
|
|
return {
|
|
amount,
|
|
bonusAmount,
|
|
channelCode,
|
|
channels,
|
|
coins,
|
|
currency,
|
|
desc: dto.desc ?? '',
|
|
id,
|
|
name:
|
|
typeof dto.name === 'string' && dto.name.length > 0
|
|
? dto.name
|
|
: `${amount}`,
|
|
payAmount,
|
|
payChannelCode,
|
|
sort,
|
|
status,
|
|
tierKey:
|
|
typeof dto.tier_key === 'string' && dto.tier_key.length > 0
|
|
? dto.tier_key
|
|
: null,
|
|
totalAmount,
|
|
title:
|
|
typeof dto.title === 'string' && dto.title.length > 0
|
|
? dto.title
|
|
: typeof dto.name === 'string' && dto.name.length > 0
|
|
? dto.name
|
|
: `${amount}`,
|
|
}
|
|
}
|
|
|
|
function normalizeFinanceOrderItem(dto: FinanceOrderItemDto) {
|
|
return {
|
|
amount: String(dto.amount ?? ''),
|
|
bonusAmount: String(dto.bonus_amount ?? ''),
|
|
orderNo: dto.order_no,
|
|
status: String(dto.status ?? ''),
|
|
}
|
|
}
|
|
|
|
function normalizeFinanceOrderList(dto: FinanceOrderListDto): FinanceOrderList {
|
|
return {
|
|
list: (dto.list ?? []).map(normalizeFinanceOrderItem),
|
|
pagination: {
|
|
page: dto.pagination?.page ?? 1,
|
|
page_size: dto.pagination?.page_size ?? DEFAULT_LIST_PAGE_SIZE,
|
|
total: dto.pagination?.total ?? 0,
|
|
},
|
|
}
|
|
}
|
|
|
|
function stringifyNullableValue(value: unknown) {
|
|
return value === null || value === undefined ? '' : String(value)
|
|
}
|
|
|
|
function normalizeWalletRecordItem(dto: WalletRecordItemDto, index: number) {
|
|
const createdAt = dto.created_at ?? dto.create_time ?? dto.time ?? null
|
|
const id =
|
|
dto.id ??
|
|
dto.record_id ??
|
|
dto.wallet_record_id ??
|
|
dto.order_no ??
|
|
`${createdAt ?? 'wallet-record'}-${index + 1}`
|
|
|
|
return {
|
|
amount: stringifyNullableValue(
|
|
dto.amount ?? dto.change_amount ?? dto.coin ?? '',
|
|
),
|
|
balanceAfter: stringifyNullableValue(
|
|
dto.balance_after ?? dto.after_balance ?? dto.balance ?? '',
|
|
),
|
|
balanceBefore: stringifyNullableValue(
|
|
dto.balance_before ?? dto.before_balance ?? '',
|
|
),
|
|
createdAt,
|
|
id: String(id),
|
|
remark: stringifyNullableValue(dto.remark ?? dto.description ?? dto.memo),
|
|
type: stringifyNullableValue(
|
|
dto.type ?? dto.change_type ?? dto.biz_type ?? dto.scene,
|
|
),
|
|
}
|
|
}
|
|
|
|
function normalizeWalletRecordList(dto: WalletRecordListDto): WalletRecordList {
|
|
return {
|
|
list: (dto.list ?? []).map(normalizeWalletRecordItem),
|
|
pagination: {
|
|
page: dto.pagination?.page ?? dto.page ?? 1,
|
|
page_size:
|
|
dto.pagination?.page_size ?? dto.page_size ?? DEFAULT_LIST_PAGE_SIZE,
|
|
total: dto.pagination?.total ?? dto.total ?? 0,
|
|
},
|
|
}
|
|
}
|
|
|
|
export async function getDepositWithdrawConfig() {
|
|
const response = await api.post<DepositWithdrawConfigDto>(
|
|
FINANCE_API_ENDPOINTS.depositWithdrawConfig,
|
|
)
|
|
const dto = unwrapFinanceEnvelope(
|
|
response as ApiResponse<DepositWithdrawConfigDto>,
|
|
'Failed to load deposit and withdrawal config',
|
|
)
|
|
|
|
return normalizeDepositWithdrawConfig(dto)
|
|
}
|
|
|
|
export async function getDepositTierList() {
|
|
const response = await api.post<
|
|
| DepositTierItemDto[]
|
|
| { items?: DepositTierItemDto[]; list?: DepositTierItemDto[] },
|
|
undefined
|
|
>(FINANCE_API_ENDPOINTS.depositTierList)
|
|
const dto = unwrapFinanceEnvelope(
|
|
response as ApiResponse<
|
|
| DepositTierItemDto[]
|
|
| { items?: DepositTierItemDto[]; list?: DepositTierItemDto[] }
|
|
>,
|
|
'Failed to load deposit tier list',
|
|
)
|
|
|
|
const tierItems = Array.isArray(dto) ? dto : (dto?.list ?? dto?.items ?? [])
|
|
|
|
return tierItems
|
|
.map(normalizeDepositTierItem)
|
|
.filter((item) => item.status === 1)
|
|
.sort((left, right) => left.sort - right.sort)
|
|
}
|
|
|
|
export async function createDeposit(payload: DepositCreateRequestDto) {
|
|
const response = await api.post<
|
|
DepositCreateResponseDto,
|
|
DepositCreateRequestDto
|
|
>(FINANCE_API_ENDPOINTS.depositCreate, {
|
|
json: payload,
|
|
})
|
|
const dto = unwrapFinanceEnvelope(
|
|
response as ApiResponse<DepositCreateResponseDto>,
|
|
'Failed to create deposit',
|
|
)
|
|
|
|
return dto
|
|
}
|
|
|
|
export async function getDepositOrderList(params?: {
|
|
page?: number
|
|
pageSize?: number
|
|
}) {
|
|
const response = await api.get<FinanceOrderListDto>(
|
|
FINANCE_API_ENDPOINTS.depositList,
|
|
{
|
|
searchParams: {
|
|
page: String(params?.page ?? 1),
|
|
page_size: String(params?.pageSize ?? DEFAULT_LIST_PAGE_SIZE),
|
|
},
|
|
},
|
|
)
|
|
const dto = unwrapFinanceEnvelope(
|
|
response as ApiResponse<FinanceOrderListDto>,
|
|
'Failed to load deposit order list',
|
|
)
|
|
|
|
return normalizeFinanceOrderList(dto)
|
|
}
|
|
|
|
export async function getWithdrawOrderList(params?: {
|
|
page?: number
|
|
pageSize?: number
|
|
}) {
|
|
const response = await api.get<FinanceOrderListDto>(
|
|
FINANCE_API_ENDPOINTS.withdrawList,
|
|
{
|
|
searchParams: {
|
|
page: String(params?.page ?? 1),
|
|
page_size: String(params?.pageSize ?? DEFAULT_LIST_PAGE_SIZE),
|
|
},
|
|
},
|
|
)
|
|
const dto = unwrapFinanceEnvelope(
|
|
response as ApiResponse<FinanceOrderListDto>,
|
|
'Failed to load withdraw order list',
|
|
)
|
|
|
|
return normalizeFinanceOrderList(dto)
|
|
}
|
|
|
|
export async function getWalletRecordList(params?: {
|
|
page?: number
|
|
pageSize?: number
|
|
type?: WalletRecordType
|
|
}) {
|
|
const response = await api.get<WalletRecordListDto>(
|
|
FINANCE_API_ENDPOINTS.walletRecordList,
|
|
{
|
|
searchParams: {
|
|
page: String(params?.page ?? 1),
|
|
page_size: String(params?.pageSize ?? DEFAULT_LIST_PAGE_SIZE),
|
|
type: params?.type ?? 'payout',
|
|
},
|
|
},
|
|
)
|
|
const dto = unwrapFinanceEnvelope(
|
|
response as ApiResponse<WalletRecordListDto>,
|
|
'Failed to load wallet record list',
|
|
)
|
|
|
|
return normalizeWalletRecordList(dto)
|
|
}
|
|
|
|
export async function createWithdraw(payload: WithdrawCreateRequestDto) {
|
|
const response = await api.post<
|
|
WithdrawCreateResponseDto,
|
|
WithdrawCreateRequestDto
|
|
>(FINANCE_API_ENDPOINTS.withdrawCreate, {
|
|
json: payload,
|
|
})
|
|
const dto = unwrapFinanceEnvelope(
|
|
response as ApiResponse<WithdrawCreateResponseDto>,
|
|
'Failed to create withdraw',
|
|
)
|
|
|
|
return dto
|
|
}
|