/** 后台手动新增赛事(投注平台最小字段) */ import { countryDisplayName, countryLogoUrl, hasCountryCrest, type BuiltinCountry, } from '../data/builtinCountries'; import { FormValidationError } from '../i18n/form-validation'; export interface MatchCreateForm { leagueId: string; leagueEn: string; leagueZh: string; leagueMs: string; startTime: string; homeTeamCode: string; awayTeamCode: string; homeTeamZh: string; homeTeamEn: string; homeTeamMs: string; awayTeamZh: string; awayTeamEn: string; awayTeamMs: string; isHot: boolean; displayOrder: number; matchName: string; stage: string; groupName: string; leagueLogoUrl: string; homeTeamLogoUrl: string; awayTeamLogoUrl: string; } export function emptyMatchForm(): MatchCreateForm { return { leagueId: '', leagueEn: 'FIFA World Cup 2026', leagueZh: '2026 世界杯', leagueMs: 'Piala Dunia 2026', startTime: '', homeTeamCode: '', awayTeamCode: '', homeTeamZh: '', homeTeamEn: '', homeTeamMs: '', awayTeamZh: '', awayTeamEn: '', awayTeamMs: '', isHot: false, displayOrder: 0, matchName: '', stage: '', groupName: '', leagueLogoUrl: '', homeTeamLogoUrl: '', awayTeamLogoUrl: '', }; } export interface AdminMarketSelection { id: string; selectionCode: string; selectionName: string; odds: number; status: string; } export interface AdminMarket { id: string; marketType: string; period: string; lineValue: number | null; status: string; promoLabel: string; selections: AdminMarketSelection[]; } export type AdminMatchDetail = { id: string; status: string; isOutright: boolean; isHot: boolean; displayOrder: number; startTime: string; leagueId?: string; leagueCode?: string; leagueEn: string; leagueZh: string; leagueMs: string; leagueLogoUrl?: string; homeTeamEn: string; homeTeamZh: string; homeTeamMs: string; homeTeamCode?: string; homeTeamLogoUrl?: string; awayTeamEn: string; awayTeamZh: string; awayTeamMs: string; awayTeamCode?: string; awayTeamLogoUrl?: string; matchName: string; stage?: string; groupName?: string; score?: { htHome: number; htAway: number; ftHome: number; ftAway: number; } | null; markets?: AdminMarket[]; }; export function normalizeStartTimeForPicker(iso?: string): string { if (!iso?.trim()) return ''; const d = new Date(iso); if (Number.isNaN(d.getTime())) return iso.slice(0, 19); const pad = (n: number) => String(n).padStart(2, '0'); return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`; } export function normalizeStartTimeForApi(value: string): string { const trimmed = value.trim(); if (!trimmed) return ''; const d = new Date(trimmed); if (Number.isNaN(d.getTime())) return trimmed; return d.toISOString(); } export function formFromDetail(d: AdminMatchDetail): MatchCreateForm { return { leagueId: d.leagueId ?? '', leagueEn: d.leagueEn, 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 ?? '', awayTeamZh: d.awayTeamZh, awayTeamEn: d.awayTeamEn, awayTeamMs: d.awayTeamMs ?? '', isHot: d.isHot, displayOrder: d.displayOrder ?? 0, matchName: d.matchName ?? '', stage: d.stage ?? '', groupName: d.groupName ?? '', leagueLogoUrl: d.leagueLogoUrl ?? '', homeTeamLogoUrl: d.homeTeamLogoUrl ?? '', awayTeamLogoUrl: d.awayTeamLogoUrl ?? '', }; } 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 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() && !form.leagueZh.trim() && !form.leagueEn.trim() && !form.leagueMs.trim() ) { throw new FormValidationError('err.league_required'); } return { leagueId: form.leagueId.trim() || undefined, 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, awayTeamEn: form.awayTeamEn.trim(), awayTeamZh: form.awayTeamZh.trim(), awayTeamMs: form.awayTeamMs.trim() || undefined, startTime: normalizeStartTimeForApi(form.startTime), isHot: form.isHot, displayOrder: form.displayOrder, matchName: form.matchName.trim() || undefined, stage: form.stage.trim() || undefined, groupName: form.groupName.trim() || undefined, leagueLogoUrl: form.leagueLogoUrl.trim() || undefined, homeTeamLogoUrl: form.homeTeamLogoUrl.trim() || undefined, awayTeamLogoUrl: form.awayTeamLogoUrl.trim() || undefined, }; } /** 编辑单场基本信息(不含联赛字段,联赛在赛事列表单独维护) */ export function buildMatchUpdatePayload(form: MatchCreateForm) { if (!form.startTime.trim()) { throw new FormValidationError('err.kickoff_required'); } 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'); } } return { homeTeamEn: form.homeTeamEn.trim(), homeTeamZh: form.homeTeamZh.trim(), homeTeamMs: form.homeTeamMs.trim() || undefined, awayTeamEn: form.awayTeamEn.trim(), awayTeamZh: form.awayTeamZh.trim(), awayTeamMs: form.awayTeamMs.trim() || undefined, startTime: normalizeStartTimeForApi(form.startTime), isHot: form.isHot, displayOrder: form.displayOrder, matchName: form.matchName.trim() || undefined, stage: form.stage.trim() || undefined, groupName: form.groupName.trim() || undefined, homeTeamLogoUrl: form.homeTeamLogoUrl.trim() || undefined, awayTeamLogoUrl: form.awayTeamLogoUrl.trim() || undefined, }; }