YD_Event.miniApp/utils/competition.js

169 lines
5.7 KiB
JavaScript
Raw Normal View History

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 withScope(data, eventProjectId, groupId) {
if (!isEmptyValue(eventProjectId)) data.eventProjectId = eventProjectId;
if (!isEmptyValue(groupId)) data.groupId = groupId;
return data;
}
function fetchCurrentCheckin({ eventProjectId, groupId } = {}) {
return request({ path: API.checkinContext, method: 'GET', data: withScope({}, eventProjectId, groupId), needAuth: true });
}
function updateCheckinStatus({ unitKey, eventProjectId, groupId, checked }) {
return request({ path: API.checkinStatus, method: 'POST', data: withScope({ unitKey, checked }, eventProjectId, groupId), needAuth: true });
}
function startCheckin({ eventProjectId, groupId } = {}) {
if (isEmptyValue(eventProjectId)) return rejectWith('请选择检录项目');
if (isEmptyValue(groupId)) return rejectWith('请选择检录组别');
return request({
path: API.checkinStart,
method: 'POST',
data: { eventProjectId, groupId },
needAuth: true
});
}
function scanCheckin({ code, eventProjectId, groupId } = {}) {
if (isEmptyValue(code)) return rejectWith('未识别到有效检录码');
const normalizedCode = String(code).trim();
if (!normalizedCode) return rejectWith('未识别到有效检录码');
return request({
path: API.checkinScan,
method: 'POST',
data: withScope({ code: normalizedCode }, eventProjectId, groupId),
needAuth: true
});
}
function markCheckinOnStage({ unitKey, eventProjectId, groupId } = {}) {
if (isEmptyValue(unitKey)) return rejectWith('缺少参赛单位标识');
return request({
path: API.checkinOnStage,
method: 'POST',
data: withScope({ unitKey }, eventProjectId, groupId),
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 });
}
// 裁判角色是 [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,
2026-09-17 14:00:10 +08:00
resolveRefereeRegistrationCode,
submitRefereeProfile,
splitRefereeRoles,
fetchRefereeQuota,
fetchRefereeApplications,
applyForReferee
};