feat: add smoke tests, agent credit ledger, and player cashback page
Introduce admin smoke-test suite with API probes, agent credit transaction history, and player cashback records; fix SmokeTestModule DI and polish admin/player UI assets. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -693,6 +693,108 @@ export class AgentsService {
|
||||
};
|
||||
}
|
||||
|
||||
async listCreditTransactions(params: {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
agentId?: bigint;
|
||||
keyword?: string;
|
||||
transactionType?: string;
|
||||
}) {
|
||||
const page = Math.max(1, params.page ?? 1);
|
||||
const pageSize = Math.min(100, Math.max(1, params.pageSize ?? 20));
|
||||
const skip = (page - 1) * pageSize;
|
||||
|
||||
const where: Prisma.AgentCreditTransactionWhereInput = {};
|
||||
|
||||
if (params.transactionType?.trim()) {
|
||||
where.transactionType = params.transactionType.trim();
|
||||
}
|
||||
|
||||
const keyword = params.keyword?.trim();
|
||||
if (keyword) {
|
||||
const matched = await this.prisma.user.findMany({
|
||||
where: {
|
||||
userType: 'AGENT',
|
||||
deletedAt: null,
|
||||
username: { contains: keyword, mode: 'insensitive' },
|
||||
},
|
||||
select: { id: true },
|
||||
take: 50,
|
||||
});
|
||||
const agentUserIds = matched.map((u) => u.id);
|
||||
if (!agentUserIds.length) {
|
||||
return { items: [], total: 0, page, pageSize };
|
||||
}
|
||||
if (params.agentId) {
|
||||
if (!agentUserIds.some((id) => id === params.agentId)) {
|
||||
return { items: [], total: 0, page, pageSize };
|
||||
}
|
||||
where.agentId = params.agentId;
|
||||
} else {
|
||||
where.agentId = { in: agentUserIds };
|
||||
}
|
||||
} else if (params.agentId) {
|
||||
where.agentId = params.agentId;
|
||||
}
|
||||
|
||||
const [rows, total] = await Promise.all([
|
||||
this.prisma.agentCreditTransaction.findMany({
|
||||
where,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
skip,
|
||||
take: pageSize,
|
||||
}),
|
||||
this.prisma.agentCreditTransaction.count({ where }),
|
||||
]);
|
||||
|
||||
const agentIds = [...new Set(rows.map((r) => r.agentId))];
|
||||
const operatorIds = [
|
||||
...new Set(rows.map((r) => r.operatorId).filter((id): id is bigint => id != null)),
|
||||
];
|
||||
|
||||
const [agentUsers, operators] = await Promise.all([
|
||||
agentIds.length
|
||||
? this.prisma.user.findMany({
|
||||
where: { id: { in: agentIds } },
|
||||
select: { id: true, username: true },
|
||||
})
|
||||
: [],
|
||||
operatorIds.length
|
||||
? this.prisma.user.findMany({
|
||||
where: { id: { in: operatorIds } },
|
||||
select: { id: true, username: true },
|
||||
})
|
||||
: [],
|
||||
]);
|
||||
|
||||
const agentNameById = new Map(agentUsers.map((u) => [u.id.toString(), u.username]));
|
||||
const operatorNameById = new Map(operators.map((u) => [u.id.toString(), u.username]));
|
||||
|
||||
return {
|
||||
items: rows.map((row) => ({
|
||||
id: row.id.toString(),
|
||||
agentId: row.agentId.toString(),
|
||||
agentUsername: agentNameById.get(row.agentId.toString()) ?? null,
|
||||
transactionType: row.transactionType,
|
||||
amount: row.amount.toString(),
|
||||
creditBefore: row.creditBefore.toString(),
|
||||
creditAfter: row.creditAfter.toString(),
|
||||
referenceType: row.referenceType,
|
||||
referenceId: row.referenceId,
|
||||
operatorId: row.operatorId?.toString() ?? null,
|
||||
operatorUsername: row.operatorId
|
||||
? (operatorNameById.get(row.operatorId.toString()) ?? null)
|
||||
: null,
|
||||
requestId: row.requestId,
|
||||
remark: row.remark,
|
||||
createdAt: row.createdAt,
|
||||
})),
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
};
|
||||
}
|
||||
|
||||
async updateAgentAdmin(
|
||||
agentId: bigint,
|
||||
data: {
|
||||
|
||||
Reference in New Issue
Block a user