TrainingFloating.vue 3.8 KB
<template>
  <view class="floating-train-btn" v-if="showBall" @click="goToTrainingPage">
    <view class="icon-wrap">
      <up-icon name="plus-circle" color="#fff" size="24"></up-icon>
    </view>
    <view class="text-wrap">
      <text class="status-text">训练中</text>
      <text class="time-text">{{ formattedStartTime }}</text>
    </view>
  </view>
</template>

<script setup>
import { computed, watch, onMounted } from 'vue';
import { useTrainingStore } from '@/sheep/store/trainingStore';
import { trainingSnapshot } from '@/sheep/store/trainingSnapshot'

const trainingStore = useTrainingStore();


const showBall = computed(() => trainingSnapshot.visible && trainingSnapshot.data !== null)

// 格式化显示时间(快照中的 trainingTimeText)
const formattedStartTime = computed(() => {
  if (!trainingSnapshot.data) return ''
  return trainingSnapshot.data.trainingTimeText || ''
})

// ========== 点击悬浮球:还原快照 → 跳转训练页 ==========
const goToTrainingPage = () => {
  if (!trainingSnapshot.data) return

  // 安全检查:如果 store 里已经有不属于本次快照的训练数据(用户在编辑中)
  if (trainingStore.id && trainingStore.id !== trainingSnapshot.data.id) {
    uni.showModal({
      title: '提示',
      content: '当前已有另一组训练数据,恢复会覆盖它,确认吗?',
      confirmText: '确认恢复',
      cancelText: '取消',
      success: (res) => {
        if (res.confirm) doRestoreAndGo()
      }
    })
    return
  }

  doRestoreAndGo()
}

const doRestoreAndGo = () => {
  const snap = trainingSnapshot.data

  // 1. 用 $patch 还原全量 state(Pinia 官方批量更新,保证响应式触发)
  trainingStore.$patch(snap)

  // 2. 补偿计时器:如果快照时计时器在跑,加上经过的时间
  if (trainingSnapshot.timerWasRunning && trainingSnapshot.timestamp) {
    const elapsed = Math.floor((Date.now() - trainingSnapshot.timestamp) / 1000)
    trainingStore.totalSeconds = (snap.totalSeconds || 0) + elapsed
  }

  // 3. 如果快照时计时器在跑,重新启动 setInterval
  if (trainingSnapshot.timerWasRunning) {
    trainingStore.isPause = false
    trainingStore.timerInterval = setInterval(() => {
      trainingStore.totalSeconds++
    }, 1000)
  }

  // 4. 清空快照,隐藏悬浮球
  trainingSnapshot.data = null
  trainingSnapshot.timestamp = null
  trainingSnapshot.timerWasRunning = false
  trainingSnapshot.visible = false

  // 5. 跳转训练页面
  uni.navigateTo({
    url: `/pages4/pages/xunji/xunji-dongzuo-lianxi?id=${snap.id}&type=${snap.type}&isTraining=true`,
  })
}

// 格式化显示“开始时间”
// const formattedStartTime = computed(() => trainingStore.trainingTimeText);

// 跳转到训练页面
// const goToTrainingPage = () => {
//   // 悬浮球消失
//   trainingStore.min = false;
//   uni.navigateTo({
//     url: `/pages4/pages/xunji/xunji-dongzuo-lianxi?id=${trainingStore.id}&type=${trainingStore.type}`,
//   });
// };

watch(() => showBall.value, (newVal) => {
  console.log('🟢 悬浮球组件监听到 showBall 变化:', newVal);
}, { immediate: true });

// 组件挂载时打印
onMounted(() => {
  console.log('🟢 悬浮球组件已挂载,当前 showBall 值:', showBall.value);
});
</script>

<style lang="scss" scoped>
.floating-train-btn {
  position: fixed;
  right: 11rpx;
  bottom: 304rpx;
  display: flex;
  align-items: center;
  background-color: #39d353;
  border-radius: 60rpx;
  padding: 16rpx 20rpx;
  box-shadow: 0 8rpx 20rpx rgba(57, 211, 83, 0.3);
  z-index: 9999;
}

.icon-wrap {
  margin-right: 12rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.text-wrap {
  display: flex;
  flex-direction: column;
  color: #fff;
}

.status-text {
  font-size: 26rpx;
  font-weight: bold;
}

.time-text {
  font-size: 22rpx;
  opacity: 0.9;
}
</style>