| | |
| | | </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 |
| | |
| | | </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"> |
| | |
| | | <!-- 添加按钮 --> |
| | | <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="#" |
| | |
| | | <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> |
| | |
| | | <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-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-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> |
| | |
| | | </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> |
| | |
| | | <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> |
| | | |
| | |
| | | <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" /> |
| | |
| | | |
| | | <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="阶段描述"> |
| | |
| | | |
| | | <!-- 阶段选择 --> |
| | | <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-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> |
| | |
| | | <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" |
| | |
| | | </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' |
| | |
| | | // Tab相关 |
| | | const activeTab = ref('stages') |
| | | |
| | | // 阶段数量选择 |
| | | const selectedStageCount = ref(1) |
| | | |
| | | // 阶段编辑弹窗相关 |
| | | const stageDialogVisible = ref(false) |
| | | const currentStageIndex = ref(-1) |
| | |
| | | matchTime: '', |
| | | address: '', |
| | | ratingSchemeId: null, |
| | | playerMax: null, |
| | | state: 1, |
| | | actualPlayerCount: 0 |
| | | }) |
| | |
| | | // 评委选择相关 |
| | | const allJudges = ref([]) |
| | | const judgeSearchText = ref('') |
| | | const selectedStageOption = ref('all') |
| | | const selectedStageOptions = ref([]) |
| | | const selectedJudges = ref([]) |
| | | const judgeLoading = ref(false) |
| | | |
| | |
| | | matchTime: '', |
| | | address: '', |
| | | ratingSchemeId: null, |
| | | playerMax: 100, |
| | | playerMax: null, |
| | | state: 1, |
| | | stages: [], |
| | | judges: [], |
| | |
| | | |
| | | // 计算属性 |
| | | const isEdit = computed(() => !!route.params.id) |
| | | |
| | | // 按sortOrder排序的阶段列表 |
| | | 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 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: [ |
| | | { 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' } |
| | | ] |
| | | } |
| | | |
| | |
| | | judgeLoading.value = true |
| | | const judges = await getAllJudges() |
| | | allJudges.value = judges || [] |
| | | console.log('加载评委列表成功:', allJudges.value.length, '个评委') |
| | | } catch (error) { |
| | | console.error('加载评委列表失败:', error) |
| | | ElMessage.error('加载评委列表失败: ' + error.message) |
| | |
| | | try { |
| | | loading.value = true |
| | | const activity = await getActivity(route.params.id) |
| | | |
| | | if (activity) { |
| | | form.value = { |
| | | id: activity.id, |
| | |
| | | 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 || [], |
| | |
| | | // 加载并回填已上传媒体:targetType=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 = { |
| | |
| | | uploaded: true, // 标记为已上传,不需要重新上传 |
| | | file: null // 已保存的文件没有file对象 |
| | | } |
| | | console.log('转换后的媒体项:', mediaItem) |
| | | return mediaItem |
| | | }) |
| | | console.log('最终的mediaFiles:', form.value.mediaFiles) |
| | | } catch (e) { |
| | | console.error('加载活动媒体失败:', e) |
| | | } |
| | | |
| | | // 设置阶段数量选择器的值 |
| | | selectedStageCount.value = (form.value && form.value.stages) ? form.value.stages.length || 1 : 1 |
| | | } |
| | | } catch (error) { |
| | | console.error('加载比赛数据失败:', error) |
| | |
| | | } |
| | | |
| | | // 阶段管理 |
| | | // 阶段数量变化处理 |
| | | const onStageCountChange = (count) => { |
| | | if (!count || !form.value || !form.value.stages) 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 suggestedNames = ['', '第一阶段', '第二阶段', '第三阶段', '第四阶段', '第五阶段'] |
| | | return suggestedNames[index] || `第${index}阶段` |
| | | } |
| | | |
| | | // 获取阶段在原始数组中的索引 |
| | | const getOriginalStageIndex = (stage) => { |
| | | if (!form.value || !form.value.stages) return -1 |
| | | return form.value.stages.findIndex(s => s === stage) |
| | | } |
| | | |
| | | const addStage = () => { |
| | | currentStageIndex.value = -1 |
| | | resetStageForm() |
| | |
| | | } |
| | | |
| | | const removeStage = async (index) => { |
| | | if (!form.value || !form.value.stages) return |
| | | |
| | | try { |
| | | await ElMessageBox.confirm('确定要删除这个阶段吗?', '提示', { |
| | | confirmButtonText: '确定', |
| | |
| | | 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 { |
| | | // 用户取消删除 |
| | |
| | | } |
| | | |
| | | const saveStage = async () => { |
| | | if (!form.value || !form.value.stages) return |
| | | |
| | | try { |
| | | await stageFormRef.value.validate() |
| | | |
| | | if (currentStageIndex.value === -1) { |
| | | // 新增阶段 |
| | | form.value.stages.push({ ...currentStage.value }) |
| | | // 新增阶段 - 设置正确的sortOrder |
| | | const newStage = { ...currentStage.value } |
| | | newStage.sortOrder = form.value.stages.length + 1 |
| | | form.value.stages.push(newStage) |
| | | } else { |
| | | // 编辑阶段 |
| | | form.value.stages[currentStageIndex.value] = { ...currentStage.value } |
| | |
| | | address: '', |
| | | ratingSchemeId: null, |
| | | playerMax: null, |
| | | sortOrder: null, // 将在saveStage中设置正确的值 |
| | | state: 1, |
| | | actualPlayerCount: 0 |
| | | } |
| | |
| | | } |
| | | |
| | | const removeJudge = async (index) => { |
| | | if (!form.value || !form.value.judges) { |
| | | ElMessage.error('表单数据未初始化') |
| | | return |
| | | } |
| | | |
| | | try { |
| | | await ElMessageBox.confirm('确定要删除这个评委吗?', '提示', { |
| | | confirmButtonText: '确定', |
| | |
| | | } |
| | | |
| | | const getJudgeStages = (judge) => { |
| | | if (!judge.stageIds || !form.value.stages) return [] |
| | | return form.value.stages.filter(stage => judge.stageIds.includes(stage.id)) |
| | | if (!judge.stageIds || !form.value || !form.value.stages) return [] |
| | | |
| | | const stages = [] |
| | | |
| | | // 检查比赛阶段 |
| | | 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 = 'all' |
| | | // 清空阶段选择 |
| | | selectedStageOptions.value = [] |
| | | selectedJudges.value = [] |
| | | } |
| | | |
| | | const handleJudgeSearch = (value) => { |
| | | console.log('搜索评委:', value) |
| | | // 搜索评委 |
| | | } |
| | | |
| | | const handleStageChange = (value) => { |
| | | console.log('选择阶段:', value) |
| | | } |
| | | |
| | | |
| | | const handleJudgeSelectionChange = (value) => { |
| | | console.log('选择评委:', value) |
| | | // 选择评委 |
| | | } |
| | | |
| | | const toggleSelectAll = () => { |
| | |
| | | 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('请选择至少一个负责阶段') |
| | | return |
| | | } |
| | | |
| | | let addedCount = 0 |
| | | |
| | | selectedJudges.value.forEach(judgeId => { |
| | |
| | | // 检查是否已经存在 |
| | | 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) |
| | | } |
| | | // 更新现有评委的阶段,合并新选择的阶段 |
| | | 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 = selectedStageOptions.value.length > 0 |
| | | ? selectedStageOptions.value.map(id => parseInt(id)) |
| | | : [] |
| | | |
| | | 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++ |
| | | } |
| | | } |
| | | }) |
| | | |
| | | // 清空选择 |
| | | selectedJudges.value = [] |
| | | selectedStageOptions.value = [] |
| | | |
| | | judgeDialogVisible.value = false |
| | | ElMessage.success(`成功添加 ${addedCount} 个评委`) |
| | |
| | | } |
| | | |
| | | 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 : '无' |
| | | } |
| | |
| | | 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 |
| | |
| | | |
| | | // 处理媒体文件上传 |
| | | const handleMediaUpload = async (activityId) => { |
| | | if (!form.value || !form.value.mediaFiles) return |
| | | |
| | | try { |
| | | for (const mediaFile of form.value.mediaFiles) { |
| | | // 跳过已经有 id 的媒体文件(已保存的) |
| | |
| | | } |
| | | |
| | | try { |
| | | console.log('开始上传文件:', mediaFile.name) |
| | | // 1. 上传文件到服务器 |
| | | const uploadResult = await uploadFile(mediaFile.file) |
| | | console.log('文件上传成功:', uploadResult) |
| | | |
| | | // 2. 保存媒体信息到数据库 |
| | | const mediaInput = { |
| | |
| | | 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 |
| | |
| | | // 提交表单 |
| | | const handleSubmit = async () => { |
| | | if (submitting.value) return |
| | | if (!form.value) return |
| | | |
| | | try { |
| | | await formRef.value.validate() |
| | | |
| | |
| | | |
| | | // 准备保存数据,只包含后端支持的字段 |
| | | const saveData = { |
| | | id: form.value.id, |
| | | pid: form.value.pid || 0, |
| | | name: form.value.name, |
| | | description: form.value.description, |
| | | signupDeadline: form.value.signupDeadline, |
| | |
| | | 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, |
| | | 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 |
| | | } |
| | | // 只在有有效ID时才添加id字段 |
| | | if (stage.id) { |
| | | stageData.id = stage.id |
| | | } |
| | | // 只在有有效ratingSchemeId时才添加该字段 |
| | | 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 |
| | | } |
| | | |
| | | // 如果有pid,添加pid字段 |
| | | if (form.value.pid) { |
| | | saveData.pid = form.value.pid |
| | | } |
| | | |
| | | const result = await saveActivity(saveData) |
| | |
| | | await loadRatingSchemes() |
| | | await loadAllJudges() |
| | | await loadActivity() |
| | | |
| | | // 如果是新建模式且没有阶段,自动创建一个阶段 |
| | | if (!isEdit.value && form.value && form.value.stages && form.value.stages.length === 0) { |
| | | onStageCountChange(1) |
| | | } |
| | | }) |
| | | </script> |
| | | |
| | |
| | | |
| | | .stage-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | justify-content: flex-start; |
| | | align-items: center; |
| | | } |
| | | |
| | |
| | | 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 { |
| | |
| | | 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> |