报时间冲突的比赛弹窗提醒
检录工作台选择项目后不用再细化到组别,按照场次顺序排列
This commit is contained in:
parent
adfc7a66fb
commit
341449efe9
@ -111,6 +111,21 @@ function toastForEventStatus(es) {
|
||||
return '当前不可报名';
|
||||
}
|
||||
|
||||
function showRefereeApplyFailure(message, fallbackMessage) {
|
||||
const content = String(message || fallbackMessage || '报名执裁失败');
|
||||
if (content.includes('执裁时间存在重叠')) {
|
||||
wx.showModal({
|
||||
title: '报名提示',
|
||||
content,
|
||||
showCancel: false,
|
||||
confirmText: '我知道了'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
wx.showToast({ title: content, icon: 'none' });
|
||||
}
|
||||
|
||||
function registrationModeText(mode) {
|
||||
const m = mode === undefined || mode === null ? null : Number(mode);
|
||||
if (m === 1) return '只允许个人报名';
|
||||
@ -913,11 +928,11 @@ Page({
|
||||
return;
|
||||
}
|
||||
if (quota && (quota.isFull || quota.canApply === false) && !quota.applied4Me) {
|
||||
wx.showToast({ title: quota.message || '裁判报名名额已满', icon: 'none' });
|
||||
showRefereeApplyFailure(quota.message, '裁判报名名额已满');
|
||||
return;
|
||||
}
|
||||
this._confirmRefereeApply();
|
||||
}).catch((err) => wx.showToast({ title: (err && err.message) || '裁判资格校验失败', icon: 'none' }))
|
||||
}).catch((err) => showRefereeApplyFailure(err && err.message, '裁判资格校验失败'))
|
||||
.finally(() => wx.hideLoading());
|
||||
},
|
||||
|
||||
@ -942,7 +957,7 @@ Page({
|
||||
this.setData({ isRegistered: true, applyDisabled: true, applyGrey: true, applyButtonText: '已报名执裁' });
|
||||
wx.showToast({ title: '报名执裁成功', icon: 'success' });
|
||||
}).catch((err) => {
|
||||
wx.showToast({ title: (err && err.message) || '报名执裁失败', icon: 'none' });
|
||||
showRefereeApplyFailure(err && err.message, '报名执裁失败');
|
||||
}).finally(() => wx.hideLoading());
|
||||
}
|
||||
});
|
||||
|
||||
@ -5,15 +5,10 @@ Page({
|
||||
loading: true,
|
||||
context: null,
|
||||
projects: [],
|
||||
projectNames: [],
|
||||
projectIndex: 0,
|
||||
groups: [],
|
||||
groupNames: [],
|
||||
groupIndex: 0,
|
||||
units: [],
|
||||
pendingUnits: [],
|
||||
checkedUnits: [],
|
||||
checkedGroups: [],
|
||||
lockedUnits: [],
|
||||
checkedCount: 0,
|
||||
pendingCount: 0,
|
||||
@ -25,7 +20,7 @@ Page({
|
||||
onLoad() { this.loadContext(); },
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.loadContext(this.currentProjectId(), this.currentGroupId()).finally(() => wx.stopPullDownRefresh());
|
||||
this.loadContext(this.currentProjectId()).finally(() => wx.stopPullDownRefresh());
|
||||
},
|
||||
|
||||
currentProjectId() {
|
||||
@ -33,14 +28,9 @@ Page({
|
||||
return item && item.eventProjectId;
|
||||
},
|
||||
|
||||
currentGroupId() {
|
||||
const item = this.data.groups[this.data.groupIndex];
|
||||
return item && item.id;
|
||||
},
|
||||
|
||||
loadContext(eventProjectId, groupId) {
|
||||
loadContext(eventProjectId) {
|
||||
this.setData({ loading: true });
|
||||
return competition.fetchCurrentCheckin({ eventProjectId, groupId })
|
||||
return competition.fetchCurrentCheckin({ eventProjectId })
|
||||
.then((context) => this.applyContext(context))
|
||||
.catch((err) => wx.showToast({ title: (err && err.message) || '检录信息加载失败', icon: 'none' }))
|
||||
.finally(() => this.setData({ loading: false }));
|
||||
@ -50,9 +40,6 @@ Page({
|
||||
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);
|
||||
@ -64,33 +51,13 @@ Page({
|
||||
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,
|
||||
@ -103,33 +70,23 @@ Page({
|
||||
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);
|
||||
if (project) this.loadContext(project.eventProjectId);
|
||||
},
|
||||
|
||||
onStartCheckin() {
|
||||
if (this.data.actionLoading) return;
|
||||
const eventProjectId = this.currentProjectId();
|
||||
const groupId = this.currentGroupId();
|
||||
wx.showModal({
|
||||
title: '开始检录',
|
||||
content: '开始后将通知本组报名人员,确认继续吗?',
|
||||
content: '开始后将通知当前项目的报名人员,确认继续吗?',
|
||||
success: (res) => {
|
||||
if (!res.confirm) return;
|
||||
this.setData({ actionLoading: true });
|
||||
competition.startCheckin({ eventProjectId, groupId })
|
||||
competition.startCheckin({ eventProjectId })
|
||||
.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);
|
||||
if (!(result && result.context)) return this.loadContext(eventProjectId);
|
||||
})
|
||||
.catch((err) => wx.showToast({ title: (err && err.message) || '开始检录失败', icon: 'none' }))
|
||||
.finally(() => this.setData({ actionLoading: false }));
|
||||
@ -145,8 +102,7 @@ Page({
|
||||
this.setData({ actionLoading: true });
|
||||
competition.scanCheckin({
|
||||
code: scan.result,
|
||||
eventProjectId: this.currentProjectId(),
|
||||
groupId: this.currentGroupId()
|
||||
eventProjectId: this.currentProjectId()
|
||||
}).then((result) => {
|
||||
// 后端在号码布不匹配时返回 success:false + message 且不带 context,
|
||||
// 必须照样给出提示,否则检录员扫错码时收不到任何反馈。
|
||||
@ -156,7 +112,7 @@ Page({
|
||||
title: (result && result.message) || (ok ? '扫码检录成功' : '扫码检录失败'),
|
||||
icon: ok ? 'success' : 'none'
|
||||
});
|
||||
if (!(result && result.context)) return this.loadContext(this.currentProjectId(), this.currentGroupId());
|
||||
if (!(result && result.context)) return this.loadContext(this.currentProjectId());
|
||||
}).catch((err) => wx.showToast({ title: (err && err.message) || '扫码检录失败', icon: 'none' }))
|
||||
.finally(() => this.setData({ actionLoading: false }));
|
||||
}
|
||||
@ -169,8 +125,7 @@ Page({
|
||||
this.setData({ updatingKey: unitKey });
|
||||
competition.markCheckinOnStage({
|
||||
unitKey,
|
||||
eventProjectId: this.currentProjectId(),
|
||||
groupId: this.currentGroupId()
|
||||
eventProjectId: this.currentProjectId()
|
||||
}).then((context) => {
|
||||
if (context) this.applyContext(context);
|
||||
wx.showToast({ title: '已标记上场', icon: 'success' });
|
||||
@ -205,7 +160,6 @@ Page({
|
||||
competition.updateCheckinStatus({
|
||||
unitKey,
|
||||
eventProjectId: this.currentProjectId(),
|
||||
groupId: this.currentGroupId(),
|
||||
checked
|
||||
}).then((res) => {
|
||||
this.applyContext(res);
|
||||
|
||||
@ -12,8 +12,8 @@
|
||||
</view>
|
||||
<view class="compact-divider"></view>
|
||||
<view class="compact-status-item group-status-item">
|
||||
<text class="compact-label">当前组别</text>
|
||||
<text class="compact-value">{{context.currentGroupName || '请选择组别'}}</text>
|
||||
<text class="compact-label">当前项目</text>
|
||||
<text class="compact-value">{{projects[projectIndex].projectName || '请选择项目'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -40,30 +40,10 @@
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="selector-separator"></view>
|
||||
|
||||
<view class="selector-heading group-heading">
|
||||
<view class="selector-step">2</view>
|
||||
<view class="selector-heading-text"><text class="selector-title">选择参赛组别</text><text class="selector-hint">点击后立即切换检录名单</text></view>
|
||||
</view>
|
||||
<scroll-view class="group-scroll" scroll-x enhanced show-scrollbar="{{false}}" scroll-with-animation>
|
||||
<view class="group-options">
|
||||
<view
|
||||
wx:for="{{groups}}"
|
||||
wx:key="id"
|
||||
class="group-option {{index === groupIndex ? 'active' : ''}} {{item.isCompleted ? 'completed' : ''}}"
|
||||
data-index="{{index}}"
|
||||
bindtap="onGroupTap"
|
||||
>
|
||||
<view class="group-active-dot"></view>
|
||||
<view class="group-option-content"><text class="group-option-name">{{item.groupName}}</text><text class="group-option-progress">{{item.checkedUnits}}/{{item.totalUnits}} · {{item.isCompleted ? '已完成' : item.progressPercent + '%'}}</text></view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<view class="checkin-toolbar" wx:if="{{context}}">
|
||||
<button class="toolbar-btn toolbar-btn--primary" loading="{{actionLoading}}" disabled="{{actionLoading}}" bindtap="onStartCheckin">开始当前组检录</button>
|
||||
<button class="toolbar-btn toolbar-btn--primary" loading="{{actionLoading}}" disabled="{{actionLoading}}" bindtap="onStartCheckin">开始当前项目检录</button>
|
||||
<button class="toolbar-btn" disabled="{{actionLoading}}" bindtap="onScanCheckin">扫码检录</button>
|
||||
</view>
|
||||
|
||||
@ -71,23 +51,23 @@
|
||||
|
||||
<block wx:if="{{context}}">
|
||||
<view class="progress-card">
|
||||
<view class="progress-top"><text class="section-title">当前组别进度</text><text class="progress-count"><text class="progress-count-main">{{checkedCount}}</text> / {{units.length}} 项</text></view>
|
||||
<view class="progress-top"><text class="section-title">当前项目进度</text><text class="progress-count"><text class="progress-count-main">{{checkedCount}}</text> / {{units.length}} 项</text></view>
|
||||
<view class="progress-track"><view class="progress-fill" style="width: {{progressPercent}}%;"></view></view>
|
||||
<view class="progress-bottom"><text>已检录 {{checkedCount}} 项</text><text>待检录 {{pendingCount}} 项</text></view>
|
||||
</view>
|
||||
|
||||
<view class="list-heading"><text class="section-title">待检录</text><text class="list-tip">按秩序册顺序</text></view>
|
||||
<view class="unit-card" wx:for="{{pendingUnits}}" wx:key="unitKey">
|
||||
<view class="unit-head"><text class="unit-title">{{item.teamName || '个人参赛'}}</text><text class="venue-badge">{{item.venueName}}</text></view>
|
||||
<view class="unit-head"><text class="unit-title">{{item.teamName || '个人参赛'}}</text><text class="venue-badge">第{{item.sessionIndex}}场 · {{item.venueName}}</text></view>
|
||||
<view class="unit-meta" wx:if="{{item.unitName}}"><text class="unit-meta-label">单位</text><text class="unit-meta-value">{{item.unitName}}</text></view>
|
||||
<view class="unit-athletes"><text class="athlete-chip" wx:for="{{item.athletes}}" wx:for-item="athlete" wx:key="id">{{athlete.name}}</text></view>
|
||||
<view class="unit-action {{updatingKey === item.unitKey ? 'disabled' : ''}}" data-key="{{item.unitKey}}" bindtap="onToggleUnit">确认检录</view>
|
||||
</view>
|
||||
<view wx:if="{{!pendingUnits.length}}" class="empty-tip">当前组别暂无待检录项</view>
|
||||
<view wx:if="{{!pendingUnits.length}}" class="empty-tip">当前项目暂无待检录项</view>
|
||||
|
||||
<view class="list-heading" wx:if="{{lockedUnits.length}}"><text class="section-title">等待前序检录</text><text class="list-tip">前一检通过后可操作</text></view>
|
||||
<view class="unit-card locked" wx:for="{{lockedUnits}}" wx:key="unitKey">
|
||||
<view class="unit-head"><text class="unit-title">{{item.teamName || '个人参赛'}}</text><text class="venue-badge">{{item.venueName}}</text></view>
|
||||
<view class="unit-head"><text class="unit-title">{{item.teamName || '个人参赛'}}</text><text class="venue-badge">第{{item.sessionIndex}}场 · {{item.venueName}}</text></view>
|
||||
<view class="unit-meta" wx:if="{{item.unitName}}"><text class="unit-meta-label">单位</text><text class="unit-meta-value">{{item.unitName}}</text></view>
|
||||
<view class="unit-athletes"><text class="athlete-chip" wx:for="{{item.athletes}}" wx:for-item="athlete" wx:key="id">{{athlete.name}}</text></view>
|
||||
<view class="unit-action disabled">{{item.lockReason}}</view>
|
||||
@ -95,15 +75,11 @@
|
||||
|
||||
<view class="checked-section-head">
|
||||
<view class="checked-section-title"><text class="section-title">已检录</text><text class="checked-count">{{checkedUnits.length}} 项</text></view>
|
||||
<text class="scope-tip">仅展示当前选中项目和组别的已检录结果</text>
|
||||
<text class="scope-tip">仅展示当前项目,按场次顺序排列</text>
|
||||
</view>
|
||||
<block wx:for="{{checkedGroups}}" wx:for-item="checkedGroup" wx:key="key">
|
||||
<view class="checked-group-head">
|
||||
<view class="checked-group-names"><text class="checked-project-name">{{checkedGroup.projectName}}</text><text class="checked-group-name">{{checkedGroup.groupName}}</text></view>
|
||||
<text class="checked-group-count">{{checkedGroup.units.length}} 项</text>
|
||||
</view>
|
||||
<view class="unit-card" wx:for="{{checkedGroup.units}}" wx:for-item="item" wx:key="unitKey">
|
||||
<view class="unit-head"><text class="unit-title">{{item.teamName || '个人参赛'}}</text><text class="venue-badge">{{item.venueName}}</text></view>
|
||||
<block wx:for="{{checkedUnits}}" wx:for-item="item" wx:key="unitKey">
|
||||
<view class="unit-card">
|
||||
<view class="unit-head"><text class="unit-title">{{item.teamName || '个人参赛'}}</text><text class="venue-badge">第{{item.sessionIndex}}场 · {{item.venueName}}</text></view>
|
||||
<view class="unit-meta" wx:if="{{item.unitName}}"><text class="unit-meta-label">单位</text><text class="unit-meta-value">{{item.unitName}}</text></view>
|
||||
<view class="unit-athletes"><text class="athlete-chip checked-chip" wx:for="{{item.athletes}}" wx:for-item="athlete" wx:key="id">{{athlete.name}}</text></view>
|
||||
<view class="checked-actions">
|
||||
|
||||
@ -25,49 +25,47 @@ function rejectWith(message) {
|
||||
return Promise.reject(new Error(message));
|
||||
}
|
||||
|
||||
function withScope(data, eventProjectId, groupId) {
|
||||
function withProjectScope(data, eventProjectId) {
|
||||
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 fetchCurrentCheckin({ eventProjectId } = {}) {
|
||||
return request({ path: API.checkinContext, method: 'GET', data: withProjectScope({}, eventProjectId), needAuth: true });
|
||||
}
|
||||
|
||||
function updateCheckinStatus({ unitKey, eventProjectId, groupId, checked }) {
|
||||
return request({ path: API.checkinStatus, method: 'POST', data: withScope({ unitKey, checked }, eventProjectId, groupId), needAuth: true });
|
||||
function updateCheckinStatus({ unitKey, eventProjectId, checked }) {
|
||||
return request({ path: API.checkinStatus, method: 'POST', data: withProjectScope({ unitKey, checked }, eventProjectId), needAuth: true });
|
||||
}
|
||||
|
||||
function startCheckin({ eventProjectId, groupId } = {}) {
|
||||
function startCheckin({ eventProjectId } = {}) {
|
||||
if (isEmptyValue(eventProjectId)) return rejectWith('请选择检录项目');
|
||||
if (isEmptyValue(groupId)) return rejectWith('请选择检录组别');
|
||||
return request({
|
||||
path: API.checkinStart,
|
||||
method: 'POST',
|
||||
data: { eventProjectId, groupId },
|
||||
data: { eventProjectId },
|
||||
needAuth: true
|
||||
});
|
||||
}
|
||||
|
||||
function scanCheckin({ code, eventProjectId, groupId } = {}) {
|
||||
function scanCheckin({ code, eventProjectId } = {}) {
|
||||
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),
|
||||
data: withProjectScope({ code: normalizedCode }, eventProjectId),
|
||||
needAuth: true
|
||||
});
|
||||
}
|
||||
|
||||
function markCheckinOnStage({ unitKey, eventProjectId, groupId } = {}) {
|
||||
function markCheckinOnStage({ unitKey, eventProjectId } = {}) {
|
||||
if (isEmptyValue(unitKey)) return rejectWith('缺少参赛单位标识');
|
||||
return request({
|
||||
path: API.checkinOnStage,
|
||||
method: 'POST',
|
||||
data: withScope({ unitKey }, eventProjectId, groupId),
|
||||
data: withProjectScope({ unitKey }, eventProjectId),
|
||||
needAuth: true
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user