From 7ad9c3c93f0cc103347ae2e2429e0122fb512e24 Mon Sep 17 00:00:00 2001 From: lrj <owen.stl@gmail.com> Date: 星期三, 01 十月 2025 21:26:12 +0800 Subject: [PATCH] feat: 修复员工管理功能并优化UI --- web/src/views/ActivityForm.vue | 225 ++++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 152 insertions(+), 73 deletions(-) diff --git a/web/src/views/ActivityForm.vue b/web/src/views/ActivityForm.vue index 3425b07..4e6d7d3 100644 --- a/web/src/views/ActivityForm.vue +++ b/web/src/views/ActivityForm.vue @@ -79,7 +79,10 @@ </el-form-item> <!-- 鍥剧墖/瑙嗛涓婁紶 --> - <el-divider content-position="left">鍥剧墖/瑙嗛</el-divider> + <el-divider content-position="left"> + 鍥剧墖/瑙嗛 + <span class="media-description">鏀寔jpg/png/mp4锛屾渶澶�3涓枃浠�</span> + </el-divider> <el-form-item label="濯掍綋鏂囦欢"> <div class="media-upload-section"> @@ -109,7 +112,7 @@ <!-- 娣诲姞鎸夐挳 --> <el-upload v-if="form.mediaFiles.length < 3" - class="media-uploader" + class="media-uploader media-uploader-left" :show-file-list="false" :before-upload="beforeMediaUpload" action="#" @@ -120,7 +123,6 @@ <div class="upload-placeholder"> <el-icon class="upload-icon"><Plus /></el-icon> <div class="upload-text">娣诲姞鍥剧墖/瑙嗛</div> - <div class="upload-tip">鏀寔jpg/png/mp4锛屾渶澶�3涓枃浠�</div> </div> </el-upload> </div> @@ -141,7 +143,7 @@ </div> </div> - <div v-if="form.stages && form.stages.length > 0" class="stages-list"> + <div v-if="form.value && form.value.stages && form.value.stages.length > 0" class="stages-list"> <div v-for="(stage, index) in sortedFormStages" :key="index" class="stage-item"> <div class="stage-info"> <div class="stage-header"> @@ -191,9 +193,8 @@ </el-tag> </template> </el-table-column> - <el-table-column label="鎿嶄綔" width="180" align="center"> + <el-table-column label="鎿嶄綔" width="100" align="center"> <template #default="{ row, $index }"> - <el-button size="small" @click="editJudge(row, $index)">缂栬緫</el-button> <el-button size="small" type="danger" @click="removeJudge($index)">鍒犻櫎</el-button> </template> </el-table-column> @@ -321,14 +322,16 @@ <!-- 闃舵閫夋嫨 --> <div style="margin-bottom: 16px;"> - <el-form-item label="娣诲姞鍒伴樁娈碉細" label-width="100px"> - <el-select v-model="selectedStageOption" style="width: 100%;" @change="handleStageChange"> - <!-- 鍙樉绀烘瘮璧涢樁娈� --> + <el-form-item label="璐熻矗闃舵锛�" label-width="100px"> + <!-- 璋冭瘯淇℃伅 --> + + <el-select v-model="selectedStageOptions" multiple style="width: 100%;" placeholder="璇烽�夋嫨璐熻矗鐨勯樁娈�"> + <!-- 浣跨敤璁$畻灞炴�� --> <el-option - v-for="stage in form.stages" - :key="stage.id" - :label="stage.name" - :value="stage.id ? stage.id.toString() : ''" + v-for="option in stageOptions" + :key="option.value" + :label="option.label" + :value="option.value" /> </el-select> </el-form-item> @@ -393,7 +396,7 @@ <el-select v-model="currentStudent.lastStageId" placeholder="璇烽�夋嫨闃舵" style="width: 100%"> <el-option label="鏃�" :value="null" /> <el-option - v-for="stage in form.stages" + v-for="stage in (form.value?.stages || [])" :key="stage.id" :label="stage.name" :value="stage.id" @@ -413,7 +416,7 @@ </template> <script setup> -import { ref, onMounted, computed } from 'vue' +import { ref, onMounted, computed, nextTick } from 'vue' import { useRouter, useRoute } from 'vue-router' import { ElMessage, ElMessageBox } from 'element-plus' import { Plus, VideoPlay, Clock, User, UserFilled, Search } from '@element-plus/icons-vue' @@ -466,7 +469,7 @@ // 璇勫閫夋嫨鐩稿叧 const allJudges = ref([]) const judgeSearchText = ref('') -const selectedStageOption = ref('all') +const selectedStageOptions = ref([]) const selectedJudges = ref([]) const judgeLoading = ref(false) @@ -521,6 +524,21 @@ }) }) +// 鐢ㄤ簬涓嬫媺妗嗙殑闃舵閫夐」 +const stageOptions = computed(() => { + if (!form.value?.stages) { + return [] + } + + return form.value.stages + .filter(stage => stage && stage.id != null) + .map(stage => ({ + label: stage.name, + value: stage.id.toString(), + stage: stage + })) +}) + // 琛ㄥ崟楠岃瘉瑙勫垯 const rules = { name: [ @@ -563,7 +581,6 @@ judgeLoading.value = true const judges = await getAllJudges() allJudges.value = judges || [] - console.log('鍔犺浇璇勫鍒楄〃鎴愬姛:', allJudges.value.length, '涓瘎濮�') } catch (error) { console.error('鍔犺浇璇勫鍒楄〃澶辫触:', error) ElMessage.error('鍔犺浇璇勫鍒楄〃澶辫触: ' + error.message) @@ -580,6 +597,7 @@ try { loading.value = true const activity = await getActivity(route.params.id) + if (activity) { form.value = { id: activity.id, @@ -599,12 +617,8 @@ // 鍔犺浇骞跺洖濉凡涓婁紶濯掍綋锛歵argetType=2 鍋囪涓衡�滄椿鍔ㄢ�濓紝濡備笉鍚岃璋冩暣 try { const medias = await getMediasByTarget(MediaTargetType.ACTIVITY, parseInt(activity.id)) - console.log('=== 鍔犺浇娲诲姩濯掍綋璋冭瘯淇℃伅 ===') - console.log('娲诲姩ID:', activity.id) - console.log('鑾峰彇鍒扮殑濯掍綋鏁版嵁:', medias) form.value.mediaFiles = (medias || []).map(m => { - console.log('澶勭悊濯掍綋鏂囦欢:', m) const isImage = (m.mediaType === 1) || (m.fileExt && ['jpg','jpeg','png','gif','webp'].includes(m.fileExt.toLowerCase())) const isVideo = (m.mediaType === 2) || (m.fileExt && ['mp4','mov','m4v','avi','mkv'].includes(m.fileExt.toLowerCase())) const mediaItem = { @@ -615,16 +629,14 @@ uploaded: true, // 鏍囪涓哄凡涓婁紶锛屼笉闇�瑕侀噸鏂颁笂浼� file: null // 宸蹭繚瀛樼殑鏂囦欢娌℃湁file瀵硅薄 } - console.log('杞崲鍚庣殑濯掍綋椤�:', mediaItem) return mediaItem }) - console.log('鏈�缁堢殑mediaFiles:', form.value.mediaFiles) - - // 璁剧疆闃舵鏁伴噺閫夋嫨鍣ㄧ殑鍊� - selectedStageCount.value = form.value.stages.length || 1 } catch (e) { console.error('鍔犺浇娲诲姩濯掍綋澶辫触:', e) } + + // 璁剧疆闃舵鏁伴噺閫夋嫨鍣ㄧ殑鍊� + selectedStageCount.value = (form.value && form.value.stages) ? form.value.stages.length || 1 : 1 } } catch (error) { console.error('鍔犺浇姣旇禌鏁版嵁澶辫触:', error) @@ -637,7 +649,7 @@ // 闃舵绠$悊 // 闃舵鏁伴噺鍙樺寲澶勭悊 const onStageCountChange = (count) => { - if (!count) return + if (!count || !form.value || !form.value.stages) return // 濡傛灉褰撳墠闃舵鏁伴噺灏戜簬閫夋嫨鐨勬暟閲忥紝鑷姩娣诲姞闃舵 while (form.value.stages.length < count) { @@ -672,6 +684,7 @@ // 鑾峰彇闃舵鍦ㄥ師濮嬫暟缁勪腑鐨勭储寮� const getOriginalStageIndex = (stage) => { + if (!form.value || !form.value.stages) return -1 return form.value.stages.findIndex(s => s === stage) } @@ -688,6 +701,8 @@ } const removeStage = async (index) => { + if (!form.value || !form.value.stages) return + try { await ElMessageBox.confirm('纭畾瑕佸垹闄よ繖涓樁娈靛悧锛�', '鎻愮ず', { confirmButtonText: '纭畾', @@ -725,6 +740,8 @@ } const saveStage = async () => { + if (!form.value || !form.value.stages) return + try { await stageFormRef.value.validate() @@ -787,6 +804,11 @@ } const removeJudge = async (index) => { + if (!form.value || !form.value.judges) { + ElMessage.error('琛ㄥ崟鏁版嵁鏈垵濮嬪寲') + return + } + try { await ElMessageBox.confirm('纭畾瑕佸垹闄よ繖涓瘎濮斿悧锛�', '鎻愮ず', { confirmButtonText: '纭畾', @@ -801,43 +823,40 @@ } const getJudgeStages = (judge) => { - if (!judge.stageIds) return [] + if (!judge.stageIds || !form.value || !form.value.stages) return [] const stages = [] - // 鍙鏌ユ瘮璧涢樁娈� - if (form.value.stages) { - const matchedStages = form.value.stages.filter(stage => judge.stageIds.includes(stage.id)) - matchedStages.forEach(stage => { + // 妫�鏌ユ瘮璧涢樁娈� + judge.stageIds.forEach(stageId => { + // 澶勭悊瀹為檯闃舵ID + const stage = form.value.stages.find(s => s.id === stageId) + if (stage) { stages.push({ id: stage.id, name: stage.name }) - }) - } + } + }) return stages } const resetJudgeDialog = () => { judgeSearchText.value = '' - // 榛樿閫夋嫨绗竴涓樁娈� - selectedStageOption.value = form.value.stages && form.value.stages.length > 0 - ? form.value.stages[0].id?.toString() || '' - : '' + // 娓呯┖闃舵閫夋嫨 + selectedStageOptions.value = [] selectedJudges.value = [] } const handleJudgeSearch = (value) => { - console.log('鎼滅储璇勫:', value) + // 鎼滅储璇勫 } -const handleStageChange = (value) => { - console.log('閫夋嫨闃舵:', value) -} + const handleJudgeSelectionChange = (value) => { - console.log('閫夋嫨璇勫:', value) + // 閫夋嫨璇勫 } const toggleSelectAll = () => { @@ -859,6 +878,17 @@ return } + if (!form.value || !form.value.judges) { + ElMessage.error('琛ㄥ崟鏁版嵁鏈垵濮嬪寲') + return + } + + // 濡傛灉鏈夐樁娈典絾娌℃湁閫夋嫨闃舵锛屽垯鎻愮ず + if (form.value && form.value.stages && form.value.stages.length > 0 && selectedStageOptions.value.length === 0) { + ElMessage.warning('璇烽�夋嫨鑷冲皯涓�涓礋璐i樁娈�') + return + } + let addedCount = 0 selectedJudges.value.forEach(judgeId => { @@ -867,14 +897,20 @@ // 妫�鏌ユ槸鍚﹀凡缁忓瓨鍦� const existingJudge = form.value.judges.find(j => j.id === judgeId) if (existingJudge) { - // 鏇存柊鐜版湁璇勫鐨勯樁娈� - const stageId = parseInt(selectedStageOption.value) - if (!existingJudge.stageIds.includes(stageId)) { - existingJudge.stageIds.push(stageId) + // 鏇存柊鐜版湁璇勫鐨勯樁娈碉紝鍚堝苟鏂伴�夋嫨鐨勯樁娈� + if (selectedStageOptions.value.length > 0) { + selectedStageOptions.value.forEach(stageId => { + const stageIdInt = parseInt(stageId) + if (!existingJudge.stageIds.includes(stageIdInt)) { + existingJudge.stageIds.push(stageIdInt) + } + }) } } else { - // 娣诲姞鏂拌瘎濮� - const stageIds = [parseInt(selectedStageOption.value)] + // 娣诲姞鏂拌瘎濮旓紝鍖呭惈鎵�鏈夐�夋嫨鐨勯樁娈� + const stageIds = selectedStageOptions.value.length > 0 + ? selectedStageOptions.value.map(id => parseInt(id)) + : [] const newJudge = { id: judge.id, @@ -886,6 +922,10 @@ } } }) + + // 娓呯┖閫夋嫨 + selectedJudges.value = [] + selectedStageOptions.value = [] judgeDialogVisible.value = false ElMessage.success(`鎴愬姛娣诲姞 ${addedCount} 涓瘎濮擿) @@ -940,7 +980,7 @@ } const getLastStage = (student) => { - if (!student.lastStageId || !form.value.stages) return '鏃�' + if (!student.lastStageId || !form.value || !form.value.stages) return '鏃�' const stage = form.value.stages.find(s => s.id === student.lastStageId) return stage ? stage.name : '鏃�' } @@ -985,13 +1025,17 @@ uploaded: false // 鏍囪涓烘湭涓婁紶 } - form.value.mediaFiles.push(mediaFile) - ElMessage.success('鏂囦欢宸查�夋嫨锛岀偣鍑绘洿鏂版寜閽椂灏嗕笂浼�') + if (form.value && form.value.mediaFiles) { + form.value.mediaFiles.push(mediaFile) + ElMessage.success('鏂囦欢宸查�夋嫨锛岀偣鍑绘洿鏂版寜閽椂灏嗕笂浼�') + } return false // 闃绘el-upload鐨勯粯璁や笂浼� } const beforeMediaUpload = (file) => { + if (!form.value || !form.value.mediaFiles) return false + if (form.value.mediaFiles.length >= 3) { ElMessage.error('鏈�澶氬彧鑳戒笂浼�3涓枃浠�!') return false @@ -1056,6 +1100,8 @@ // 澶勭悊濯掍綋鏂囦欢涓婁紶 const handleMediaUpload = async (activityId) => { + if (!form.value || !form.value.mediaFiles) return + try { for (const mediaFile of form.value.mediaFiles) { // 璺宠繃宸茬粡鏈� id 鐨勫獟浣撴枃浠讹紙宸蹭繚瀛樼殑锛� @@ -1074,10 +1120,8 @@ } try { - console.log('寮�濮嬩笂浼犳枃浠�:', mediaFile.name) // 1. 涓婁紶鏂囦欢鍒版湇鍔″櫒 const uploadResult = await uploadFile(mediaFile.file) - console.log('鏂囦欢涓婁紶鎴愬姛:', uploadResult) // 2. 淇濆瓨濯掍綋淇℃伅鍒版暟鎹簱 const mediaInput = { @@ -1089,11 +1133,7 @@ targetType: MediaTargetType.ACTIVITY, // 娲诲姩 targetId: parseInt(activityId) // 杞崲涓烘暟瀛楃被鍨� } - - console.log('鍑嗗淇濆瓨濯掍綋淇℃伅:', mediaInput) - console.log('娲诲姩ID:', activityId) const savedMedia = await saveMedia(mediaInput) - console.log(`濯掍綋鏂囦欢 ${mediaFile.name} 涓婁紶骞朵繚瀛樻垚鍔�:`, savedMedia) // 鏇存柊濯掍綋鏂囦欢淇℃伅 mediaFile.id = savedMedia.id @@ -1117,6 +1157,8 @@ // 鎻愪氦琛ㄥ崟 const handleSubmit = async () => { if (submitting.value) return + if (!form.value) return + try { await formRef.value.validate() @@ -1124,8 +1166,6 @@ // 鍑嗗淇濆瓨鏁版嵁锛屽彧鍖呭惈鍚庣鏀寔鐨勫瓧娈� const saveData = { - id: form.value.id, - pid: form.value.pid || 0, name: form.value.name, description: form.value.description, signupDeadline: form.value.signupDeadline, @@ -1134,22 +1174,41 @@ ratingSchemeId: form.value.ratingSchemeId, playerMax: form.value.playerMax, state: form.value.state || 1, - stages: form.value.stages ? form.value.stages.map(stage => ({ - id: stage.id, - name: stage.name, - description: stage.description, - matchTime: stage.matchTime, - 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 => ({ + stages: form.value.stages ? form.value.stages.map(stage => { + const stageData = { + name: stage.name, + description: stage.description, + matchTime: stage.matchTime, + address: stage.address, + playerMax: stage.playerMax, + sortOrder: stage.sortOrder, + state: stage.state || 1 + } + // 鍙湪鏈夋湁鏁圛D鏃舵墠娣诲姞id瀛楁 + if (stage.id) { + stageData.id = stage.id + } + // 鍙湪鏈夋湁鏁坮atingSchemeId鏃舵墠娣诲姞璇ュ瓧娈� + if (stage.ratingSchemeId) { + stageData.ratingSchemeId = stage.ratingSchemeId + } + return stageData + }) : [], + judges: form.value.judges ? form.value.judges.filter(judge => judge.id && judge.name).map(judge => ({ judgeId: judge.id, judgeName: judge.name, stageIds: judge.stageIds || [] })) : [] + } + + // 濡傛灉鏄紪杈戞ā寮忥紝娣诲姞id瀛楁 + if (isEdit.value && form.value.id) { + saveData.id = form.value.id + } + + // 濡傛灉鏈塸id锛屾坊鍔爌id瀛楁 + if (form.value.pid) { + saveData.pid = form.value.pid } const result = await saveActivity(saveData) @@ -1195,7 +1254,7 @@ await loadActivity() // 濡傛灉鏄柊寤烘ā寮忎笖娌℃湁闃舵锛岃嚜鍔ㄥ垱寤轰竴涓樁娈� - if (!isEdit.value && form.value.stages.length === 0) { + if (!isEdit.value && form.value && form.value.stages && form.value.stages.length === 0) { onStageCountChange(1) } }) @@ -1572,4 +1631,24 @@ flex: 1; padding-left: 8px; } + +/* 濯掍綋鎻忚堪鏂囨湰鏍峰紡 */ +.media-description { + font-size: 12px; + color: #909399; + font-weight: normal; + margin-left: 8px; +} + +/* 濯掍綋涓婁紶鎸夐挳 */ +.media-uploader-left { + margin-left: 16px; +} + +.media-container { + display: flex; + align-items: flex-start; + gap: 16px; + flex-wrap: wrap; +} </style> \ No newline at end of file -- Gitblit v1.8.0