feat(player+api): 桌面端钱包/注单栏重构,首页快速下注与移动端体验优化

桌面端:
- 新增 DesktopWalletPageHeader 统一钱包子导航,移除重复大标题
- 重构我的余额页布局(居中窄卡片 + 余额/统计/账户设置)
- 新增 DesktopBetSlipRail 可折叠注单侧栏,优化 BetSlipPanel 交互
- 首页 upcoming 赛事卡片支持胜平负/让球/大小球快速下注
- 优化 DesktopShell 布局、3D 轮播、各账户/消息/充值页面样式

移动端:
- 重构 MobileWalletView 钱包页 UI
- 修复 MarketSelectionsPanel 下注区黑色背景问题
- 新增 PageBackButton 与 useSmartBack 智能返回逻辑
- 优化公告/消息/个人中心等详情页导航

API:
- listUpcomingPublished 支持 includeMarkets,返回首页卡片所需核心玩法
This commit is contained in:
2026-06-30 16:11:27 +08:00
parent ef5b9416cc
commit 7f563326d8
73 changed files with 2866 additions and 1552 deletions

View File

@@ -190,7 +190,7 @@ export class PlayerController {
this.content.listActive('BANNER', locale),
this.content.listActiveAnnouncements(locale),
this.matches.listPublished(locale, undefined, { includeMarkets: false }),
this.matches.listUpcomingPublished(locale),
this.matches.listUpcomingPublished(locale, { includeMarkets: true }),
this.systemConfig.getInboxFeatureEnabled(),
]);
const timeZone = safeTimeZone(headerTimeZone);

View File

@@ -1592,17 +1592,42 @@ export class MatchesService {
);
}
/** 首页卡片快速下注所需的核心玩法类型 */
private static readonly HOME_CARD_MARKET_TYPES = [
'FT_1X2',
'FT_HANDICAP',
'FT_OVER_UNDER',
] as const;
/** 未来 N 天内开赛的已发布赛事(按开赛时间升序,不限 isHot */
async listUpcomingPublished(
locale = 'en-US',
options?: { limit?: number; days?: number },
options?: { limit?: number; days?: number; includeMarkets?: boolean },
) {
const limit = options?.limit ?? 50;
const days = options?.days ?? 3;
const includeMarkets = options?.includeMarkets ?? false;
const now = new Date();
const end = new Date(now);
end.setDate(end.getDate() + days);
const marketsRelation = includeMarkets
? {
where: {
status: { in: ['OPEN', 'SUSPENDED', 'CLOSED'] },
showOnPlayer: true,
marketType: { in: [...MatchesService.HOME_CARD_MARKET_TYPES] },
},
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'] },
@@ -1625,14 +1650,14 @@ export class MatchesService {
homeTeam: true,
awayTeam: true,
score: true,
markets: this.playerMarketStatusInclude,
markets: marketsRelation,
},
orderBy: [{ startTime: 'asc' }, { displayOrder: 'asc' }],
take: limit,
});
return Promise.all(
matches.map((m) => this.enrichMatch(m, locale, { omitMarkets: true })),
matches.map((m) => this.enrichMatch(m, locale, { omitMarkets: !includeMarkets })),
);
}