// 比赛数据适配器:统一接口返回和比赛服 websocket 的字段结构。 // 页面继续使用原来的 camelCase 数据,后端可以返回 snake_case 或新的 matchInfo 包装结构。 export const MATCH_STATUS_BY_TEXT = { MATCH_STATUS_READY: 0, MATCH_STATUS_STARTED: 1, MATCH_STATUS_END: 2, MATCH_STATUS_TIMEOUT: 3, MATCH_STATUS_UNEXPECTEDLY: 4, }; export function pickField(source, camelKey, snakeKey) { return source?.[camelKey] ?? source?.[snakeKey]; } export function normalizeId(value) { if (value === undefined || value === null || value === "") return ""; return String(value); } function toCamelKey(key) { return key.replace(/_([a-z0-9])/g, (_, character) => character.toUpperCase()); } export function normalizePlainObject(value) { if (Array.isArray(value)) return value.map(normalizePlainObject); if (!value || typeof value !== "object") return value; return Object.keys(value).reduce((result, key) => { result[toCamelKey(key)] = normalizePlainObject(value[key]); return result; }, {}); } function normalizeMapValues(map = {}) { return Object.keys(map || {}).reduce((result, key) => { result[key] = normalizePlainObject(map[key]); return result; }, {}); } function normalizeShootListMap(map = {}) { return Object.keys(map || {}).reduce((result, key) => { const value = map[key]; const items = Array.isArray(value) ? value : Array.isArray(value?.items) ? value.items : []; result[key] = items.map(normalizePlainObject); return result; }, {}); } function normalizeRound(round = {}) { const normalized = normalizePlainObject(round); normalized.shoots = normalizeShootListMap(round.shoots || normalized.shoots); normalized.scores = normalizeMapValues(round.scores || normalized.scores); return normalized; } export function normalizeMatchInfo(matchInfo = {}) { if (!matchInfo || typeof matchInfo !== "object") return matchInfo; const normalized = normalizePlainObject(matchInfo); const statusText = normalized.statusText || matchInfo.status_text; if ( (normalized.status === undefined || normalized.status === null || normalized.status === "") && MATCH_STATUS_BY_TEXT[statusText] !== undefined ) { normalized.status = MATCH_STATUS_BY_TEXT[statusText]; } if (matchInfo.teams || normalized.teams) { normalized.teams = normalizeMapValues(matchInfo.teams || normalized.teams); } if (Array.isArray(matchInfo.rounds || normalized.rounds)) { normalized.rounds = (matchInfo.rounds || normalized.rounds).map(normalizeRound); } if (matchInfo.current || normalized.current) { normalized.current = normalizePlainObject(matchInfo.current || normalized.current); } if (matchInfo.next || normalized.next) { normalized.next = normalizePlainObject(matchInfo.next || normalized.next); } if (matchInfo.shoot_data || normalized.shootData) { normalized.shootData = normalizePlainObject(matchInfo.shoot_data || normalized.shootData); } if (Array.isArray(matchInfo.result_list || normalized.resultList)) { normalized.resultList = (matchInfo.result_list || normalized.resultList).map( normalizePlainObject ); } return normalized; } export function normalizeBattleApiResult(result) { if (!result || typeof result !== "object") return result; // request 通常已经解出顶层 data;这里额外兼容未解包和旧版扁平结构。 const resultData = result.data && typeof result.data === "object" ? result.data : null; const payload = resultData && (resultData.matchInfo || resultData.match_info) ? resultData : result; const matchInfo = payload.matchInfo || payload.match_info || payload; const normalized = normalizeMatchInfo(matchInfo); const serverAddr = payload.serverAddr || payload.server_addr || matchInfo.serverAddr || matchInfo.server_addr || normalized.serverAddr; if (serverAddr) normalized.serverAddr = serverAddr; return normalized; }