feat(admin,player,api): 优胜冠军通用管理与界面精简
管理端新增冠军盘列表/编辑、展开懒加载与 ECharts 修复;各列表页去掉重复标题。玩家端支持多赛事冠军盘、分批加载与语言切换刷新。API 扩展 outright CRUD 与列表性能优化。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -260,6 +260,52 @@ class BatchOutrightOddsDto {
|
||||
updates!: OutrightOddsUpdateItemDto[];
|
||||
}
|
||||
|
||||
class CreateOutrightDto {
|
||||
@IsString()
|
||||
leagueId!: string;
|
||||
|
||||
@IsString()
|
||||
titleZh!: string;
|
||||
|
||||
@IsString()
|
||||
titleEn!: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
status?: string;
|
||||
}
|
||||
|
||||
class UpdateOutrightDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
status?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
matchName?: string;
|
||||
|
||||
@IsOptional()
|
||||
isHot?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
displayOrder?: number;
|
||||
}
|
||||
|
||||
class AddOutrightSelectionDto {
|
||||
@IsString()
|
||||
teamCode!: string;
|
||||
|
||||
@IsString()
|
||||
teamZh!: string;
|
||||
|
||||
@IsString()
|
||||
teamEn!: string;
|
||||
|
||||
@IsNumber()
|
||||
@Min(1.01)
|
||||
odds!: number;
|
||||
}
|
||||
|
||||
class CashbackPreviewDto {
|
||||
@IsString()
|
||||
periodStart!: string;
|
||||
@@ -648,24 +694,111 @@ export class AdminController {
|
||||
return jsonResponse(selection);
|
||||
}
|
||||
|
||||
@Get('outrights/wc2026')
|
||||
async getWc2026Outright() {
|
||||
const data = await this.outright.getWc2026ForAdmin();
|
||||
@Get('outrights')
|
||||
async listOutrights() {
|
||||
const data = await this.outright.listForAdmin();
|
||||
return jsonResponse(data);
|
||||
}
|
||||
|
||||
@Get('outrights/leagues')
|
||||
async listOutrightLeagues() {
|
||||
const data = await this.outright.listLeagueOptions();
|
||||
return jsonResponse(data);
|
||||
}
|
||||
|
||||
@Post('outrights')
|
||||
async createOutright(@Body() dto: CreateOutrightDto) {
|
||||
const data = await this.outright.createForAdmin({
|
||||
leagueId: BigInt(dto.leagueId),
|
||||
titleZh: dto.titleZh,
|
||||
titleEn: dto.titleEn,
|
||||
status: dto.status,
|
||||
});
|
||||
return jsonResponse(data);
|
||||
}
|
||||
|
||||
@Post('outrights/import/wc2026')
|
||||
async importWc2026Outright() {
|
||||
const data = await this.outright.importWc2026Canonical();
|
||||
return jsonResponse(data);
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
@Get('outrights/wc2026')
|
||||
async getWc2026OutrightLegacy() {
|
||||
const list = await this.outright.listForAdmin();
|
||||
const wc = list.find((e) => e.leagueCode === 'WC2026');
|
||||
if (!wc) throw new BadRequestException('WC2026 outright not found — run import');
|
||||
return jsonResponse(await this.outright.getForAdmin(BigInt(wc.id)));
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
@Put('outrights/wc2026/odds')
|
||||
async updateWc2026OutrightOdds(
|
||||
async updateWc2026OutrightOddsLegacy(
|
||||
@CurrentUser('id') operatorId: bigint,
|
||||
@Body() dto: BatchOutrightOddsDto,
|
||||
) {
|
||||
const data = await this.outright.updateWc2026Odds(dto.updates, operatorId);
|
||||
const list = await this.outright.listForAdmin();
|
||||
const wc = list.find((e) => e.leagueCode === 'WC2026');
|
||||
if (!wc) throw new BadRequestException('WC2026 outright not found');
|
||||
return jsonResponse(
|
||||
await this.outright.batchUpdateOdds(BigInt(wc.id), dto.updates, operatorId),
|
||||
);
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
@Post('outrights/wc2026/apply-canonical')
|
||||
async applyWc2026CanonicalLegacy() {
|
||||
return jsonResponse(await this.outright.importWc2026Canonical());
|
||||
}
|
||||
|
||||
@Get('outrights/:matchId')
|
||||
async getOutright(@Param('matchId') matchId: string) {
|
||||
const data = await this.outright.getForAdmin(BigInt(matchId));
|
||||
return jsonResponse(data);
|
||||
}
|
||||
|
||||
@Post('outrights/wc2026/apply-canonical')
|
||||
async applyWc2026Canonical() {
|
||||
const data = await this.outright.applyWc2026Canonical();
|
||||
@Put('outrights/:matchId')
|
||||
async updateOutright(
|
||||
@Param('matchId') matchId: string,
|
||||
@Body() dto: UpdateOutrightDto,
|
||||
) {
|
||||
const data = await this.outright.updateForAdmin(BigInt(matchId), dto);
|
||||
return jsonResponse(data);
|
||||
}
|
||||
|
||||
@Put('outrights/:matchId/odds')
|
||||
async updateOutrightOdds(
|
||||
@CurrentUser('id') operatorId: bigint,
|
||||
@Param('matchId') matchId: string,
|
||||
@Body() dto: BatchOutrightOddsDto,
|
||||
) {
|
||||
const data = await this.outright.batchUpdateOdds(
|
||||
BigInt(matchId),
|
||||
dto.updates,
|
||||
operatorId,
|
||||
);
|
||||
return jsonResponse(data);
|
||||
}
|
||||
|
||||
@Post('outrights/:matchId/selections')
|
||||
async addOutrightSelection(
|
||||
@Param('matchId') matchId: string,
|
||||
@Body() dto: AddOutrightSelectionDto,
|
||||
) {
|
||||
const data = await this.outright.addSelection(BigInt(matchId), dto);
|
||||
return jsonResponse(data);
|
||||
}
|
||||
|
||||
@Delete('outrights/:matchId/selections/:selectionId')
|
||||
async removeOutrightSelection(
|
||||
@Param('matchId') matchId: string,
|
||||
@Param('selectionId') selectionId: string,
|
||||
) {
|
||||
const data = await this.outright.closeSelection(
|
||||
BigInt(matchId),
|
||||
BigInt(selectionId),
|
||||
);
|
||||
return jsonResponse(data);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user