78 lines
3.2 KiB
TypeScript
78 lines
3.2 KiB
TypeScript
import cloud from "@lafjs/cloud";
|
|
import { compareVersions } from "@/versionPolicy";
|
|
import { refreshTaskData } from "@/dailyTaskService";
|
|
|
|
export const DAILY_TASK_MIN_VERSION = "1.0.88";
|
|
const OFFSET = 8 * 3600000;
|
|
const DAY = 86400000;
|
|
export const LEGACY_TARGETS = { levelPass: 3, share: 1, useEnergy: 10, useProp: 3 };
|
|
|
|
export function supportsDailyTaskV2(version: unknown): boolean {
|
|
const compared = compareVersions(version, DAILY_TASK_MIN_VERSION);
|
|
return compared !== null && compared >= 0;
|
|
}
|
|
|
|
export function parseTask(stored: any): any {
|
|
if (typeof stored !== "string") return stored;
|
|
try { return JSON.parse(stored); } catch { return null; }
|
|
}
|
|
|
|
export function isV2Task(stored: any): boolean {
|
|
return Number(parseTask(stored)?.version) >= 2;
|
|
}
|
|
|
|
export function taskVersionError() {
|
|
return { code: 0, errorCode: "DAILY_TASK_VERSION_REQUIRED", data: null,
|
|
msg: "每日任务已升级,请更新客户端后重新进入", minVersion: DAILY_TASK_MIN_VERSION };
|
|
}
|
|
|
|
export function taskConflict() {
|
|
return { code: 0, data: null, msg: "任务数据已更新,请重新读取后重试" };
|
|
}
|
|
|
|
/** 旧 taskTime 使用 UTC 时间戳加 8 小时,保留该约定兼容已发布客户端。 */
|
|
export function refreshLegacyTask(stored: any, taskTime: any, now = Date.now()): any {
|
|
const old = parseTask(stored);
|
|
const reset = Math.floor((now + OFFSET) / DAY) * DAY > (Number(taskTime) || 0);
|
|
const task: any = {};
|
|
Object.keys(LEGACY_TARGETS).forEach(key => {
|
|
const value = reset ? 0 : Math.max(0, Number(old?.[key]?.value) || 0);
|
|
const claimed = !reset && old?.[key]?.state === 2;
|
|
task[key] = { value, target: LEGACY_TARGETS[key], state: claimed ? 2 : value >= LEGACY_TARGETS[key] ? 1 : 0 };
|
|
});
|
|
return task;
|
|
}
|
|
|
|
/** 比较读取时的 task/taskTime,防止旧请求覆盖迁移结果,也防止重复领奖。 */
|
|
export async function writeTask(dbname: string, user: any, task: any, taskTime: number): Promise<boolean> {
|
|
const filter: any = { _id: user._id };
|
|
for (const key of ["task", "taskTime"]) {
|
|
filter[key] = Object.prototype.hasOwnProperty.call(user, key) ? user[key] : { $exists: false };
|
|
}
|
|
const result = await cloud.mongo.db.collection(dbname).updateOne(filter, {
|
|
$set: { task: JSON.stringify(task), taskTime },
|
|
});
|
|
return result.matchedCount === 1;
|
|
}
|
|
|
|
/** 所有登录分支共用;仅从旧协议迁移到新协议,绝不反向覆盖。 */
|
|
export async function ensureLoginTasks(dbname: string, user: any, version: unknown) {
|
|
const modern = supportsDailyTaskV2(version);
|
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
if (!modern && isV2Task(user.task)) return { error: taskVersionError() };
|
|
const now = Date.now();
|
|
const task = modern ? refreshTaskData(user.task, user._id, Number(user.levelAmount) + 1 || 1, now).data
|
|
: refreshLegacyTask(user.task, user.taskTime, now);
|
|
const taskTime = modern ? now : now + OFFSET;
|
|
if (await writeTask(dbname, user, task, taskTime)) {
|
|
user.task = JSON.stringify(task);
|
|
user.taskTime = taskTime;
|
|
return { user };
|
|
}
|
|
const latest = await cloud.database().collection(dbname).where({ _id: user._id }).getOne();
|
|
if (!latest.data) return { error: taskConflict() };
|
|
user = latest.data;
|
|
}
|
|
return { error: taskConflict() };
|
|
}
|