feat(admin,api,player): 优胜赛配置、赛事管理重构与玩家端投注体验优化
管理端拆分赛事/优胜赛 Tab,新增联赛优胜赔率面板(批量、排序、外侧删除);统一 list-chrome 工具栏对齐与列表页布局;Dashboard 失败重试、Users 操作下拉、小屏侧栏等体验修复。 API 扩展优胜赛与赛事目录接口,完善投注与钱包查询;玩家端重构赛事卡片、串关面板、注单/钱包页,新增注单详情、下注成功动画与下拉刷新。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
/** 后台手动新增赛事(投注平台最小字段) */
|
||||
|
||||
import {
|
||||
countryDisplayName,
|
||||
countryLogoUrl,
|
||||
hasCountryCrest,
|
||||
type BuiltinCountry,
|
||||
} from '../data/builtinCountries';
|
||||
import { FormValidationError } from '../i18n/form-validation';
|
||||
|
||||
export interface MatchCreateForm {
|
||||
@@ -8,6 +14,8 @@ export interface MatchCreateForm {
|
||||
leagueZh: string;
|
||||
leagueMs: string;
|
||||
startTime: string;
|
||||
homeTeamCode: string;
|
||||
awayTeamCode: string;
|
||||
homeTeamZh: string;
|
||||
homeTeamEn: string;
|
||||
homeTeamMs: string;
|
||||
@@ -31,6 +39,8 @@ export function emptyMatchForm(): MatchCreateForm {
|
||||
leagueZh: '2026 世界杯',
|
||||
leagueMs: 'Piala Dunia 2026',
|
||||
startTime: '',
|
||||
homeTeamCode: '',
|
||||
awayTeamCode: '',
|
||||
homeTeamZh: '',
|
||||
homeTeamEn: '',
|
||||
homeTeamMs: '',
|
||||
@@ -122,6 +132,8 @@ export function formFromDetail(d: AdminMatchDetail): MatchCreateForm {
|
||||
leagueZh: d.leagueZh,
|
||||
leagueMs: d.leagueMs ?? '',
|
||||
startTime: normalizeStartTimeForPicker(d.startTime),
|
||||
homeTeamCode: d.homeTeamCode ?? '',
|
||||
awayTeamCode: d.awayTeamCode ?? '',
|
||||
homeTeamZh: d.homeTeamZh,
|
||||
homeTeamEn: d.homeTeamEn,
|
||||
homeTeamMs: d.homeTeamMs ?? '',
|
||||
@@ -139,19 +151,67 @@ export function formFromDetail(d: AdminMatchDetail): MatchCreateForm {
|
||||
};
|
||||
}
|
||||
|
||||
export function fillBuiltinTeam(
|
||||
form: MatchCreateForm,
|
||||
side: 'home' | 'away',
|
||||
country: BuiltinCountry,
|
||||
) {
|
||||
const msName = countryDisplayName(country, 'ms-MY');
|
||||
const logo = countryLogoUrl(country, hasCountryCrest(country) ? 'crest' : 'flag');
|
||||
if (side === 'home') {
|
||||
form.homeTeamCode = country.code;
|
||||
form.homeTeamZh = country.nameZh;
|
||||
form.homeTeamEn = country.nameEn;
|
||||
form.homeTeamMs = msName;
|
||||
form.homeTeamLogoUrl = logo;
|
||||
} else {
|
||||
form.awayTeamCode = country.code;
|
||||
form.awayTeamZh = country.nameZh;
|
||||
form.awayTeamEn = country.nameEn;
|
||||
form.awayTeamMs = msName;
|
||||
form.awayTeamLogoUrl = logo;
|
||||
}
|
||||
}
|
||||
|
||||
export function clearBuiltinTeam(form: MatchCreateForm, side: 'home' | 'away') {
|
||||
if (side === 'home') {
|
||||
form.homeTeamCode = '';
|
||||
form.homeTeamZh = '';
|
||||
form.homeTeamEn = '';
|
||||
form.homeTeamMs = '';
|
||||
form.homeTeamLogoUrl = '';
|
||||
} else {
|
||||
form.awayTeamCode = '';
|
||||
form.awayTeamZh = '';
|
||||
form.awayTeamEn = '';
|
||||
form.awayTeamMs = '';
|
||||
form.awayTeamLogoUrl = '';
|
||||
}
|
||||
}
|
||||
|
||||
export function buildPlatformPayload(form: MatchCreateForm) {
|
||||
if (!form.startTime.trim()) {
|
||||
throw new FormValidationError('err.kickoff_required');
|
||||
}
|
||||
const homeOk = form.homeTeamZh.trim() || form.homeTeamEn.trim() || form.homeTeamMs.trim();
|
||||
const awayOk = form.awayTeamZh.trim() || form.awayTeamEn.trim() || form.awayTeamMs.trim();
|
||||
if (!homeOk || !awayOk) {
|
||||
throw new FormValidationError('err.teams_required');
|
||||
}
|
||||
const homeKey = `${form.homeTeamZh.trim()}|${form.homeTeamEn.trim()}|${form.homeTeamMs.trim()}`.toLowerCase();
|
||||
const awayKey = `${form.awayTeamZh.trim()}|${form.awayTeamEn.trim()}|${form.awayTeamMs.trim()}`.toLowerCase();
|
||||
if (homeKey === awayKey) {
|
||||
throw new FormValidationError('err.teams_same');
|
||||
const homeCode = form.homeTeamCode.trim().toUpperCase();
|
||||
const awayCode = form.awayTeamCode.trim().toUpperCase();
|
||||
if (homeCode && awayCode) {
|
||||
if (homeCode === awayCode) {
|
||||
throw new FormValidationError('err.teams_same');
|
||||
}
|
||||
} else if (homeCode || awayCode) {
|
||||
throw new FormValidationError('err.team_country_required');
|
||||
} else {
|
||||
const homeOk = form.homeTeamZh.trim() || form.homeTeamEn.trim() || form.homeTeamMs.trim();
|
||||
const awayOk = form.awayTeamZh.trim() || form.awayTeamEn.trim() || form.awayTeamMs.trim();
|
||||
if (!homeOk || !awayOk) {
|
||||
throw new FormValidationError('err.team_country_required');
|
||||
}
|
||||
const homeKey = `${form.homeTeamZh.trim()}|${form.homeTeamEn.trim()}|${form.homeTeamMs.trim()}`.toLowerCase();
|
||||
const awayKey = `${form.awayTeamZh.trim()}|${form.awayTeamEn.trim()}|${form.awayTeamMs.trim()}`.toLowerCase();
|
||||
if (homeKey === awayKey) {
|
||||
throw new FormValidationError('err.teams_same');
|
||||
}
|
||||
}
|
||||
if (
|
||||
!form.leagueId.trim() &&
|
||||
@@ -167,6 +227,8 @@ export function buildPlatformPayload(form: MatchCreateForm) {
|
||||
leagueEn: form.leagueEn.trim(),
|
||||
leagueZh: form.leagueZh.trim(),
|
||||
leagueMs: form.leagueMs.trim() || undefined,
|
||||
homeTeamCode: homeCode || undefined,
|
||||
awayTeamCode: awayCode || undefined,
|
||||
homeTeamEn: form.homeTeamEn.trim(),
|
||||
homeTeamZh: form.homeTeamZh.trim(),
|
||||
homeTeamMs: form.homeTeamMs.trim() || undefined,
|
||||
|
||||
Reference in New Issue
Block a user