feat(daily-task): 返回周任务倒计时时间

This commit is contained in:
huanghaipeng 2026-09-07 14:46:31 +08:00
parent 6c35c7506d
commit 04ed8d700f
3 changed files with 26 additions and 5 deletions

View File

@ -30,6 +30,8 @@ export type DailyWeeklyTaskData = {
version: 2;
dayKey: string;
weekKey: string;
weekEndsAt: number;
serverNow: number;
dailyTasks: DailyTask[];
weeklyStars: number;
weeklyRewards: WeeklyReward[];
@ -128,4 +130,3 @@ export const WEEKLY_REWARDS: WeeklyReward[] = [
{ rewardId: "weekly_105", target: 105, state: 0, rewards: [{ type: "infinite_health", count: 3600 }, { type: "hammer", count: 1 }] },
{ rewardId: "weekly_140", target: 140, state: 0, rewards: [{ type: "infinite_rocket", count: 900 }, { type: "infinite_hourglass", count: 900 }, { type: "coin", count: 1500 }] },
];

View File

@ -18,6 +18,11 @@ export function getWeekKey(nowMs = Date.now()): string {
return new Date(shifted.getTime() - (day - 1) * DAY_MS).toISOString().slice(0, 10);
}
export function getWeekEndsAt(nowMs = Date.now()): number {
const weekKey = getWeekKey(nowMs);
return Date.parse(`${weekKey}T00:00:00+08:00`) + 7 * DAY_MS;
}
function hash(input: string): number {
let value = 2166136261;
for (let i = 0; i < input.length; i++) {
@ -56,6 +61,7 @@ export function refreshTaskData(
): { data: DailyWeeklyTaskData; changed: boolean } {
const dayKey = getDayKey(nowMs);
const weekKey = getWeekKey(nowMs);
const weekEndsAt = getWeekEndsAt(nowMs);
const parsed = typeof stored === "string" ? safeParse(stored) : stored;
const valid = parsed && (parsed as DailyWeeklyTaskData).version === 2
&& Array.isArray((parsed as DailyWeeklyTaskData).dailyTasks)
@ -66,9 +72,12 @@ export function refreshTaskData(
const newDay = !old || old.dayKey !== dayKey;
if (!newDay && !newWeek) {
const changed = old.weekEndsAt !== weekEndsAt;
old.weekEndsAt = weekEndsAt;
old.serverNow = nowMs;
applyLocks(old.dailyTasks);
applyWeeklyStates(old);
return { data: old, changed: false };
return { data: old, changed };
}
const previousTaskIds = old ? old.dailyTasks.map(task => task.taskId) : [];
@ -76,6 +85,8 @@ export function refreshTaskData(
version: 2,
dayKey,
weekKey,
weekEndsAt,
serverNow: nowMs,
dailyTasks: selectDailyTasks(uid, dayKey, Math.max(1, level), previousTaskIds),
weeklyStars: newWeek ? 0 : Number(old?.weeklyStars) || 0,
weeklyRewards: newWeek
@ -141,4 +152,3 @@ function applyWeeklyStates(data: DailyWeeklyTaskData): void {
function safeParse(value: string): unknown {
try { return JSON.parse(value); } catch (_) { return null; }
}

View File

@ -12,12 +12,23 @@ registerHooks({
},
});
const { getDayKey, getWeekKey, refreshTaskData, mergeClientProgress, claimDaily, claimWeekly } = await import(serviceUrl);
const { getDayKey, getWeekKey, getWeekEndsAt, refreshTaskData, mergeClientProgress, claimDaily, claimWeekly } = await import(serviceUrl);
test("uses Shanghai natural day and Monday week keys", () => {
assert.equal(getDayKey(Date.parse("2026-09-06T15:59:59Z")), "2026-09-06");
assert.equal(getDayKey(Date.parse("2026-09-06T16:00:00Z")), "2026-09-07");
assert.equal(getWeekKey(Date.parse("2026-09-06T16:00:00Z")), "2026-09-07");
assert.equal(getWeekEndsAt(Date.parse("2026-09-06T16:00:00Z")), Date.parse("2026-09-14T00:00:00+08:00"));
});
test("returns current server time and refreshes it on repeated reads", () => {
const firstNow = Date.parse("2026-09-07T04:00:00Z");
const secondNow = firstNow + 5000;
const first = refreshTaskData(null, "user-time", 20, firstNow).data;
const second = refreshTaskData(JSON.stringify(first), "user-time", 20, secondNow);
assert.equal(second.changed, false);
assert.equal(second.data.serverNow, secondNow);
assert.equal(second.data.weekEndsAt, Date.parse("2026-09-14T00:00:00+08:00"));
});
test("migrates legacy tasks into five v2 stages totaling twenty stars", () => {
@ -77,4 +88,3 @@ test("daily reset preserves stars while weekly reset clears them", () => {
assert.equal(monday.weeklyStars, 0);
assert.ok(monday.weeklyRewards.every(reward => reward.state === 0));
});