From 93eb6b470773bc49ea6e1a9d4cbd914eb95d525b Mon Sep 17 00:00:00 2001 From: lrj <owen.stl@gmail.com> Date: 星期二, 30 九月 2025 17:38:04 +0800 Subject: [PATCH] feat: 完善比赛晋级功能并清理测试文件 --- web/src/views/ActivityForm.vue | 248 +++++++++++++++++++++++++++++++++---------------- 1 files changed, 166 insertions(+), 82 deletions(-) diff --git a/web/src/views/ActivityForm.vue b/web/src/views/ActivityForm.vue index 140c631..5cadcfc 100644 --- a/web/src/views/ActivityForm.vue +++ b/web/src/views/ActivityForm.vue @@ -65,19 +65,9 @@ </el-col> </el-row> - <el-row :gutter="20"> - <el-col :span="12"> - <el-form-item label="姣旇禌鍦板潃" prop="address"> - <el-input v-model="form.address" placeholder="璇疯緭鍏ユ瘮璧涘湴鍧�" /> - </el-form-item> - </el-col> - - <el-col :span="12"> - <el-form-item label="浜烘暟" prop="playerMax"> - <el-input-number v-model="form.playerMax" :min="1" :max="9999" style="width: 100%" /> - </el-form-item> - </el-col> - </el-row> + <el-form-item label="姣旇禌鍦板潃" prop="address"> + <el-input v-model="form.address" placeholder="璇疯緭鍏ユ瘮璧涘湴鍧�" /> + </el-form-item> <el-form-item label="姣旇禌鎻忚堪" prop="description"> <el-input @@ -146,35 +136,33 @@ <el-tab-pane label="姣旇禌闃舵" name="stages"> <div class="stages-header"> <span>姣旇禌闃舵</span> - <el-button size="small" type="primary" @click="addStage">娣诲姞闃舵</el-button> + <div class="stages-controls"> + <el-button size="small" type="primary" @click="addStage">娣诲姞闃舵</el-button> + </div> </div> <div v-if="form.stages && form.stages.length > 0" class="stages-list"> - <div v-for="(stage, index) in form.stages" :key="index" class="stage-item"> + <div v-for="(stage, index) in sortedFormStages" :key="index" class="stage-item"> <div class="stage-info"> - <div class="stage-name">{{ stage.name || '鏈懡鍚嶉樁娈�' }}</div> + <div class="stage-header"> + <span class="stage-order">{{ stage.sortOrder || '-' }}</span> + <span class="stage-name">{{ stage.name || '鏈懡鍚嶉樁娈�' }}</span> + </div> <div class="stage-details"> <span class="detail-item"> <el-icon><Clock /></el-icon> {{ formatDateTime(stage.matchTime) }} </span> - <span class="detail-item"> - <el-icon><User /></el-icon> - {{ stage.playerMax || 0 }} 浜� - </span> - <span class="detail-item"> - <el-icon><UserFilled /></el-icon> - 瀹為檯: {{ stage.actualPlayerCount || 0 }} 浜� - </span> + <el-tag :type="stage.state === 1 ? 'success' : 'info'" size="small"> {{ stage.state === 1 ? '杩涜涓�' : '鏈紑濮�' }} </el-tag> </div> </div> <div class="stage-actions"> - <el-button size="small" @click="editStage(stage, index)">缂栬緫</el-button> + <el-button size="small" @click="editStage(stage, getOriginalStageIndex(stage))">缂栬緫</el-button> <el-button size="small" @click="closeStage(stage)" v-if="stage.state === 1">鍏抽棴</el-button> - <el-button size="small" type="danger" @click="removeStage(index)">鍒犻櫎</el-button> + <el-button size="small" type="danger" @click="removeStage(getOriginalStageIndex(stage))">鍒犻櫎</el-button> </div> </div> </div> @@ -214,37 +202,7 @@ <el-empty v-if="!form.judges || form.judges.length === 0" description="鏆傛棤璇勫" /> </el-tab-pane> - <!-- 瀛﹀憳鍒楄〃 --> - <el-tab-pane label="瀛﹀憳鍒楄〃" name="students"> - <div class="students-header"> - <span>瀛﹀憳鍒楄〃</span> - </div> - - <el-table :data="form.students" style="width: 100%" border> - <el-table-column label="瀛﹀憳鍚嶇О" prop="name" /> - <el-table-column label="鏈�鍚庡弬涓庣殑姣旇禌闃舵" width="200"> - <template #default="{ row }"> - {{ getLastStage(row) }} - </template> - </el-table-column> - <el-table-column label="鎿嶄綔" width="250" align="center"> - <template #default="{ row, $index }"> - <el-button size="small" @click="viewStudent(row, $index)">鏌ョ湅</el-button> - <el-button size="small" type="primary" @click="rateStudent(row, $index)">璇勫垎</el-button> - <el-button size="small" @click="commentStudent(row, $index)">鐐硅瘎</el-button> - <el-button - size="small" - :type="row.isAdvanced ? 'success' : 'warning'" - @click="toggleAdvancement(row, $index)" - > - {{ row.isAdvanced ? '宸叉檵绾�' : '鏅嬬骇' }} - </el-button> - </template> - </el-table-column> - </el-table> - - <el-empty v-if="!form.students || form.students.length === 0" description="鏆傛棤瀛﹀憳" /> - </el-tab-pane> + </el-tabs> </div> @@ -274,6 +232,26 @@ <el-input v-model="currentStage.name" placeholder="璇疯緭鍏ラ樁娈靛悕绉�" maxlength="30" /> </el-form-item> + <el-form-item label="姣旇禌闃舵椤哄簭" prop="sortOrder"> + <el-select v-model="currentStage.sortOrder" placeholder="璇烽�夋嫨闃舵椤哄簭" style="width: 100%"> + <el-option label="1" :value="1" /> + <el-option label="2" :value="2" /> + <el-option label="3" :value="3" /> + <el-option label="4" :value="4" /> + <el-option label="5" :value="5" /> + </el-select> + </el-form-item> + + <el-form-item label="瀛﹀憳浜烘暟" prop="playerMax"> + <el-input-number + v-model="currentStage.playerMax" + :min="1" + :max="1000" + placeholder="璇疯緭鍏ュ鍛樹汉鏁�" + style="width: 100%" + /> + </el-form-item> + <el-form-item label="璇勫垎妯℃澘"> <el-select v-model="currentStage.ratingSchemeId" placeholder="缁ф壙姣旇禌妯℃澘" style="width: 100%"> <el-option label="缁ф壙姣旇禌妯℃澘" :value="null" /> @@ -299,10 +277,6 @@ <el-form-item label="闃舵鍦板潃"> <el-input v-model="currentStage.address" placeholder="璇疯緭鍏ラ樁娈靛湴鍧�" /> - </el-form-item> - - <el-form-item label="浜烘暟"> - <el-input-number v-model="currentStage.playerMax" :min="1" :max="9999" style="width: 100%" /> </el-form-item> <el-form-item label="闃舵鎻忚堪"> @@ -349,7 +323,7 @@ <div style="margin-bottom: 16px;"> <el-form-item label="娣诲姞鍒伴樁娈碉細" label-width="100px"> <el-select v-model="selectedStageOption" style="width: 100%;" @change="handleStageChange"> - <el-option label="鎵�鏈夐樁娈�" value="all" /> + <!-- 鍙樉绀烘瘮璧涢樁娈� --> <el-option v-for="stage in form.stages" :key="stage.id" @@ -462,6 +436,9 @@ // Tab鐩稿叧 const activeTab = ref('stages') +// 闃舵鏁伴噺閫夋嫨 +const selectedStageCount = ref(1) + // 闃舵缂栬緫寮圭獥鐩稿叧 const stageDialogVisible = ref(false) const currentStageIndex = ref(-1) @@ -472,7 +449,6 @@ matchTime: '', address: '', ratingSchemeId: null, - playerMax: null, state: 1, actualPlayerCount: 0 }) @@ -524,7 +500,7 @@ matchTime: '', address: '', ratingSchemeId: null, - playerMax: 100, + playerMax: null, state: 1, stages: [], judges: [], @@ -534,6 +510,16 @@ // 璁$畻灞炴�� const isEdit = computed(() => !!route.params.id) + +// 鎸塻ortOrder鎺掑簭鐨勯樁娈靛垪琛� +const sortedFormStages = computed(() => { + if (!form.value.stages) return [] + return [...form.value.stages].sort((a, b) => { + const orderA = a.sortOrder || 999 + const orderB = b.sortOrder || 999 + return orderA - orderB + }) +}) // 琛ㄥ崟楠岃瘉瑙勫垯 const rules = { @@ -553,6 +539,10 @@ name: [ { required: true, message: '璇疯緭鍏ラ樁娈靛悕绉�', trigger: 'blur' }, { max: 30, message: '闃舵鍚嶇О涓嶈兘瓒呰繃30涓瓧绗�', trigger: 'blur' } + ], + playerMax: [ + { required: true, message: '璇疯緭鍏ュ鍛樹汉鏁�', trigger: 'blur' }, + { type: 'number', min: 1, max: 1000, message: '瀛﹀憳浜烘暟蹇呴』鍦�1-1000涔嬮棿', trigger: 'blur' } ] } @@ -599,7 +589,7 @@ matchTime: activity.matchTime || '', address: activity.address || '', ratingSchemeId: activity.ratingSchemeId, - playerMax: activity.playerMax || 100, + playerMax: activity.playerMax, state: activity.state, stages: activity.stages || [], judges: activity.judges || [], @@ -629,6 +619,9 @@ return mediaItem }) console.log('鏈�缁堢殑mediaFiles:', form.value.mediaFiles) + + // 璁剧疆闃舵鏁伴噺閫夋嫨鍣ㄧ殑鍊� + selectedStageCount.value = form.value.stages.length || 1 } catch (e) { console.error('鍔犺浇娲诲姩濯掍綋澶辫触:', e) } @@ -642,6 +635,45 @@ } // 闃舵绠$悊 +// 闃舵鏁伴噺鍙樺寲澶勭悊 +const onStageCountChange = (count) => { + if (!count) return + + // 濡傛灉褰撳墠闃舵鏁伴噺灏戜簬閫夋嫨鐨勬暟閲忥紝鑷姩娣诲姞闃舵 + while (form.value.stages.length < count) { + const stageIndex = form.value.stages.length + 1 + form.value.stages.push({ + id: null, + name: getDefaultStageName(stageIndex), + description: '', + matchTime: '', + address: form.value.address || '', + ratingSchemeId: form.value.ratingSchemeId, + sortOrder: stageIndex, + state: 1, + actualPlayerCount: 0 + }) + } + + // 濡傛灉褰撳墠闃舵鏁伴噺澶氫簬閫夋嫨鐨勬暟閲忥紝鍒犻櫎澶氫綑鐨勯樁娈� + if (form.value.stages.length > count) { + form.value.stages = form.value.stages.slice(0, count) + } + + ElMessage.success(`宸茶缃负${count}涓樁娈礰) +} + +// 鑾峰彇榛樿闃舵鍚嶇О +const getDefaultStageName = (index) => { + const stageNames = ['', '娴烽��', '澶嶈禌', '鍗婂喅璧�', '鍐宠禌', '鎬诲喅璧�'] + return stageNames[index] || `绗�${index}闃舵` +} + +// 鑾峰彇闃舵鍦ㄥ師濮嬫暟缁勪腑鐨勭储寮� +const getOriginalStageIndex = (stage) => { + return form.value.stages.findIndex(s => s === stage) +} + const addStage = () => { currentStageIndex.value = -1 resetStageForm() @@ -662,6 +694,15 @@ type: 'warning' }) form.value.stages.splice(index, 1) + + // 閲嶆柊鎺掑簭sortOrder + form.value.stages.forEach((stage, idx) => { + stage.sortOrder = idx + 1 + }) + + // 鏇存柊閫夋嫨鐨勯樁娈垫暟閲� + selectedStageCount.value = form.value.stages.length + ElMessage.success('鍒犻櫎鎴愬姛') } catch { // 鐢ㄦ埛鍙栨秷鍒犻櫎 @@ -687,8 +728,10 @@ await stageFormRef.value.validate() if (currentStageIndex.value === -1) { - // 鏂板闃舵 - form.value.stages.push({ ...currentStage.value }) + // 鏂板闃舵 - 璁剧疆姝g‘鐨剆ortOrder + const newStage = { ...currentStage.value } + newStage.sortOrder = form.value.stages.length + 1 + form.value.stages.push(newStage) } else { // 缂栬緫闃舵 form.value.stages[currentStageIndex.value] = { ...currentStage.value } @@ -710,6 +753,7 @@ address: '', ratingSchemeId: null, playerMax: null, + sortOrder: null, // 灏嗗湪saveStage涓缃纭殑鍊� state: 1, actualPlayerCount: 0 } @@ -756,13 +800,30 @@ } const getJudgeStages = (judge) => { - if (!judge.stageIds || !form.value.stages) return [] - return form.value.stages.filter(stage => judge.stageIds.includes(stage.id)) + if (!judge.stageIds) return [] + + const stages = [] + + // 鍙鏌ユ瘮璧涢樁娈� + if (form.value.stages) { + const matchedStages = form.value.stages.filter(stage => judge.stageIds.includes(stage.id)) + matchedStages.forEach(stage => { + stages.push({ + id: stage.id, + name: stage.name + }) + }) + } + + return stages } const resetJudgeDialog = () => { judgeSearchText.value = '' - selectedStageOption.value = 'all' + // 榛樿閫夋嫨绗竴涓樁娈� + selectedStageOption.value = form.value.stages && form.value.stages.length > 0 + ? form.value.stages[0].id?.toString() || '' + : '' selectedJudges.value = [] } @@ -806,22 +867,18 @@ const existingJudge = form.value.judges.find(j => j.id === judgeId) if (existingJudge) { // 鏇存柊鐜版湁璇勫鐨勯樁娈� - if (selectedStageOption.value === 'all') { - existingJudge.stageIds = form.value.stages.map(s => s.id).filter(id => id != null) - } else { - const stageId = parseInt(selectedStageOption.value) - if (!existingJudge.stageIds.includes(stageId)) { - existingJudge.stageIds.push(stageId) - } + const stageId = parseInt(selectedStageOption.value) + if (!existingJudge.stageIds.includes(stageId)) { + existingJudge.stageIds.push(stageId) } } else { // 娣诲姞鏂拌瘎濮� + const stageIds = [parseInt(selectedStageOption.value)] + const newJudge = { id: judge.id, name: judge.name, - stageIds: selectedStageOption.value === 'all' - ? form.value.stages.map(s => s.id).filter(id => id != null) - : [parseInt(selectedStageOption.value)] + stageIds: stageIds } form.value.judges.push(newJudge) addedCount++ @@ -1084,6 +1141,7 @@ address: stage.address, ratingSchemeId: stage.ratingSchemeId, playerMax: stage.playerMax, + sortOrder: stage.sortOrder, state: stage.state || 1 })) : [], judges: form.value.judges ? form.value.judges.map(judge => ({ @@ -1134,6 +1192,11 @@ await loadRatingSchemes() await loadAllJudges() await loadActivity() + + // 濡傛灉鏄柊寤烘ā寮忎笖娌℃湁闃舵锛岃嚜鍔ㄥ垱寤轰竴涓樁娈� + if (!isEdit.value && form.value.stages.length === 0) { + onStageCountChange(1) + } }) </script> @@ -1169,7 +1232,7 @@ .stage-header { display: flex; - justify-content: space-between; + justify-content: flex-start; align-items: center; } @@ -1271,11 +1334,32 @@ flex: 1; } +.stage-header { + display: flex; + align-items: center; + margin-bottom: 8px; +} + +.stage-order { + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + background-color: #409eff; + color: white; + border-radius: 50%; + font-size: 12px; + font-weight: 600; + flex-shrink: 0; +} + .stage-name { font-size: 16px; font-weight: 500; color: #303133; - margin-bottom: 8px; + margin: 0; + margin-left: 4px; } .stage-details { -- Gitblit v1.8.0