MatchMaster/server/laf-cloud/functions/jungleTreasure.ts
2026-08-07 10:59:22 +08:00

140 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import cloud from "@lafjs/cloud";
import Utils from "@/Utils";
import * as JungleConfigModule from "@/jungleConfig";
// Laf 会为共享云函数生成 index 类型声明,该声明可能滞后于实际命名导出。
const JungleConfig: any = JungleConfigModule as any;
const db = cloud.database();
const USER_STATE_FIELD = "jungleTreasureState";
/**
* action=read返回 51 个档位状态及完整配置。
* action=claim将指定档位从 1 改为 2不检查前置档位。
*/
export default async function jungleTreasure(ctx: FunctionContext) {
const body = ctx.body || {};
const action = String(body.action || "").toLowerCase();
const uid = body.uid;
const dbname = body.gameName === "iaa" ? "usersAd" : "users";
if (action !== "read" && action !== "claim") {
return fail("无效的操作类型,请使用 read 或 claim");
}
if (!uid) {
return fail("未获取到uid");
}
const userResult = await db.collection(dbname).where({ _id: uid }).getOne();
const user = userResult.data;
if (!user) {
return fail("未获取到玩家信息");
}
if (user.token && !Utils.checkToken(body.token, user.token)) {
return fail("token校验失败");
}
let storedStateValue: unknown = user[USER_STATE_FIELD];
let serverState = JungleConfig.normalizeStoredJungleState(storedStateValue);
// 兼容旧对象/数组格式:玩家下次读取时自动改存为 JSON 字符串。
if (!JungleConfig.isCurrentJungleState(storedStateValue) || typeof storedStateValue !== "string") {
storedStateValue = JungleConfig.serializeJungleState(serverState);
const initialized = await db.collection(dbname).where({ _id: uid }).update({
[USER_STATE_FIELD]: storedStateValue,
});
if (isUpdateFailed(initialized)) {
return fail("礼包状态初始化失败");
}
}
if (action === "read") {
return readSuccess(serverState);
}
const claimResult = JungleConfig.claimJungleTier(serverState, body.tierId);
if (!claimResult.ok || !claimResult.state || !claimResult.tierId) {
return fail(claimResult.message || "礼包领取失败");
}
// 字符串不能按数组下标查询;比较完整旧值,避免并发请求覆盖彼此或重复领取。
const updateResult = await db.collection(dbname).where({
_id: uid,
[USER_STATE_FIELD]: storedStateValue,
}).update({
[USER_STATE_FIELD]: JungleConfig.serializeJungleState(claimResult.state),
});
if (isUpdateFailed(updateResult)) {
return fail("礼包状态已变化,请重新读取后再领取");
}
// 付费档领取完成后,将支付订单从待发货改为已发货,避免登录补单重复处理。
if (claimResult.paidOrderNo) {
await db.collection("order").where({
outTradeNo: claimResult.paidOrderNo,
openid: user.openid,
state: 1,
}).update({
state: 2,
getTime: new Date(Date.now() + 8 * 3600000),
});
}
// 按需求重新读取并返回服务器中的最新状态数组。
const latestUserResult = await db.collection(dbname).where({ _id: uid }).getOne();
if (!latestUserResult.data) {
return fail("礼包领取后读取状态失败");
}
serverState = JungleConfig.normalizeStoredJungleState(latestUserResult.data[USER_STATE_FIELD]);
return claimSuccess(claimResult.tierId, serverState);
}
function readSuccess(state: any) {
const serverNow = Date.now();
// Laf 共享函数更新后可能暂时使用旧的 JungleStoredState 类型缓存。
// 运行时仍由新版 jungleConfig 保证 expiresAt 已存在。
const stateWithExpiry: any = state;
const expiresAt = stateWithExpiry.expiresAt;
return {
code: 1,
data: {
tierStates: state.tierStates,
revision: state.revision,
expiresAt,
serverNow,
updatedAt: state.updatedAt,
config: {
...JungleConfig.JUNGLE_TREASURE_CONFIG,
endAt: expiresAt,
},
},
msg: "读取成功",
};
}
function claimSuccess(
claimedTierId: number,
state: any,
) {
const stateWithExpiry: any = state;
return {
code: 1,
data: {
claimedTierId,
tierStates: state.tierStates,
revision: state.revision,
expiresAt: stateWithExpiry.expiresAt,
serverNow: Date.now(),
updatedAt: state.updatedAt,
},
msg: "领取成功",
};
}
function isUpdateFailed(result: any): boolean {
return Boolean(result && (result.ok === false || result.updated === 0));
}
function fail(msg: string) {
return { code: 0, data: null, msg };
}