马梓彭 b157e73eb2 新增检录进度页面
新增裁判认证页面
对接检录页面
对接成绩查询页面
2026-09-01 23:13:21 +08:00

217 lines
8.4 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 competition = require('../../../utils/competition');
Page({
data: {
loading: true,
context: null,
projects: [],
projectNames: [],
projectIndex: 0,
groups: [],
groupNames: [],
groupIndex: 0,
units: [],
pendingUnits: [],
checkedUnits: [],
checkedGroups: [],
lockedUnits: [],
checkedCount: 0,
pendingCount: 0,
progressPercent: 0,
updatingKey: '',
actionLoading: false
},
onLoad() { this.loadContext(); },
onPullDownRefresh() {
this.loadContext(this.currentProjectId(), this.currentGroupId()).finally(() => wx.stopPullDownRefresh());
},
currentProjectId() {
const item = this.data.projects[this.data.projectIndex];
return item && item.eventProjectId;
},
currentGroupId() {
const item = this.data.groups[this.data.groupIndex];
return item && item.id;
},
loadContext(eventProjectId, groupId) {
this.setData({ loading: true });
return competition.fetchCurrentCheckin({ eventProjectId, groupId })
.then((context) => this.applyContext(context))
.catch((err) => wx.showToast({ title: (err && err.message) || '检录信息加载失败', icon: 'none' }))
.finally(() => this.setData({ loading: false }));
},
applyContext(context) {
const projects = (context && context.projects) || [];
let projectIndex = projects.findIndex((item) => String(item.eventProjectId) === String(context.selectedEventProjectId));
if (projectIndex < 0) projectIndex = 0;
const groups = (projects[projectIndex] && projects[projectIndex].groups) || [];
let groupIndex = groups.findIndex((item) => String(item.id) === String(context.selectedGroupId));
if (groupIndex < 0) groupIndex = 0;
const units = (context && context.units) || [];
const pendingUnits = Array.isArray(context && context.pendingUnits) ? context.pendingUnits : units.filter((item) => item.canCheck && !item.checked);
const checkedUnits = Array.isArray(context && context.checkedUnits) ? context.checkedUnits : units.filter((item) => item.checked);
const lockedUnits = Array.isArray(context && context.lockedUnits) ? context.lockedUnits : units.filter((item) => !item.canCheck);
const totalRounds = Number(context && (context.totalCheckins || context.totalRounds)) || 0;
const currentRound = Number(context && (context.currentCheckinNo || context.currentRound)) || 0;
const rounds = Array.from({ length: totalRounds }, (_, index) => {
const number = index + 1;
return { number, state: number < currentRound ? 'done' : number === currentRound ? 'active' : '', label: number < currentRound ? '✓' : String(number) };
});
const checkedCount = units.filter((item) => item.checked).length;
const checkedGroups = [];
checkedUnits.forEach((item) => {
const key = `${item.eventProjectId || item.projectId}-${item.groupId || item.groupName}`;
let group = checkedGroups.find((entry) => entry.key === key);
if (!group) {
group = {
key,
projectName: item.projectName || '未命名项目',
groupName: item.groupName || '未分组',
units: []
};
checkedGroups.push(group);
}
group.units.push(item);
});
this.setData({
context: context ? Object.assign({}, context, { rounds }) : null,
projects,
projectNames: projects.map((item) => item.projectName),
projectIndex,
groups,
groupNames: groups.map((item) => item.groupName),
groupIndex,
units,
pendingUnits,
checkedUnits,
checkedGroups,
lockedUnits,
checkedCount,
pendingCount: pendingUnits.length,
progressPercent: units.length ? Math.round(checkedCount * 100 / units.length) : 0
});
},
onProjectTap(e) {
if (this.data.loading) return;
const projectIndex = Number(e.currentTarget.dataset.index) || 0;
if (projectIndex === this.data.projectIndex) return;
const project = this.data.projects[projectIndex];
const group = project && project.groups && project.groups[0];
if (project && group) this.loadContext(project.eventProjectId, group.id);
},
onGroupTap(e) {
if (this.data.loading) return;
const groupIndex = Number(e.currentTarget.dataset.index) || 0;
if (groupIndex === this.data.groupIndex) return;
const group = this.data.groups[groupIndex];
if (group) this.loadContext(this.currentProjectId(), group.id);
},
onStartCheckin() {
if (this.data.actionLoading) return;
const eventProjectId = this.currentProjectId();
const groupId = this.currentGroupId();
wx.showModal({
title: '开始检录',
content: '开始后将通知本组报名人员,确认继续吗?',
success: (res) => {
if (!res.confirm) return;
this.setData({ actionLoading: true });
competition.startCheckin({ eventProjectId, groupId })
.then((result) => {
if (result && result.context) this.applyContext(result.context);
wx.showToast({ title: (result && result.message) || '检录已开始', icon: 'none' });
if (!(result && result.context)) return this.loadContext(eventProjectId, groupId);
})
.catch((err) => wx.showToast({ title: (err && err.message) || '开始检录失败', icon: 'none' }))
.finally(() => this.setData({ actionLoading: false }));
}
});
},
onScanCheckin() {
if (this.data.actionLoading) return;
wx.scanCode({
scanType: ['qrCode', 'barCode'],
success: (scan) => {
this.setData({ actionLoading: true });
competition.scanCheckin({
code: scan.result,
eventProjectId: this.currentProjectId(),
groupId: this.currentGroupId()
}).then((result) => {
// 后端在号码布不匹配时返回 success:false + message 且不带 context,
// 必须照样给出提示,否则检录员扫错码时收不到任何反馈。
const ok = !result || result.success !== false;
if (result && result.context) this.applyContext(result.context);
wx.showToast({
title: (result && result.message) || (ok ? '扫码检录成功' : '扫码检录失败'),
icon: ok ? 'success' : 'none'
});
if (!(result && result.context)) return this.loadContext(this.currentProjectId(), this.currentGroupId());
}).catch((err) => wx.showToast({ title: (err && err.message) || '扫码检录失败', icon: 'none' }))
.finally(() => this.setData({ actionLoading: false }));
}
});
},
onMarkOnStage(e) {
const unitKey = e.currentTarget.dataset.key;
if (!unitKey || this.data.updatingKey) return;
this.setData({ updatingKey: unitKey });
competition.markCheckinOnStage({
unitKey,
eventProjectId: this.currentProjectId(),
groupId: this.currentGroupId()
}).then((context) => {
if (context) this.applyContext(context);
wx.showToast({ title: '已标记上场', icon: 'success' });
}).catch((err) => wx.showToast({ title: (err && err.message) || '标记上场失败', icon: 'none' }))
.finally(() => this.setData({ updatingKey: '' }));
},
onToggleUnit(e) {
const unitKey = e.currentTarget.dataset.key;
const current = this.data.units.find((item) => item.unitKey === unitKey)
|| this.data.checkedUnits.find((item) => item.unitKey === unitKey);
if (!current || !current.canCheck || this.data.updatingKey) return;
const checked = !current.checked;
if (current.checked) {
wx.showModal({
title: '取消检录',
content: `确认取消${current.teamName || current.athletes.map((item) => item.name).join('、')}的当前检录吗?`,
confirmText: '确认取消',
confirmColor: '#d94b4b',
success: (res) => {
if (res.confirm) this.updateUnitStatus(current, checked);
}
});
return;
}
this.updateUnitStatus(current, checked);
},
updateUnitStatus(current, checked) {
const unitKey = current.unitKey;
this.setData({ updatingKey: unitKey });
competition.updateCheckinStatus({
unitKey,
eventProjectId: this.currentProjectId(),
groupId: this.currentGroupId(),
checked
}).then((res) => {
this.applyContext(res);
wx.showToast({ title: checked ? '该列已完成检录' : '已取消该列检录', icon: 'none' });
}).catch((err) => wx.showToast({ title: (err && err.message) || '操作失败', icon: 'none' }))
.finally(() => this.setData({ updatingKey: '' }));
}
});