feat(theme-2): sync inbox/announcements/presence/deposit from main

This commit is contained in:
2026-06-18 09:38:33 +08:00
parent ec51b675e3
commit e56029225e
86 changed files with 6828 additions and 928 deletions

View File

@@ -50,6 +50,8 @@ import { P } from './admin-permissions';
import { DatabaseResetService } from '../../infrastructure/database/database-reset.service';
import { SmokeTestService } from '../../domains/operations/smoke-tests/smoke-test.service';
import { DepositService } from '../../domains/deposit/deposit.service';
import { PlayerMessagesService } from '../../domains/player-messages/player-messages.service';
import { PresenceService } from '../../domains/presence/presence.service';
import {
IsString,
IsNumber,
@@ -272,6 +274,10 @@ class CreateStaffDto {
@IsString()
roleCode!: string;
@IsOptional()
@IsString()
visibleMenus?: string;
}
class UpdateStaffDto {
@@ -287,6 +293,10 @@ class UpdateStaffDto {
@IsString()
@MinLength(8)
password?: string;
@IsOptional()
@IsString()
visibleMenus?: string;
}
class ResetPlayerPasswordDto {
@@ -1046,6 +1056,10 @@ class CreateContentDto {
@IsString()
endTime?: string | null;
@IsOptional()
@IsBoolean()
notifyInbox?: boolean;
@IsArray()
translations!: ContentTranslationDto[];
}
@@ -1085,6 +1099,16 @@ class ContentStatusDto {
status!: string;
}
class InboxNotifySettingsDto {
@IsOptional()
@IsBoolean()
inboxEnabled?: boolean;
@IsOptional()
@IsBoolean()
deposit?: boolean;
}
class CashbackPreviewDto {
@IsString()
periodStart!: string;
@@ -1209,9 +1233,18 @@ export class AdminController {
private databaseReset: DatabaseResetService,
private smokeTests: SmokeTestService,
private depositService: DepositService,
private playerMessages: PlayerMessagesService,
private staff: AdminStaffService,
private presence: PresenceService,
) {}
@Get('presence/online-count')
@RequirePermissions(P.usersView)
async getOnlinePlayerCount() {
const count = await this.presence.getOnlineCount();
return jsonResponse({ count, asOf: new Date().toISOString() });
}
@Get('dashboard')
@RequirePermissions(P.reports)
async getDashboard() {
@@ -1500,6 +1533,23 @@ export class AdminController {
return jsonResponse(updated);
}
@Delete('staff/:id')
@RequirePermissions(P.settings)
async deleteStaff(
@CurrentUser('id') operatorId: bigint,
@Param('id') id: string,
) {
await this.staff.deleteStaff(BigInt(id), operatorId);
await this.audit.log({
operatorId,
operatorType: 'ADMIN',
action: 'DELETE_STAFF',
module: 'STAFF',
targetId: id,
});
return jsonResponse({ deleted: true });
}
@Delete('users/:id')
@RequirePermissions(P.usersCreate)
async deletePlayer(
@@ -3104,6 +3154,20 @@ export class AdminController {
return urls;
}
@Get('contents/inbox-notify-settings')
@RequirePermissions(P.content, P.reports)
async getInboxNotifySettings() {
const settings = await this.systemConfig.getInboxNotifySettings();
return jsonResponse(settings);
}
@Put('contents/inbox-notify-settings')
@RequirePermissions(P.content)
async updateInboxNotifySettings(@Body() dto: InboxNotifySettingsDto) {
const settings = await this.systemConfig.updateInboxNotifySettings(dto);
return jsonResponse(settings);
}
@Get('contents')
@RequirePermissions(P.content, P.reports)
async listContents(
@@ -3128,8 +3192,34 @@ export class AdminController {
@Post('contents')
@RequirePermissions(P.content)
async createContent(@Body() dto: CreateContentDto) {
const item = await this.content.create(dto);
return jsonResponse(item);
const { notifyInbox, ...createDto } = dto;
const item = await this.content.create(createDto);
let notifiedCount: number | undefined;
if (notifyInbox && (createDto.status ?? 'DRAFT') === 'ACTIVE') {
const inboxEnabled = await this.systemConfig.getInboxFeatureEnabled();
if (inboxEnabled) {
const translations = createDto.translations.map((tr) => ({
locale: tr.locale,
title: tr.title,
body: tr.body,
}));
if (createDto.contentType === 'BANNER') {
notifiedCount = await this.playerMessages.broadcastBannerPromotion({
contentId: BigInt(item.id),
translations,
});
} else if (
createDto.contentType === 'NOTICE' ||
createDto.contentType === 'TICKER'
) {
notifiedCount = await this.playerMessages.broadcastAnnouncementPromotion({
contentId: BigInt(item.id),
translations,
});
}
}
}
return jsonResponse({ ...item, notifiedCount });
}
@Put('contents/:id')
@@ -3349,6 +3439,13 @@ export class AdminController {
return jsonResponse(result);
}
@Get('deposit-orders/pending-count')
@RequirePermissions(P.depositReview)
async depositPendingCount() {
const count = await this.depositService.countPendingDepositOrders();
return jsonResponse({ count });
}
@Get('deposit-orders/:id/audit-logs')
@RequirePermissions(P.depositReview)
async depositOrderAuditLogs(@Param('id') id: string) {