feat(badges): 添加用户勋章系统,支持睡眠挑战勋章自动授予
实现完整的用户勋章功能模块: - 新增 BadgeConfig 和 UserBadge 数据模型,支持勋章配置和用户勋章管理 - 新增 BadgeService 服务,提供勋章授予、查询、展示状态管理等核心功能 - 在挑战服务中集成勋章授予逻辑,完成首次睡眠打卡授予 goodSleep 勋章,完成睡眠挑战授予 sleepChallengeMonth 勋章 - 新增用户勋章相关接口:获取用户勋章列表、获取可用勋章列表、标记勋章已展示 - 支持勋章分类(睡眠、运动、饮食等)、排序、启用状态管理 - 支持勋章来源追踪(挑战、系统、手动授予)和元数据记录
This commit is contained in:
105
src/users/models/user-badge.model.ts
Normal file
105
src/users/models/user-badge.model.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { Column, Model, Table, DataType, ForeignKey, BelongsTo } from 'sequelize-typescript';
|
||||
import { User } from './user.model';
|
||||
import { BadgeConfig } from './badge-config.model';
|
||||
|
||||
export enum BadgeSource {
|
||||
CHALLENGE = 'challenge',
|
||||
MANUAL = 'manual',
|
||||
SYSTEM = 'system',
|
||||
}
|
||||
|
||||
@Table({
|
||||
tableName: 't_user_badges',
|
||||
underscored: true,
|
||||
timestamps: true,
|
||||
indexes: [
|
||||
{
|
||||
unique: true,
|
||||
fields: ['user_id', 'badge_code'],
|
||||
name: 'unique_user_badge',
|
||||
},
|
||||
{
|
||||
fields: ['user_id'],
|
||||
},
|
||||
{
|
||||
fields: ['badge_code'],
|
||||
},
|
||||
{
|
||||
fields: ['awarded_at'],
|
||||
},
|
||||
],
|
||||
})
|
||||
export class UserBadge extends Model {
|
||||
@Column({
|
||||
type: DataType.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
})
|
||||
declare id: number;
|
||||
|
||||
@ForeignKey(() => User)
|
||||
@Column({
|
||||
type: DataType.STRING,
|
||||
allowNull: false,
|
||||
comment: '用户ID',
|
||||
})
|
||||
declare userId: string;
|
||||
|
||||
@ForeignKey(() => BadgeConfig)
|
||||
@Column({
|
||||
type: DataType.STRING(64),
|
||||
allowNull: false,
|
||||
comment: '勋章代码',
|
||||
})
|
||||
declare badgeCode: string;
|
||||
|
||||
@Column({
|
||||
type: DataType.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: DataType.NOW,
|
||||
comment: '获得时间',
|
||||
})
|
||||
declare awardedAt: Date;
|
||||
|
||||
@Column({
|
||||
type: DataType.ENUM(...Object.values(BadgeSource)),
|
||||
allowNull: false,
|
||||
defaultValue: BadgeSource.SYSTEM,
|
||||
comment: '授予来源',
|
||||
})
|
||||
declare source: BadgeSource;
|
||||
|
||||
@Column({
|
||||
type: DataType.STRING(128),
|
||||
allowNull: true,
|
||||
comment: '来源ID(如挑战ID)',
|
||||
})
|
||||
declare sourceId: string;
|
||||
|
||||
@Column({
|
||||
type: DataType.JSON,
|
||||
allowNull: true,
|
||||
comment: '额外元数据',
|
||||
})
|
||||
declare metadata: Record<string, any>;
|
||||
|
||||
@Column({
|
||||
type: DataType.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false,
|
||||
comment: '是否已展示过(客户端展示勋章获得动画后设置为true)',
|
||||
})
|
||||
declare isShow: boolean;
|
||||
|
||||
@Column({
|
||||
type: DataType.DATE,
|
||||
defaultValue: DataType.NOW,
|
||||
})
|
||||
declare createdAt: Date;
|
||||
|
||||
@BelongsTo(() => User)
|
||||
declare user: User;
|
||||
|
||||
@BelongsTo(() => BadgeConfig, 'badgeCode')
|
||||
declare badge: BadgeConfig;
|
||||
}
|
||||
Reference in New Issue
Block a user