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 }; }