feat: 手动充值、邀请码注册与后台管理增强

新增玩家手动充值全流程(收款方式配置、充值下单/审核、钱包上分),
支持邀请码注册、邀请历史与专属返水率;完善后台代理/玩家管理与响应式操作栏,
并补充前台注册、充值页及多语言错误码。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-11 12:20:11 +08:00
parent 618fb49511
commit 10485ecfaf
98 changed files with 7908 additions and 856 deletions

View File

@@ -9,6 +9,7 @@ import { Decimal } from '@prisma/client/runtime/library';
import { generateBatchNo } from '../../shared/common/decorators';
import { assertPlayerUsername } from '@thebet365/shared';
import { appBadRequest, appForbidden, appNotFound } from '../../shared/common/app-error';
import { assignInviteCodeWithHistory } from '../../shared/common/invite-code.util';
function dec(v: Decimal | null | undefined) {
return v?.toString() ?? '0';
@@ -774,6 +775,7 @@ export class AgentsService {
phone: p.user.preferences?.phone ?? null,
email: p.user.preferences?.email ?? null,
locale: p.user.locale,
inviteCode: p.user.inviteCode ?? null,
createdAt: p.createdAt,
updatedAt: p.updatedAt,
};
@@ -849,6 +851,7 @@ export class AgentsService {
email: profile.user.preferences?.email ?? null,
managedPassword: profile.user.preferences?.managedPassword ?? null,
locale: profile.user.locale,
inviteCode: profile.user.inviteCode ?? null,
lastLoginAt: profile.user.auth?.lastLoginAt ?? null,
loginFailCount: profile.user.auth?.loginFailCount ?? 0,
createdAt: profile.createdAt,
@@ -1232,6 +1235,7 @@ export class AgentsService {
parentId: null,
},
});
await assignInviteCodeWithHistory(tx, userId);
if (user.preferences) {
await tx.userPreference.update({
@@ -1295,10 +1299,17 @@ export class AgentsService {
) {
await this.validateAgentLevel(data.level, data.parentAgentId);
let resolvedCashbackRate = data.cashbackRate ?? 0;
if (data.parentAgentId) {
const parentProfile = await this.prisma.agentProfile.findUnique({
where: { userId: data.parentAgentId },
select: { cashbackRate: true },
});
resolvedCashbackRate =
data.cashbackRate ?? (parentProfile ? Number(parentProfile.cashbackRate) : 0);
await this.assertChildAgentWithinParent(data.parentAgentId, {
creditLimit: data.creditLimit ?? 0,
cashbackRate: data.cashbackRate ?? 0,
cashbackRate: resolvedCashbackRate,
maxSingleDeposit: data.maxSingleDeposit,
maxDailyDeposit: data.maxDailyDeposit,
});
@@ -1320,6 +1331,7 @@ export class AgentsService {
locale,
},
});
await assignInviteCodeWithHistory(tx, user.id);
await tx.userAuth.create({
data: { userId: user.id, passwordHash: hash },
@@ -1340,7 +1352,7 @@ export class AgentsService {
level: data.level,
parentAgentId: data.parentAgentId,
creditLimit: data.creditLimit ?? 0,
cashbackRate: data.cashbackRate ?? 0,
cashbackRate: resolvedCashbackRate,
maxSingleDeposit,
maxDailyDeposit,
},
@@ -1522,11 +1534,27 @@ export class AgentsService {
}
async getDirectPlayers(agentId: bigint) {
return this.prisma.user.findMany({
where: { parentId: agentId, userType: 'PLAYER' },
include: { wallet: true },
const rows = await this.prisma.user.findMany({
where: { parentId: agentId, userType: 'PLAYER', deletedAt: null },
include: {
wallet: true,
usedInvite: { select: { code: true } },
},
orderBy: { createdAt: 'desc' },
});
return rows.map((u) => ({
id: u.id.toString(),
username: u.username,
status: u.status,
createdAt: u.createdAt,
inviteCode: u.usedInvite?.code ?? null,
wallet: u.wallet
? {
availableBalance: u.wallet.availableBalance.toString(),
frozenBalance: u.wallet.frozenBalance.toString(),
}
: undefined,
}));
}
async getChildAgents(agentId: bigint) {