feat: split admin dashboard, improve match ops, and player closed-match UX
Admin: add match/player overview sub-nav; refine settlement flow and league match management UI; improve action button enabled/disabled styles; enhance logo upload and outright odds sync. API: expose matchPhase/bettingOpen for closed matches; league publish guards; settlement preview with auto score save; outright team auto-sync. Player: watermark for closed/settled states; keep match and bet details visible; remove default login credentials. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -83,6 +83,8 @@ export type AdminMatchDetail = {
|
||||
isHot: boolean;
|
||||
displayOrder: number;
|
||||
startTime: string;
|
||||
leagueId?: string;
|
||||
leagueCode?: string;
|
||||
leagueEn: string;
|
||||
leagueZh: string;
|
||||
leagueMs: string;
|
||||
@@ -127,7 +129,7 @@ export function normalizeStartTimeForApi(value: string): string {
|
||||
|
||||
export function formFromDetail(d: AdminMatchDetail): MatchCreateForm {
|
||||
return {
|
||||
leagueId: '',
|
||||
leagueId: d.leagueId ?? '',
|
||||
leagueEn: d.leagueEn,
|
||||
leagueZh: d.leagueZh,
|
||||
leagueMs: d.leagueMs ?? '',
|
||||
@@ -246,3 +248,47 @@ export function buildPlatformPayload(form: MatchCreateForm) {
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user