feat(daily-task): 新增每日和每周任务调试接口
This commit is contained in:
parent
ca1e9012c5
commit
3e51bcc95e
45
laf-cloud/dailyTaskDebug.API.md
Normal file
45
laf-cloud/dailyTaskDebug.API.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# 每日/周任务调试接口
|
||||
|
||||
云函数:`dailyTaskDebug`
|
||||
|
||||
仅用于开发和体验环境。部署前配置服务端环境变量 `DAILY_TASK_DEBUG_KEY`;未配置时接口不可用。请求还必须携带当前用户 token,且用户数据中的 `isDebug` 为 `true` 或字符串 `"true"`。
|
||||
|
||||
公共请求字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"uid": "用户ID",
|
||||
"token": "登录token",
|
||||
"debugKey": "服务端配置的DAILY_TASK_DEBUG_KEY",
|
||||
"gameName": "可选,iaa时使用usersAd",
|
||||
"action": "操作名称"
|
||||
}
|
||||
```
|
||||
|
||||
## 每日任务操作
|
||||
|
||||
- 完成指定任务:`action=complete_daily`,附加 `taskId` 或 `slot`(0~4)。
|
||||
- 设置指定任务进度:`action=set_daily_progress`,附加 `taskId` 或 `slot`,以及 `value`。
|
||||
- 完成当天全部任务:`action=complete_all_daily`。任务仍遵守阶段锁定规则,需要依次调用正式领奖接口解锁。
|
||||
- 重置当天任务:`action=reset_daily`。保留本周星星和周奖励状态。
|
||||
|
||||
示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"uid": "debug-user",
|
||||
"token": "token",
|
||||
"debugKey": "secret",
|
||||
"action": "complete_daily",
|
||||
"slot": 0
|
||||
}
|
||||
```
|
||||
|
||||
## 周任务操作
|
||||
|
||||
- 设置周星星:`action=set_weekly_stars`,附加 `value`,范围自动限制为 0~140。
|
||||
- 增加周星星:`action=add_weekly_stars`,附加正数或负数 `value`。
|
||||
- 重置周任务:`action=reset_weekly`。保留当天任务及进度。
|
||||
- 重置每日和周任务:`action=reset_all`。
|
||||
|
||||
成功响应会返回修改后的完整 `data.task`。测试接口只修改任务数据,不直接发放金币或道具;奖励仍通过正式 `getTaskReward` 接口领取。
|
||||
90
laf-cloud/functions/dailyTaskDebug.ts
Normal file
90
laf-cloud/functions/dailyTaskDebug.ts
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import cloud from "@lafjs/cloud";
|
||||
import Utils from "@/Utils";
|
||||
import { WEEKLY_REWARDS } from "@/dailyTaskConfig";
|
||||
import { refreshTaskData } from "@/dailyTaskService";
|
||||
|
||||
const db = cloud.database();
|
||||
|
||||
export default async function (ctx: FunctionContext) {
|
||||
const body = ctx.body || {};
|
||||
const uid = body.uid;
|
||||
if (!uid) return { code: 0, data: null, msg: "未获取到uid" };
|
||||
|
||||
const dbname = body.gameName === "iaa" ? "usersAd" : "users";
|
||||
const result = await db.collection(dbname).where({ _id: uid }).getOne();
|
||||
const user = result.data;
|
||||
if (!user) return { code: 0, data: null, msg: "未获取到用户信息" };
|
||||
if (user.token && !Utils.checkToken(body.token, user.token)) {
|
||||
return { code: 0, data: null, msg: "token校验失败" };
|
||||
}
|
||||
if (user.isDebug !== true && user.isDebug !== "true") {
|
||||
return { code: 403, data: null, msg: "仅调试账号可调用" };
|
||||
}
|
||||
const debugKey = process.env.DAILY_TASK_DEBUG_KEY;
|
||||
if (!debugKey || body.debugKey !== debugKey) {
|
||||
return { code: 403, data: null, msg: "调试密钥校验失败" };
|
||||
}
|
||||
|
||||
const level = Number(user.levelAmount) + 1 || 1;
|
||||
let task = refreshTaskData(user.task, uid, level).data;
|
||||
const action = String(body.action || "");
|
||||
|
||||
if (action === "set_daily_progress" || action === "complete_daily") {
|
||||
const dailyTask = findDailyTask(task.dailyTasks, body.taskId, body.slot);
|
||||
if (!dailyTask) return { code: 0, data: { task }, msg: "未找到指定每日任务" };
|
||||
const value = action === "complete_daily" ? dailyTask.target : Number(body.value);
|
||||
if (!Number.isFinite(value)) return { code: 0, data: { task }, msg: "value必须是数字" };
|
||||
dailyTask.value = Math.max(0, Math.min(dailyTask.target, value));
|
||||
if (dailyTask.state !== 2) dailyTask.state = dailyTask.value >= dailyTask.target ? 1 : 0;
|
||||
}
|
||||
else if (action === "complete_all_daily") {
|
||||
task.dailyTasks.forEach(dailyTask => {
|
||||
if (dailyTask.state === 2) return;
|
||||
dailyTask.value = dailyTask.target;
|
||||
dailyTask.state = 1;
|
||||
});
|
||||
}
|
||||
else if (action === "set_weekly_stars" || action === "add_weekly_stars") {
|
||||
const value = Number(body.value);
|
||||
if (!Number.isFinite(value)) return { code: 0, data: { task }, msg: "value必须是数字" };
|
||||
const stars = action === "add_weekly_stars" ? task.weeklyStars + value : value;
|
||||
task.weeklyStars = Math.max(0, Math.min(140, stars));
|
||||
}
|
||||
else if (action === "reset_daily") {
|
||||
task.dayKey = "";
|
||||
task = refreshTaskData(task, uid, level).data;
|
||||
}
|
||||
else if (action === "reset_weekly") {
|
||||
task.weeklyStars = 0;
|
||||
task.weeklyRewards = cloneWeeklyRewards();
|
||||
}
|
||||
else if (action === "reset_all") {
|
||||
task.dayKey = "";
|
||||
task.weekKey = "";
|
||||
task = refreshTaskData(task, uid, level).data;
|
||||
}
|
||||
else {
|
||||
return { code: 0, data: { task }, msg: "不支持的调试操作" };
|
||||
}
|
||||
|
||||
task = refreshTaskData(task, uid, level).data;
|
||||
await db.collection(dbname).where({ _id: uid }).update({
|
||||
task: JSON.stringify(task),
|
||||
taskTime: Date.now(),
|
||||
});
|
||||
return { code: 1, data: { task }, msg: "调试任务数据更新成功" };
|
||||
}
|
||||
|
||||
function findDailyTask(tasks: any[], taskId: unknown, slot: unknown) {
|
||||
if (taskId != null && taskId !== "") return tasks.find(task => task.taskId === String(taskId));
|
||||
const slotNumber = Number(slot);
|
||||
return Number.isInteger(slotNumber) ? tasks.find(task => task.slot === slotNumber) : null;
|
||||
}
|
||||
|
||||
function cloneWeeklyRewards() {
|
||||
return WEEKLY_REWARDS.map(reward => ({
|
||||
...reward,
|
||||
state: 0 as const,
|
||||
rewards: reward.rewards.map(item => ({ ...item })),
|
||||
}));
|
||||
}
|
||||
93
laf-cloud/tests/daily-task-debug.test.mjs
Normal file
93
laf-cloud/tests/daily-task-debug.test.mjs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { registerHooks } from "node:module";
|
||||
|
||||
const configUrl = new URL("../functions/dailyTaskConfig.ts", import.meta.url);
|
||||
const serviceUrl = new URL("../functions/dailyTaskService.ts", import.meta.url);
|
||||
const functionUrl = new URL("../functions/dailyTaskDebug.ts", import.meta.url);
|
||||
const state = { user: null };
|
||||
|
||||
registerHooks({
|
||||
resolve(specifier, context, nextResolve) {
|
||||
if (specifier === "@/dailyTaskConfig") return { url: configUrl.href, shortCircuit: true };
|
||||
if (specifier === "@/dailyTaskService") return { url: serviceUrl.href, shortCircuit: true };
|
||||
if (specifier === "@/Utils") {
|
||||
return { url: "data:text/javascript,export default { checkToken: (a, b) => a === b }", shortCircuit: true };
|
||||
}
|
||||
if (specifier === "@lafjs/cloud") {
|
||||
return {
|
||||
url: `data:text/javascript,export default globalThis.__dailyTaskDebugCloud`,
|
||||
shortCircuit: true,
|
||||
};
|
||||
}
|
||||
return nextResolve(specifier, context);
|
||||
},
|
||||
});
|
||||
|
||||
globalThis.__dailyTaskDebugCloud = {
|
||||
database() {
|
||||
return {
|
||||
collection() {
|
||||
return {
|
||||
where() {
|
||||
return {
|
||||
async getOne() { return { data: state.user }; },
|
||||
async update(data) { Object.assign(state.user, data); return { updated: 1 }; },
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
process.env.DAILY_TASK_DEBUG_KEY = "debug-key";
|
||||
|
||||
const handler = (await import(functionUrl)).default;
|
||||
|
||||
function makeUser(isDebug = "true") {
|
||||
state.user = { _id: "debug-user", token: "token", isDebug, levelAmount: 20, task: null };
|
||||
}
|
||||
|
||||
async function call(action, extra = {}) {
|
||||
return handler({ body: { uid: "debug-user", token: "token", debugKey: "debug-key", action, ...extra } });
|
||||
}
|
||||
|
||||
test("rejects non-debug users", async () => {
|
||||
makeUser(false);
|
||||
const result = await call("complete_all_daily");
|
||||
assert.equal(result.code, 403);
|
||||
});
|
||||
|
||||
test("rejects an invalid debug key", async () => {
|
||||
makeUser();
|
||||
const result = await call("complete_all_daily", { debugKey: "wrong-key" });
|
||||
assert.equal(result.code, 403);
|
||||
});
|
||||
|
||||
test("completes one daily task by slot", async () => {
|
||||
makeUser();
|
||||
const result = await call("complete_daily", { slot: 0 });
|
||||
assert.equal(result.code, 1);
|
||||
assert.equal(result.data.task.dailyTasks[0].value, result.data.task.dailyTasks[0].target);
|
||||
assert.equal(result.data.task.dailyTasks[0].state, 1);
|
||||
});
|
||||
|
||||
test("sets weekly stars and unlocks matching rewards", async () => {
|
||||
makeUser();
|
||||
const result = await call("set_weekly_stars", { value: 105 });
|
||||
assert.equal(result.data.task.weeklyStars, 105);
|
||||
assert.deepEqual(result.data.task.weeklyRewards.map(item => item.state), [1, 1, 1, 0]);
|
||||
});
|
||||
|
||||
test("daily reset preserves weekly progress and weekly reset preserves daily tasks", async () => {
|
||||
makeUser();
|
||||
const weekly = await call("set_weekly_stars", { value: 70 });
|
||||
state.user.task = JSON.stringify(weekly.data.task);
|
||||
const resetDaily = await call("reset_daily");
|
||||
assert.equal(resetDaily.data.task.weeklyStars, 70);
|
||||
const dailyIds = resetDaily.data.task.dailyTasks.map(item => item.taskId);
|
||||
state.user.task = JSON.stringify(resetDaily.data.task);
|
||||
const resetWeekly = await call("reset_weekly");
|
||||
assert.equal(resetWeekly.data.task.weeklyStars, 0);
|
||||
assert.deepEqual(resetWeekly.data.task.dailyTasks.map(item => item.taskId), dailyIds);
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user