const { API } = require('./constants'); const { request } = require('./http'); const { normalizeCheckinProgress } = require('./checkin-progress'); function fetchScoreEvents() { return request({ path: API.scoreEvents, method: 'GET', needAuth: false }); } function fetchScoreFilters(eventId) { return request({ path: API.scoreFilters, method: 'GET', data: { eventId }, needAuth: false }); } function queryScores({ eventId, projectId, groupName, keyword } = {}) { return request({ path: API.scoreQuery, method: 'GET', data: { eventId, projectId, groupName, keyword }, needAuth: false }); } function isEmptyValue(value) { return value === undefined || value === null || value === ''; } // 参数校验一律以 reject 返回,不能同步 throw: // 调用方普遍写成 fn().then().catch().finally(),同步抛出会绕过 catch/finally, // 造成 loading 遮罩不消失、按钮 loading 锁死。 function rejectWith(message) { return Promise.reject(new Error(message)); } function withProjectScope(data, eventProjectId) { if (!isEmptyValue(eventProjectId)) data.eventProjectId = eventProjectId; return data; } function fetchCurrentCheckin({ eventProjectId } = {}) { return request({ path: API.checkinContext, method: 'GET', data: withProjectScope({}, eventProjectId), needAuth: true }); } function updateCheckinStatus({ unitKey, eventProjectId, checked }) { return request({ path: API.checkinStatus, method: 'POST', data: withProjectScope({ unitKey, checked }, eventProjectId), needAuth: true }); } function startCheckin({ eventProjectId } = {}) { if (isEmptyValue(eventProjectId)) return rejectWith('请选择检录项目'); return request({ path: API.checkinStart, method: 'POST', data: { eventProjectId }, needAuth: true }); } function scanCheckin({ code, eventProjectId } = {}) { if (isEmptyValue(code)) return rejectWith('未识别到有效检录码'); const normalizedCode = String(code).trim(); if (!normalizedCode) return rejectWith('未识别到有效检录码'); return request({ path: API.checkinScan, method: 'POST', data: withProjectScope({ code: normalizedCode }, eventProjectId), needAuth: true }); } function markCheckinOnStage({ unitKey, eventProjectId } = {}) { if (isEmptyValue(unitKey)) return rejectWith('缺少参赛单位标识'); return request({ path: API.checkinOnStage, method: 'POST', data: withProjectScope({ unitKey }, eventProjectId), needAuth: true }); } function fetchCheckinProgress(eventId) { if (isEmptyValue(eventId)) return rejectWith('缺少赛事ID'); return request({ path: API.checkinProgress, method: 'GET', data: { eventId }, needAuth: true }) .then(normalizeCheckinProgress); } function fetchRefereeProfileOptions() { return request({ path: API.refereeProfileOptions, method: 'GET', needAuth: true }) .then((res) => (res && typeof res === 'object' ? res : {})); } function fetchRefereeProfile() { // 裁判未提交资料时后端返回 data:null,统一归一为空对象,避免调用方读字段时抛错 return request({ path: API.refereeProfile, method: 'GET', needAuth: true }) .then((res) => (res && typeof res === 'object' ? res : {})); } function resolveRefereeRegistrationCode(code) { if (isEmptyValue(code)) return rejectWith('裁判报名码无效'); return request({ path: API.refereeRegistrationCode(String(code).trim()), method: 'GET', needAuth: false }); } // 裁判角色是 [Flags] 位枚举(1-主裁 2-表现 4-难度 8-创意编排 16-完成质量)。 // 接口文档在 RefereeProfileSubmitInput/RefereeProfileDto 两处误写为 int 数组, // 后端实际按单个 RefereeRole 反序列化,因此提交前合并为位标志,回显时再拆开。 function combineRefereeRoles(roles) { const list = Array.isArray(roles) ? roles : [roles]; return list.reduce((mask, item) => { const value = Number(item); return Number.isFinite(value) && value > 0 ? mask | value : mask; }, 0); } function splitRefereeRoles(value) { if (Array.isArray(value)) return value.map(Number).filter((item) => Number.isFinite(item) && item > 0); const mask = Number(value); if (!Number.isFinite(mask) || mask <= 0) return []; const result = []; for (let bit = 1; bit <= mask; bit *= 2) { if (mask & bit) result.push(bit); } return result; } function submitRefereeProfile(payload) { const data = Object.assign({}, payload || {}); data.roles = combineRefereeRoles(data.roles); return request({ path: API.refereeProfileSubmit, method: 'POST', data, needAuth: true }); } function fetchRefereeQuota(eventId) { if (isEmptyValue(eventId)) return rejectWith('缺少赛事ID'); return request({ path: API.refereeApplicationQuota, method: 'GET', data: { eventId }, needAuth: true }); } function fetchRefereeApplications() { return request({ path: API.refereeApplications, method: 'GET', needAuth: true }); } function applyForReferee(event) { const payload = event && typeof event === 'object' ? event : {}; if (isEmptyValue(payload.eventId)) return rejectWith('缺少赛事ID'); return request({ path: API.refereeApply, method: 'POST', data: { eventId: payload.eventId }, needAuth: true }); } module.exports = { fetchScoreEvents, fetchScoreFilters, queryScores, fetchCurrentCheckin, updateCheckinStatus, startCheckin, scanCheckin, markCheckinOnStage, fetchCheckinProgress, fetchRefereeProfileOptions, fetchRefereeProfile, resolveRefereeRegistrationCode, submitRefereeProfile, splitRefereeRoles, fetchRefereeQuota, fetchRefereeApplications, applyForReferee };