| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- import { postRemittance } from "@/lib/remittance-client";
- export type RemittanceChannel = {
- id: string;
- code: string;
- requestUrl: string;
- icon: string;
- name: string;
- description: string;
- amountRange: string;
- processingTime: string;
- fee: string;
- groupName: string;
- groupOrder: number;
- channelType: number | null;
- bankValid: number;
- };
- export type BankChannelOption = {
- value: string;
- label: string;
- currency: string;
- };
- function toNumber(v: unknown): number | null {
- if (typeof v === "number" && Number.isFinite(v)) return v;
- if (typeof v === "string" && v.trim()) {
- const n = Number(v);
- if (Number.isFinite(n)) return n;
- }
- return null;
- }
- function pickString(record: Record<string, unknown>, keys: string[]): string {
- for (const key of keys) {
- const value = record[key];
- if (typeof value === "string" && value.trim()) return value.trim();
- }
- return "";
- }
- function pickAmountRange(record: Record<string, unknown>): string {
- const min = toNumber(
- record.minAmount ?? record.amountMin ?? record.lowerAmount ?? record.min,
- );
- const max = toNumber(
- record.maxAmount ?? record.amountMax ?? record.upperAmount ?? record.max,
- );
- const unit = pickString(record, ["currency", "currencyCode", "coin", "unit"]).toUpperCase();
- if (min !== null && max !== null) {
- return `$${min} - $${max}${unit ? ` ${unit}` : ""}`;
- }
- const rangeText = pickString(record, ["amountRange", "limitRange", "amountDesc"]);
- return rangeText || "-";
- }
- function pickFee(record: Record<string, unknown>): string {
- const feeRate = toNumber(record.feeRate ?? record.rate);
- if (feeRate !== null) {
- if (feeRate <= 1) return `${(feeRate * 100).toFixed(2).replace(/\.00$/, "")}%`;
- return `${feeRate.toFixed(2).replace(/\.00$/, "")}%`;
- }
- const fee = pickString(record, ["fee", "charge", "feeDesc"]);
- return fee || "0%";
- }
- const CHANNEL_GROUP_NAME_MAP: Record<number, string> = {
- 1: "国际转账支付",
- 2: "中国网银支付",
- 3: "数字货币",
- 4: "电子钱包",
- 5: "CWG 电子卡",
- };
- const CHANNEL_GROUP_DISPLAY_ORDER: Record<number, number> = {
- 3: 1, // 数字货币
- 2: 2, // 中国网银支付
- 1: 3, // 国际转账支付
- 4: 4, // 电子钱包
- 5: 5, // CWG 电子卡
- };
- function pickGroupId(record: Record<string, unknown>): number | null {
- const id = toNumber(
- record.type ??
- record.channelType ??
- record.payTypeType ??
- record.groupId ??
- record.channelGroupId ??
- record.channelClassify ??
- record.channelCategory ??
- record.categoryId ??
- record.payTypeGroup ??
- record.payTypeClassify,
- );
- if (id === null) return null;
- if (id >= 1 && id <= 5) return id;
- return null;
- }
- function normalizeChannelList(raw: unknown): RemittanceChannel[] {
- if (!raw || typeof raw !== "object") return [];
- const container = raw as Record<string, unknown>;
- const inner =
- container.data ??
- container.list ??
- container.rows ??
- container.records ??
- container.channels;
- const source = Array.isArray(inner) ? inner : [];
- const output: RemittanceChannel[] = [];
- for (const item of source) {
- if (!item || typeof item !== "object") continue;
- const row = item as Record<string, unknown>;
- const id = String(
- row.id ??
- row.channelId ??
- row.payTypeId ??
- row.code ??
- row.channelCode ??
- output.length + 1,
- );
- const name =
- pickString(row, ["name", "channelName", "payType", "channelCode", "code"]) || "-";
- const code = pickString(row, ["code", "channelCode", "payCode", "channelNo"]) || id;
- const requestUrl = pickString(row, ["requestUrl", "payUrl", "url"]) || "/xfgpay/pay";
- const icon = pickString(row, ["icon", "logo", "img", "image", "iconUrl"]);
- const processingTime =
- pickString(row, ["processingTime", "processTime", "arrivalTime", "timeDesc"]) || "1 hours";
- const groupId = pickGroupId(row);
- const fallbackGroupName =
- pickString(row, [
- "groupName",
- "categoryName",
- "channelGroup",
- "payScene",
- "group",
- ]) || "支付通道";
- const groupName = groupId ? CHANNEL_GROUP_NAME_MAP[groupId] : fallbackGroupName;
- const groupOrder = groupId ? (CHANNEL_GROUP_DISPLAY_ORDER[groupId] ?? 999) : 999;
- output.push({
- id,
- code,
- requestUrl,
- icon,
- name,
- description: name || "-",
- amountRange: pickAmountRange(row),
- processingTime,
- fee: pickFee(row),
- groupName,
- groupOrder,
- channelType: toNumber(row.type ?? row.channelType ?? row.payTypeType),
- bankValid: toNumber(row.bankValid) ?? 0,
- });
- }
- return output;
- }
- export async function fetchRemittanceChannels(): Promise<RemittanceChannel[]> {
- let raw: unknown;
- try {
- raw = await postRemittance<unknown>("/remit/channel/list", {});
- } catch {
- raw = await postRemittance<unknown>("/remittance/channel/list", {});
- }
- return normalizeChannelList(raw);
- }
- function normalizeBankChannelList(raw: unknown): BankChannelOption[] {
- if (!raw || typeof raw !== "object") return [];
- const container = raw as Record<string, unknown>;
- const inner =
- container.data ??
- container.list ??
- container.rows ??
- container.records ??
- container.channels;
- const source = Array.isArray(inner) ? inner : [];
- const output: BankChannelOption[] = [];
- for (const item of source) {
- if (!item || typeof item !== "object") continue;
- const row = item as Record<string, unknown>;
- const value = pickString(row, ["code", "name", "currency", "enName"]);
- if (!value) continue;
- const label = pickString(row, ["name", "enName", "currency", "code"]) || value;
- const currency = pickString(row, ["currency", "code", "name"]) || "USDT";
- output.push({ value, label, currency });
- }
- return output;
- }
- export async function fetchBankChannelOptions(channelCode?: string): Promise<BankChannelOption[]> {
- const body = channelCode ? { channelCode } : {};
- const raw = await postRemittance<unknown>("/channel/bank/list", body);
- return normalizeBankChannelList(raw);
- }
- export async function submitXfgPayOrder(input: {
- requestUrl: string;
- amount: number;
- bankCode?: string;
- goodIds: string[];
- payName: string;
- payPhone: string;
- }): Promise<{ raw: unknown; resultUrl: string | null }> {
- const normalizedRequestUrl = `/${input.requestUrl.replace(/^\/+|\/+$/g, "")}`;
- const amount = String(input.amount);
- const path = input.bankCode
- ? `${normalizedRequestUrl}/1/${encodeURIComponent(amount)}/${encodeURIComponent(input.bankCode)}/0`
- : `${normalizedRequestUrl}/1/${encodeURIComponent(amount)}/0`;
- const body = {
- goodIds: input.goodIds,
- payName: input.payName,
- payPhone: input.payPhone,
- };
- const data = await postRemittance<unknown>(path, body);
- return { raw: data, resultUrl: pickResultUrl(data) };
- }
- function pickResultUrl(raw: unknown): string | null {
- if (!raw || typeof raw !== "object") return null;
- const o = raw as Record<string, unknown>;
- const candidates: unknown[] = [
- o.result,
- o.url,
- o.payUrl,
- o.redirectUrl,
- ];
- if (o.data && typeof o.data === "object" && o.data !== null) {
- const d = o.data as Record<string, unknown>;
- candidates.push(d.result, d.url, d.payUrl, d.redirectUrl);
- }
- for (const item of candidates) {
- if (typeof item === "string" && item.trim()) return item.trim();
- }
- return null;
- }
|