115 lines
5.2 KiB
JavaScript
115 lines
5.2 KiB
JavaScript
|
|
function asArray(value) {
|
||
|
|
if (Array.isArray(value)) return value;
|
||
|
|
if (value == null || value === '') return [];
|
||
|
|
return [value];
|
||
|
|
}
|
||
|
|
|
||
|
|
function asNumber(value, fallback = 0) {
|
||
|
|
const number = Number(value);
|
||
|
|
return Number.isFinite(number) ? number : fallback;
|
||
|
|
}
|
||
|
|
|
||
|
|
function clampPercent(value) {
|
||
|
|
return Math.max(0, Math.min(100, asNumber(value)));
|
||
|
|
}
|
||
|
|
|
||
|
|
function formatDateTime(value) {
|
||
|
|
if (!value) return '—';
|
||
|
|
const date = new Date(value);
|
||
|
|
if (Number.isNaN(date.getTime())) return String(value);
|
||
|
|
const pad = (number) => String(number).padStart(2, '0');
|
||
|
|
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
function containsAbnormalText(value) {
|
||
|
|
return /(异常|失败|取消|作废|拒绝|未通过|超时)/.test(String(value || ''));
|
||
|
|
}
|
||
|
|
|
||
|
|
function normalizeStage(stage, index = 0) {
|
||
|
|
const source = stage && typeof stage === 'object' ? stage : {};
|
||
|
|
const stageStatus = asNumber(source.stageStatus, -1);
|
||
|
|
const totalUnits = Math.max(0, asNumber(source.totalUnits));
|
||
|
|
const checkedUnits = Math.max(0, asNumber(source.checkedUnits));
|
||
|
|
const rawPercent = asNumber(source.progressPercent);
|
||
|
|
const isAbnormal = ![1, 2, 3, 4].includes(stageStatus) || checkedUnits > totalUnits || rawPercent < 0 || rawPercent > 100 || containsAbnormalText(source.stageStatusText);
|
||
|
|
const athleteNames = asArray(source.athleteNames);
|
||
|
|
return Object.assign({}, source, {
|
||
|
|
stageKey: source.stageKey || `${source.eventProjectId || 'project'}-${source.groupId || 'group'}-${index}`,
|
||
|
|
stageStatus,
|
||
|
|
totalUnits,
|
||
|
|
checkedUnits,
|
||
|
|
progressPercent: clampPercent(rawPercent),
|
||
|
|
displayName: source.displayName || [source.projectName, source.groupName].filter(Boolean).join(' - ') || '未命名项目',
|
||
|
|
stageStatusText: source.stageStatusText || (isAbnormal ? '状态异常' : '等待中'),
|
||
|
|
athleteNames,
|
||
|
|
athleteNamesText: athleteNames.join('、') || '—',
|
||
|
|
isAbnormal,
|
||
|
|
statusClass: isAbnormal ? 'abnormal' : `status-${stageStatus}`
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function normalizeRound(round) {
|
||
|
|
const source = round && typeof round === 'object' ? round : {};
|
||
|
|
const passed = source.passed === true;
|
||
|
|
const isAbnormal = containsAbnormalText(source.statusText || source.checkinStatusText);
|
||
|
|
return Object.assign({}, source, {
|
||
|
|
checkinNo: asNumber(source.checkinNo),
|
||
|
|
checkinName: source.checkinName || `${asNumber(source.checkinNo)}检`,
|
||
|
|
passed,
|
||
|
|
checkedTimeText: passed ? formatDateTime(source.checkedTime) : '待完成',
|
||
|
|
checkerNameText: passed ? (source.checkerName || '—') : '—',
|
||
|
|
isAbnormal,
|
||
|
|
statusClass: isAbnormal ? 'abnormal' : (passed ? 'passed' : 'pending')
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function normalizeMine(item) {
|
||
|
|
const source = item && typeof item === 'object' ? item : {};
|
||
|
|
const checkinStatus = asNumber(source.checkinStatus, -1);
|
||
|
|
const isAbnormal = ![0, 1, 2, 3].includes(checkinStatus) || containsAbnormalText(source.checkinStatusText) || containsAbnormalText(source.notice);
|
||
|
|
const athleteNames = asArray(source.athleteNames);
|
||
|
|
return Object.assign({}, source, {
|
||
|
|
checkinStatus,
|
||
|
|
displayName: source.displayName || [source.projectName, source.groupName].filter(Boolean).join(' - ') || '未命名项目',
|
||
|
|
athleteNames,
|
||
|
|
athleteNamesText: athleteNames.join('、') || '—',
|
||
|
|
rounds: asArray(source.rounds).map(normalizeRound),
|
||
|
|
checkinStatusText: source.checkinStatusText || (isAbnormal ? '状态异常' : '等待中'),
|
||
|
|
isAbnormal,
|
||
|
|
statusClass: isAbnormal ? 'abnormal' : `status-${checkinStatus}`
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function normalizeCheckinProgress(payload) {
|
||
|
|
const source = payload && typeof payload === 'object' ? payload : {};
|
||
|
|
const stages = asArray(source.stages).map((stage, index) => normalizeStage(stage, index));
|
||
|
|
const mine = asArray(source.mine).map(normalizeMine);
|
||
|
|
const currentCheckin = source.currentCheckin ? normalizeStage(source.currentCheckin) : null;
|
||
|
|
const currentCompeting = source.currentCompeting ? normalizeStage(source.currentCompeting) : null;
|
||
|
|
const competingMine = currentCompeting && mine.find((item) =>
|
||
|
|
String(item.eventProjectId) === String(currentCompeting.eventProjectId) &&
|
||
|
|
String(item.groupId || '') === String(currentCompeting.groupId || '')
|
||
|
|
);
|
||
|
|
const currentCompetingDetail = currentCompeting ? Object.assign({}, currentCompeting, {
|
||
|
|
unitNameText: currentCompeting.unitName || (competingMine && competingMine.unitName) || '—',
|
||
|
|
teamNameText: currentCompeting.teamName || (competingMine && competingMine.teamName) || '—',
|
||
|
|
athleteNamesText: currentCompeting.athleteNamesText !== '—'
|
||
|
|
? currentCompeting.athleteNamesText
|
||
|
|
: ((competingMine && competingMine.athleteNamesText) || '—'),
|
||
|
|
registrationTypeText: currentCompeting.registrationTypeText || '个人报名'
|
||
|
|
}) : null;
|
||
|
|
return Object.assign({}, source, {
|
||
|
|
eventName: source.eventName || '检录进度',
|
||
|
|
serverTimeText: source.serverTimeText || formatDateTime(source.serverTime),
|
||
|
|
weekDayText: source.weekDayText || '',
|
||
|
|
currentCheckin,
|
||
|
|
currentCompeting,
|
||
|
|
currentCompetingDetail,
|
||
|
|
stages,
|
||
|
|
mine,
|
||
|
|
hasData: !!currentCheckin || !!currentCompeting || stages.length > 0 || mine.length > 0
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
module.exports = { normalizeCheckinProgress };
|