feat(admin,player,api): 玩家账号密码管理与代理上下分
新增玩家头像、可查密码与全局改密/改账号开关;玩家资料页合并账号密码展示;代理直属玩家列表支持自定义上下分。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -29,6 +29,7 @@ import { AuditService } from '../../domains/operations/audit/audit.service';
|
||||
import { BetsService } from '../../domains/betting/bets.service';
|
||||
import { PrismaService } from '../../shared/prisma/prisma.service';
|
||||
import { AdminDashboardService } from './admin-dashboard.service';
|
||||
import { SystemConfigService } from '../../shared/config/system-config.service';
|
||||
import {
|
||||
IsString,
|
||||
IsNumber,
|
||||
@@ -127,6 +128,25 @@ class UpdatePlayerAdminDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
parentId?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
username?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MinLength(8)
|
||||
password?: string;
|
||||
}
|
||||
|
||||
class PlayerAccountSettingsDto {
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
allowPasswordChange?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
allowUsernameChange?: boolean;
|
||||
}
|
||||
|
||||
class CreateAgentAdminDto {
|
||||
@@ -442,6 +462,7 @@ export class AdminController {
|
||||
private bets: BetsService,
|
||||
private prisma: PrismaService,
|
||||
private readonly dashboardService: AdminDashboardService,
|
||||
private systemConfig: SystemConfigService,
|
||||
) {}
|
||||
|
||||
@Get('dashboard')
|
||||
@@ -450,6 +471,28 @@ export class AdminController {
|
||||
return jsonResponse(overview);
|
||||
}
|
||||
|
||||
@Get('users/settings/account')
|
||||
async getPlayerAccountSettings() {
|
||||
const settings = await this.systemConfig.getPlayerAccountSettings();
|
||||
return jsonResponse(settings);
|
||||
}
|
||||
|
||||
@Put('users/settings/account')
|
||||
async updatePlayerAccountSettings(
|
||||
@CurrentUser('id') operatorId: bigint,
|
||||
@Body() dto: PlayerAccountSettingsDto,
|
||||
) {
|
||||
const settings = await this.systemConfig.updatePlayerAccountSettings(dto);
|
||||
await this.audit.log({
|
||||
operatorId,
|
||||
operatorType: 'ADMIN',
|
||||
action: 'UPDATE_PLAYER_ACCOUNT_SETTINGS',
|
||||
module: 'USERS',
|
||||
afterData: JSON.stringify(settings),
|
||||
});
|
||||
return jsonResponse(settings);
|
||||
}
|
||||
|
||||
@Get('users')
|
||||
async listUsers(
|
||||
@Query('page') page?: string,
|
||||
|
||||
@@ -13,6 +13,7 @@ import { JwtAuthGuard, PlayerGuard } from '../../domains/identity/guards';
|
||||
import { CurrentUser } from '../../shared/common/decorators';
|
||||
import { jsonResponse } from '../../shared/common/filters';
|
||||
import { UsersService } from '../../domains/identity/users.service';
|
||||
import { SystemConfigService } from '../../shared/config/system-config.service';
|
||||
import { WalletService } from '../../domains/ledger/wallet.service';
|
||||
import { MatchesService } from '../../domains/catalog/matches.service';
|
||||
import { OutrightService } from '../../domains/catalog/outright.service';
|
||||
@@ -72,6 +73,14 @@ class UpdateProfileDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
email?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
avatarKey?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
username?: string;
|
||||
}
|
||||
|
||||
@ApiTags('Player')
|
||||
@@ -87,12 +96,39 @@ export class PlayerController {
|
||||
private bets: BetsService,
|
||||
private content: ContentService,
|
||||
private cashback: CashbackService,
|
||||
private systemConfig: SystemConfigService,
|
||||
) {}
|
||||
|
||||
private async formatPlayerProfile(user: NonNullable<Awaited<ReturnType<UsersService['findById']>>>) {
|
||||
const accountSettings = await this.systemConfig.getPlayerAccountSettings();
|
||||
const prefs = user.preferences;
|
||||
const viewablePassword = prefs?.managedPassword ?? null;
|
||||
const safePrefs = prefs
|
||||
? (({
|
||||
managedPassword: _m,
|
||||
allowPasswordChange: _a,
|
||||
allowUsernameChange: _b,
|
||||
...rest
|
||||
}) => rest)(prefs)
|
||||
: {};
|
||||
return {
|
||||
...user,
|
||||
id: user.id.toString(),
|
||||
parentId: user.parentId?.toString() ?? null,
|
||||
preferences: {
|
||||
...safePrefs,
|
||||
viewablePassword,
|
||||
allowPasswordChange: accountSettings.allowPasswordChange,
|
||||
allowUsernameChange: accountSettings.allowUsernameChange,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@Get('profile')
|
||||
async profile(@CurrentUser('id') userId: bigint) {
|
||||
const user = await this.users.findById(userId);
|
||||
return jsonResponse(user);
|
||||
if (!user) return jsonResponse(null);
|
||||
return jsonResponse(await this.formatPlayerProfile(user));
|
||||
}
|
||||
|
||||
@Post('language')
|
||||
@@ -104,7 +140,8 @@ export class PlayerController {
|
||||
@Patch('profile')
|
||||
async updateProfile(@CurrentUser('id') userId: bigint, @Body() dto: UpdateProfileDto) {
|
||||
const user = await this.users.updateProfile(userId, dto);
|
||||
return jsonResponse(user);
|
||||
if (!user) return jsonResponse(null);
|
||||
return jsonResponse(await this.formatPlayerProfile(user));
|
||||
}
|
||||
|
||||
@Get('home')
|
||||
|
||||
Reference in New Issue
Block a user