YD_Event.miniApp/utils/competition.js
ltx d17f43135d feat: 完善多角色赛事服务功能
- 新增参赛者、裁判、检录员角色识别及角色化首页与个人中心
- 新增裁判注册、身份认证提示、赛事执裁报名及报名记录查询
- 新增检录工作台,支持检录任务、轮次状态与运动员检录操作
- 新增赛事成绩查询页面及成绩详情展示
- 封装成绩、检录和裁判报名接口,补充请求参数清理逻辑
- 新增检录 Tab 图标、页面路由及本地开发配置
- 新增 Git 忽略规则,排除依赖、构建缓存、日志和本地工具文件
2026-08-07 11:28:38 +08:00

162 lines
7.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const { API } = require('./constants');
const { request } = require('./http');
// 已对接 YD_Event.Admin;如需离线演示可临时改回 true。
const USE_LOCAL_MOCK = false;
const CHECKIN_STORAGE_KEY = 'mockCheckinAthletes';
const REFEREE_APPLICATIONS_KEY = 'mockRefereeApplications';
const MOCK_SCORE_EVENTS = [
{ id: 'event-2026-summer', name: '2026 跃享跳花样跳绳公开赛' },
{ id: 'event-2026-city', name: '跃享跳城市挑战赛' }
];
const MOCK_SCORES = [
{
id: 'score-001', eventId: 'event-2026-summer', eventName: '2026 跃享跳花样跳绳公开赛',
athleteName: '陈跃', athleteNo: 'A018', category: '个人花样', groupName: 'U12 男子组',
roundName: '决赛', rank: 1, totalScore: '86.50', difficultyScore: '28.50',
executionScore: '30.00', creativityScore: '28.00', status: '成绩有效',
judgeScores: [
{ label: '难度裁判', score: '28.50' }, { label: '完成裁判', score: '30.00' },
{ label: '创意裁判', score: '28.00' }
]
},
{
id: 'score-002', eventId: 'event-2026-summer', eventName: '2026 跃享跳花样跳绳公开赛',
athleteName: '林晓', athleteNo: 'A026', category: '个人花样', groupName: 'U12 女子组',
roundName: '决赛', rank: 2, totalScore: '84.20', difficultyScore: '27.70',
executionScore: '29.00', creativityScore: '27.50', status: '成绩有效',
judgeScores: [
{ label: '难度裁判', score: '27.70' }, { label: '完成裁判', score: '29.00' },
{ label: '创意裁判', score: '27.50' }
]
},
{
id: 'score-003', eventId: 'event-2026-city', eventName: '跃享跳城市挑战赛',
athleteName: '跃动少年队', athleteNo: 'T009', category: '团体花样', groupName: '公开组',
roundName: '预赛', rank: 3, totalScore: '81.80', difficultyScore: '26.80',
executionScore: '28.00', creativityScore: '27.00', status: '成绩有效',
judgeScores: [
{ label: '难度裁判', score: '26.80' }, { label: '完成裁判', score: '28.00' },
{ label: '创意裁判', score: '27.00' }
]
}
];
const DEFAULT_CHECKIN_ATHLETES = [
{ id: 'athlete-01', userId: 'user-01', bibNo: 'A018', name: '陈跃', teamName: '跃动俱乐部', checked: true, canCheck: true, orderBookSessionName: '第1场 · 30秒单摇' },
{ id: 'athlete-02', userId: 'user-02', bibNo: 'A021', name: '周航', teamName: '星火跳绳队', checked: true, canCheck: true, orderBookSessionName: '第1场 · 30秒单摇' },
{ id: 'athlete-03', userId: 'user-03', bibNo: 'A024', name: '许嘉', teamName: '青苗体育', checked: false, canCheck: true, orderBookSessionName: '第2场 · 花样跳绳' },
{ id: 'athlete-04', userId: 'user-04', bibNo: 'A027', name: '江晨', teamName: '跃动俱乐部', checked: false, canCheck: true, orderBookSessionName: '第2场 · 花样跳绳' }
];
function clone(data) {
return JSON.parse(JSON.stringify(data));
}
function mockResolve(data) {
return new Promise((resolve) => setTimeout(() => resolve(clone(data)), 180));
}
function fetchScoreEvents() {
if (USE_LOCAL_MOCK) return mockResolve(MOCK_SCORE_EVENTS);
return request({ path: API.scoreEvents, method: 'GET', needAuth: false });
}
function queryScores({ eventId, keyword } = {}) {
if (!USE_LOCAL_MOCK) {
return request({ path: API.scoreQuery, method: 'GET', data: { eventId, keyword }, needAuth: false });
}
const search = String(keyword || '').trim().toLowerCase();
const rows = MOCK_SCORES.filter((item) => {
const eventMatched = !eventId || item.eventId === eventId;
const keywordMatched = !search || [item.athleteName, item.athleteNo, item.groupName]
.some((value) => String(value || '').toLowerCase().includes(search));
return eventMatched && keywordMatched;
});
return mockResolve({ rows, total: rows.length });
}
function fetchCurrentCheckin({ eventProjectId, groupId } = {}) {
if (!USE_LOCAL_MOCK) {
const data = {};
if (eventProjectId !== undefined && eventProjectId !== null && eventProjectId !== '') {
data.eventProjectId = eventProjectId;
}
if (groupId !== undefined && groupId !== null && groupId !== '') {
data.groupId = groupId;
}
return request({ path: API.checkinContext, method: 'GET', data, needAuth: true });
}
const stored = wx.getStorageSync(CHECKIN_STORAGE_KEY);
const athletes = Array.isArray(stored) ? stored : clone(DEFAULT_CHECKIN_ATHLETES);
const rounds = [{ round: 1, order: 1 }, { round: 2, order: 2 }];
const pendingAthletes = athletes.filter((item) => !item.checked && item.canCheck);
const checkedAthletes = athletes.filter((item) => item.checked);
const lockedAthletes = athletes.filter((item) => !item.checked && !item.canCheck);
return mockResolve({
eventId: 'event-2026-summer', eventName: '2026 跃享跳花样跳绳公开赛', venue: '一号检录区',
totalCheckins: 2, currentCheckinNo: 1, currentCheckinName: '一检',
totalRounds: 2, currentRound: 1, roundName: '一检', currentSessionVenue: '一号检录区',
rounds, athletes, pendingAthletes, checkedAthletes, lockedAthletes
});
}
function updateCheckinStatus({ unitKey, eventProjectId, groupId, checked }) {
if (!USE_LOCAL_MOCK) {
const data = { unitKey, checked };
if (eventProjectId !== undefined && eventProjectId !== null && eventProjectId !== '') {
data.eventProjectId = eventProjectId;
}
if (groupId !== undefined && groupId !== null && groupId !== '') {
data.groupId = groupId;
}
return request({ path: API.checkinStatus, method: 'POST', data, needAuth: true });
}
return fetchCurrentCheckin().then((context) => {
const units = (context.units || []).map((item) => item.unitKey === unitKey ? Object.assign({}, item, { checked: !!checked }) : item);
return Object.assign({}, context, { units });
});
}
function fetchRefereeApplications() {
if (!USE_LOCAL_MOCK) {
return request({ path: API.refereeApplications, method: 'GET', needAuth: true });
}
const stored = wx.getStorageSync(REFEREE_APPLICATIONS_KEY);
return mockResolve({ rows: Array.isArray(stored) ? stored : [], total: Array.isArray(stored) ? stored.length : 0 });
}
function applyForReferee(event) {
const payload = event && typeof event === 'object' ? event : {};
if (!USE_LOCAL_MOCK) {
return request({ path: API.refereeApply, method: 'POST', data: { eventId: payload.eventId }, needAuth: true });
}
return fetchRefereeApplications().then((res) => {
const rows = (res && res.rows) || [];
const exists = rows.some((item) => String(item.eventId) === String(payload.eventId));
if (!exists) {
rows.unshift(Object.assign({}, payload, {
id: `referee-${payload.eventId}`,
applicationId: `mock-${Date.now()}`,
applicationStatus: 1,
applicationStatusText: '已报名执裁',
appliedAt: new Date().toISOString()
}));
wx.setStorageSync(REFEREE_APPLICATIONS_KEY, rows);
}
return { success: true, alreadyApplied: exists, rows };
});
}
module.exports = {
USE_LOCAL_MOCK,
fetchScoreEvents,
queryScores,
fetchCurrentCheckin,
updateCheckinStatus,
fetchRefereeApplications,
applyForReferee
};