Merge branch 'main' of 47.107.44.202:xionglijia/18xchat

This commit is contained in:
2025-09-11 17:07:35 +08:00
12 changed files with 122 additions and 37 deletions
+1
View File
@@ -62,6 +62,7 @@ export class OrderData extends BaseData {
vo.status = mapQueryOrderStatus(res.status);
vo.retCode = res.retCode ?? 0;
this._orders.set(orderId, vo);
console.log("更新订单数据:", vo);
}
/** 获取所有需要继续轮询查询的订单 id */
+44 -10
View File
@@ -6,41 +6,75 @@ import { PaymentApi } from "./PaymentApi";
import proto from 'db://assets/Scripts/proto/proto.pb.js';
export interface PollOptions {
maxDurationMs: number; // 轮询时长(例如 2分钟)
startIntervalMs: number; // 初始间隔(例如 2s
maxIntervalMs: number; // 最大间隔(例如 10s
jitter?: boolean; // 抖动
maxDurationMs: number; // 最大轮询时长(超过就自动退出)(例如 2分钟)
startIntervalMs: number; // 第一次轮询等待的间隔(例如 2s
maxIntervalMs: number; // 最大允许的间隔,防止指数增长过大(例如 10s
jitter?: boolean; // 是否启用抖动(让等待时间带点随机性,避免所有客户端同一时间请求服务器)
}
export class PaymentPoller {
private cancelled = false;
private currentPollCount = 0; // 轮询次数
// 取消轮询
cancel() { this.cancelled = true; }
cancel() {
this.cancelled = true;
}
// 轮询订单
async poll(orderId: string, opt: PollOptions, onTick?: (d: proto.cs.ICSQueryOrderRes) => void): Promise<proto.cs.ICSQueryOrderRes | null> {
// 获取当前轮询次数
public getCurrentPollCount(): number {
return this.currentPollCount;
}
/**
* 轮询订单
* @param orderId 要查询的订单 ID
* @param opt 轮询配置(间隔、最大时长、是否抖动)
* @param onTick 可选回调函数,每次轮询到结果时调用
* @returns 最终查询到的订单结果 ICSQueryOrderRes,或者 null(超时/被取消)
*/
async poll(orderId: string, opt: PollOptions, onTick?: (d: proto.cs.ICSQueryOrderRes) => void): Promise<proto.cs.ICSQueryOrderRes> {
const t0 = Date.now();
let interval = opt.startIntervalMs;
while (!this.cancelled) {
// 增加轮询次数
this.currentPollCount++;
// 查询
let reqData = {orderId: orderId};
console.log("第 ", this.currentPollCount, " 次轮询订单的请求数据:", reqData);
const r = await PaymentApi.I.queryOrder(reqData);
console.log("第 ", this.currentPollCount, " 次轮询订单的响应数据:", r);
if (r.code === proto.cs.EnmRetCode.SUCCESS && r.data) {
// 回调
onTick?.(r.data);
// 订单状态,-1:失败,0:成功,1:处理中
if ([-1, 0].indexOf(r.data.status) !== -1) {
return r.data;
}
}
// 退出条件
if (Date.now() - t0 > opt.maxDurationMs) return null;
// 轮询超时
if (Date.now() - t0 > opt.maxDurationMs) {
let resultData: proto.cs.ICSQueryOrderRes = {
status: 92, // 自定义的状态,代表客户端轮询超时
retCode: 0,
balance: 0,
vipExpire: 0,
}
return resultData;
}
// 等待
await this.sleep(this.jitter(interval, opt));
// 每次轮询后,interval 会按照 1.5 倍增长,直到达到最大间隔 maxIntervalMs,避免在短时间内重复请求
interval = Math.min(interval * 1.5, opt.maxIntervalMs);
}
return null;
// 至此,代表取消了轮询订单
let resultData: proto.cs.ICSQueryOrderRes = {
status: 90, // 自定义的状态,代表取消
retCode: 0,
balance: 0,
vipExpire: 0,
}
return resultData;
}
// 用来暂停一定的时间(ms 毫秒),并让轮询进入等待状态
@@ -32,12 +32,12 @@ export class PaymentService {
}
/** 发起支付:创建订单→打开URL→回到App后开始轮询 */
async startPayment(req: proto.cs.ICSCreateOrderReq, open: OpenStrategy = "system"): Promise<proto.cs.ICSQueryOrderRes | null> {
async startPayment(req: proto.cs.ICSCreateOrderReq, open: OpenStrategy = "system"): Promise<proto.cs.ICSQueryOrderRes> {
// 下单
const create = await PaymentApi.I.createOrder(req);
console.log("创建订单的响应数据:", create);
if (create.code !== proto.cs.EnmRetCode.SUCCESS || !create.data) {
return { status: -1, retCode: -1 };
return { status: -1, retCode: -1, balance: 0, vipExpire: 0};
}
const { orderId, payUrl } = create.data;
this.bus.emit(PaymentEvents.Started, { orderId });
@@ -108,6 +108,7 @@ export class PaymentService {
return new Promise<void>((resolve) => {
let finished = false;
const finish = () => {
console.log("应用回到 finish");
if (finished) return;
finished = true;
// 安全移除监听
@@ -117,6 +118,7 @@ export class PaymentService {
const onShow = () => {
// 应用回到前台
console.log("应用回到了前台");
finish();
};
@@ -124,8 +126,8 @@ export class PaymentService {
game.on(Game.EVENT_SHOW, onShow, this);
// 兜底:某些环境(桌面浏览器)可能不会触发隐藏/显示事件,避免一直卡住
const FALLBACK_MS = 15000; // 按需调整
setTimeout(finish, FALLBACK_MS);
const FALLBACK_MS = 25000; // 按需调整
// setTimeout(finish, FALLBACK_MS);
});
}
}
@@ -22,13 +22,15 @@ export function mapQueryOrderStatus(
case 1: return "PENDING"; // 处理中
case 0: return "SUCCESS"; // 成功
case -1: return "FAILED"; // 失败
case 90: return "CANCELED"; // 取消
case 92: return "TIMEOUT"; // 轮询超时
default: return "CREATED"; // 未知/初始,按“已创建”兜底
}
}
/** 是否为终态(无需再轮询) */
export function isTerminalStatus(s: OrderStatus): boolean {
return s === "SUCCESS" || s === "FAILED" || s === "CANCELED" || s === "EXPIRED";
return s === "SUCCESS" || s === "FAILED" || s === "CANCELED" || s === "EXPIRED" || s === "TIMEOUT";
}
/** 是否应继续轮询查询订单 */
+1
View File
@@ -9,6 +9,7 @@ export type OrderStatus =
| "SUCCESS" // 成功
| "FAILED" // 失败
| "CANCELED" // 取消
| "TIMEOUT" // 轮询超时
| "EXPIRED"; // 过期
// 订单数据的数据结构
@@ -186,10 +186,19 @@ export class PurchasePanel extends li_BaseView {
const reqData = {
goodId
};
// let res = await PaymentService.I.startPayment(reqData);
// if (res) {
// }
let res = await PaymentService.I.startPayment(reqData);
console.log("支付完成的响应数据:", res);
if (res) {
let status = res.status;
if (status === -1) {
console.log("支付失败!!!,错误码:", res.retCode);
} else if (status === 0) {
console.log("支付成功!!!");
const walletData = DataManager.I.getDataById<WalletData>(DataId.Wallet);
walletData.balance = Number(res.balance);
walletData.vipExpire = Number(res.vipExpire);
}
}
}
onDestroy() {