feat(player): 注册账号、登录双模式与移动端性能优化
注册必填 7-32 位账号,手机号区号/本地号分存;登录默认账号模式并支持切换手机号登录;Player i18n 拆包与赛事接口优化。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { isPreMatchKickoff, resolveTranslationFallback } from '@thebet365/shared';
|
||||
import { isPreMatchKickoff, MarketType, resolveTranslationFallback } from '@thebet365/shared';
|
||||
import { Cron, CronExpression } from '@nestjs/schedule';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { Decimal } from '@prisma/client/runtime/library';
|
||||
@@ -26,6 +26,23 @@ import { syncWc2026OutrightMarket } from './wc2026-outright.sync';
|
||||
|
||||
const OUTRIGHT_PLACEHOLDER_CODE = 'OUT';
|
||||
|
||||
const PLAYER_PARLAY_MARKET_TYPES = [
|
||||
MarketType.FT_HANDICAP,
|
||||
MarketType.FT_OVER_UNDER,
|
||||
MarketType.FT_1X2,
|
||||
MarketType.FT_ODD_EVEN,
|
||||
MarketType.HT_HANDICAP,
|
||||
MarketType.HT_OVER_UNDER,
|
||||
MarketType.HT_1X2,
|
||||
] as const;
|
||||
|
||||
export type ListPublishedOptions = {
|
||||
/** 响应中是否包含 markets(列表页默认 false,仅摘要) */
|
||||
includeMarkets?: boolean;
|
||||
/** 仅返回串关玩法 markets(需 includeMarkets=true) */
|
||||
parlayMarketsOnly?: boolean;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class MatchesService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
@@ -1158,7 +1175,11 @@ export class MatchesService {
|
||||
return resolveTranslationFallback(map, locale);
|
||||
}
|
||||
|
||||
async enrichMatch(match: Record<string, unknown>, locale: string) {
|
||||
async enrichMatch(
|
||||
match: Record<string, unknown>,
|
||||
locale: string,
|
||||
options?: { omitMarkets?: boolean },
|
||||
) {
|
||||
const m = match as {
|
||||
id: bigint;
|
||||
leagueId: bigint;
|
||||
@@ -1230,7 +1251,7 @@ export class MatchesService {
|
||||
}>,
|
||||
}),
|
||||
};
|
||||
if (m.markets) {
|
||||
if (m.markets && !options?.omitMarkets) {
|
||||
return {
|
||||
...base,
|
||||
markets: m.markets.map((market) => ({
|
||||
@@ -1302,7 +1323,41 @@ export class MatchesService {
|
||||
orderBy: { sortOrder: 'asc' as const },
|
||||
};
|
||||
|
||||
async listPublished(locale = 'en-US', leagueId?: bigint) {
|
||||
/** 仅 status 字段,用于列表页计算 bettingOpen,不返回给客户端 */
|
||||
private playerMarketStatusInclude = {
|
||||
where: { status: { in: ['OPEN', 'SUSPENDED', 'CLOSED'] } },
|
||||
select: {
|
||||
status: true,
|
||||
selections: { select: { status: true } },
|
||||
},
|
||||
};
|
||||
|
||||
async listPublished(
|
||||
locale = 'en-US',
|
||||
leagueId?: bigint,
|
||||
options?: ListPublishedOptions,
|
||||
) {
|
||||
const includeMarkets = options?.includeMarkets ?? true;
|
||||
const parlayMarketsOnly = options?.parlayMarketsOnly ?? false;
|
||||
|
||||
const marketWhere = {
|
||||
status: { in: ['OPEN', 'SUSPENDED', 'CLOSED'] },
|
||||
...(parlayMarketsOnly ? { marketType: { in: [...PLAYER_PARLAY_MARKET_TYPES] } } : {}),
|
||||
};
|
||||
|
||||
const marketsRelation = includeMarkets
|
||||
? {
|
||||
where: marketWhere,
|
||||
include: {
|
||||
selections: {
|
||||
where: { status: { in: ['OPEN', 'SUSPENDED', 'CLOSED'] } },
|
||||
orderBy: { sortOrder: 'asc' as const },
|
||||
},
|
||||
},
|
||||
orderBy: { sortOrder: 'asc' as const },
|
||||
}
|
||||
: this.playerMarketStatusInclude;
|
||||
|
||||
const matches = await this.prisma.match.findMany({
|
||||
where: {
|
||||
status: { in: ['PUBLISHED', 'CLOSED', 'PENDING_SETTLEMENT', 'SETTLED'] },
|
||||
@@ -1317,12 +1372,22 @@ export class MatchesService {
|
||||
homeTeam: true,
|
||||
awayTeam: true,
|
||||
score: true,
|
||||
markets: this.playerMarketInclude,
|
||||
markets: marketsRelation,
|
||||
},
|
||||
orderBy: [{ isHot: 'desc' }, { displayOrder: 'asc' }, { startTime: 'asc' }],
|
||||
});
|
||||
|
||||
return Promise.all(matches.map((m) => this.enrichMatch(m, locale)));
|
||||
const enriched = await Promise.all(
|
||||
matches.map((m) => this.enrichMatch(m, locale, { omitMarkets: !includeMarkets })),
|
||||
);
|
||||
|
||||
if (!includeMarkets || !parlayMarketsOnly) return enriched;
|
||||
|
||||
return enriched.filter(
|
||||
(m) =>
|
||||
Array.isArray((m as { markets?: unknown[] }).markets) &&
|
||||
(m as { markets: unknown[] }).markets.length > 0,
|
||||
);
|
||||
}
|
||||
|
||||
async getMatchDetail(matchId: bigint, locale = 'en-US') {
|
||||
|
||||
Reference in New Issue
Block a user