ExerciseSetTable.vue 8.58 KB
<template>
  <div class="sets-table-wrapper">
    <div class="table-title">
      组数配置(
      <span v-if="type === 0">无氧运动</span>
      <span v-else-if="type === 1">有氧运动</span>
      <span v-else-if="type === 2">计次训练</span>
      <span v-else-if="type === 3">计时训练</span>
      <span v-else-if="type === 4">自重加重</span>
      <span v-else-if="type === 5">自重减重</span>
      <span v-else-if="type === 6">间歇训练</span>

    </div>

    <table class="sets-table" border="1" cellpadding="8" cellspacing="0">
      <thead>
        <tr>
          <th width="80">操作</th>

          <!-- 无氧 -->
          <th v-if="type === 0" width="120">重量(kg)</th>
          <th v-if="type === 0" width="120">次数</th>
          <th v-if="type === 0" width="140">休息时间(秒)</th>

          <!-- 有氧 -->
          <th v-if="type === 1" width="100">时</th>
          <th v-if="type === 1" width="100">分</th>
          <th v-if="type === 1" width="100">秒</th>
          <th v-if="type === 1" width="120">千米</th>
          <th v-if="type === 1" width="140">休息时间(秒)</th>

          <!-- 计次 -->
          <th v-if="type === 2" width="120">次数</th>
          <th v-if="type === 2" width="140">休息时间(秒)</th>

          <!-- 计时 -->
          <th v-if="type === 3" width="100">时</th>
          <th v-if="type === 3" width="100">分</th>
          <th v-if="type === 3" width="100">秒</th>
          <th v-if="type === 3" width="140">休息时间(秒)</th>

          <!-- 自重加重/减重 -->
          <th v-if="type === 4 || type === 5" width="120">重量</th>
          <th v-if="type === 4 || type === 5" width="140">休息时间(秒)</th>

          <th v-if="type === 6" width="140">组数</th>
          <th v-if="type === 6" width="140">单次时长(秒)</th>
          <th v-if="type === 6" width="140">间歇</th>
        </tr>
      </thead>

      <tbody>
        <tr v-for="(set, setIndex) in sets" :key="setIndex" class="set-row">
          <td>
            <el-button type="text" @click="delSet(setIndex)" :disabled="sets.length <= 1">
              <template #icon>
                <Minus />
              </template>
            </el-button>
            <el-button v-if="setIndex === sets.length - 1" type="text" @click="addSet" style="margin-left: 8px">
              <template #icon>
                <Plus />
              </template>
            </el-button>
          </td>

          <!-- 无氧 -->
          <td v-if="type === 0">
            <el-input-number :model-value="set.weight" :min="0" :step="0.5" style="width: 80%"
              @change="val => handleFieldChange(setIndex, 'weight', val)" />
          </td>
          <td v-if="type === 0">
            <el-input-number :model-value="set.reps" :min="0" style="width: 80%"
              @change="val => handleFieldChange(setIndex, 'reps', val)" />
          </td>
          <td v-if="type === 0">
            <el-input-number :model-value="set.restTime" :min="0" style="width: 80%"
              @change="val => handleFieldChange(setIndex, 'restTime', val)" />
          </td>

          <!-- 有氧:时 分 秒 -->
          <td v-if="type === 1">
            <el-input-number v-model="tempH[setIndex]" :min="0" @change="() => calcDuration(setIndex)"
              style="width:100%" />
          </td>
          <td v-if="type === 1">
            <el-input-number v-model="tempM[setIndex]" :min="0" :max="59" @change="() => calcDuration(setIndex)"
              style="width:100%" />
          </td>
          <td v-if="type === 1">
            <el-input-number v-model="tempS[setIndex]" :min="0" :max="59" @change="() => calcDuration(setIndex)"
              style="width:100%" />
          </td>
          <td v-if="type === 1">
            <el-input-number :model-value="set.distance" :min="0" style="width: 80%"
              @change="val => handleFieldChange(setIndex, 'distance', val)" />
          </td>
          <td v-if="type === 1">
            <el-input-number :model-value="set.restTime" :min="0" style="width: 80%"
              @change="val => handleFieldChange(setIndex, 'restTime', val)" />
          </td>

          <!-- 计次 -->
          <td v-if="type === 2">
            <el-input-number :model-value="set.reps" :min="0" style="width: 80%"
              @change="val => handleFieldChange(setIndex, 'reps', val)" />
          </td>
          <td v-if="type === 2">
            <el-input-number :model-value="set.restTime" :min="0" style="width: 80%"
              @change="val => handleFieldChange(setIndex, 'restTime', val)" />
          </td>

          <!-- 计时:时 分 秒 -->
          <td v-if="type === 3">
            <el-input-number v-model="tempH[setIndex]" :min="0" @change="() => calcDuration(setIndex)"
              style="width:100%" />
          </td>
          <td v-if="type === 3">
            <el-input-number v-model="tempM[setIndex]" :min="0" :max="59" @change="() => calcDuration(setIndex)"
              style="width:100%" />
          </td>
          <td v-if="type === 3">
            <el-input-number v-model="tempS[setIndex]" :min="0" :max="59" @change="() => calcDuration(setIndex)"
              style="width:100%" />
          </td>
          <td v-if="type === 3">
            <el-input-number :model-value="set.restTime" :min="0" style="width: 80%"
              @change="val => handleFieldChange(setIndex, 'restTime', val)" />
          </td>

          <!-- 自重 -->
          <td v-if="type === 4 || type === 5">
            <el-input-number :model-value="set.weight" :min="0" style="width: 80%"
              @change="val => handleFieldChange(setIndex, 'weight', val)" />
          </td>
          <td v-if="type === 4 || type === 5">
            <el-input-number :model-value="set.restTime" :min="0" style="width: 80%"
              @change="val => handleFieldChange(setIndex, 'restTime', val)" />
          </td>

          <!-- 间歇(保持原样) -->
          <td v-if="type === 6">
            <el-input-number :model-value="set.reps" :min="0" style="width: 80%"
              @change="val => handleFieldChange(setIndex, 'reps', val)" />
          </td>
          <td v-if="type === 6">
            <el-input-number :model-value="set.duration" :min="0" style="width: 80%"
              @change="val => handleFieldChange(setIndex, 'duration', val)" />
          </td>
          <td v-if="type === 6">
            <el-input-number :model-value="set.restTime" :min="0" style="width: 80%"
              @change="val => handleFieldChange(setIndex, 'restTime', val)" />
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script setup>
import { Plus, Minus } from '@element-plus/icons-vue'
import { ref, watch } from 'vue'

const props = defineProps({
  type: Number,
  sets: Array
})

const emit = defineEmits(['update:sets'])

// 临时存储 时、分、秒
const tempH = ref([])
const tempM = ref([])
const tempS = ref([])

// 把总秒数拆分为 时:分:秒
function splitDuration(setIndex) {
  const sec = props.sets[setIndex]?.duration || 0
  const h = Math.floor(sec / 3600)
  const m = Math.floor((sec % 3600) / 60)
  const s = sec % 60
  tempH.value[setIndex] = h
  tempM.value[setIndex] = m
  tempS.value[setIndex] = s
}

// 计算总秒数并通知父组件更新
function calcDuration(setIndex) {
  const h = tempH.value[setIndex] || 0
  const m = tempM.value[setIndex] || 0
  const s = tempS.value[setIndex] || 0
  const total = h * 3600 + m * 60 + s
  handleFieldChange(setIndex, 'duration', total)
}

// 通用字段更新方法(通过 emit 通知父组件,不直接修改 props)
function handleFieldChange(setIndex, field, value) {
  const newSets = props.sets.map((set, idx) => {
    if (idx === setIndex) {
      return { ...set, [field]: value }
    }
    return set
  })
  emit('update:sets', newSets)
}

// 初始化所有行
function initAll() {
  if (props.type === 1 || props.type === 3) {
    props.sets.forEach((_, idx) => splitDuration(idx))
  }
}

// 监听 sets 变化(编辑回显)
watch(() => props.sets, () => initAll(), { deep: true, immediate: true })
watch(() => props.type, () => initAll(), { immediate: true })

// 新增
const addSet = () => {
  const newSet = { weight: 0, reps: 0, duration: 0, distance: 0, restTime: 0 }
  const newSets = [...props.sets, newSet]
  emit('update:sets', newSets)
}

// 删除
const delSet = (index) => {
  const newSets = [...props.sets]
  newSets.splice(index, 1)
  emit('update:sets', newSets)
}
</script>

<style scoped>
.sets-table-wrapper {
  margin: 16px 0;
}

.table-title {
  margin-bottom: 8px;
  font-weight: bold;
}

.sets-table {
  width: 100%;
  border-collapse: collapse;
}
</style>