- 球赛/串关/优胜冠军、赛事详情、历史投注与个人资料编辑 - 固定顶栏、公告与底栏,仅内容区滚动 - 底部导航与站点 favicon 使用 logo,登录页精简 - API 种子、冠军盘与历史注单增强 Co-authored-by: Cursor <cursoragent@cursor.com>
205 lines
5.5 KiB
TypeScript
205 lines
5.5 KiB
TypeScript
import {
|
|
Controller,
|
|
Get,
|
|
Post,
|
|
Patch,
|
|
Body,
|
|
Param,
|
|
Query,
|
|
UseGuards,
|
|
} from '@nestjs/common';
|
|
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
|
import { JwtAuthGuard, PlayerGuard } from '../../domains/identity/guards';
|
|
import { CurrentUser } from '../../shared/common/decorators';
|
|
import { jsonResponse } from '../../shared/common/filters';
|
|
import { UsersService } from '../../domains/identity/users.service';
|
|
import { WalletService } from '../../domains/ledger/wallet.service';
|
|
import { MatchesService } from '../../domains/catalog/matches.service';
|
|
import { BetsService } from '../../domains/betting/bets.service';
|
|
import { ContentService } from '../../domains/operations/content/content.service';
|
|
import { CashbackService } from '../../domains/operations/cashback/cashback.service';
|
|
import { IsString, IsNumber, IsArray, ValidateNested, Min, IsOptional } from 'class-validator';
|
|
import { Type } from 'class-transformer';
|
|
|
|
class SingleBetDto {
|
|
@IsString()
|
|
selectionId!: string;
|
|
|
|
@IsString()
|
|
oddsVersion!: string;
|
|
|
|
@IsNumber()
|
|
@Min(0.01)
|
|
stake!: number;
|
|
|
|
@IsString()
|
|
requestId!: string;
|
|
}
|
|
|
|
class ParlayLegDto {
|
|
@IsString()
|
|
selectionId!: string;
|
|
|
|
@IsString()
|
|
oddsVersion!: string;
|
|
}
|
|
|
|
class ParlayBetDto {
|
|
@IsArray()
|
|
@ValidateNested({ each: true })
|
|
@Type(() => ParlayLegDto)
|
|
legs!: ParlayLegDto[];
|
|
|
|
@IsNumber()
|
|
@Min(0.01)
|
|
stake!: number;
|
|
|
|
@IsString()
|
|
requestId!: string;
|
|
}
|
|
|
|
class LocaleDto {
|
|
@IsString()
|
|
locale!: string;
|
|
}
|
|
|
|
class UpdateProfileDto {
|
|
@IsOptional()
|
|
@IsString()
|
|
phone?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
email?: string;
|
|
}
|
|
|
|
@ApiTags('Player')
|
|
@Controller('player')
|
|
@UseGuards(JwtAuthGuard, PlayerGuard)
|
|
@ApiBearerAuth()
|
|
export class PlayerController {
|
|
constructor(
|
|
private users: UsersService,
|
|
private wallet: WalletService,
|
|
private matches: MatchesService,
|
|
private bets: BetsService,
|
|
private content: ContentService,
|
|
private cashback: CashbackService,
|
|
) {}
|
|
|
|
@Get('profile')
|
|
async profile(@CurrentUser('id') userId: bigint) {
|
|
const user = await this.users.findById(userId);
|
|
return jsonResponse(user);
|
|
}
|
|
|
|
@Post('language')
|
|
async setLanguage(@CurrentUser('id') userId: bigint, @Body() dto: LocaleDto) {
|
|
const result = await this.users.updateLocale(userId, dto.locale);
|
|
return jsonResponse(result);
|
|
}
|
|
|
|
@Patch('profile')
|
|
async updateProfile(@CurrentUser('id') userId: bigint, @Body() dto: UpdateProfileDto) {
|
|
const user = await this.users.updateProfile(userId, dto);
|
|
return jsonResponse(user);
|
|
}
|
|
|
|
@Get('home')
|
|
async home(@CurrentUser('locale') locale: string) {
|
|
const [banners, notices, ticker, hotMatches, todayMatches] = await Promise.all([
|
|
this.content.listActive('BANNER', locale),
|
|
this.content.listActive('NOTICE', locale),
|
|
this.content.listActive('TICKER', locale),
|
|
this.matches.listPublished(locale),
|
|
this.matches.listPublished(locale),
|
|
]);
|
|
return jsonResponse({
|
|
banners,
|
|
notices,
|
|
ticker,
|
|
hotMatches: (hotMatches as Array<{ isHot?: boolean }>).filter((m) => m.isHot),
|
|
todayMatches,
|
|
});
|
|
}
|
|
|
|
@Get('matches')
|
|
async listMatches(
|
|
@CurrentUser('locale') locale: string,
|
|
@Query('leagueId') leagueId?: string,
|
|
) {
|
|
const items = await this.matches.listPublished(locale, leagueId ? BigInt(leagueId) : undefined);
|
|
return jsonResponse(items);
|
|
}
|
|
|
|
@Get('outrights')
|
|
async listOutrights(@CurrentUser('locale') locale: string) {
|
|
const items = await this.matches.listOutrights(locale);
|
|
return jsonResponse(items);
|
|
}
|
|
|
|
@Get('matches/:id')
|
|
async matchDetail(@Param('id') id: string, @CurrentUser('locale') locale: string) {
|
|
const match = await this.matches.getMatchDetail(BigInt(id), locale);
|
|
return jsonResponse(match);
|
|
}
|
|
|
|
@Post('bets/single')
|
|
async singleBet(@CurrentUser('id') userId: bigint, @CurrentUser('parentId') parentId: bigint, @Body() dto: SingleBetDto) {
|
|
const bet = await this.bets.placeSingleBet(
|
|
userId,
|
|
parentId,
|
|
BigInt(dto.selectionId),
|
|
BigInt(dto.oddsVersion),
|
|
dto.stake,
|
|
dto.requestId,
|
|
);
|
|
return jsonResponse(bet);
|
|
}
|
|
|
|
@Post('bets/parlay')
|
|
async parlayBet(@CurrentUser('id') userId: bigint, @CurrentUser('parentId') parentId: bigint, @Body() dto: ParlayBetDto) {
|
|
const bet = await this.bets.placeParlayBet(
|
|
userId,
|
|
parentId,
|
|
dto.legs.map((l) => ({ selectionId: BigInt(l.selectionId), oddsVersion: BigInt(l.oddsVersion) })),
|
|
dto.stake,
|
|
dto.requestId,
|
|
);
|
|
return jsonResponse(bet);
|
|
}
|
|
|
|
@Get('bets')
|
|
async myBets(
|
|
@CurrentUser('id') userId: bigint,
|
|
@CurrentUser('locale') locale: string,
|
|
@Query('status') status?: string,
|
|
@Query('page') page?: string,
|
|
) {
|
|
const result = await this.bets.getUserBets(userId, status, page ? parseInt(page) : 1);
|
|
const items = await this.matches.enrichBetsForHistory(result.items, locale);
|
|
return jsonResponse({ ...result, items });
|
|
}
|
|
|
|
@Get('bets/:betNo')
|
|
async betDetail(@CurrentUser('id') userId: bigint, @Param('betNo') betNo: string) {
|
|
const bet = await this.bets.getBetByNo(betNo, userId);
|
|
return jsonResponse(bet);
|
|
}
|
|
|
|
@Get('wallet/transactions')
|
|
async transactions(
|
|
@CurrentUser('id') userId: bigint,
|
|
@Query('page') page?: string,
|
|
) {
|
|
const result = await this.wallet.getTransactions(userId, page ? parseInt(page) : 1);
|
|
return jsonResponse(result);
|
|
}
|
|
|
|
@Get('cashbacks')
|
|
async cashbacks(@CurrentUser('id') userId: bigint) {
|
|
const items = await this.cashback.getUserCashbacks(userId);
|
|
return jsonResponse(items);
|
|
}
|
|
}
|