2026-08-07 11:28:38 +08:00
|
|
|
|
const { API } = require('./constants');
|
|
|
|
|
|
const { request } = require('./http');
|
2026-09-01 23:13:21 +08:00
|
|
|
|
const { normalizeCheckinProgress } = require('./checkin-progress');
|
2026-08-07 11:28:38 +08:00
|
|
|
|
|
2026-09-01 23:13:21 +08:00
|
|
|
|
function fetchScoreEvents() {
|
|
|
|
|
|
return request({ path: API.scoreEvents, method: 'GET', needAuth: false });
|
|
|
|
|
|
}
|
2026-08-07 11:28:38 +08:00
|
|
|
|
|
2026-09-01 23:13:21 +08:00
|
|
|
|
function fetchScoreFilters(eventId) {
|
|
|
|
|
|
return request({ path: API.scoreFilters, method: 'GET', data: { eventId }, needAuth: false });
|
|
|
|
|
|
}
|
2026-08-07 11:28:38 +08:00
|
|
|
|
|
2026-09-01 23:13:21 +08:00
|
|
|
|
function queryScores({ eventId, projectId, groupName, keyword } = {}) {
|
|
|
|
|
|
return request({ path: API.scoreQuery, method: 'GET', data: { eventId, projectId, groupName, keyword }, needAuth: false });
|
2026-08-07 11:28:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-01 23:13:21 +08:00
|
|
|
|
function isEmptyValue(value) {
|
|
|
|
|
|
return value === undefined || value === null || value === '';
|
2026-08-07 11:28:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-01 23:13:21 +08:00
|
|
|
|
// 参数校验一律以 reject 返回,不能同步 throw:
|
|
|
|
|
|
// 调用方普遍写成 fn().then().catch().finally(),同步抛出会绕过 catch/finally,
|
|
|
|
|
|
// 造成 loading 遮罩不消失、按钮 loading 锁死。
|
|
|
|
|
|
function rejectWith(message) {
|
|
|
|
|
|
return Promise.reject(new Error(message));
|
2026-08-07 11:28:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-21 14:15:59 +08:00
|
|
|
|
function withProjectScope(data, eventProjectId) {
|
2026-09-01 23:13:21 +08:00
|
|
|
|
if (!isEmptyValue(eventProjectId)) data.eventProjectId = eventProjectId;
|
|
|
|
|
|
return data;
|
2026-08-07 11:28:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-21 14:15:59 +08:00
|
|
|
|
function fetchCurrentCheckin({ eventProjectId } = {}) {
|
|
|
|
|
|
return request({ path: API.checkinContext, method: 'GET', data: withProjectScope({}, eventProjectId), needAuth: true });
|
2026-08-07 11:28:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-21 14:15:59 +08:00
|
|
|
|
function updateCheckinStatus({ unitKey, eventProjectId, checked }) {
|
|
|
|
|
|
return request({ path: API.checkinStatus, method: 'POST', data: withProjectScope({ unitKey, checked }, eventProjectId), needAuth: true });
|
2026-09-01 23:13:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-21 14:15:59 +08:00
|
|
|
|
function startCheckin({ eventProjectId } = {}) {
|
2026-09-01 23:13:21 +08:00
|
|
|
|
if (isEmptyValue(eventProjectId)) return rejectWith('请选择检录项目');
|
|
|
|
|
|
return request({
|
|
|
|
|
|
path: API.checkinStart,
|
|
|
|
|
|
method: 'POST',
|
2026-09-21 14:15:59 +08:00
|
|
|
|
data: { eventProjectId },
|
2026-09-01 23:13:21 +08:00
|
|
|
|
needAuth: true
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-21 14:15:59 +08:00
|
|
|
|
function scanCheckin({ code, eventProjectId } = {}) {
|
2026-09-01 23:13:21 +08:00
|
|
|
|
if (isEmptyValue(code)) return rejectWith('未识别到有效检录码');
|
|
|
|
|
|
const normalizedCode = String(code).trim();
|
|
|
|
|
|
if (!normalizedCode) return rejectWith('未识别到有效检录码');
|
|
|
|
|
|
return request({
|
|
|
|
|
|
path: API.checkinScan,
|
|
|
|
|
|
method: 'POST',
|
2026-09-21 14:15:59 +08:00
|
|
|
|
data: withProjectScope({ code: normalizedCode }, eventProjectId),
|
2026-09-01 23:13:21 +08:00
|
|
|
|
needAuth: true
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-21 14:15:59 +08:00
|
|
|
|
function markCheckinOnStage({ unitKey, eventProjectId } = {}) {
|
2026-09-01 23:13:21 +08:00
|
|
|
|
if (isEmptyValue(unitKey)) return rejectWith('缺少参赛单位标识');
|
|
|
|
|
|
return request({
|
|
|
|
|
|
path: API.checkinOnStage,
|
|
|
|
|
|
method: 'POST',
|
2026-09-21 14:15:59 +08:00
|
|
|
|
data: withProjectScope({ unitKey }, eventProjectId),
|
2026-09-01 23:13:21 +08:00
|
|
|
|
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 : {}));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-17 14:00:10 +08:00
|
|
|
|
function resolveRefereeRegistrationCode(code) {
|
|
|
|
|
|
if (isEmptyValue(code)) return rejectWith('裁判报名码无效');
|
|
|
|
|
|
return request({ path: API.refereeRegistrationCode(String(code).trim()), method: 'GET', needAuth: false });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-01 23:13:21 +08:00
|
|
|
|
// 裁判角色是 [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);
|
2026-08-07 11:28:38 +08:00
|
|
|
|
}
|
2026-09-01 23:13:21 +08:00
|
|
|
|
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
|
2026-08-07 11:28:38 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-01 23:13:21 +08:00
|
|
|
|
function fetchRefereeQuota(eventId) {
|
|
|
|
|
|
if (isEmptyValue(eventId)) return rejectWith('缺少赛事ID');
|
|
|
|
|
|
return request({ path: API.refereeApplicationQuota, method: 'GET', data: { eventId }, needAuth: true });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-07 11:28:38 +08:00
|
|
|
|
function fetchRefereeApplications() {
|
2026-09-01 23:13:21 +08:00
|
|
|
|
return request({ path: API.refereeApplications, method: 'GET', needAuth: true });
|
2026-08-07 11:28:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function applyForReferee(event) {
|
|
|
|
|
|
const payload = event && typeof event === 'object' ? event : {};
|
2026-09-01 23:13:21 +08:00
|
|
|
|
if (isEmptyValue(payload.eventId)) return rejectWith('缺少赛事ID');
|
|
|
|
|
|
return request({
|
|
|
|
|
|
path: API.refereeApply,
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
data: { eventId: payload.eventId },
|
|
|
|
|
|
needAuth: true
|
2026-08-07 11:28:38 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
|
|
fetchScoreEvents,
|
2026-09-01 23:13:21 +08:00
|
|
|
|
fetchScoreFilters,
|
2026-08-07 11:28:38 +08:00
|
|
|
|
queryScores,
|
|
|
|
|
|
fetchCurrentCheckin,
|
|
|
|
|
|
updateCheckinStatus,
|
2026-09-01 23:13:21 +08:00
|
|
|
|
startCheckin,
|
|
|
|
|
|
scanCheckin,
|
|
|
|
|
|
markCheckinOnStage,
|
|
|
|
|
|
fetchCheckinProgress,
|
|
|
|
|
|
fetchRefereeProfileOptions,
|
|
|
|
|
|
fetchRefereeProfile,
|
2026-09-17 14:00:10 +08:00
|
|
|
|
resolveRefereeRegistrationCode,
|
2026-09-01 23:13:21 +08:00
|
|
|
|
submitRefereeProfile,
|
|
|
|
|
|
splitRefereeRoles,
|
|
|
|
|
|
fetchRefereeQuota,
|
2026-08-07 11:28:38 +08:00
|
|
|
|
fetchRefereeApplications,
|
|
|
|
|
|
applyForReferee
|
|
|
|
|
|
};
|