perf: 优化类型问题
This commit is contained in:
@@ -1,10 +1,5 @@
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import {
|
||||
IsEnum,
|
||||
IsNumber,
|
||||
IsString,
|
||||
validateSync,
|
||||
} from 'class-validator';
|
||||
import { IsEnum, IsNumber, IsString, validateSync } from 'class-validator';
|
||||
|
||||
enum Environment {
|
||||
Development = 'development',
|
||||
|
||||
@@ -138,9 +138,7 @@ export class AuthService {
|
||||
);
|
||||
|
||||
if (existing) {
|
||||
this.logger.warn(
|
||||
`用户 ${userId} 已完成关卡 ${dto.levelId},不重复奖励`,
|
||||
);
|
||||
this.logger.warn(`用户 ${userId} 已完成关卡 ${dto.levelId},不重复奖励`);
|
||||
return { points: user.points };
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { IsIn, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
export class UserAssetsResponseDto {
|
||||
@ApiProperty({ description: '积分' })
|
||||
points: number;
|
||||
points!: number;
|
||||
}
|
||||
|
||||
export class ConsumePointRequestDto {
|
||||
@@ -11,7 +11,7 @@ export class ConsumePointRequestDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@IsIn(['hint_unlock'])
|
||||
reason: 'hint_unlock';
|
||||
reason!: 'hint_unlock';
|
||||
|
||||
@ApiProperty({ description: '关卡 ID', required: false })
|
||||
@IsString()
|
||||
@@ -28,21 +28,21 @@ export class EarnPointRequestDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@IsIn(['level_complete'])
|
||||
reason: 'level_complete';
|
||||
reason!: 'level_complete';
|
||||
|
||||
@ApiProperty({ description: '关卡 ID' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
levelId: string;
|
||||
levelId!: string;
|
||||
}
|
||||
|
||||
export class GameDataResponseDto {
|
||||
@ApiProperty({ description: '用户信息' })
|
||||
user: {
|
||||
user!: {
|
||||
id: string;
|
||||
points: number;
|
||||
};
|
||||
|
||||
@ApiProperty({ description: '已完成的关卡 ID 列表' })
|
||||
completedLevelIds: string[];
|
||||
completedLevelIds!: string[];
|
||||
}
|
||||
|
||||
@@ -5,24 +5,24 @@ export class WxLoginRequestDto {
|
||||
@ApiProperty({ description: '微信 wx.login 返回的 code' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
code: string;
|
||||
code!: string;
|
||||
}
|
||||
|
||||
export class UserInfoDto {
|
||||
@ApiProperty({ description: '用户 ID' })
|
||||
id: string;
|
||||
id!: string;
|
||||
|
||||
@ApiProperty({ description: '用户昵称', nullable: true })
|
||||
nickname: string | null;
|
||||
nickname!: string | null;
|
||||
|
||||
@ApiProperty({ description: '积分' })
|
||||
points: number;
|
||||
points!: number;
|
||||
}
|
||||
|
||||
export class WxLoginResponseDto {
|
||||
@ApiProperty({ description: 'JWT 访问令牌' })
|
||||
token: string;
|
||||
token!: string;
|
||||
|
||||
@ApiProperty({ description: '用户信息' })
|
||||
user: UserInfoDto;
|
||||
user!: UserInfoDto;
|
||||
}
|
||||
|
||||
@@ -13,18 +13,18 @@ import { User } from './user.entity';
|
||||
@Index('idx_user_level', ['userId', 'levelId'], { unique: true })
|
||||
export class UserLevelProgress {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
id!: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 191, name: 'user_id' })
|
||||
userId: string;
|
||||
userId!: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 191, name: 'level_id' })
|
||||
levelId: string;
|
||||
levelId!: string;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
user: User;
|
||||
user!: User;
|
||||
|
||||
@CreateDateColumn({ name: 'completed_at' })
|
||||
completedAt: Date;
|
||||
completedAt!: Date;
|
||||
}
|
||||
|
||||
@@ -10,28 +10,28 @@ import {
|
||||
@Entity('wx_users')
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
id!: string;
|
||||
|
||||
@Index('idx_user_openid', { unique: true })
|
||||
@Column({ type: 'varchar', length: 128 })
|
||||
openid: string;
|
||||
openid!: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 255, name: 'session_key', nullable: true })
|
||||
sessionKey: string | null;
|
||||
sessionKey!: string | null;
|
||||
|
||||
@Column({ type: 'varchar', length: 100, nullable: true })
|
||||
nickname: string | null;
|
||||
nickname!: string | null;
|
||||
|
||||
@Column({ type: 'text', name: 'avatar_url', nullable: true })
|
||||
avatarUrl: string | null;
|
||||
avatarUrl!: string | null;
|
||||
|
||||
/** 积分(默认 10) */
|
||||
@Column({ type: 'int', default: 10 })
|
||||
points: number;
|
||||
points!: number;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt: Date;
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'updated_at' })
|
||||
updatedAt: Date;
|
||||
updatedAt!: Date;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ import { UserLevelProgress } from '../entities/user-level-progress.entity';
|
||||
import { IUserLevelProgressRepository } from './user-level-progress.repository.interface';
|
||||
|
||||
@Injectable()
|
||||
export class UserLevelProgressRepository
|
||||
implements IUserLevelProgressRepository
|
||||
{
|
||||
export class UserLevelProgressRepository implements IUserLevelProgressRepository {
|
||||
constructor(
|
||||
@InjectRepository(UserLevelProgress)
|
||||
private readonly repository: Repository<UserLevelProgress>,
|
||||
|
||||
@@ -13,7 +13,7 @@ export class CreateShareDto {
|
||||
@IsString()
|
||||
@IsNotEmpty({ message: '标题不能为空' })
|
||||
@MaxLength(100, { message: '标题不能超过100个字符' })
|
||||
title: string;
|
||||
title!: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '6个关卡ID',
|
||||
@@ -23,5 +23,5 @@ export class CreateShareDto {
|
||||
@ArrayMinSize(6, { message: '需要恰好6个关卡' })
|
||||
@ArrayMaxSize(6, { message: '需要恰好6个关卡' })
|
||||
@IsString({ each: true })
|
||||
levelIds: string[];
|
||||
levelIds!: string[];
|
||||
}
|
||||
|
||||
@@ -2,48 +2,48 @@ import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class CreateShareResponseDto {
|
||||
@ApiProperty({ description: '分享码' })
|
||||
shareCode: string;
|
||||
shareCode!: string;
|
||||
|
||||
@ApiProperty({ description: '分享标题' })
|
||||
title: string;
|
||||
title!: string;
|
||||
|
||||
@ApiProperty({ description: '关卡数量' })
|
||||
levelCount: number;
|
||||
levelCount!: number;
|
||||
}
|
||||
|
||||
export class ShareLevelDto {
|
||||
@ApiProperty()
|
||||
id: string;
|
||||
id!: string;
|
||||
|
||||
@ApiProperty()
|
||||
level: number;
|
||||
level!: number;
|
||||
|
||||
@ApiProperty()
|
||||
imageUrl: string;
|
||||
imageUrl!: string;
|
||||
|
||||
@ApiProperty()
|
||||
answer: string;
|
||||
answer!: string;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
hint1: string | null;
|
||||
hint1!: string | null;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
hint2: string | null;
|
||||
hint2!: string | null;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
hint3: string | null;
|
||||
hint3!: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
sortOrder: number;
|
||||
sortOrder!: number;
|
||||
}
|
||||
|
||||
export class JoinShareResponseDto {
|
||||
@ApiProperty({ description: '分享码' })
|
||||
shareCode: string;
|
||||
shareCode!: string;
|
||||
|
||||
@ApiProperty({ description: '分享标题' })
|
||||
title: string;
|
||||
title!: string;
|
||||
|
||||
@ApiProperty({ description: '关卡列表', type: [ShareLevelDto] })
|
||||
levels: ShareLevelDto[];
|
||||
levels!: ShareLevelDto[];
|
||||
}
|
||||
|
||||
@@ -15,32 +15,32 @@ import { ShareParticipant } from './share-participant.entity';
|
||||
@Entity('share_configs')
|
||||
export class ShareConfig {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
id!: string;
|
||||
|
||||
@Index('idx_share_code', { unique: true })
|
||||
@Column({ type: 'varchar', length: 8, name: 'share_code' })
|
||||
shareCode: string;
|
||||
shareCode!: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 100 })
|
||||
title: string;
|
||||
title!: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 191, name: 'sharer_id' })
|
||||
sharerId: string;
|
||||
sharerId!: string;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'sharer_id' })
|
||||
sharer: User;
|
||||
sharer!: User;
|
||||
|
||||
/** 有序 JSON 数组,存储 6 个关卡 ID */
|
||||
@Column({ type: 'json', name: 'level_ids' })
|
||||
levelIds: string[];
|
||||
levelIds!: string[];
|
||||
|
||||
@OneToMany(() => ShareParticipant, (p) => p.shareConfig)
|
||||
participants: ShareParticipant[];
|
||||
participants!: ShareParticipant[];
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt: Date;
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'updated_at' })
|
||||
updatedAt: Date;
|
||||
updatedAt!: Date;
|
||||
}
|
||||
|
||||
@@ -15,23 +15,23 @@ import { ShareConfig } from './share-config.entity';
|
||||
@Unique('uq_share_participant', ['shareConfigId', 'participantId'])
|
||||
export class ShareParticipant {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
id!: string;
|
||||
|
||||
@Index('idx_share_config_id')
|
||||
@Column({ type: 'varchar', length: 191, name: 'share_config_id' })
|
||||
shareConfigId: string;
|
||||
shareConfigId!: string;
|
||||
|
||||
@ManyToOne(() => ShareConfig, (sc) => sc.participants)
|
||||
@JoinColumn({ name: 'share_config_id' })
|
||||
shareConfig: ShareConfig;
|
||||
shareConfig!: ShareConfig;
|
||||
|
||||
@Column({ type: 'varchar', length: 191, name: 'participant_id' })
|
||||
participantId: string;
|
||||
participantId!: string;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'participant_id' })
|
||||
participant: User;
|
||||
participant!: User;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt: Date;
|
||||
createdAt!: Date;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,10 @@ export class ShareController {
|
||||
@Post()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOperation({ summary: '创建分享', description: '选择6关+标题,生成分享码' })
|
||||
@ApiOperation({
|
||||
summary: '创建分享',
|
||||
description: '选择6关+标题,生成分享码',
|
||||
})
|
||||
@ApiResponse({ status: 201, description: '创建成功' })
|
||||
@ApiResponse({ status: 400, description: '参数错误' })
|
||||
async createShare(
|
||||
|
||||
@@ -68,10 +68,7 @@ export class ShareService {
|
||||
};
|
||||
}
|
||||
|
||||
async joinShare(
|
||||
userId: string,
|
||||
code: string,
|
||||
): Promise<JoinShareResponseDto> {
|
||||
async joinShare(userId: string, code: string): Promise<JoinShareResponseDto> {
|
||||
const config = await this.shareConfigRepository.findByShareCode(code);
|
||||
if (!config) {
|
||||
throw new NotFoundException('分享不存在或已过期');
|
||||
|
||||
@@ -2,31 +2,31 @@ import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class GameConfigResponseDto {
|
||||
@ApiProperty({ description: '配置ID' })
|
||||
id: string;
|
||||
id!: string;
|
||||
|
||||
@ApiProperty({ description: '配置键名' })
|
||||
configKey: string;
|
||||
configKey!: string;
|
||||
|
||||
@ApiProperty({ description: '配置值' })
|
||||
configValue: string;
|
||||
configValue!: string;
|
||||
|
||||
@ApiProperty({ description: '配置描述', nullable: true })
|
||||
description: string | null;
|
||||
description!: string | null;
|
||||
|
||||
@ApiProperty({ description: '是否激活' })
|
||||
isActive: boolean;
|
||||
isActive!: boolean;
|
||||
|
||||
@ApiProperty({ description: '创建时间' })
|
||||
createdAt: Date;
|
||||
createdAt!: Date;
|
||||
|
||||
@ApiProperty({ description: '更新时间' })
|
||||
updatedAt: Date;
|
||||
updatedAt!: Date;
|
||||
}
|
||||
|
||||
export class GameConfigListResponseDto {
|
||||
@ApiProperty({ type: [GameConfigResponseDto], description: '配置列表' })
|
||||
configs: GameConfigResponseDto[];
|
||||
configs!: GameConfigResponseDto[];
|
||||
|
||||
@ApiProperty({ description: '配置总数' })
|
||||
total: number;
|
||||
total!: number;
|
||||
}
|
||||
|
||||
@@ -2,40 +2,40 @@ import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class LevelResponseDto {
|
||||
@ApiProperty({ description: '关卡编号' })
|
||||
level: number;
|
||||
level!: number;
|
||||
|
||||
@ApiProperty({ description: '关卡ID' })
|
||||
id: string;
|
||||
id!: string;
|
||||
|
||||
@ApiProperty({ description: '图片URL' })
|
||||
imageUrl: string;
|
||||
imageUrl!: string;
|
||||
|
||||
@ApiProperty({ description: '答案' })
|
||||
answer: string;
|
||||
answer!: string;
|
||||
|
||||
@ApiProperty({ description: '提示1', nullable: true })
|
||||
hint1: string | null;
|
||||
hint1!: string | null;
|
||||
|
||||
@ApiProperty({ description: '提示2', nullable: true })
|
||||
hint2: string | null;
|
||||
hint2!: string | null;
|
||||
|
||||
@ApiProperty({ description: '提示3', nullable: true })
|
||||
hint3: string | null;
|
||||
hint3!: string | null;
|
||||
|
||||
@ApiProperty({ description: '排序顺序' })
|
||||
sortOrder: number;
|
||||
sortOrder!: number;
|
||||
|
||||
@ApiProperty({ description: '创建时间' })
|
||||
createdAt: Date;
|
||||
createdAt!: Date;
|
||||
|
||||
@ApiProperty({ description: '更新时间' })
|
||||
updatedAt: Date;
|
||||
updatedAt!: Date;
|
||||
}
|
||||
|
||||
export class LevelListResponseDto {
|
||||
@ApiProperty({ type: [LevelResponseDto], description: '关卡列表' })
|
||||
levels: LevelResponseDto[];
|
||||
levels!: LevelResponseDto[];
|
||||
|
||||
@ApiProperty({ description: '关卡总数' })
|
||||
total: number;
|
||||
total!: number;
|
||||
}
|
||||
|
||||
@@ -9,27 +9,27 @@ import {
|
||||
@Entity('game_configs')
|
||||
export class GameConfig {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
id!: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 255, name: 'config_key' })
|
||||
configKey: string;
|
||||
configKey!: string;
|
||||
|
||||
@Column({ type: 'text', name: 'config_value' })
|
||||
configValue: string;
|
||||
configValue!: string;
|
||||
|
||||
@Column({
|
||||
type: 'varchar',
|
||||
length: 100,
|
||||
nullable: true,
|
||||
})
|
||||
description: string | null;
|
||||
description!: string | null;
|
||||
|
||||
@Column({ type: 'boolean', default: true, name: 'is_active' })
|
||||
isActive: boolean;
|
||||
isActive!: boolean;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt: Date;
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'updated_at' })
|
||||
updatedAt: Date;
|
||||
updatedAt!: Date;
|
||||
}
|
||||
|
||||
@@ -9,29 +9,29 @@ import {
|
||||
@Entity('levels')
|
||||
export class Level {
|
||||
@PrimaryColumn({ type: 'varchar', length: 191 })
|
||||
id: string;
|
||||
id!: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 191, name: 'image_url' })
|
||||
imageUrl: string;
|
||||
imageUrl!: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 191 })
|
||||
answer: string;
|
||||
answer!: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 191, nullable: true })
|
||||
hint1: string | null;
|
||||
hint1!: string | null;
|
||||
|
||||
@Column({ type: 'varchar', length: 191, nullable: true })
|
||||
hint2: string | null;
|
||||
hint2!: string | null;
|
||||
|
||||
@Column({ type: 'varchar', length: 191, nullable: true })
|
||||
hint3: string | null;
|
||||
hint3!: string | null;
|
||||
|
||||
@Column({ type: 'int', name: 'sort_order', default: 0 })
|
||||
sortOrder: number;
|
||||
sortOrder!: number;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt: Date;
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'updated_at' })
|
||||
updatedAt: Date;
|
||||
updatedAt!: Date;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
"target": "ES2023",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
|
||||
Reference in New Issue
Block a user