diff --git a/src/views/match/manage/dialog.vue b/src/views/match/manage/dialog.vue index 7ec9af4..08e0f3d 100644 --- a/src/views/match/manage/dialog.vue +++ b/src/views/match/manage/dialog.vue @@ -296,13 +296,14 @@ const handleNext = async () => { // 处理提交 const handleSubmit = async () => { - if (!stepRef.value) return; + if (!stepRef.value || submitting.value) return; + successDialogVisible.value = false; + submitting.value = true; try { // 调用子组件的验证方法 const valid = await stepRef.value.validate(); if (valid) { - submitting.value = true; const b = formData.value.basicInfo; const rawProjects = formData.value.projectConfig?.projects ?? []; const projects = rawProjects.map((p) => { @@ -346,9 +347,8 @@ const handleSubmit = async () => { registrationLimit: formData.value.projectConfig?.registrationLimit, feeConfig: formData.value.feeConfig, }; - if (payload.id) await eventPut(payload); - else await eventPost(payload); - submitting.value = false; + const response = payload.id ? await eventPut(payload) : await eventPost(payload); + if (response?.statusCode !== 200) return; successDialogVisible.value = true; } else { ElMessage.warning('请完善当前步骤的信息'); @@ -356,6 +356,7 @@ const handleSubmit = async () => { } catch (error) { console.error('提交失败:', error); ElMessage.error('提交失败,请重试'); + } finally { submitting.value = false; } }; diff --git a/src/views/scoring/orderbook/index.vue b/src/views/scoring/orderbook/index.vue index 9637195..bb075c8 100644 --- a/src/views/scoring/orderbook/index.vue +++ b/src/views/scoring/orderbook/index.vue @@ -4,11 +4,11 @@ 1下载模板2上传解析3确认导入 - 下载秩序册模板选择 Excel 文件{{ file.name }}上传并解析 + 下载秩序册模板选择 Excel 文件{{ file.name }}上传并解析 总行数{{result.totalRows}}有效行{{result.validRows}}场次{{result.preview?.sessionCount||0}}出场记录{{result.preview?.entryCount||0}}裁判{{result.preview?.refereeCount||0}}错误 / 警告{{result.errorCount}} / {{result.warningCount}} - {{row.level==='error'?'错误':'警告'}} - 请修正错误后重新上传,存在错误时不能确认导入。解析通过,确认后将生成场地、场次、出场记录及裁判数据。确认导入 + {{row.level==='error'?'错误':'警告'}} + {{confirmError}}请修正错误后重新上传,存在错误时不能确认导入。解析通过,确认后将生成场地、场次、出场记录及裁判数据。确认导入 @@ -30,15 +30,52 @@ onMounted(() => { const currentEvent=resolveScoringEvent(route.query); const eventId=ref(currentEvent.eventId),eventName=ref(currentEvent.eventName); const file=ref(null),result=ref(null),parsing=ref(false),confirming=ref(false); +const confirmError = ref(''); +let operationVersion = 0; if(!eventId.value)router.replace({path:'/scoring/launcher',query:{selectEvent:'1'}}); function changeEvent(){router.push({path:'/scoring/launcher',query:{selectEvent:'1'}})} -function syncEvent(){const next=resolveScoringEvent(route.query);eventId.value=next.eventId;eventName.value=next.eventName;file.value=null;result.value=null} +function syncEvent(){const next=resolveScoringEvent(route.query);eventId.value=next.eventId;eventName.value=next.eventName;file.value=null;result.value=null;confirmError.value='';operationVersion++} watch(()=>[route.query.eventId,route.query.eventName],syncEvent); -function selectFile(uploadFile){file.value=uploadFile.raw;result.value=null} +function selectFile(uploadFile){file.value=uploadFile.raw;result.value=null;confirmError.value='';operationVersion++} function saveBlob(blob,name){const url=URL.createObjectURL(blob);const a=document.createElement('a');a.href=url;a.download=name;document.body.appendChild(a);a.click();a.remove();URL.revokeObjectURL(url)} async function downloadTemplate(){saveBlob(await orderBookTemplateGet(),'秩序册导入模板.xlsx')} -async function parseFile(){parsing.value=true;try{const res=await orderBookImportPost(eventId.value,file.value);result.value=res?.data||null;if(result.value)ElMessage.success(result.value.errorCount?'解析完成,请处理错误项':'解析通过,请确认导入')}finally{parsing.value=false}} -async function confirmImport(){await ElMessageBox.confirm('确认导入当前秩序册?本次导入将覆盖原有编排,并清除旧场次的裁判分配;导入后可直接配置检录员。','确认导入',{type:'warning'});confirming.value=true;try{const res=await orderBookConfirmPost(result.value.batchId);ElMessage.success(`导入完成:${res?.data?.entryCount||0} 条出场记录`);result.value=null;file.value=null}finally{confirming.value=false}} + +async function parseFile() { + if (!file.value || !eventId.value || parsing.value || confirming.value) return; + const version = ++operationVersion; + result.value = null; confirmError.value = ''; parsing.value = true; + try { + const res = await orderBookImportPost(eventId.value, file.value); + if (version !== operationVersion || res?.statusCode !== 200) return; + result.value = res.data || null; + if (!result.value) return; + if (result.value.errorCount > 0 || result.value.status === 20) ElMessage.warning('解析完成,请处理错误项后重新上传'); + else ElMessage.success('解析通过,请确认导入'); + } catch (error) { + console.error('秩序册解析失败', error); // 请求拦截器负责提示,保留文件供重试。 + } finally { parsing.value = false; } +} + +async function confirmImport() { + if (parsing.value || confirming.value || confirmError.value || result.value?.status !== 10 || result.value.errorCount > 0) return; + const version = operationVersion, batchId = result.value.batchId; + confirming.value = true; + try { + await ElMessageBox.confirm('确认导入当前秩序册?本次导入将覆盖原有编排,并清除旧场次的裁判分配;导入后可直接配置检录员。', '确认导入', { type: 'warning' }); + if (version !== operationVersion) return; + const res = await orderBookConfirmPost(batchId); + if (version !== operationVersion) return; + if (res?.statusCode !== 200 || !res.data) { + confirmError.value = '确认导入失败,请根据错误提示处理后重新上传并解析。'; + return; + } + ElMessage.success('导入完成:' + res.data.entryCount + ' 条出场记录'); + result.value = null; file.value = null; + } catch (error) { + if (error !== 'cancel' && error !== 'close' && version === operationVersion) + confirmError.value = '确认导入未完成,请核实结果后重新上传并解析。'; + } finally { confirming.value = false; } +}