Merge branch 'main' of http://8.153.108.90:3000/YD/YD_Event.Web
This commit is contained in:
commit
778830c147
@ -109,3 +109,18 @@ export const eventregistrationDeleteDelete = (data) => {
|
|||||||
export const eventregistrationSetstatusPatch = (data) => {
|
export const eventregistrationSetstatusPatch = (data) => {
|
||||||
return http.patch('/eventregistration/setstatus', 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}`);
|
||||||
|
};
|
||||||
@ -13,6 +13,36 @@
|
|||||||
<div style="height:100px;"></div>
|
<div style="height:100px;"></div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="报名管理" name="second">
|
<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"
|
<ProTable ref="tableRef" :request-api="eventregistrationPagePost" :columns="columns" :pagination="true"
|
||||||
:tool-button="false" :initParam="initParam" toolButton preserve-expanded-content
|
:tool-button="false" :initParam="initParam" toolButton preserve-expanded-content
|
||||||
@selectionChange="selection">
|
@selectionChange="selection">
|
||||||
@ -290,7 +320,7 @@ import { ElMessage, ElMessageBox } from 'element-plus';
|
|||||||
import { Check, View, Download, Rank, Warning } from '@element-plus/icons-vue';
|
import { Check, View, Download, Rank, Warning } from '@element-plus/icons-vue';
|
||||||
import { eventDetailGet } from '/@/api/match/event';
|
import { eventDetailGet } from '/@/api/match/event';
|
||||||
import { eventarrangementListGet, eventarrangementPut, eventarrangementExportPost, eventarrangementPreviewPost } from '/@/api/match/eventarrangement';
|
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 { eventscorePageathletePost, eventscorePagecoachleaderPost, eventscoreImportscorePost, eventscoreDownloadtemplateGet, eventscoreExportcertificatePost, eventscoreIssuecertificatePost, eventscoreGetCertificateDetailGet, eventscoreIssuepointsPost } from '/@/api/match/eventscore';
|
||||||
import { certificateListGet } from '/@/api/match/certificate';
|
import { certificateListGet } from '/@/api/match/certificate';
|
||||||
import Step1BasicInfo from './Steps/Step1BasicInfo.vue';
|
import Step1BasicInfo from './Steps/Step1BasicInfo.vue';
|
||||||
@ -326,6 +356,24 @@ const selectedCertificateId = ref();
|
|||||||
const issuingCertificate = ref(false);
|
const issuingCertificate = ref(false);
|
||||||
const certificateForm = ref({});
|
const certificateForm = ref({});
|
||||||
const certificateList = 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({
|
const formData = ref({
|
||||||
// 步骤1:基本信息
|
// 步骤1:基本信息
|
||||||
@ -441,6 +489,9 @@ const openDialog = async (id) => {
|
|||||||
// 等待对话框渲染完成后刷新表格数据
|
// 等待对话框渲染完成后刷新表格数据
|
||||||
await nextTick()
|
await nextTick()
|
||||||
refreshScoreTable()
|
refreshScoreTable()
|
||||||
|
|
||||||
|
// 获取报名统计数据
|
||||||
|
await fetchRegistrationStats();
|
||||||
};
|
};
|
||||||
|
|
||||||
const initSortable = () => {
|
const initSortable = () => {
|
||||||
@ -619,11 +670,58 @@ const columns = reactive([
|
|||||||
{ prop: 'action', label: '操作', align: 'center', width: 140, fixed: 'right' },
|
{ 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 onSureOrder = async (id) => {
|
||||||
const res = await eventregistrationBatchauditPost({ ids: [id], 'paymentStatus': 1 });
|
const res = await eventregistrationBatchauditPost({ ids: [id], 'paymentStatus': 1 });
|
||||||
if (res.succeeded) {
|
if (res.succeeded) {
|
||||||
ElMessage.success('操作成功!');
|
ElMessage.success('操作成功!');
|
||||||
initParam.value.refresh = !initParam.value.refresh;
|
initParam.value.refresh = !initParam.value.refresh;
|
||||||
|
// 审核完成后刷新统计数据
|
||||||
|
await fetchRegistrationStats();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const selectListIds = ref()
|
const selectListIds = ref()
|
||||||
@ -800,6 +898,8 @@ const allSure = async () => {
|
|||||||
if (res.succeeded) {
|
if (res.succeeded) {
|
||||||
ElMessage.success('操作成功!');
|
ElMessage.success('操作成功!');
|
||||||
initParam.value.refresh = !initParam.value.refresh;
|
initParam.value.refresh = !initParam.value.refresh;
|
||||||
|
// 审核完成后刷新统计数据
|
||||||
|
await fetchRegistrationStats();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1409,6 +1509,81 @@ defineExpose({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<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 {
|
.arrangement-container {
|
||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user