Checkpoint: v2.0完整版本:新增社区排行榜、每日打卡、24种成就徽章、实时摄像头姿势分析、在线录制(稳定压缩流/断线重连/自动剪辑)、移动端全面适配。47个测试通过。包含完整开发文档。

这个提交包含在:
Manus
2026-03-14 08:04:00 -04:00
父节点 36907d1110
当前提交 2c418b482e
修改 22 个文件,包含 4370 行新增41 行删除

查看文件

@@ -412,6 +412,65 @@ ${recentScores.length > 0 ? `- 用户最近的分析数据: ${JSON.stringify(rec
return { rating: user?.ntrpRating || 1.5 };
}),
}),
// Daily check-in system
checkin: router({
today: protectedProcedure.query(async ({ ctx }) => {
return db.getTodayCheckin(ctx.user.id);
}),
do: protectedProcedure
.input(z.object({
notes: z.string().optional(),
minutesTrained: z.number().optional(),
}).optional())
.mutation(async ({ ctx, input }) => {
const result = await db.checkinToday(ctx.user.id, input?.notes, input?.minutesTrained);
// Check for new badges after check-in
const newBadges = await db.checkAndAwardBadges(ctx.user.id);
return { ...result, newBadges };
}),
history: protectedProcedure
.input(z.object({ limit: z.number().default(60) }).optional())
.query(async ({ ctx, input }) => {
return db.getUserCheckins(ctx.user.id, input?.limit || 60);
}),
}),
// Badge system
badge: router({
list: protectedProcedure.query(async ({ ctx }) => {
const earned = await db.getUserBadges(ctx.user.id);
const allBadges = Object.entries(db.BADGE_DEFINITIONS).map(([key, def]) => {
const earnedBadge = earned.find(b => b.badgeKey === key);
return {
key,
...def,
earned: !!earnedBadge,
earnedAt: earnedBadge?.earnedAt || null,
};
});
return allBadges;
}),
check: protectedProcedure.mutation(async ({ ctx }) => {
const newBadges = await db.checkAndAwardBadges(ctx.user.id);
return { newBadges: newBadges.map(key => ({ key, ...db.BADGE_DEFINITIONS[key] })) };
}),
definitions: publicProcedure.query(() => {
return Object.entries(db.BADGE_DEFINITIONS).map(([key, def]) => ({ key, ...def }));
}),
}),
// Leaderboard
leaderboard: router({
get: protectedProcedure
.input(z.object({
sortBy: z.enum(["ntrpRating", "totalMinutes", "totalSessions", "totalShots"]).default("ntrpRating"),
limit: z.number().default(50),
}).optional())
.query(async ({ input }) => {
return db.getLeaderboard(input?.sortBy || "ntrpRating", input?.limit || 50);
}),
}),
});
// NTRP Rating calculation function