369 lines
14 KiB
JavaScript
369 lines
14 KiB
JavaScript
import {
|
|
APPLICATION_STATUS,
|
|
FINANCE_OPERATIONS,
|
|
WALLET_IDENTITIES,
|
|
operationAllowsZeroRechargeAmount,
|
|
} 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),
|
|
appName: stringValue(item.appName ?? item.app_name),
|
|
approvedAtMs: numberOrNull(item.approvedAtMs ?? item.approved_at_ms),
|
|
approverName: stringValue(
|
|
item.approverName ?? item.approver_name ?? item.approverAccount ?? item.approver_account,
|
|
),
|
|
approverUserId: item.approverUserId ?? item.approver_user_id,
|
|
auditImageUrl: stringValue(item.auditImageUrl ?? item.audit_image_url),
|
|
auditRemark: stringValue(item.auditRemark ?? item.audit_remark),
|
|
auditTransactionId: stringValue(item.auditTransactionId ?? item.audit_transaction_id),
|
|
createdAtMs: numberOrNull(item.createdAtMs ?? item.created_at_ms),
|
|
freezeTransactionId: stringValue(item.freezeTransactionId ?? item.freeze_transaction_id),
|
|
id: item.id ?? item.withdrawalApplicationId ?? item.withdrawal_application_id,
|
|
salaryAssetType: stringValue(item.salaryAssetType ?? item.salary_asset_type),
|
|
status: stringValue(item.status),
|
|
updatedAtMs: numberOrNull(item.updatedAtMs ?? item.updated_at_ms),
|
|
userId: stringValue(item.userId ?? item.user_id),
|
|
withdrawAddress: stringValue(item.withdrawAddress ?? item.withdraw_address),
|
|
withdrawAmount: numberValue(item.withdrawAmount ?? item.withdraw_amount),
|
|
withdrawAmountMinor: numberValue(item.withdrawAmountMinor ?? item.withdraw_amount_minor),
|
|
withdrawMethod: stringValue(item.withdrawMethod ?? item.withdraw_method),
|
|
};
|
|
}
|
|
|
|
export function normalizeWithdrawalApplicationPage(data = {}) {
|
|
const items = Array.isArray(data.items) ? data.items : [];
|
|
return {
|
|
items: items.map(normalizeWithdrawalApplication),
|
|
page: Number(data.page || 1),
|
|
pageSize: Number(data.pageSize ?? data.page_size ?? items.length),
|
|
total: Number(data.total ?? items.length),
|
|
};
|
|
}
|
|
|
|
export function normalizeRechargeBill(item = {}) {
|
|
return {
|
|
appCode: stringValue(item.appCode ?? item.app_code),
|
|
appName: stringValue(item.appName ?? item.app_name),
|
|
billAmountMinor: numberOrNull(item.billAmountMinor ?? item.bill_amount_minor),
|
|
billAmountText: stringValue(
|
|
item.billAmountText ?? item.bill_amount_text ?? item.billAmount ?? item.bill_amount,
|
|
),
|
|
coinAmount: numberValue(item.coinAmount ?? item.coin_amount),
|
|
commandId: stringValue(item.commandId ?? item.command_id),
|
|
createdAtMs: numberOrNull(item.createdAtMs ?? item.created_at_ms),
|
|
currencyCode: stringValue(item.currencyCode ?? item.currency_code) || "USD",
|
|
exchangeCoinAmount: numberValue(item.exchangeCoinAmount ?? item.exchange_coin_amount),
|
|
exchangeUsdMinorAmount: numberValue(item.exchangeUsdMinorAmount ?? item.exchange_usd_minor_amount),
|
|
externalRef: stringValue(item.externalRef ?? item.external_ref),
|
|
id: stringValue(item.id ?? item.transactionId ?? item.transaction_id),
|
|
paidSyncedAtMs: numberOrNull(item.paidSyncedAtMs ?? item.paid_synced_at_ms),
|
|
providerAmountMinor: numberOrNull(item.providerAmountMinor ?? item.provider_amount_minor),
|
|
providerCode: stringValue(item.providerCode ?? item.provider_code),
|
|
providerFeeMicro: numberOrNull(item.providerFeeMicro ?? item.provider_fee_micro),
|
|
providerNetMicro: numberOrNull(item.providerNetMicro ?? item.provider_net_micro),
|
|
providerTaxMicro: numberOrNull(item.providerTaxMicro ?? item.provider_tax_micro),
|
|
rechargeType: stringValue(item.rechargeType ?? item.recharge_type),
|
|
status: stringValue(item.status),
|
|
taxDeductionMinor: numberOrNull(
|
|
item.taxDeductionMinor ??
|
|
item.tax_deduction_minor ??
|
|
item.thirdPartyTaxDeductionMinor ??
|
|
item.third_party_tax_deduction_minor,
|
|
),
|
|
taxDeductionText: stringValue(
|
|
item.taxDeductionText ??
|
|
item.tax_deduction_text ??
|
|
item.thirdPartyTaxDeduction ??
|
|
item.third_party_tax_deduction,
|
|
),
|
|
taxRate: numberOrNull(item.taxRate ?? item.tax_rate ?? item.thirdPartyTaxRate ?? item.third_party_tax_rate),
|
|
transactionId: stringValue(item.transactionId ?? item.transaction_id),
|
|
usdMinorAmount: numberValue(item.usdMinorAmount ?? item.usd_minor_amount),
|
|
userPaidAmountMicro: numberOrNull(
|
|
item.userPaidAmountMicro ?? item.user_paid_amount_micro ?? item.paidAmountMicro ?? item.paid_amount_micro,
|
|
),
|
|
userPaidAmountMinor: numberOrNull(
|
|
item.userPaidAmountMinor ??
|
|
item.user_paid_amount_minor ??
|
|
item.paidAmountMinor ??
|
|
item.paid_amount_minor ??
|
|
item.providerAmountMinor ??
|
|
item.provider_amount_minor,
|
|
),
|
|
userPaidCurrencyCode: stringValue(item.userPaidCurrencyCode ?? item.user_paid_currency_code),
|
|
userPaidText: stringValue(
|
|
item.userPaidText ??
|
|
item.user_paid_text ??
|
|
item.userPaidAmount ??
|
|
item.user_paid_amount ??
|
|
item.paidAmount ??
|
|
item.paid_amount,
|
|
),
|
|
};
|
|
}
|
|
|
|
export function normalizeRechargeBillPage(data = {}) {
|
|
const rawItems = Array.isArray(data.items) ? data.items : Array.isArray(data.bills) ? data.bills : [];
|
|
return {
|
|
items: rawItems.map(normalizeRechargeBill),
|
|
page: Number(data.page || 1),
|
|
pageSize: Number(data.pageSize ?? data.page_size ?? rawItems.length),
|
|
total: Number(data.total ?? rawItems.length),
|
|
};
|
|
}
|
|
|
|
const EMPTY_RECHARGE_SUMMARY_BUCKET = { billCount: 0, coinAmount: 0, usdMinorAmount: 0 };
|
|
|
|
export const EMPTY_RECHARGE_SUMMARY = {
|
|
googlePlay: EMPTY_RECHARGE_SUMMARY_BUCKET,
|
|
thirdParty: EMPTY_RECHARGE_SUMMARY_BUCKET,
|
|
total: EMPTY_RECHARGE_SUMMARY_BUCKET,
|
|
};
|
|
|
|
function normalizeRechargeSummaryBucket(bucket = {}) {
|
|
return {
|
|
billCount: numberValue(bucket.billCount ?? bucket.bill_count) || 0,
|
|
coinAmount: numberValue(bucket.coinAmount ?? bucket.coin_amount) || 0,
|
|
usdMinorAmount: numberValue(bucket.usdMinorAmount ?? bucket.usd_minor_amount) || 0,
|
|
};
|
|
}
|
|
|
|
export function normalizeRechargeSummary(data = {}) {
|
|
return {
|
|
googlePlay: normalizeRechargeSummaryBucket(data.googlePlay ?? data.google_play),
|
|
thirdParty: normalizeRechargeSummaryBucket(data.thirdParty ?? data.third_party),
|
|
total: normalizeRechargeSummaryBucket(data.total),
|
|
};
|
|
}
|
|
|
|
export function mergeRechargeSummaries(summaries = []) {
|
|
const merged = normalizeRechargeSummary({});
|
|
for (const summary of summaries) {
|
|
for (const key of ["googlePlay", "thirdParty", "total"]) {
|
|
merged[key] = {
|
|
billCount: merged[key].billCount + summary[key].billCount,
|
|
coinAmount: merged[key].coinAmount + summary[key].coinAmount,
|
|
usdMinorAmount: merged[key].usdMinorAmount + summary[key].usdMinorAmount,
|
|
};
|
|
}
|
|
}
|
|
return merged;
|
|
}
|
|
|
|
export function normalizeRechargeRegions(data = {}) {
|
|
const items = Array.isArray(data.items) ? data.items : Array.isArray(data) ? data : [];
|
|
return items
|
|
.map((item) => {
|
|
const regionId = numberOrNull(item.regionId ?? item.region_id);
|
|
if (!regionId) {
|
|
return null;
|
|
}
|
|
return {
|
|
name: stringValue(item.name),
|
|
regionCode: stringValue(item.regionCode ?? item.region_code),
|
|
regionId,
|
|
};
|
|
})
|
|
.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 "币商充值";
|
|
}
|
|
if (value === "google_play_recharge") {
|
|
return "谷歌充值";
|
|
}
|
|
if (value === "mifapay") {
|
|
return "三方充值 · MiFaPay";
|
|
}
|
|
if (value === "v5pay") {
|
|
return "三方充值 · V5Pay";
|
|
}
|
|
if (value === "usdt_trc20") {
|
|
return "三方充值 · USDT";
|
|
}
|
|
if (value === "apple_recharge") {
|
|
return "苹果充值";
|
|
}
|
|
if (value === "huawei_recharge") {
|
|
return "华为充值";
|
|
}
|
|
if (value === "telegram_recharge") {
|
|
return "Telegram 充值";
|
|
}
|
|
if (value === "web_recharge") {
|
|
return "三方充值 · Web";
|
|
}
|
|
return value || "-";
|
|
}
|
|
|
|
export function statusLabel(value) {
|
|
return APPLICATION_STATUS.find(([status]) => status === value)?.[1] || value || "-";
|
|
}
|
|
|
|
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)) {
|
|
return "-";
|
|
}
|
|
return number.toLocaleString("zh-CN", { maximumFractionDigits: 2 });
|
|
}
|
|
|
|
export function formatTime(ms) {
|
|
const value = Number(ms);
|
|
if (!Number.isFinite(value) || value <= 0) {
|
|
return "-";
|
|
}
|
|
return new Intl.DateTimeFormat("zh-CN", {
|
|
day: "2-digit",
|
|
hour: "2-digit",
|
|
hourCycle: "h23",
|
|
minute: "2-digit",
|
|
month: "2-digit",
|
|
timeZone: "Asia/Shanghai",
|
|
year: "numeric",
|
|
}).format(value);
|
|
}
|
|
|
|
export function formatUsdMinor(value, currency = "USD") {
|
|
const number = Number(value);
|
|
if (!Number.isFinite(number)) {
|
|
return "-";
|
|
}
|
|
return `${currency || "USD"} ${(number / 100).toLocaleString("zh-CN", {
|
|
maximumFractionDigits: 2,
|
|
minimumFractionDigits: 2,
|
|
})}`;
|
|
}
|
|
|
|
export function formatMicroMoney(value, currency = "USD") {
|
|
const number = Number(value);
|
|
if (!Number.isFinite(number)) {
|
|
return "-";
|
|
}
|
|
return `${currency || "USD"} ${(number / 1_000_000).toLocaleString("zh-CN", {
|
|
maximumFractionDigits: 6,
|
|
minimumFractionDigits: 2,
|
|
})}`;
|
|
}
|
|
|
|
export function formatPercent(value) {
|
|
const number = Number(value);
|
|
if (!Number.isFinite(number)) {
|
|
return "";
|
|
}
|
|
const percent = number > 1 ? number : number * 100;
|
|
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;
|
|
}
|
|
return Number(value);
|
|
}
|
|
|
|
function numberOrNull(value) {
|
|
const nextValue = Number(value);
|
|
return Number.isFinite(nextValue) ? nextValue : null;
|
|
}
|
|
|
|
function stringValue(value) {
|
|
return String(value ?? "").trim();
|
|
}
|