|
|
@@ -0,0 +1,205 @@
|
|
|
+<template>
|
|
|
+ <div v-if="visible" class="play-prompt-overlay">
|
|
|
+ <div class="play-prompt-container">
|
|
|
+ <button class="close-button" @click="handleClose">× 取消</button>
|
|
|
+ <h3 class="prompt-title">即将跳转下一节</h3>
|
|
|
+ <div class="countdown-container">
|
|
|
+ <div class="countdown-circle">
|
|
|
+ <span class="countdown-number">{{ countdown }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, onMounted, onUnmounted, watch } from 'vue'
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ visible: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ duration: {
|
|
|
+ type: Number,
|
|
|
+ default: 5
|
|
|
+ },
|
|
|
+ message: {
|
|
|
+ type: String,
|
|
|
+ // default: '准备好开始下一节了吗?'
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const emit = defineEmits(['countdownEnd', 'close'])
|
|
|
+
|
|
|
+const countdown = ref(props.duration)
|
|
|
+let countdownTimer = null
|
|
|
+
|
|
|
+const handleClose = () => {
|
|
|
+ stopCountdown()
|
|
|
+ emit('close')
|
|
|
+}
|
|
|
+
|
|
|
+const startCountdown = () => {
|
|
|
+ countdown.value = props.duration
|
|
|
+
|
|
|
+ if (countdownTimer) {
|
|
|
+ clearInterval(countdownTimer)
|
|
|
+ }
|
|
|
+
|
|
|
+ countdownTimer = setInterval(() => {
|
|
|
+ countdown.value--
|
|
|
+
|
|
|
+ if (countdown.value <= 0) {
|
|
|
+ clearInterval(countdownTimer)
|
|
|
+ emit('countdownEnd')
|
|
|
+ }
|
|
|
+ }, 1000)
|
|
|
+}
|
|
|
+
|
|
|
+const stopCountdown = () => {
|
|
|
+ if (countdownTimer) {
|
|
|
+ clearInterval(countdownTimer)
|
|
|
+ countdownTimer = null
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+watch(() => props.visible, (newVisible) => {
|
|
|
+ if (newVisible) {
|
|
|
+ startCountdown()
|
|
|
+ } else {
|
|
|
+ stopCountdown()
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ if (props.visible) {
|
|
|
+ startCountdown()
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ stopCountdown()
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+@use 'sass:math';
|
|
|
+
|
|
|
+// 定义rpx转换函数
|
|
|
+@function rpx($px) {
|
|
|
+ @return math.div($px, 750) * 100vw;
|
|
|
+}
|
|
|
+
|
|
|
+.play-prompt-overlay {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ // background-color: rgba(0, 0, 0, 0.7);
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: flex-start;
|
|
|
+ padding-top: rpx(10);
|
|
|
+ z-index: 9999;
|
|
|
+}
|
|
|
+
|
|
|
+.play-prompt-container {
|
|
|
+ background: linear-gradient(135deg, #ffffff, #f0f0f0);
|
|
|
+ border-radius: rpx(10);
|
|
|
+ padding: rpx(6);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: rpx(5);
|
|
|
+ box-shadow: 0 rpx(10) rpx(20) rgba(0, 0, 0, 0.3);
|
|
|
+ max-width: 80%;
|
|
|
+ animation: fadeInScale 0.5s ease-out;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.close-button {
|
|
|
+ width: rpx(35);
|
|
|
+ height: rpx(20);
|
|
|
+ // border: 1px solid #333;
|
|
|
+ border: none;
|
|
|
+ color: white;
|
|
|
+ background: linear-gradient(135deg, #9370db, #b19cd9);
|
|
|
+ font-size: rpx(8);
|
|
|
+ font-weight: bold;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ cursor: pointer;
|
|
|
+ z-index: 10;
|
|
|
+ outline: none;
|
|
|
+ box-shadow: none;
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
+ border-radius: rpx(8);
|
|
|
+ gap: rpx(5);
|
|
|
+}
|
|
|
+
|
|
|
+.prompt-title {
|
|
|
+ font-size: rpx(8);
|
|
|
+ color: #333;
|
|
|
+ margin: 0;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+
|
|
|
+.prompt-message {
|
|
|
+ font-size: rpx(7);
|
|
|
+ color: #666;
|
|
|
+ margin-bottom: rpx(30);
|
|
|
+}
|
|
|
+
|
|
|
+.countdown-container {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.countdown-circle {
|
|
|
+ width: rpx(20);
|
|
|
+ height: rpx(20);
|
|
|
+ border-radius: 50%;
|
|
|
+ background: linear-gradient(135deg, #6a5acd, #9370db);
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ box-shadow: 0 rpx(10) rpx(20) rgba(106, 90, 205, 0.4);
|
|
|
+ animation: pulse 1s infinite;
|
|
|
+}
|
|
|
+
|
|
|
+.countdown-number {
|
|
|
+ font-size: rpx(10);
|
|
|
+ font-weight: bold;
|
|
|
+ color: white;
|
|
|
+ text-shadow: 0 rpx(2) rpx(4) rgba(0, 0, 0, 0.3);
|
|
|
+}
|
|
|
+
|
|
|
+// 动画效果
|
|
|
+@keyframes fadeInScale {
|
|
|
+ from {
|
|
|
+ opacity: 0;
|
|
|
+ transform: scale(0.8);
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ opacity: 1;
|
|
|
+ transform: scale(1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes pulse {
|
|
|
+ 0% {
|
|
|
+ transform: scale(1);
|
|
|
+ }
|
|
|
+ 50% {
|
|
|
+ transform: scale(1.05);
|
|
|
+ }
|
|
|
+ 100% {
|
|
|
+ transform: scale(1);
|
|
|
+ }
|
|
|
+}
|
|
|
+</style><!-- 即将播放下一节提示 -->
|