修复bug
This commit is contained in:
parent
570f28a7e1
commit
c4d302f0ca
@ -283,4 +283,13 @@ export const usereventregistrationGroupTeamLimitGet = (eventId) => {
|
||||
*/
|
||||
export const usereventregistrationProjectCompletionCheckPost = (data) => {
|
||||
return http.post('/usereventregistration/project-completion/check', data);
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询订单支付状态
|
||||
* @param {string} orderNo - 订单号
|
||||
* @returns {Promise<number>} - 0:未支付, 1:已支付
|
||||
*/
|
||||
export const usereventregistrationOrderStatusGet = (orderNo) => {
|
||||
return http.get(`/usereventregistration/order/status/${orderNo}`);
|
||||
};
|
||||
@ -104,14 +104,14 @@
|
||||
</el-form-item>
|
||||
<span v-else>{{ localFormData.registrationLimit.individualProjectLimit }}</span>
|
||||
</div>
|
||||
<div class="limit-summary__card">
|
||||
<div class="limit-summary__card" v-if="!isOnlyIndividual">
|
||||
<div class="limit-summary__label">
|
||||
<span class="required-star" v-if="!readonly">*</span>
|
||||
团队项目限报数
|
||||
</div>
|
||||
<el-form-item v-if="!readonly"
|
||||
prop="registrationLimit.teamProjectLimit"
|
||||
:rules="[{ required: true, message: '请填写团队项目限报数', trigger: 'change' }]"
|
||||
:rules="isOnlyIndividual ? [] : [{ required: true, message: '请填写团队项目限报数', trigger: 'change' }]"
|
||||
style="margin: 0"
|
||||
>
|
||||
<el-input-number v-model="localFormData.registrationLimit.teamProjectLimit" :min="0" :step="1" :disabled="readonly" />
|
||||
@ -147,7 +147,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, nextTick } from 'vue';
|
||||
import { ref, watch, nextTick, computed } from 'vue';
|
||||
import ProTable from '/@/components/ProTable/index.vue';
|
||||
import { projectPageGet, projectDetailGet } from '/@/api/match/project';
|
||||
import { ElMessage } from 'element-plus';
|
||||
@ -158,6 +158,11 @@ const props = defineProps({
|
||||
});
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
// 判断是否只允许个人报名
|
||||
const isOnlyIndividual = computed(() => {
|
||||
return props.modelValue?.registrationType === 0;
|
||||
});
|
||||
|
||||
const formRef = ref(null);
|
||||
const localFormData = ref({
|
||||
projects: [],
|
||||
@ -297,10 +302,16 @@ watch(
|
||||
|
||||
/* addProject and removeProject are declared above to avoid initialization order issues */
|
||||
|
||||
const rules = {
|
||||
'registrationLimit.individualProjectLimit': [{ required: true, message: '请填写个人项目限报数', trigger: 'change' }],
|
||||
'registrationLimit.teamProjectLimit': [{ required: true, message: '请填写团队项目限报数', trigger: 'change' }],
|
||||
};
|
||||
const rules = computed(() => {
|
||||
const baseRules = {
|
||||
'registrationLimit.individualProjectLimit': [{ required: true, message: '请填写个人项目限报数', trigger: 'change' }],
|
||||
};
|
||||
// 只有在不是仅允许个人报名时,才添加团队项目限报数的验证
|
||||
if (!isOnlyIndividual.value) {
|
||||
baseRules['registrationLimit.teamProjectLimit'] = [{ required: true, message: '请填写团队项目限报数', trigger: 'change' }];
|
||||
}
|
||||
return baseRules;
|
||||
});
|
||||
|
||||
const validate = async () => {
|
||||
if (!formRef.value) return false;
|
||||
|
||||
@ -96,7 +96,10 @@ const currentStepData = computed(() => {
|
||||
case 1:
|
||||
return formData.value.units;
|
||||
case 2:
|
||||
return formData.value.projectConfig;
|
||||
return {
|
||||
...formData.value.projectConfig,
|
||||
registrationType: formData.value.basicInfo.registrationType
|
||||
};
|
||||
case 3:
|
||||
return formData.value.feeConfig;
|
||||
}
|
||||
@ -113,7 +116,8 @@ const handleStepDataUpdate = (newData) => {
|
||||
break;
|
||||
case 2:
|
||||
console.log('Received data from step', activeStep.value, newData);
|
||||
formData.value.projectConfig = newData;
|
||||
const { registrationType, ...projectConfig } = newData;
|
||||
formData.value.projectConfig = projectConfig;
|
||||
break;
|
||||
case 3:
|
||||
formData.value.feeConfig = newData;
|
||||
|
||||
@ -100,9 +100,9 @@ const columns = reactive([
|
||||
prop: 'registrationType',
|
||||
label: '报名方式',
|
||||
enum: [
|
||||
{ label: '两者都有', value: 0 },
|
||||
{ label: '只允许个人报名', value: 1 },
|
||||
{ label: '只允许团队报名', value: 2 },
|
||||
{ label: '只允许个人报名', value: 0 },
|
||||
{ label: '只允许团队报名', value: 1 },
|
||||
{ label: '两者都有', value: 2 },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@ -2,23 +2,28 @@
|
||||
<div class="system-menu-container layout-padding">
|
||||
<ProTable ref="tableRef" :request-api="orderPageGet" :columns="columns" :pagination="true"
|
||||
:tool-button="true">
|
||||
<!-- <template #tools>
|
||||
<el-button v-auth="'order:export'" type="primary" icon="ele-Plus" @click="onOpenMenu"> 导出 </el-button>
|
||||
</template> -->
|
||||
<template #tools>
|
||||
<el-button v-auth="'order:export'" type="primary" :loading="exportLoading" @click="handleExport">
|
||||
<template #icon>
|
||||
<el-icon><Download /></el-icon>
|
||||
</template>
|
||||
导出
|
||||
</el-button>
|
||||
</template>
|
||||
<template #index="scope">
|
||||
{{ scope.$index + 1 }}
|
||||
</template>
|
||||
<template #paymentMethod="scope">
|
||||
{{ scope.row.paymentMethod }}
|
||||
{{ getPaymentMethodText(scope.row.paymentMethod) }}
|
||||
</template>
|
||||
<template #orderType="scope">
|
||||
{{ scope.row.orderType }}
|
||||
{{ getOrderTypeText(scope.row.orderType) }}
|
||||
</template>
|
||||
<template #registrationMode="scope">
|
||||
{{ scope.row.registrationMode }}
|
||||
{{ getRegistrationModeText(scope.row.registrationMode) }}
|
||||
</template>
|
||||
<template #orderStatus="scope">
|
||||
{{ scope.row.orderStatusText || scope.row.orderStatus }}
|
||||
{{ scope.row.orderStatusText || getOrderStatusText(scope.row.orderStatus) }}
|
||||
</template>
|
||||
<template #action="scope">
|
||||
<el-button size="small" text type="primary" @click="onOpenMenu(scope.row.id)">
|
||||
@ -49,11 +54,14 @@
|
||||
<script setup >
|
||||
import { ref, computed } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { Download } from '@element-plus/icons-vue';
|
||||
import ProTable from '/@/components/ProTable/index.vue';
|
||||
import { orderPageGet , orderDetailGet} from '/@/api/match/order';
|
||||
import { orderPageGet , orderDetailGet, orderExportGet } from '/@/api/match/order';
|
||||
|
||||
// 定义表单引用类型
|
||||
const formRef = ref();
|
||||
const tableRef = ref();
|
||||
const exportLoading = ref(false);
|
||||
|
||||
const formData = ref({
|
||||
orderNo: '',
|
||||
@ -104,6 +112,38 @@ const normalizeNames = (value) => {
|
||||
return '';
|
||||
};
|
||||
|
||||
const getRegistrationModeText = (value) => {
|
||||
const v = Number(value);
|
||||
if (v === 1) return '个人';
|
||||
if (v === 2) return '团队';
|
||||
return '-';
|
||||
};
|
||||
|
||||
const getOrderTypeText = (value) => {
|
||||
const v = Number(value);
|
||||
if (v === 1) return '收款';
|
||||
if (v === 2) return '退款';
|
||||
return '-';
|
||||
};
|
||||
|
||||
const getPaymentMethodText = (value) => {
|
||||
const v = Number(value);
|
||||
if (v === 1) return '线上';
|
||||
if (v === 2) return '线下';
|
||||
return '-';
|
||||
};
|
||||
|
||||
const getOrderStatusText = (value) => {
|
||||
const v = Number(value);
|
||||
if (v === 0) return '待支付';
|
||||
if (v === 1) return '已支付';
|
||||
if (v === 2) return '已取消';
|
||||
if (v === 3) return '已退款';
|
||||
if (v === 4) return '已发货';
|
||||
if (v === 5) return '已完成';
|
||||
return '-';
|
||||
};
|
||||
|
||||
const detailTableData = computed(() => {
|
||||
const items = formData.value?.items ?? [];
|
||||
const persons = formData.value?.persons ?? [];
|
||||
@ -147,6 +187,35 @@ const onOpenMenu = async(id) => {
|
||||
isShowDialog.value = true;
|
||||
};
|
||||
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
exportLoading.value = true;
|
||||
|
||||
const searchParams = tableRef.value?.searchParam || {};
|
||||
|
||||
const response = await orderExportGet(searchParams);
|
||||
|
||||
const blob = new Blob([response], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
});
|
||||
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `订单列表_${new Date().getTime()}.xlsx`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
ElMessage.success('导出成功');
|
||||
} catch (error) {
|
||||
console.error('导出失败:', error);
|
||||
ElMessage.error('导出失败,请稍后重试');
|
||||
} finally {
|
||||
exportLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@ -25,11 +25,35 @@
|
||||
</template>
|
||||
|
||||
<template #registrationStartTime="scope">
|
||||
{{ formatRange(scope.row.registrationStartTime, scope.row.registrationEndTime) }}
|
||||
<div class="time-range-display">
|
||||
<div class="time-item">
|
||||
<span class="time-label">开始</span>
|
||||
<span class="time-value">{{ formatDateTime(scope.row.registrationStartTime) }}</span>
|
||||
</div>
|
||||
<div class="time-separator">
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</div>
|
||||
<div class="time-item">
|
||||
<span class="time-label">结束</span>
|
||||
<span class="time-value">{{ formatDateTime(scope.row.registrationEndTime) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #matchStartTime="scope">
|
||||
{{ formatRange(scope.row.matchStartTime, scope.row.matchEndTime) }}
|
||||
<div class="time-range-display">
|
||||
<div class="time-item">
|
||||
<span class="time-label">开始</span>
|
||||
<span class="time-value">{{ formatDateTime(scope.row.matchStartTime) }}</span>
|
||||
</div>
|
||||
<div class="time-separator">
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</div>
|
||||
<div class="time-item">
|
||||
<span class="time-label">结束</span>
|
||||
<span class="time-value">{{ formatDateTime(scope.row.matchEndTime) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #action="scope">
|
||||
@ -70,6 +94,21 @@
|
||||
<!-- 赛事报名三步弹窗 -->
|
||||
<el-dialog title="赛事报名" v-model="isShowRegisterDialog" width="900px" :close-on-click-modal="false"
|
||||
@closed="clearRegisterState">
|
||||
<!-- 规则提示 -->
|
||||
<el-alert
|
||||
title="报名规则"
|
||||
type="info"
|
||||
:closable="false"
|
||||
style="margin-bottom: 20px;"
|
||||
show-icon
|
||||
>
|
||||
<template #default>
|
||||
<ul style="margin: 0; padding-left: 20px;">
|
||||
<li>一次报名操作仅允许选择并提交<strong>单个团队</strong>内的运动员</li>
|
||||
<li>该团队只能报名参与<strong>一个项目</strong></li>
|
||||
</ul>
|
||||
</template>
|
||||
</el-alert>
|
||||
<el-steps :active="activeStep" finish-status="success" align-center>
|
||||
<el-step title="选择报名项目" />
|
||||
<el-step title="分配队员" />
|
||||
@ -244,7 +283,7 @@
|
||||
<!-- 队伍数量限制提示 -->
|
||||
<el-alert
|
||||
v-if="showTeamLimitHint"
|
||||
title="若管理后台配置一个组别只能限报2队,添加2队后,“添加”按钮隐藏"
|
||||
title="若管理后台配置一个组别只能限报2队,添加2队后,"添加"按钮隐藏"
|
||||
type="info"
|
||||
:closable="false"
|
||||
style="margin-bottom: 12px;"
|
||||
@ -402,7 +441,7 @@
|
||||
<script setup>
|
||||
import { ref, computed, nextTick, onUnmounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { Close, Picture, Loading, CircleCheck } from '@element-plus/icons-vue';
|
||||
import { Close, Picture, Loading, CircleCheck, ArrowRight } from '@element-plus/icons-vue';
|
||||
import ProTable from '/@/components/ProTable/index.vue';
|
||||
import { formatDate } from '/@/utils/formatTime';
|
||||
import {
|
||||
@ -417,6 +456,7 @@ import {
|
||||
usereventregistrationRegistrationLimitCheckPost,
|
||||
usereventregistrationGroupTeamLimitGet,
|
||||
usereventregistrationProjectCompletionCheckPost,
|
||||
usereventregistrationOrderStatusGet,
|
||||
} from '/@/api/match/usereventregistration';
|
||||
import { teamPageGet, teamDetailGet } from '/@/api/match/unitUser';
|
||||
import QRCode from 'qrcodejs2-fixes';
|
||||
@ -442,8 +482,8 @@ const columns = ref([
|
||||
{ prop: 'registrationType', label: '报名方式', align: 'center', width: 120 },
|
||||
{ prop: 'chargeMode', label: '收费模式', align: 'center', width: 120 },
|
||||
{ prop: 'status', label: '赛事状态', align: 'center', width: 120 },
|
||||
{ prop: 'registrationStartTime', label: '报名起止时间', align: 'center', minWidth: 220 },
|
||||
{ prop: 'matchStartTime', label: '比赛起止时间', align: 'center', minWidth: 220 },
|
||||
{ prop: 'registrationStartTime', label: '报名起止时间', align: 'center', minWidth: 320 },
|
||||
{ prop: 'matchStartTime', label: '比赛起止时间', align: 'center', minWidth: 320 },
|
||||
{ prop: 'action', label: '操作', align: 'center', fixed: 'right', width: 210 },
|
||||
]);
|
||||
|
||||
@ -766,6 +806,15 @@ const toggleGroupSelection = (id) => {
|
||||
if (idx >= 0) {
|
||||
selectedGroupIds.value.splice(idx, 1);
|
||||
} else {
|
||||
// 检查是否已经选择了其他项目的组别
|
||||
const groupToAdd = allGroups.value.find(g => g.id === id);
|
||||
if (groupToAdd && selectedGroupIds.value.length > 0) {
|
||||
const existingProjectId = allGroups.value.find(g => g.id === selectedGroupIds.value[0])?.projectId;
|
||||
if (groupToAdd.projectId !== existingProjectId) {
|
||||
ElMessage.warning('一次报名只能选择一个项目,请先取消已选择的项目');
|
||||
return;
|
||||
}
|
||||
}
|
||||
selectedGroupIds.value.push(id);
|
||||
}
|
||||
};
|
||||
@ -811,6 +860,7 @@ const teamMembers = ref([]);
|
||||
const teamMemberLoading = ref(false);
|
||||
const activeAssignGroupId = ref(null); // 当前正在分配队员的组别ID
|
||||
const groupMemberMap = ref({}); // { groupId: [member, ...] }
|
||||
const usedTeamId = ref(null); // 本次报名已使用的团队ID
|
||||
|
||||
const previewLoading = ref(false);
|
||||
const previewData = ref(null);
|
||||
@ -856,6 +906,7 @@ const clearRegisterState = () => {
|
||||
teamMemberLoading.value = false;
|
||||
activeAssignGroupId.value = null;
|
||||
groupMemberMap.value = {};
|
||||
usedTeamId.value = null;
|
||||
memberValidationMap.value = {};
|
||||
groupTeamLimitMap.value = {};
|
||||
memberRegistrationLimitMap.value = {};
|
||||
@ -889,6 +940,7 @@ const resetStep2AndBeyond = () => {
|
||||
teamMemberLoading.value = false;
|
||||
activeAssignGroupId.value = null;
|
||||
groupMemberMap.value = {};
|
||||
usedTeamId.value = null;
|
||||
previewData.value = null;
|
||||
previewLoading.value = false;
|
||||
draftRegistrationId.value = null;
|
||||
@ -947,6 +999,15 @@ const fetchTeamList = async () => {
|
||||
const onTeamChange = async (teamId) => {
|
||||
teamMembers.value = [];
|
||||
if (!teamId) return;
|
||||
|
||||
// 检查是否已经分配了其他团队的队员
|
||||
if (usedTeamId.value && usedTeamId.value !== teamId) {
|
||||
ElMessage.warning('本次报名已选择了其他团队的队员,请先移除已分配的队员');
|
||||
// 恢复到之前选择的团队
|
||||
selectedTeamId.value = usedTeamId.value;
|
||||
return;
|
||||
}
|
||||
|
||||
teamMemberLoading.value = true;
|
||||
try {
|
||||
const { succeeded, data } = await teamDetailGet(teamId);
|
||||
@ -960,6 +1021,7 @@ const onTeamChange = async (teamId) => {
|
||||
mobile: m.mobile ?? '',
|
||||
gender: m.gender ?? '',
|
||||
role: m.role ?? '',
|
||||
teamId: teamId, // 添加团队ID
|
||||
}));
|
||||
}
|
||||
} catch {
|
||||
@ -1065,6 +1127,12 @@ const assignMemberToActiveGroup = async (member) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查队员是否来自已选择的团队
|
||||
if (usedTeamId.value && member.teamId !== usedTeamId.value) {
|
||||
ElMessage.warning('本次报名只能选择同一个团队的队员');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取当前组别信息进行验证
|
||||
const group = selectedGroupItems.value.find(g => g.id === gId);
|
||||
if (group) {
|
||||
@ -1073,10 +1141,14 @@ const assignMemberToActiveGroup = async (member) => {
|
||||
ElMessage.warning(validation.message);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
groupMemberMap.value[gId].push({ ...member });
|
||||
// 设置已使用的团队
|
||||
if (!usedTeamId.value) {
|
||||
usedTeamId.value = member.teamId;
|
||||
}
|
||||
|
||||
groupMemberMap.value[gId].push({ ...member, teamId: member.teamId });
|
||||
// 实时检查项目完成人数和报名限制
|
||||
await checkProjectCompletion();
|
||||
await checkRegistrationLimit();
|
||||
@ -1086,6 +1158,17 @@ const assignMemberToActiveGroup = async (member) => {
|
||||
const removeMemberFromGroup = (groupId, memberId) => {
|
||||
if (!groupMemberMap.value[groupId]) return;
|
||||
groupMemberMap.value[groupId] = groupMemberMap.value[groupId].filter((m) => (m.userId ?? m.id) !== memberId);
|
||||
|
||||
// 检查是否还有队员,如果没有则重置已使用的团队
|
||||
let hasMembers = false;
|
||||
Object.values(groupMemberMap.value).forEach(members => {
|
||||
if (members.length > 0) {
|
||||
hasMembers = true;
|
||||
}
|
||||
});
|
||||
if (!hasMembers) {
|
||||
usedTeamId.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
// 验证优惠券
|
||||
@ -1368,17 +1451,11 @@ const startPolling = (orderNo) => {
|
||||
|
||||
pollingTimer = setInterval(async () => {
|
||||
try {
|
||||
// TODO: 调用后端接口查询支付状态
|
||||
// const { succeeded, data } = await usereventregistrationQueryPayStatusGet(orderNo);
|
||||
|
||||
// 暂时模拟支付成功(实际应该调用后端接口)
|
||||
// 这里应该根据实际返回的状态进行处理
|
||||
|
||||
// 模拟5秒后支付成功
|
||||
// if (data?.status === 'SUCCESS') {
|
||||
// stopPolling();
|
||||
// onPaymentSuccess();
|
||||
// }
|
||||
const { succeeded, data } = await usereventregistrationOrderStatusGet(orderNo);
|
||||
if (succeeded && data === 1) {
|
||||
stopPolling();
|
||||
onPaymentSuccess();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('查询支付状态失败:', error);
|
||||
}
|
||||
@ -1397,11 +1474,12 @@ const stopPolling = () => {
|
||||
|
||||
// 支付成功处理
|
||||
const onPaymentSuccess = () => {
|
||||
pollingStatus.value = '支付成功!';
|
||||
ElMessage.success('支付成功!报名已完成');
|
||||
initParam.value.refresh = !initParam.value.refresh;
|
||||
setTimeout(() => {
|
||||
isShowRegisterDialog.value = false;
|
||||
}, 1500);
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
// 取消支付
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user