feat(admin,api,player): 代理层级管理、额度上下分与玩家钱包详情
新增代理管理器与二级代理体系,完善信用额度/上下分上下文与冻结策略;代理端玩家与子代理管理增强;玩家端新增钱包详情页与交易筛选优化。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -101,6 +101,15 @@ class CreatePlayerAdminDto {
|
||||
@IsOptional()
|
||||
asTier1Agent?: boolean;
|
||||
|
||||
/** 创建为二级代理(需要 parentAgentId) */
|
||||
@IsOptional()
|
||||
asSubAgent?: boolean;
|
||||
|
||||
/** 二级代理的上级代理 ID */
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
parentAgentId?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
@@ -110,6 +119,16 @@ class CreatePlayerAdminDto {
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
cashbackRate?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
maxSingleDeposit?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
maxDailyDeposit?: number;
|
||||
}
|
||||
|
||||
class UpdatePlayerAdminDto {
|
||||
@@ -154,6 +173,16 @@ class PlayerAccountSettingsDto {
|
||||
allowUsernameChange?: boolean;
|
||||
}
|
||||
|
||||
class AgentSuspendSettingsDto {
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
suspendFreezeDirectPlayers?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
suspendBlockPlayerLogin?: boolean;
|
||||
}
|
||||
|
||||
class ResetDatabaseDto {
|
||||
@IsString()
|
||||
@Equals('RESET')
|
||||
@@ -181,6 +210,16 @@ class CreateAgentAdminDto {
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
cashbackRate?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
maxSingleDeposit?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
maxDailyDeposit?: number;
|
||||
}
|
||||
|
||||
class UpdateAgentAdminDto {
|
||||
@@ -204,6 +243,29 @@ class UpdateAgentAdminDto {
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
cashbackRate?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
maxSingleDeposit?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
maxDailyDeposit?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
username?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
password?: string;
|
||||
|
||||
/** 冻结时是否级联冻结直属玩家 */
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
freezeDirectPlayers?: boolean;
|
||||
}
|
||||
|
||||
class DepositDto {
|
||||
@@ -717,6 +779,30 @@ export class AdminController {
|
||||
return jsonResponse(settings);
|
||||
}
|
||||
|
||||
@Get('agents/settings/suspend')
|
||||
@RequirePermissions(P.settings)
|
||||
async getAgentSuspendSettings() {
|
||||
const settings = await this.systemConfig.getAgentSuspendSettings();
|
||||
return jsonResponse(settings);
|
||||
}
|
||||
|
||||
@Put('agents/settings/suspend')
|
||||
@RequirePermissions(P.settings)
|
||||
async updateAgentSuspendSettings(
|
||||
@CurrentUser('id') operatorId: bigint,
|
||||
@Body() dto: AgentSuspendSettingsDto,
|
||||
) {
|
||||
const settings = await this.systemConfig.updateAgentSuspendSettings(dto);
|
||||
await this.audit.log({
|
||||
operatorId,
|
||||
operatorType: 'ADMIN',
|
||||
action: 'UPDATE_AGENT_SUSPEND_SETTINGS',
|
||||
module: 'AGENTS',
|
||||
afterData: JSON.stringify(settings),
|
||||
});
|
||||
return jsonResponse(settings);
|
||||
}
|
||||
|
||||
@Get('settings/betting-limits')
|
||||
@RequirePermissions(P.settings)
|
||||
async getBettingLimits() {
|
||||
@@ -830,17 +916,21 @@ export class AdminController {
|
||||
depositRemark: dto.remark,
|
||||
depositRequestId: `create-player-${dto.username}-${Date.now()}`,
|
||||
asTier1Agent: dto.asTier1Agent,
|
||||
asSubAgent: dto.asSubAgent,
|
||||
parentAgentId: dto.parentAgentId ? BigInt(dto.parentAgentId) : undefined,
|
||||
creditLimit: dto.creditLimit,
|
||||
cashbackRate: dto.cashbackRate,
|
||||
maxSingleDeposit: dto.maxSingleDeposit,
|
||||
maxDailyDeposit: dto.maxDailyDeposit,
|
||||
});
|
||||
await this.audit.log({
|
||||
operatorId,
|
||||
operatorType: 'ADMIN',
|
||||
action: dto.asTier1Agent ? 'CREATE_AGENT' : 'CREATE_PLAYER',
|
||||
module: dto.asTier1Agent ? 'AGENTS' : 'USERS',
|
||||
action: dto.asTier1Agent || dto.asSubAgent ? 'CREATE_AGENT' : 'CREATE_PLAYER',
|
||||
module: dto.asTier1Agent || dto.asSubAgent ? 'AGENTS' : 'USERS',
|
||||
targetId: user.id.toString(),
|
||||
});
|
||||
if (dto.asTier1Agent) {
|
||||
if (dto.asTier1Agent || dto.asSubAgent) {
|
||||
const detail = await this.agents.getAgentAdminDetail(user.id);
|
||||
return jsonResponse(detail);
|
||||
}
|
||||
@@ -884,11 +974,13 @@ export class AdminController {
|
||||
@Query('page') page?: string,
|
||||
@Query('pageSize') pageSize?: string,
|
||||
@Query('keyword') keyword?: string,
|
||||
@Query('parentAgentId') parentAgentId?: string,
|
||||
) {
|
||||
const result = await this.agents.listAgentsAdmin({
|
||||
page: page ? parseInt(page, 10) : 1,
|
||||
pageSize: pageSize ? parseInt(pageSize, 10) : 10,
|
||||
keyword,
|
||||
parentAgentId: parentAgentId ? BigInt(parentAgentId) : undefined,
|
||||
});
|
||||
return jsonResponse(result);
|
||||
}
|
||||
@@ -929,6 +1021,8 @@ export class AdminController {
|
||||
phone: dto.phone,
|
||||
email: dto.email,
|
||||
cashbackRate: dto.cashbackRate,
|
||||
maxSingleDeposit: dto.maxSingleDeposit,
|
||||
maxDailyDeposit: dto.maxDailyDeposit,
|
||||
});
|
||||
await this.audit.log({
|
||||
operatorId,
|
||||
@@ -961,7 +1055,7 @@ export class AdminController {
|
||||
@Post('wallet/deposit')
|
||||
@RequirePermissions(P.walletDeposit)
|
||||
async deposit(@CurrentUser('id') operatorId: bigint, @Body() dto: DepositDto & { userId: string }) {
|
||||
const result = await this.wallet.deposit(
|
||||
const result = await this.agents.adminDepositToPlayer(
|
||||
BigInt(dto.userId),
|
||||
dto.amount,
|
||||
operatorId,
|
||||
@@ -971,6 +1065,13 @@ export class AdminController {
|
||||
return jsonResponse(result);
|
||||
}
|
||||
|
||||
@Get('wallet/transfer-context/:userId')
|
||||
@RequirePermissions(P.walletDeposit, P.walletWithdraw)
|
||||
async walletTransferContext(@Param('userId') userId: string) {
|
||||
const ctx = await this.agents.getPlayerTransferContext(BigInt(userId), { forAdmin: true });
|
||||
return jsonResponse(ctx);
|
||||
}
|
||||
|
||||
@Post('wallet/withdraw')
|
||||
@RequirePermissions(P.walletWithdraw)
|
||||
async withdraw(@CurrentUser('id') operatorId: bigint, @Body() dto: DepositDto & { userId: string }) {
|
||||
|
||||
Reference in New Issue
Block a user