lrj
昨天 93eb6b470773bc49ea6e1a9d4cbd914eb95d525b
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)
// 按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 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 })
      // 新增阶段 - 设置正确的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 }
@@ -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 {