add-train-popup.vue 5.25 KB
<template>
  <!-- 添加自助训练底部弹窗 -->
  <view v-if="visible" class="popup-overlay" @click="close">
    <view class="popup-bottom" @click.stop>
      <view class="popup-options">
        <view class="popup-option" @click="handleAddFromPlan" v-if="planListCount > 0">
          <view class=" icon-wrap">
            <image src="/static/icons/plan.png" mode="aspectFit"></image>
          </view>
          <view class="text-wrap" @click="">
            <text class="option-title">从训练计划中添加</text>
            <text class="option-desc">从我的训练计划中添加</text>
          </view>
        </view>

        <view class="popup-option" @click="handleAddFromTemplate">
          <view class="icon-wrap">
            <image src="/static/icons/template.png" mode="aspectFit"></image>
          </view>
          <view class="text-wrap">
            <text class="option-title">使用训练模板</text>
            <text class="option-desc">官方训练模板和自定义模板</text>
          </view>
        </view>

        <view class="popup-option" @click="handleFreeTraining">
          <view class="icon-wrap">
            <image src="/static/icons/free.png" mode="aspectFit"></image>
          </view>
          <view class="text-wrap">
            <text class="option-title">自由训练</text>
            <text class="option-desc">新建空白训练</text>
          </view>
        </view>
      </view>

      <view class="close-btn" @click="close">
        <text>x</text>
      </view>
    </view>
    <!-- 我的计划添加弹窗,显示最新添加的计划的模板列表 传递-->
    <WodeJihuaTianjiaTancuang v-model:visible="showPlanPopup" @get-plan-list-length="getPlanListLength" :isAdd="true"
      :plan-id="lastPlanId" :is-my-plan="true" />
  </view>
</template>

<script setup>
import { ref, onMounted, computed } from 'vue'
import WodeJihuaTianjiaTancuang from '@/pages/xunji/components/wode-jihua-tianjia-tancuang.vue'
import QueryPlanApi from '@/sheep/api/plan/queryplan'


// 控制训练计划弹窗显示
const showPlanPopup = ref(false)
const planListCount = ref(0)

const props = defineProps({
  visible: {
    type: Boolean,
    default: false
  }
})

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

// 关闭弹窗
const close = () => {
  emit('update:visible', false)
}

// 三个逻辑全部放在子组件内部
const handleAddFromPlan = () => {
  // close() // 关闭当前弹窗
  showPlanPopup.value = true
}

const getPlanListLength = (len) => {
  planListCount.value = len
}

const handleAddFromTemplate = () => {
  uni.navigateTo({ url: '/pages4/pages/xunji/xunji-rili-tianjia-moban' })
  close()
}

const handleFreeTraining = () => {
  uni.navigateTo({ url: '/pages4/pages/xunji/xunji-dongzuo-lianxi' })
  close()
}

// 获取我的计划列表的最后一个planid,传递到WodeJihuaTianjiaTancuang中
// 计划列表
const planList = ref([])

// 获取我的全部训练计划
const fetchMyPlanList = async () => {
  try {
    const res = await QueryPlanApi.getMyPlan()
    if (res.code === 0 && res.data) {
      planList.value = res.data
    } else {
      uni.showToast({ title: '获取计划失败', icon: 'none' })
    }
  } catch (err) {
    console.error('获取计划列表报错:', err)
    uni.showToast({ title: '网络异常', icon: 'none' })
  }
}

// 计算属性:拿到列表最后一条计划id,无数据返回null
const lastPlanId = computed(() => {
  if (!Array.isArray(planList.value) || planList.value.length === 0) return null
  const lastPlan = planList.value.at(-1)
  return lastPlan?.id ?? null
})

onMounted(() => {
  fetchMyPlanList()
})


</script>

<style lang="scss" scoped>
/* 半透明黑色遮罩层 —— 内容靠底部!! */
.popup-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 0, 0.8);
  z-index: 9999;
  display: flex;
  flex-direction: column;
  /* 核心:靠下 */
  justify-content: flex-end;
  align-items: center;
  /* 距离底部一点距离,不贴着最底下 */
  padding-bottom: 150rpx;
}

/* 弹窗主体容器 */
.popup-bottom {
  width: 85%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 70rpx;
  margin-bottom: 100rpx;
}

/* 选项列表 */
.popup-options {
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 20rpx;
}

/* 单个选项项 */
.popup-option {
  width: 100%;
  // background: rgba(255, 255, 255, 0.1);
  border-radius: 16rpx;
  padding: 24rpx 30rpx;
  display: flex;
  align-items: center;

  gap: 24rpx;
}

/* 黄色图标容器 */
.icon-wrap {
  width: 80rpx;
  height: 80rpx;
  border-radius: 50%;
  background: #ffd60a;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;

  image {
    width: 40rpx;
    height: 40rpx;
  }
}

/* 文字区域 */
.text-wrap {
  display: flex;
  flex-direction: column;
  gap: 8rpx;
}

.option-title {
  font-size: 32rpx;
  color: #fff;
  font-weight: 500;
}

.option-desc {
  font-size: 26rpx;
  color: rgba(255, 255, 255, 0.7);
}

/* 底部关闭按钮 */
.close-btn {
  width: 88rpx;
  height: 88rpx;
  border-radius: 50%;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;

  text {
    font-size: 40rpx;
    color: #000;
    line-height: 1;
  }
}
</style>