Browse Source

修改弹框部分逻辑

丸子 3 tháng trước cách đây
mục cha
commit
635d61e190

+ 7 - 1
src/components/blockly/MapGame.vue

@@ -2459,11 +2459,17 @@ onUnmounted(() => {
   display: flex;
   align-items: center;
   justify-content: center;
-  font-size: rpx(15);
+  font-size: rpx(13);
   font-weight: bold;
   border: none;
   cursor: pointer;
   transition: all 0.3s ease;
+  // 防止文字换行
+  white-space: nowrap; 
+  // 超出部分省略号显示
+  overflow: hidden;
+  // 超出部分省略号显示
+  text-overflow: ellipsis;
 }
 
 .game-badge:hover {

+ 26 - 14
src/components/popup/PlayPrompt.vue

@@ -1,6 +1,6 @@
 <template>
-  <div v-if="visible" class="play-prompt-overlay">
-    <div class="play-prompt-container">
+  <div v-if="visible" class="play-prompt-overlay" @click="handleClose">
+    <div class="play-prompt-container" @click.stop>
       <button class="close-button" @click="handleClose">× 取消</button>
       <h3 class="prompt-title">即将跳转下一节</h3>
       <div class="countdown-container">
@@ -17,68 +17,78 @@ import { ref, onMounted, onUnmounted, watch } from 'vue'
 
 const props = defineProps({
   visible: {
-    type: Boolean,
-    default: false
+    type: Boolean, // 弹窗是否可见
+    default: false // 默认不可见
   },
   duration: {
-    type: Number,
-    default: 5
-  },
-  message: {
-    type: String,
-    // default: '准备好开始下一节了吗?'
+    type: Number, // 倒计时持续时间
+    default: 5 // 默认5秒
   }
 })
 
 const emit = defineEmits(['countdownEnd', 'close'])
 
+// 倒计时秒数,初始值为props.duration
 const countdown = ref(props.duration)
+// 存储倒计时实例
 let countdownTimer = null
 
 const handleClose = () => {
-  stopCountdown()
+  // 停止倒计时
+  stopCountdown() 
+  // 触发关闭事件
   emit('close')
 }
 
 const startCountdown = () => {
+  // 重置倒计时为初始值
   countdown.value = props.duration
   
   if (countdownTimer) {
+    // 如果已有计时器在运行, 清除之前的计时器
     clearInterval(countdownTimer)
   }
-  
+  // 创建新的计时器,每秒执行一次
   countdownTimer = setInterval(() => {
+    // 倒计时减1
     countdown.value--
-    
     if (countdown.value <= 0) {
+      // 当倒计时结束时,清除计时器
       clearInterval(countdownTimer)
+      // 触发倒计时结束事件
       emit('countdownEnd')
     }
   }, 1000)
 }
 
 const stopCountdown = () => {
+  // 如果倒计时存在,清除计时器
   if (countdownTimer) {
     clearInterval(countdownTimer)
+    // 重置计时器变量为null
     countdownTimer = null
   }
 }
 
 watch(() => props.visible, (newVisible) => {
+  // 当弹窗显示时,启动倒计时
   if (newVisible) {
-    startCountdown()
+    startCountdown() 
   } else {
+    // 当弹窗隐藏时,停止倒计时
     stopCountdown()
   }
 })
 
 onMounted(() => {
+  // 如果弹窗初始状态就是显示的,启动倒计时
   if (props.visible) {
     startCountdown()
   }
 })
 
 onUnmounted(() => {
+  // 组件卸载时清除计时器
   stopCountdown()
 })
 </script>
@@ -103,6 +113,7 @@ onUnmounted(() => {
   align-items: flex-start;
   padding-top: rpx(10);
   z-index: 9999;
+  pointer-events: auto;
 }
 
 .play-prompt-container {
@@ -117,6 +128,7 @@ onUnmounted(() => {
   max-width: 80%;
   animation: fadeInScale 0.5s ease-out;
   position: relative;
+  pointer-events: auto;
 }
 
 .close-button {

+ 57 - 15
src/components/popup/PromptPopup.vue

@@ -1,18 +1,17 @@
 <template>
   <div v-if="visible" class="prompt-popup-overlay">
     <div class="prompt-popup-content">
-      <!-- <h3 class="prompt-title">提示</h3> -->
-      <p class="prompt-message">已经播放完最后一节,是否返回列表页?</p>
+      <p class="prompt-message">已经播放完最后一节,是否返回课程页?</p>
       <div class="prompt-buttons">
-        <button class="prompt-btn cancel" @click="handleCancel">取消</button>
-        <button class="prompt-btn confirm" @click="handleConfirm">确定</button>
+        <button class="prompt-btn cancel" @click="handleCancel">任意操作取消</button>
+        <button class="prompt-btn confirm" @click="handleConfirm">确定{{ countdown > 0 ? `(${countdown}s)` : '' }}</button>
       </div>
     </div>
   </div>
 </template>
 
 <script setup>
-import { defineProps, defineEmits } from 'vue';
+import { ref, watch, onUnmounted } from 'vue';
 
 const props = defineProps({
   visible: {
@@ -23,14 +22,64 @@ const props = defineProps({
 
 const emit = defineEmits(['confirm', 'cancel']);
 
+// 倒计时秒数,初始值为5
+const countdown = ref(5); 
+// 存储计时器实例
+let timer = null;
+
 const handleConfirm = () => {
+  clearTimer();
   emit('confirm');
 };
 
 const handleCancel = () => {
+  clearTimer();
   emit('cancel');
 };
 
+// 倒计时函数
+const startCountdown = () => {
+  // 先清除课程存在的旧计时器
+  clearTimer(); 
+  // 重置倒计时为5秒
+  countdown.value = 5; 
+  // 创建新的计时器,每秒执行一次
+  timer = setInterval(() => {
+    // 倒计时减1
+    countdown.value--;
+    if (countdown.value <= 0) {
+      // 倒计时时,清除计时器
+      clearTimer();
+      // 触发确认事件
+      emit('confirm');
+    }
+  }, 1000);
+};
+
+const clearTimer = () => {
+  if (timer) {
+      // 如果倒计时存在, 清除计时器
+    clearInterval(timer);
+    // 重置计时器变量
+    timer = null;
+  }
+};
+
+watch(() => props.visible, (newVal) => {
+  if (newVal) {
+    // 当弹窗显示时, 启动倒计时
+    startCountdown();
+  } else {
+    // 当弹窗隐藏时, 清除计时器
+    clearTimer();
+  }
+});
+
+onUnmounted(() => {
+  // 组件卸载时清除计时器,避免内存泄漏
+  clearTimer();
+});
+
 </script>
 
 <style scoped lang="scss">
@@ -51,24 +100,17 @@ const handleCancel = () => {
   align-items: flex-start;
   padding-top: rpx(10);
   z-index: 1000;
+  pointer-events: none;
 }
 
 .prompt-popup-content {
   background-color: white;
-  border-radius: rpx(4);
+  border-radius: rpx(8);
   padding: rpx(5);
   width: 90%;
   max-width: rpx(160);
   box-shadow: 0 rpx(2) rpx(6) rgba(0, 0, 0, 0.15);
-}
-
-.prompt-title {
-  margin-top: 0;
-  margin-bottom: rpx(8);
-  font-size: rpx(9);
-  font-weight: 600;
-  color: #333;
-  text-align: center;
+  pointer-events: auto;
 }
 
 .prompt-message {

+ 17 - 1
src/views/AIPage/AIDevelop.vue

@@ -1,6 +1,6 @@
 <template>
   <!-- AI发展历程 -->
-  <div class="home-container">
+  <div class="home-container" @click="handlePageClick">
     <!-- 展开收起侧边栏 -->
     <div
       class="icon-expand"
@@ -513,6 +513,22 @@ const handlePlayPromptClose = () => {
   playPromptVisible.value = false
 }
 
+// 处理页面点击事件,关闭提示弹窗
+const handlePageClick = (event) => {
+  // 检查点击目标是否在弹窗内部
+  const promptPopupElement = event.target.closest('.prompt-popup-content');
+  const playPromptElement = event.target.closest('.play-prompt-container');
+  
+  // 如果点击目标不在弹窗内部,则关闭弹窗
+  if (!promptPopupElement && promptPopupVisible.value) {
+    promptPopupVisible.value = false;
+  }
+  
+  if (!playPromptElement && playPromptVisible.value) {
+    playPromptVisible.value = false;
+  }
+}
+
 // 搜索
 const querySearch = (queryString, cb) => {
   const sections = getAllCourseSections()

+ 17 - 1
src/views/laboratory/ExperimentalInterface.vue

@@ -1,7 +1,7 @@
 <!-- 实验界面 -->
  <template>
   <!-- 编程课程视频页面 -->
-  <div class="home-container">
+  <div class="home-container" @click="handlePageClick">
     <div class="content-box">
       <div class="box-1">
         <div class="inner-box left-box">
@@ -383,6 +383,22 @@ const handlePlayPromptClose = () => {
   playPromptVisible.value = false
 }
 
+// 处理页面点击事件,关闭提示弹窗
+const handlePageClick = (event) => {
+  // 检查点击目标是否在弹窗内部
+  const promptPopupElement = event.target.closest('.prompt-popup-content');
+  const playPromptElement = event.target.closest('.play-prompt-container');
+  
+  // 如果点击目标不在弹窗内部,则关闭弹窗
+  if (!promptPopupElement && promptPopupVisible.value) {
+    promptPopupVisible.value = false;
+  }
+  
+  if (!playPromptElement && playPromptVisible.value) {
+    playPromptVisible.value = false;
+  }
+}
+
 // 处理父组件传递的课程数据
 const handleParentCourseData = (courseData = props.courseData) => {
   if (!courseData) return false

+ 21 - 5
src/views/programming/Interface.vue

@@ -1,6 +1,6 @@
 <template>
   <!-- 编程课程视频页面 -->
-  <div class="home-container">
+  <div class="home-container" @click="handlePageClick">
     <div class="content-box">
       <div class="box-1">
         <div class="inner-box left-box">
@@ -265,6 +265,9 @@ const playNextVideo = () => {
     if (currentIndex !== -1 && currentIndex < props.courseList.length - 1) {
       const nextCourse = props.courseList[currentIndex + 1]
 
+      // 关闭播放提示弹窗
+      playPromptVisible.value = false;
+      
       // 更新当前课程数据
       handleParentCourseData(nextCourse)
       courseId.value = course.value.id;
@@ -369,6 +372,19 @@ const handlePromptCancel = () => {
   promptPopupVisible.value = false
 }
 
+// 处理页面点击事件,关闭提示弹窗
+const handlePageClick = (event) => {
+  // 只有当弹窗可见时才执行关闭操作
+  if (promptPopupVisible.value) {
+    // 检查点击目标是否在弹窗内部
+    const popupElement = event.target.closest('.prompt-popup-content');
+    // 如果点击目标不在弹窗内部,则关闭弹窗
+    if (!popupElement) {
+      promptPopupVisible.value = false;
+    }
+  }
+}
+
 // 处理播放提示关闭
 const handlePlayPromptClose = () => {
   playPromptVisible.value = false
@@ -657,14 +673,14 @@ $text-color: #483d8b; // 文本颜色:靛蓝色
   display: flex;
   align-items: center;
   margin-left: rpx(7);
-  gap: 10px;
-  padding: 10px 20px;
+  gap: rpx(5);
+  padding: rpx(5) rpx(10);
   background-color: rgba(255, 255, 255, 0.8);
-  border-radius: 30px;
+  border-radius: rpx(10);
   backdrop-filter: blur(10px);
   cursor: pointer;
   transition: all 0.3s ease;
-  font-size: 16px;
+  font-size: rpx(8);
   color: #333;
   font-weight: 500;
   width: fit-content;