This commit is contained in:
ltx 2026-05-15 13:46:14 +08:00
commit 778830c147
2 changed files with 191 additions and 1 deletions

View File

@ -108,4 +108,19 @@ export const eventregistrationDeleteDelete = (data) => {
*/
export const eventregistrationSetstatusPatch = (data) => {
return http.patch('/eventregistration/setstatus', data);
};
/**
* 获取报名统计数据
* @param {number} eventId - 赛事ID
* @returns {Promise<{
* totalParticipants: number,
* individualParticipants: number,
* teamCount: number,
* teamParticipants: number,
* pendingReview: number
* }>}
*/
export const eventregistrationStatsGet = (eventId) => {
return http.get(`/eventregistration/stats/${eventId}`);
};

View File

@ -13,6 +13,36 @@
<div style="height:100px;"></div>
</el-tab-pane>
<el-tab-pane label="报名管理" name="second">
<!-- 统计区块 -->
<div class="registration-stats-container">
<div class="stats-card" v-loading="statsLoading">
<div class="stats-row">
<div class="stat-item">
<div class="stat-label">报名总人数</div>
<div class="stat-value">{{ animatedCounts.totalParticipants }}<span class="stat-unit">人</span></div>
</div>
<div class="stat-divider"></div>
<div class="stat-item">
<div class="stat-label">个人项目</div>
<div class="stat-value">{{ animatedCounts.individualParticipants }}<span class="stat-unit">人</span></div>
</div>
<div class="stat-divider"></div>
<div class="stat-item">
<div class="stat-label">团队项目</div>
<div class="stat-value">
<span>{{ animatedCounts.teamCount }}<span class="stat-unit">队</span></span>
<span style="margin: 0 8px;">/</span>
<span>{{ animatedCounts.teamParticipants }}<span class="stat-unit">人</span></span>
</div>
</div>
<div class="stat-divider"></div>
<div class="stat-item">
<div class="stat-label">待审核</div>
<div class="stat-value" style="color: #e6a23c;">{{ animatedCounts.pendingReview }}</div>
</div>
</div>
</div>
</div>
<ProTable ref="tableRef" :request-api="eventregistrationPagePost" :columns="columns" :pagination="true"
:tool-button="false" :initParam="initParam" toolButton preserve-expanded-content
@selectionChange="selection">
@ -290,7 +320,7 @@ import { ElMessage, ElMessageBox } from 'element-plus';
import { Check, View, Download, Rank, Warning } from '@element-plus/icons-vue';
import { eventDetailGet } from '/@/api/match/event';
import { eventarrangementListGet, eventarrangementPut, eventarrangementExportPost, eventarrangementPreviewPost } from '/@/api/match/eventarrangement';
import { eventregistrationPagePost, eventregistrationBatchauditPost, eventregistrationMaterialurlsPost } from '/@/api/match/eventregistration';
import { eventregistrationPagePost, eventregistrationBatchauditPost, eventregistrationMaterialurlsPost, eventregistrationStatsGet } from '/@/api/match/eventregistration';
import { eventscorePageathletePost, eventscorePagecoachleaderPost, eventscoreImportscorePost, eventscoreDownloadtemplateGet, eventscoreExportcertificatePost, eventscoreIssuecertificatePost, eventscoreGetCertificateDetailGet, eventscoreIssuepointsPost } from '/@/api/match/eventscore';
import { certificateListGet } from '/@/api/match/certificate';
import Step1BasicInfo from './Steps/Step1BasicInfo.vue';
@ -326,6 +356,24 @@ const selectedCertificateId = ref();
const issuingCertificate = ref(false);
const certificateForm = ref({});
const certificateList = ref([]);
// 报名统计相关
const registrationStats = ref({
totalParticipants: 0,
individualParticipants: 0,
teamCount: 0,
teamParticipants: 0,
pendingReview: 0
});
const statsLoading = ref(false);
const animatedCounts = ref({
totalParticipants: 0,
individualParticipants: 0,
teamCount: 0,
teamParticipants: 0,
pendingReview: 0
});
// 表单数据(响应式对象)
const formData = ref({
// 步骤1:基本信息
@ -441,6 +489,9 @@ const openDialog = async (id) => {
// 等待对话框渲染完成后刷新表格数据
await nextTick()
refreshScoreTable()
// 获取报名统计数据
await fetchRegistrationStats();
};
const initSortable = () => {
@ -619,11 +670,58 @@ const columns = reactive([
{ prop: 'action', label: '操作', align: 'center', width: 140, fixed: 'right' },
]);
// 获取报名统计数据
const fetchRegistrationStats = async () => {
if (!initParam.value.eventId) return;
statsLoading.value = true;
try {
const res = await eventregistrationStatsGet(initParam.value.eventId);
if (res?.succeeded && res?.data) {
registrationStats.value = res.data;
// 启动数字动画
animateNumbers(res.data);
}
} catch (error) {
console.error('获取统计数据失败:', error);
} finally {
statsLoading.value = false;
}
};
// 数字动画函数
const animateNumbers = (targetStats) => {
const duration = 1500; // 动画持续时间(毫秒)
const startTime = Date.now();
const animate = () => {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
// 使用 easeOutQuart 缓动函数
const easeProgress = 1 - Math.pow(1 - progress, 4);
animatedCounts.value.totalParticipants = Math.floor(targetStats.totalParticipants * easeProgress);
animatedCounts.value.individualParticipants = Math.floor(targetStats.individualParticipants * easeProgress);
animatedCounts.value.teamCount = Math.floor(targetStats.teamCount * easeProgress);
animatedCounts.value.teamParticipants = Math.floor(targetStats.teamParticipants * easeProgress);
animatedCounts.value.pendingReview = Math.floor(targetStats.pendingReview * easeProgress);
if (progress < 1) {
requestAnimationFrame(animate);
}
};
animate();
};
const onSureOrder = async (id) => {
const res = await eventregistrationBatchauditPost({ ids: [id], 'paymentStatus': 1 });
if (res.succeeded) {
ElMessage.success('操作成功!');
initParam.value.refresh = !initParam.value.refresh;
// 审核完成后刷新统计数据
await fetchRegistrationStats();
}
};
const selectListIds = ref()
@ -800,6 +898,8 @@ const allSure = async () => {
if (res.succeeded) {
ElMessage.success('操作成功!');
initParam.value.refresh = !initParam.value.refresh;
// 审核完成后刷新统计数据
await fetchRegistrationStats();
}
}
@ -1409,6 +1509,81 @@ defineExpose({
</script>
<style scoped>
.registration-stats-container {
margin-bottom: 16px;
}
.stats-card {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
padding: 24px 32px;
}
.stats-row {
display: flex;
justify-content: space-around;
align-items: center;
flex-wrap: wrap;
gap: 16px;
}
.stat-item {
flex: 1;
min-width: 180px;
text-align: center;
}
.stat-label {
font-size: 14px;
color: #909399;
margin-bottom: 8px;
}
.stat-value {
font-size: 28px;
font-weight: 600;
color: #303133;
}
.stat-unit {
font-size: 16px;
font-weight: normal;
margin-left: 4px;
}
.stat-divider {
width: 1px;
height: 60px;
background: #ebeef5;
}
/* 响应式样式 */
@media (max-width: 768px) {
.stats-card {
padding: 16px;
}
.stats-row {
flex-direction: column;
gap: 20px;
}
.stat-item {
width: 100%;
min-width: auto;
}
.stat-divider {
width: 60%;
height: 1px;
}
.stat-value {
font-size: 24px;
}
}
.arrangement-container {
padding: 20px 0;
}