支付协议修改
This commit is contained in:
@@ -38,10 +38,10 @@ export class OrderData extends BaseData {
|
|||||||
wallet: res.wallet || "", // 充值钱包地址
|
wallet: res.wallet || "", // 充值钱包地址
|
||||||
amount: res.amount || "", // 充值金额
|
amount: res.amount || "", // 充值金额
|
||||||
expire: res.Expire || 0, // 过期时间,单位: 秒
|
expire: res.Expire || 0, // 过期时间,单位: 秒
|
||||||
expireUnix: res.ExpireUnix || "", // 过期时间戳
|
expireUnix: res.ExpireUnix || "", // 过期时间戳,秒
|
||||||
status: "CREATED" as OrderStatus, // 订单状态
|
status: "CREATED" as OrderStatus, // 订单状态
|
||||||
retCode: 0, // 失败时的原因码
|
retCode: 0, // 失败时的原因码
|
||||||
createdAt: Date.now(), // 订单创建时间
|
createdAt: Date.now(), // 订单创建时间,毫秒
|
||||||
};
|
};
|
||||||
this._orders.set(orderId, vo);
|
this._orders.set(orderId, vo);
|
||||||
console.log("保存订单数据:", this._orders);
|
console.log("保存订单数据:", this._orders);
|
||||||
@@ -83,6 +83,69 @@ export class OrderData extends BaseData {
|
|||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 根据订单 id 获取支付url */
|
||||||
|
public getPayUrlById(id: string): string {
|
||||||
|
let oneData = this.getOrderDataById(id);
|
||||||
|
if (!oneData) return "";
|
||||||
|
return oneData.payUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 根据订单 id 获取支付类型 */
|
||||||
|
public getPayTypeById(id: string): number {
|
||||||
|
let oneData = this.getOrderDataById(id);
|
||||||
|
if (!oneData) return 0;
|
||||||
|
return oneData.payType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 根据订单 id 获取网络类型 */
|
||||||
|
public getNetworkById(id: string): number {
|
||||||
|
let oneData = this.getOrderDataById(id);
|
||||||
|
if (!oneData) return 0;
|
||||||
|
return oneData.network;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 根据订单 id 获取充值钱包地址 */
|
||||||
|
public getWalletById(id: string): string {
|
||||||
|
let oneData = this.getOrderDataById(id);
|
||||||
|
if (!oneData) return "";
|
||||||
|
return oneData.wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 根据订单 id 获取充值金额 */
|
||||||
|
public getAmountById(id: string): string {
|
||||||
|
let oneData = this.getOrderDataById(id);
|
||||||
|
if (!oneData) return "";
|
||||||
|
return oneData.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 根据订单 id 获取过期时间,单位: 秒 */
|
||||||
|
public getExpireById(id: string): number {
|
||||||
|
let oneData = this.getOrderDataById(id);
|
||||||
|
if (!oneData) return 0;
|
||||||
|
return oneData.expire;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 根据订单 id 获取过期时间戳,秒 */
|
||||||
|
public getExpireUnixById(id: string): string {
|
||||||
|
let oneData = this.getOrderDataById(id);
|
||||||
|
if (!oneData) return "";
|
||||||
|
return oneData.expireUnix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 根据订单 id 获取订单失败时的原因码 */
|
||||||
|
public getRetCodeById(id: string): number {
|
||||||
|
let oneData = this.getOrderDataById(id);
|
||||||
|
if (!oneData) return 0;
|
||||||
|
return oneData.retCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 根据订单 id 获取订单创建时间,毫秒 */
|
||||||
|
public getCreatedAtById(id: string): number {
|
||||||
|
let oneData = this.getOrderDataById(id);
|
||||||
|
if (!oneData) return 0;
|
||||||
|
return oneData.createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
/** --------------------------------------------------------- 缓存逻辑 --------------------------------------------------------- */
|
/** --------------------------------------------------------- 缓存逻辑 --------------------------------------------------------- */
|
||||||
|
|
||||||
private ensureMap(): Map<string, OrderVO> {
|
private ensureMap(): Map<string, OrderVO> {
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* 现金支付流程
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import { PaymentOpenerFactory } from "./PaymentOpener";
|
||||||
|
import PaymentPoller from "./PaymentPoller";
|
||||||
|
import type { PaymentFlow } from "./PaymentFlow";
|
||||||
|
import type proto from "db://assets/Scripts/proto/proto.pb.js";
|
||||||
|
import { type OpenStrategy } from "./PaymentOpener";
|
||||||
|
import { DataManager, DataId } from "db://assets/Scripts/chat18x/data/DataManager";
|
||||||
|
import { OrderData } from "db://assets/Scripts/chat18x/data/OrderData";
|
||||||
|
|
||||||
|
export class CashInrFlow implements PaymentFlow {
|
||||||
|
constructor(private waitAppResume: (open: OpenStrategy) => Promise<void>) {}
|
||||||
|
|
||||||
|
async run(orderId: string, payUrl: string, open: OpenStrategy): Promise<proto.cs.ICSQueryOrderRes | null> {
|
||||||
|
// 打开支付页
|
||||||
|
await PaymentOpenerFactory.create(open).open(payUrl);
|
||||||
|
// 等待回到前台(系统浏览器策略下)
|
||||||
|
// - 如果是 inapp/minigame,可在 WebView/回跳时立即开始轮询;
|
||||||
|
// - 这里给一个通用的“等待前台”方法(可用 Cocos 的 onShow/onHide 自行接入)
|
||||||
|
await this.waitAppResume(open);
|
||||||
|
// 开始轮询
|
||||||
|
const data = await this.pollOrder(orderId);
|
||||||
|
// 刷新订单数据
|
||||||
|
const orderData = DataManager.I.getDataById<OrderData>(DataId.Order);
|
||||||
|
orderData.applyQueryOrder(orderId, data);
|
||||||
|
// 返回结果
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async resume(orderId: string, _payUrl: string): Promise<proto.cs.ICSQueryOrderRes | null> {
|
||||||
|
// 直接恢复轮询
|
||||||
|
return this.pollOrder(orderId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async pollOrder(orderId: string) {
|
||||||
|
const poller = new PaymentPoller();
|
||||||
|
return poller.poll(orderId, {
|
||||||
|
maxDurationMs: 2 * 60 * 1000,
|
||||||
|
startIntervalMs: 2000,
|
||||||
|
maxIntervalMs: 10000,
|
||||||
|
jitter: true,
|
||||||
|
}, (d) => console.log());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "806a1ac4-3dd3-4744-b846-c6915c171a32",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* 支付流程的相关接口
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import type proto from "db://assets/Scripts/proto/proto.pb.js";
|
||||||
|
import { type OpenStrategy } from "./PaymentOpener";
|
||||||
|
|
||||||
|
export interface PaymentFlow {
|
||||||
|
/** 开始支付流程 */
|
||||||
|
run(orderId: string, payUrl: string, open: OpenStrategy): Promise<proto.cs.ICSQueryOrderRes | null>;
|
||||||
|
|
||||||
|
/** 恢复未完成订单 */
|
||||||
|
resume(orderId: string, payUrl: string): Promise<proto.cs.ICSQueryOrderRes | null>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "61bfae9e-5202-4dce-8ce6-1d31ca7e5593",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -6,6 +6,9 @@ import { EventTarget, game, Game } from "cc";
|
|||||||
import { PaymentApi } from "./PaymentApi";
|
import { PaymentApi } from "./PaymentApi";
|
||||||
import { PaymentOpenerFactory, type OpenStrategy } from "./PaymentOpener";
|
import { PaymentOpenerFactory, type OpenStrategy } from "./PaymentOpener";
|
||||||
import PaymentPoller from "./PaymentPoller";
|
import PaymentPoller from "./PaymentPoller";
|
||||||
|
import { PaymentFlow } from "./PaymentFlow";
|
||||||
|
import { CashInrFlow } from "./CashInrFlow";
|
||||||
|
import { WebUsdFlow } from "./WebUsdFlow";
|
||||||
import proto from 'db://assets/Scripts/proto/proto.pb.js';
|
import proto from 'db://assets/Scripts/proto/proto.pb.js';
|
||||||
import { DataManager, DataId } from "db://assets/Scripts/chat18x/data/DataManager";
|
import { DataManager, DataId } from "db://assets/Scripts/chat18x/data/DataManager";
|
||||||
import { OrderData } from "db://assets/Scripts/chat18x/data/OrderData";
|
import { OrderData } from "db://assets/Scripts/chat18x/data/OrderData";
|
||||||
@@ -15,7 +18,16 @@ import { InnerMsgCode } from "../../Main/Config/InnerMsgCode";
|
|||||||
export class PaymentService {
|
export class PaymentService {
|
||||||
private static _I: PaymentService | null = null;
|
private static _I: PaymentService | null = null;
|
||||||
static get I() { return this._I ?? (this._I = new PaymentService()); }
|
static get I() { return this._I ?? (this._I = new PaymentService()); }
|
||||||
private constructor() {}
|
/** 策略表 */
|
||||||
|
private flowMap: Record<number, PaymentFlow> = {};
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
this.flowMap = {};
|
||||||
|
let num1 = proto.cs.EnmPayType.EPT_Cash_INR;
|
||||||
|
this.flowMap[num1] = new CashInrFlow(this.waitAppResumeIfNeeded.bind(this));
|
||||||
|
let num2 = proto.cs.EnmPayType.EPT_WEB3_USD;
|
||||||
|
this.flowMap[num2] = new WebUsdFlow(5000);
|
||||||
|
}
|
||||||
|
|
||||||
/** 发起支付:创建订单→打开URL→回到App后开始轮询 */
|
/** 发起支付:创建订单→打开URL→回到App后开始轮询 */
|
||||||
async startPayment(req: proto.cs.ICSCreateOrderReq, open: OpenStrategy = "system"): Promise<proto.cs.ICSQueryOrderRes> {
|
async startPayment(req: proto.cs.ICSCreateOrderReq, open: OpenStrategy = "system"): Promise<proto.cs.ICSQueryOrderRes> {
|
||||||
@@ -34,27 +46,9 @@ export class PaymentService {
|
|||||||
// 发出事件,支付订单创建成功
|
// 发出事件,支付订单创建成功
|
||||||
Utils.sendInnerMsg(InnerMsgCode.PayOrderCreateSucc, { orderId: orderId });
|
Utils.sendInnerMsg(InnerMsgCode.PayOrderCreateSucc, { orderId: orderId });
|
||||||
|
|
||||||
// 打开支付页
|
// 分发流程
|
||||||
await PaymentOpenerFactory.create(open).open(payUrl);
|
const flow = this.flowMap[req.payType];
|
||||||
|
return flow?.run(orderId, payUrl, open) ?? null;
|
||||||
// 等待回到前台(系统浏览器策略下)
|
|
||||||
// - 如果是 inapp/minigame,可在 WebView/回跳时立即开始轮询;
|
|
||||||
// - 这里给一个通用的“等待前台”方法(可用 Cocos 的 onShow/onHide 自行接入)
|
|
||||||
await this.waitAppResumeIfNeeded(open);
|
|
||||||
|
|
||||||
// 轮询
|
|
||||||
const poller = new PaymentPoller();
|
|
||||||
const data = await poller.poll(orderId, {
|
|
||||||
maxDurationMs: 2 * 60 * 1000,
|
|
||||||
startIntervalMs: 2000,
|
|
||||||
maxIntervalMs: 10000,
|
|
||||||
jitter: true,
|
|
||||||
}, (d) => console.log());
|
|
||||||
|
|
||||||
// 刷新订单数据
|
|
||||||
orderData.applyQueryOrder(orderId, data);
|
|
||||||
// 返回结果
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** App 回到前台后恢复未完成订单的轮询(在 onShow 时调用) */
|
/** App 回到前台后恢复未完成订单的轮询(在 onShow 时调用) */
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* web3 USD 支付流程
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import PaymentPoller from "./PaymentPoller";
|
||||||
|
import type { PaymentFlow } from "./PaymentFlow";
|
||||||
|
import type proto from "db://assets/Scripts/proto/proto.pb.js";
|
||||||
|
import { type OpenStrategy } from "./PaymentOpener";
|
||||||
|
import { DataManager, DataId } from "db://assets/Scripts/chat18x/data/DataManager";
|
||||||
|
import { OrderData } from "db://assets/Scripts/chat18x/data/OrderData";
|
||||||
|
|
||||||
|
export class WebUsdFlow implements PaymentFlow {
|
||||||
|
constructor(private delayMs: number = 5000) {}
|
||||||
|
|
||||||
|
async run(orderId: string, _payUrl: string, _open: OpenStrategy): Promise<proto.cs.ICSQueryOrderRes | null> {
|
||||||
|
// 延时
|
||||||
|
await this.delay(this.delayMs);
|
||||||
|
// 开始轮询
|
||||||
|
const data = await this.pollOrder(orderId);
|
||||||
|
// 刷新订单数据
|
||||||
|
const orderData = DataManager.I.getDataById<OrderData>(DataId.Order);
|
||||||
|
orderData.applyQueryOrder(orderId, data);
|
||||||
|
// 返回结果
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async resume(orderId: string, _payUrl: string): Promise<proto.cs.ICSQueryOrderRes | null> {
|
||||||
|
// 直接轮询(也可以选择先 delay 一下再 poll,看业务需求)
|
||||||
|
return this.pollOrder(orderId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async pollOrder(orderId: string) {
|
||||||
|
const poller = new PaymentPoller();
|
||||||
|
return poller.poll(orderId, {
|
||||||
|
maxDurationMs: 2 * 60 * 1000,
|
||||||
|
startIntervalMs: 2000,
|
||||||
|
maxIntervalMs: 10000,
|
||||||
|
jitter: true,
|
||||||
|
}, (d) => console.log());
|
||||||
|
}
|
||||||
|
|
||||||
|
private delay(ms: number) {
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "87ddca36-23cb-411d-bbe9-3bd948ec5490",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user