Просмотр исходного кода

feat: 定时关闭功能完成

- 添加定时关闭按钮到player页面
- 实现15/30/45/60分钟定时选项
- 倒计时显示和自动暂停功能
MyFramework User 5 месяцев назад
Родитель
Сommit
3a254772d6
3 измененных файлов с 83 добавлено и 2 удалено
  1. 5 0
      claude-progress.txt
  2. 2 2
      feature_list_phase2.json
  3. 76 0
      my-uniapp-vue3/src/pages/player/index.vue

+ 5 - 0
claude-progress.txt

@@ -53,3 +53,8 @@
   - 后端测试: CRUD全部通过
   - 前端测试: 收藏页面加载正常,显示收藏列表
   - 状态: done
+[2026-04-04 11:06] 功能5 定时关闭完成
+  - 在player页面添加定时关闭按钮
+  - 实现15/30/45/60分钟定时选项
+  - 倒计时显示和自动暂停功能
+  - 状态: done

+ 2 - 2
feature_list_phase2.json

@@ -91,8 +91,8 @@
         "5. 等待或快进到定时时间",
         "6. 验证播放自动暂停"
       ],
-      "status": "init",
-      "passes": false
+      "status": "done",
+      "passes": true
     },
     {
       "id": 6,

+ 76 - 0
my-uniapp-vue3/src/pages/player/index.vue

@@ -79,6 +79,10 @@
 
     <!-- 底部操作 -->
     <view class="bottom-actions">
+      <button class="action-btn" @click="showTimerPicker = true">
+        <text class="action-icon">⏰</text>
+        <text class="action-text">{{ timerRemaining > 0 ? formatTimer(timerRemaining) : '定时' }}</text>
+      </button>
       <button class="action-btn" @click="handleDownload">
         <text class="action-icon">⬇</text>
         <text class="action-text">下载</text>
@@ -89,6 +93,24 @@
       </button>
     </view>
 
+    <!-- 定时关闭选择器 -->
+    <view v-if="showTimerPicker" class="rate-picker" @click="showTimerPicker = false">
+      <view class="rate-content" @click.stop>
+        <text class="rate-title">定时关闭</text>
+        <view class="rate-options">
+          <view
+            v-for="option in timerOptions"
+            :key="option.value"
+            class="rate-item"
+            :class="{ active: timerDuration === option.value }"
+            @click="handleSetTimer(option.value)"
+          >
+            <text>{{ option.label }}</text>
+          </view>
+        </view>
+      </view>
+    </view>
+
     <!-- 播放速度选择器 -->
     <view v-if="showRatePicker" class="rate-picker" @click="showRatePicker = false">
       <view class="rate-content" @click.stop>
@@ -122,9 +144,22 @@ const audioStore = useAudioStore();
 const audioId = ref('');
 const audio = ref<AudioItem | null>(null);
 const showRatePicker = ref(false);
+const showTimerPicker = ref(false);
 const savedProgress = ref(0); // 保存的历史进度
 const showResumePrompt = ref(false); // 显示继续播放提示
 
+// 定时关闭状态
+const timerDuration = ref(0); // 定时时长(秒),0表示未设置
+const timerRemaining = ref(0); // 剩余时间(秒)
+const timerOptions = [
+  { label: '15分钟', value: 15 * 60 },
+  { label: '30分钟', value: 30 * 60 },
+  { label: '45分钟', value: 45 * 60 },
+  { label: '60分钟', value: 60 * 60 },
+  { label: '关闭定时', value: 0 },
+];
+let timerInterval: number | null = null;
+
 // 从 store 获取状态
 const isPlaying = computed(() => audioStore.isPlaying);
 const currentTime = computed(() => audioStore.currentTime);
@@ -178,6 +213,10 @@ onUnmounted(() => {
   if (progressSaveTimer) {
     clearInterval(progressSaveTimer);
   }
+  // 清除定时关闭
+  if (timerInterval) {
+    clearInterval(timerInterval);
+  }
 });
 
 // 监听播放进度变化
@@ -326,6 +365,43 @@ function handleSetRate(rate: number) {
   showRatePicker.value = false;
 }
 
+// 设置定时关闭
+function handleSetTimer(seconds: number) {
+  timerDuration.value = seconds;
+  timerRemaining.value = seconds;
+  showTimerPicker.value = false;
+
+  // 清除之前的定时器
+  if (timerInterval) {
+    clearInterval(timerInterval);
+    timerInterval = null;
+  }
+
+  if (seconds > 0) {
+    // 启动倒计时
+    timerInterval = setInterval(() => {
+      if (timerRemaining.value > 0) {
+        timerRemaining.value--;
+      } else {
+        // 时间到,暂停播放
+        audioStore.pause();
+        if (timerInterval) {
+          clearInterval(timerInterval);
+          timerInterval = null;
+        }
+        uni.showToast({ title: '定时关闭,播放已暂停', icon: 'none' });
+      }
+    }, 1000) as unknown as number;
+  }
+}
+
+// 格式化定时器显示
+function formatTimer(seconds: number): string {
+  const mins = Math.floor(seconds / 60);
+  const secs = seconds % 60;
+  return `${mins}:${secs.toString().padStart(2, '0')}`;
+}
+
 // 切换收藏
 async function toggleFavorite() {
   if (!audio.value) return;