Browse Source

完善细节

shmily1213 3 weeks ago
parent
commit
a0050b392e

+ 2 - 2
src/api/modules/study.ts

@@ -103,7 +103,7 @@ export function commitExamineePaper(params: ExamPaperSubmit) {
  * 获取试卷结果
  */
 export function getExamineeResult(examineeId: number) {
-  return flyio.get('/front/exam/loadExaminee', { params: { examineeId } }) as Promise<ApiResponse<any>>;
+  return flyio.get('/front/exam/loadExaminee', { examineeId }) as Promise<ApiResponse<any>>;
 }
 
 
@@ -186,7 +186,7 @@ export function getSimulationExamSubjects() {
  */
 export function beginExaminee(examineeId: number) {
   return flyio.get('/front/exam/beginExaminee', { examineeId }) as Promise<ApiResponse<Examinee>>;
-} 
+}
 
 
 /**

+ 6 - 14
src/composables/useExam.ts

@@ -78,7 +78,6 @@ export const useExam = () => {
       state.forEach(item => {
         qs.progress = calcProgress(qs);
         if (qs.typeId === item.type) {
-          // qs.isDone = isDone(qs);
           item.list.push({
             question: qs,
             index: i
@@ -102,17 +101,14 @@ export const useExam = () => {
     return stateQuestionList.value.filter(q => q.isDone || q.isNotKnow).length;
   });
   const notDoneCount = computed(() => {
-    // return questionList.value.length - doneCount.value;
     return stateQuestionList.value.length - doneCount.value;
   });
-  const notKnowCount = computed(() => {
-    // return groupedQuestionList.value.reduce((acc, item) => acc + item.list.filter(q => q.question.isNotKnow).length, 0);
-    return stateQuestionList.value.filter(q => q.isNotKnow).length;
-  });
-  const markCount = computed(() => {
-    // return groupedQuestionList.value.reduce((acc, item) => acc + item.list.filter(q => q.question.isMark).length, 0);
-    return stateQuestionList.value.filter(q => q.isMark).length;
-  });
+  // const notKnowCount = computed(() => {
+  //   return stateQuestionList.value.filter(q => q.isNotKnow).length;
+  // });
+  // const markCount = computed(() => {
+  //   return stateQuestionList.value.filter(q => q.isMark).length;
+  // });
   // 包含子题的题目计算整体做题进度
   const calcProgress = (qs: Study.Question): number => {
     if (qs.subQuestions && qs.subQuestions.length > 0) {
@@ -121,7 +117,6 @@ export const useExam = () => {
     return qs.isDone ? 100 : 0;
   }
   const isDone = (qs: Study.Question): boolean => {
-    // console.log(qs.answers, qs.answers && qs.answers.filter(item => !!item).length > 0 || !!qs.isNotKnow)
     if (qs.subQuestions && qs.subQuestions.length > 0) {
       return qs.subQuestions.every(q => isDone(q));
     }
@@ -242,7 +237,6 @@ export const useExam = () => {
     const arr: Study.Question[] = list.map(item => {
       return parseQuestion(item);
     });
-    console.log('处理后的题目', arr)
     questionList.value = arr;
   }
   const reset = () => {
@@ -272,8 +266,6 @@ export const useExam = () => {
     totalCount,
     doneCount,
     notDoneCount,
-    notKnowCount,
-    markCount,
     questionTypeDesc,
     nextQuestion,
     prevQuestion,

+ 23 - 19
src/pagesMain/pages/index/components/index-popup.vue

@@ -6,26 +6,30 @@
     <root-portal externalClass="theme-ie">
       <!-- #endif -->
       <uv-popup ref="popupRef" mode="bottom" :round="16" :closeOnClickOverlay="false">
-        <view class="popup-content">
-          <view class="p-40">
-            <view class="text-32 text-fore-title font-bold">请确认信息</view>
-            <view class="mt-10 text-26 text-fore-light">让我们开始体验升学备考之旅吧!</view>
-          </view>
-          <view class="mx-30 pb-50">
-            <view class="flex items-center px-42 bg-back rounded-40 h-104 box-border">
-              <view class="flex-shrink-0">所在省份</view>
-              <ie-picker ref="pickerRef" v-model="form.location" :list="provinceList" :customStyle="customStyle"
-                placeholder="请选择" key-label="dictLabel" key-value="dictValue">
-              </ie-picker>
-            </view>
-            <view class="mt-30 flex items-center px-42 bg-back rounded-40 h-104 box-border">
-              <view class="flex-shrink-0">考生类别</view>
-              <ie-picker ref="pickerRef" v-model="form.examType" :list="examTypeList" :disabled="!form.location"
-                :customStyle="customStyle" placeholder="请选择" key-label="dictLabel" key-value="dictValue">
-              </ie-picker>
+        <view class="popup-content relative">
+          <ie-image :is-oss="true" src="/study-bg15.png" custom-class="absolute top-0 left-0 w-full h-392 z-0"
+            mode="aspectFill" />
+          <view class="relative z-1">
+            <view class="px-88 pt-60 pb-60">
+              <view class="text-40 text-fore-title font-bold">请确认信息</view>
+              <view class="mt-16 text-32 text-fore-light">让我们开始体验升学备考之旅吧!</view>
             </view>
-            <view class="mt-140">
-              <ie-button type="primary" @click="handleConfirm">立即体验</ie-button>
+            <view class="mx-46 pb-50">
+              <view class="flex items-center px-42 bg-back rounded-15 h-104 box-border">
+                <view class="flex-shrink-0">所在省份</view>
+                <ie-picker ref="pickerRef" v-model="form.location" :list="provinceList" :customStyle="customStyle"
+                  placeholder="请选择" key-label="dictLabel" key-value="dictValue">
+                </ie-picker>
+              </view>
+              <view class="mt-30 flex items-center px-42 bg-back rounded-15 h-104 box-border">
+                <view class="flex-shrink-0">考生类别</view>
+                <ie-picker ref="pickerRef" v-model="form.examType" :list="examTypeList" :disabled="!form.location"
+                  :customStyle="customStyle" placeholder="请选择" key-label="dictLabel" key-value="dictValue">
+                </ie-picker>
+              </view>
+              <view class="mt-140">
+                <ie-button type="primary" @click="handleConfirm">立即体验</ie-button>
+              </view>
             </view>
           </view>
         </view>

+ 1 - 1
src/pagesStudy/components/exam-record-item.vue

@@ -31,7 +31,7 @@ const handleDetail = () => {
   if (isFinished.value) {
     transferTo('/pagesStudy/pages/simulation-analysis/simulation-analysis', {
       data: {
-        id: props.data.id
+        examineeId: props.data.id
       }
     });
   } else {

+ 7 - 5
src/pagesStudy/pages/index/index.vue

@@ -62,9 +62,11 @@
     </view>
     <index-menu />
     <index-banner />
-    <view class="h-16 bg-back my-32"></view>
-    <index-test :directed-school="firstDirectedSchool" />
-    <index-exam-record />
+    <block v-if="hasTestAndRecord">
+      <view class="h-16 bg-back my-32"></view>
+      <index-test :directed-school="firstDirectedSchool" />
+      <index-exam-record />
+    </block>
   </ie-page>
 </template>
 
@@ -73,7 +75,7 @@ import IndexMenu from './compoentns/index-menu.vue';
 import IndexBanner from './compoentns/index-banner.vue';
 import IndexTest from './compoentns/index-test.vue';
 import IndexExamRecord from './compoentns/index-exam-record.vue';
-import { EnumDictName } from '@/common/enum';
+import { EnumDictName, EnumExamType } from '@/common/enum';
 import { useUserStore } from '@/store/userStore';
 import { useTransferPage } from '@/hooks/useTransferPage';
 import { getDirectedSchool } from '@/api/modules/study';
@@ -82,7 +84,7 @@ import IePage from '@/components/ie-page/ie-page.vue';
 
 const { transferTo } = useTransferPage();
 const userStore = useUserStore();
-
+const hasTestAndRecord = computed(() => userStore.getExamType !== EnumExamType.VHS);
 // 通过 ref 获取 ie-page 组件实例
 const iePageRef = ref<InstanceType<typeof IePage>>();
 

+ 11 - 0
src/pagesStudy/pages/simulation-analysis/simulation-analysis.vue

@@ -38,6 +38,17 @@
 import RateChart from './components/rate-chart.vue';
 import ExamStat from './components/exam-stat.vue';
 import ScoreStat from './components/score-stat.vue';
+import { getExamineeResult } from '@/api/modules/study';
+import { useTransferPage } from '@/hooks/useTransferPage';
+const { prevData } = useTransferPage();
+const examineeResult = ref<any>(null);
+const loadData = async () => {
+  const res = await getExamineeResult(prevData.value.examineeId);
+  examineeResult.value = res.data;
+};
+onLoad(() => {
+  loadData();
+});
 onPageScroll(() => { })
 </script>
 

+ 4 - 0
src/pagesStudy/pages/start-exam/components/question-correct-popup.vue

@@ -57,8 +57,12 @@ const open = (id: number) => {
   questionId.value = id;
   popupRef.value.open();
 }
+const emit = defineEmits<{
+  close: [];
+}>();
 const close = () => {
   popupRef.value.close();
+  emit('close');
 }
 const handleSubmit = () => {
   loading.value = true;

+ 14 - 4
src/pagesStudy/pages/start-exam/components/question-item.vue

@@ -26,8 +26,8 @@
     </view>
     <view v-if="question.subQuestions.length" class="is-sub-question">
       <question-item :question="subQuestion" v-for="(subQuestion, index) in question.subQuestions" :key="subQuestion.id"
-        :is-sub-question="true" :index="index" :total="question.subQuestions.length" @update:question="handleSubQuestionUpdate" @select="handleSelectOption"
-        @notKnow="handleSelectNotKnow" />
+        :is-sub-question="true" :index="index" :total="question.subQuestions.length"
+        @update:question="handleSubQuestionUpdate" @select="handleSelectOption" @notKnow="handleSelectNotKnow" />
     </view>
   </view>
 </template>
@@ -143,8 +143,18 @@ const findNotDoneSubQuestion = () => {
   }
 }
 const changeQuestion = () => {
-  if (props.question.isDone) {
-    nextQuestion?.();
+  // 判断是多选还是单选
+  if (props.question.typeId === EnumQuestionType.MULTIPLE_CHOICE) {
+    // 多选题,选择不会时切换下一题,否则不自动切换
+    if (props.question.isNotKnow) {
+      nextQuestion?.();
+    } else {
+      return;
+    }
+  } else {
+    if (props.question.isDone) {
+      nextQuestion?.();
+    }
   }
 }
 

+ 354 - 0
src/pagesStudy/pages/start-exam/components/question-swiper-tip.vue

@@ -0,0 +1,354 @@
+<template>
+  <!-- 使用 class 动画实现渐入渐出,兼容微信小程序 -->
+  <view v-if="isShowing" class="swiper-tip-container" :class="{ 'is-fading-out': isFadingOut }">
+    <!-- 半透明遮罩层(先显示)-->
+    <view class="mask-overlay" :class="{ 'is-fading-out': isFadingOut }"></view>
+    
+    <!-- 内容层(延迟显示)-->
+    <view class="content-wrapper" :class="{ 'is-fading-out': isFadingOut }">
+        <!-- 左滑提示(上一题) -->
+        <view v-if="showLeft" class="arrow-container arrow-left">
+          <view class="arrow-wrapper">
+            <view class="arrow"></view>
+            <view class="arrow arrow-delay-1"></view>
+            <view class="arrow arrow-delay-2"></view>
+          </view>
+          <text class="tip-text">左滑下一题</text>
+        </view>
+
+        <!-- 中间提示文字 -->
+        <view v-if="centerText" class="center-text">
+          <text class="text">{{ centerText }}</text>
+        </view>
+
+        <!-- 右滑提示(下一题) -->
+        <view v-if="showRight" class="arrow-container arrow-right">
+          <view class="arrow-wrapper">
+            <view class="arrow"></view>
+            <view class="arrow arrow-delay-1"></view>
+            <view class="arrow arrow-delay-2"></view>
+          </view>
+          <text class="tip-text">右滑上一题</text>
+        </view>
+
+        <!-- 下一步按钮(绝对定位在中间文字下方) -->
+        <view v-if="showNextButton" class="next-button-wrapper">
+          <view class="next-button" @click="handleNext">
+            <text class="button-text">下一步</text>
+          </view>
+        </view>
+      </view>
+    </view>
+</template>
+
+<script lang="ts" setup>
+interface Props {
+  visible?: boolean;        // 是否显示提示
+  showLeft?: boolean;       // 是否显示左滑提示
+  showRight?: boolean;      // 是否显示右滑提示
+  centerText?: string;      // 中间提示文字
+  showNextButton?: boolean; // 是否显示"下一步"按钮
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  visible: false,
+  showLeft: true,
+  showRight: true,
+  centerText: '滑动切换题目',
+  showNextButton: true
+});
+
+const emit = defineEmits<{
+  next: []  // 点击"下一步"按钮时触发
+}>();
+
+// 内部状态控制动画
+const isShowing = ref(false);
+const isFadingOut = ref(false);
+
+// 监听 visible 变化,控制渐入渐出动画
+watch(() => props.visible, (newVal) => {
+  if (newVal) {
+    // 显示:立即渲染并播放渐入动画
+    isShowing.value = true;
+    isFadingOut.value = false;
+  } else {
+    // 隐藏:先播放渐出动画,300ms后再移除DOM
+    isFadingOut.value = true;
+    setTimeout(() => {
+      isShowing.value = false;
+      isFadingOut.value = false;
+    }, 300);
+  }
+}, { immediate: true });
+
+// 处理下一步按钮点击
+const handleNext = () => {
+  emit('next');
+};
+</script>
+
+<style lang="scss" scoped>
+.swiper-tip-container {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  pointer-events: none;
+  z-index: 100;
+}
+
+// 遮罩层(先显示,快速渐入)
+.mask-overlay {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.3);
+  pointer-events: auto;
+  
+  // 遮罩层渐入动画(0.2s,无延迟)
+  opacity: 0;
+  animation: maskFadeIn 0.2s ease-in-out forwards;
+  
+  // 遮罩层渐出动画
+  &.is-fading-out {
+    animation: maskFadeOut 0.3s ease-in-out forwards;
+  }
+}
+
+// 遮罩层渐入动画
+@keyframes maskFadeIn {
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+  }
+}
+
+// 遮罩层渐出动画
+@keyframes maskFadeOut {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+  }
+}
+
+// 内容层(延迟显示,带缩放效果)
+.content-wrapper {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: space-around;
+  padding: 0 30rpx;
+  box-sizing: border-box;
+  pointer-events: none;
+  z-index: 1;
+  
+  // 内容层渐入动画(延迟0.2s,让遮罩层先显示)
+  opacity: 0;
+  transform: scale(0.95);
+  animation: contentFadeIn 0.3s ease-in-out 0.2s forwards;
+  
+  // 内容层渐出动画
+  &.is-fading-out {
+    animation: contentFadeOut 0.3s ease-in-out forwards;
+  }
+}
+
+// 内容层渐入动画
+@keyframes contentFadeIn {
+  from {
+    opacity: 0;
+    transform: scale(0.95);
+  }
+  to {
+    opacity: 1;
+    transform: scale(1);
+  }
+}
+
+// 内容层渐出动画
+@keyframes contentFadeOut {
+  from {
+    opacity: 1;
+    transform: scale(1);
+  }
+  to {
+    opacity: 0;
+    transform: scale(0.95);
+  }
+}
+
+.arrow-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 16rpx;
+  flex-shrink: 0;
+  z-index: 1;
+}
+
+.arrow-wrapper {
+  position: relative;
+  width: 80rpx;
+  height: 60rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.arrow {
+  position: absolute;
+  width: 40rpx;
+  height: 40rpx;
+  border-left: 6rpx solid #fff;  // 改为白色,在半透明黑色背景上更清晰
+  border-bottom: 6rpx solid #fff;
+  opacity: 0;
+  filter: drop-shadow(0 2rpx 4rpx rgba(0, 0, 0, 0.4));  // 添加阴影增强可见性
+  z-index: 1;
+  
+  // 左箭头
+  .arrow-left & {
+    transform: rotate(45deg);
+    animation: slide-left 2s ease-in-out infinite;  // 增加到2秒,更流畅
+  }
+  
+  // 右箭头
+  .arrow-right & {
+    transform: rotate(-135deg);
+    animation: slide-right 2s ease-in-out infinite;  // 增加到2秒,更流畅
+  }
+  
+  // 延迟动画,创建均匀分布的效果
+  &.arrow-delay-1 {
+    animation-delay: 0.5s;  // 从0.3s增加到0.5s,更均匀
+  }
+  
+  &.arrow-delay-2 {
+    animation-delay: 1s;  // 从0.6s增加到1s,更均匀
+  }
+}
+
+.tip-text {
+  font-size: 24rpx;
+  color: #fff;
+  font-weight: 500;
+  white-space: nowrap;
+  text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.3);
+  z-index: 1;
+}
+
+// 中间提示文字(白色背景卡片,与左右箭头图标对齐)
+.center-text {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 16rpx;
+  flex-shrink: 0;
+  z-index: 1;
+  
+  // 恢复白色背景卡片样式
+  background: rgba(255, 255, 255, 0.95);
+  padding: 20rpx 40rpx;
+  border-radius: 40rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
+  
+  // 向上偏移,与箭头图标对齐(不包含下方文字的高度)
+  // 箭头容器有 gap: 16rpx + 文字高度约 40rpx,所以向上偏移一半
+  margin-bottom: 30rpx;
+  
+  .text {
+    font-size: 28rpx;
+    color: #333;
+    font-weight: 500;
+    white-space: nowrap;
+  }
+}
+
+// 下一步按钮容器(绝对定位)
+.next-button-wrapper {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  margin-top: 140rpx;  // 向下偏移,显示在中间文字下方
+  z-index: 1;
+}
+
+// 下一步按钮
+.next-button {
+  // background: linear-gradient(135deg, #1976D2 0%, #1565C0 100%);
+  @apply bg-primary;
+  padding: 12rpx 30rpx;
+  // border-radius: 40rpx;
+  border-radius: 4px;
+  box-shadow: 0 6rpx 20rpx rgba(25, 118, 210, 0.3);
+  pointer-events: auto;
+  transition: all 0.3s ease;
+  white-space: nowrap;
+  
+  &:active {
+    transform: scale(0.95);
+    box-shadow: 0 4rpx 12rpx rgba(25, 118, 210, 0.2);
+  }
+  
+  .button-text {
+    font-size: 24rpx;
+    color: #fff;
+    font-weight: 600;
+    letter-spacing: 2rpx;
+  }
+}
+
+// 左滑动画
+@keyframes slide-left {
+  0% {
+    opacity: 0;
+    transform: translateX(30rpx) rotate(45deg);  // 增加移动距离
+  }
+  
+  30% {
+    opacity: 1;  // 提前完全显示
+  }
+  
+  70% {
+    opacity: 1;  // 延长完全显示时间
+  }
+  
+  100% {
+    opacity: 0;
+    transform: translateX(-30rpx) rotate(45deg);  // 增加移动距离
+  }
+}
+
+// 右滑动画
+@keyframes slide-right {
+  0% {
+    opacity: 0;
+    transform: translateX(-30rpx) rotate(-135deg);  // 增加移动距离
+  }
+  
+  30% {
+    opacity: 1;  // 提前完全显示
+  }
+  
+  70% {
+    opacity: 1;  // 延长完全显示时间
+  }
+  
+  100% {
+    opacity: 0;
+    transform: translateX(30rpx) rotate(-135deg);  // 增加移动距离
+  }
+}
+</style>

+ 1 - 1
src/pagesStudy/pages/start-exam/start-exam copy.vue

@@ -105,7 +105,7 @@ import { NEXT_QUESTION, PREV_QUESTION, NEXT_QUESTION_QUICKLY, PREV_QUESTION_QUIC
 // import { Examinee, ExamPaper, ExamPaperSubmit } from '@/types/study';
 const { prevData, transferBack } = useTransferPage();
 const { setQuestionList, questionList, groupedQuestionList, stateQuestionList, questionTypeDesc, favoriteList, notKnowList, markList, currentIndex,
-  totalCount, doneCount, notDoneCount, notKnowCount, markCount, isAllDone, nextQuestion, prevQuestion, nextQuestionQuickly, prevQuestionQuickly, swiperDuration,
+  totalCount, doneCount, notDoneCount, isAllDone, nextQuestion, prevQuestion, nextQuestionQuickly, prevQuestionQuickly, swiperDuration,
   formatPracticeDuration, formatExamDuration, practiceDuration, startPracticeDuration, stopPracticeDuration,
   examDuration, startExamDuration, stopExamDuration, setExamDuration, setCountDownCallback, changeIndex, setDuration, reset } = useExam();
 

+ 51 - 17
src/pagesStudy/pages/start-exam/start-exam.vue

@@ -87,8 +87,10 @@
       </view>
     </view>
   </question-stats-popup>
-  <question-correct-popup ref="questionCorrectPopupRef" />
-  <fast-guide v-model:show="guideShow" :list="guideList" v-model:index="guideIndex"></fast-guide>
+  <question-correct-popup ref="questionCorrectPopupRef" @close="handleCorrectClose" />
+  <fast-guide v-model:show="guideShow" :list="guideList" v-model:index="guideIndex"
+    @close="handleGuideClose"></fast-guide>
+  <question-swiper-tip :visible="showSwiperTip" @next="handleSwiperTipNext" />
 </template>
 
 <script lang="ts" setup>
@@ -96,46 +98,49 @@ import QuestionWrap from './components/question-wrap.vue';
 import QuestionStatsPopup from './components/question-stats-popup.vue';
 import QuestionProgress from './components/question-progress.vue';
 import QuestionCorrectPopup from './components/question-correct-popup.vue';
+import QuestionSwiperTip from './components/question-swiper-tip.vue';
 import { useTransferPage } from '@/hooks/useTransferPage';
+import { useUserStore } from '@/store/userStore';
 import { EnumPaperType } from '@/common/enum';
 import { getOpenExaminee, getPaper, commitExamineePaper, collectQuestion, cancelCollectQuestion, beginExaminee } from '@/api/modules/study';
 import { useExam } from '@/composables/useExam';
 import { Study } from '@/types';
 import { NEXT_QUESTION, PREV_QUESTION, NEXT_QUESTION_QUICKLY, PREV_QUESTION_QUICKLY } from '@/types/injectionSymbols';
 import { number } from 'echarts';
+const userStore = useUserStore();
 // import { Examinee, ExamPaper, ExamPaperSubmit } from '@/types/study';
 const { prevData, transferBack } = useTransferPage();
-const { setQuestionList, questionList, groupedQuestionList, stateQuestionList, questionTypeDesc, favoriteList, notKnowList, markList, currentIndex,
-  totalCount, doneCount, notDoneCount, notKnowCount, markCount, isAllDone, nextQuestion, prevQuestion, nextQuestionQuickly, prevQuestionQuickly, swiperDuration,
-  formatPracticeDuration, formatExamDuration, practiceDuration, startPracticeDuration, stopPracticeDuration,
-  examDuration, startExamDuration, stopExamDuration, setExamDuration, setCountDownCallback, changeIndex, setDuration, reset } = useExam();
+const { setQuestionList, questionList, groupedQuestionList, questionTypeDesc, currentIndex,
+  totalCount, doneCount, notDoneCount, isAllDone, nextQuestion, prevQuestion, nextQuestionQuickly, prevQuestionQuickly, swiperDuration,
+  formatPracticeDuration, practiceDuration, startPracticeDuration, stopPracticeDuration, changeIndex, setDuration, reset } = useExam();
 
 provide(NEXT_QUESTION, nextQuestion);
 provide(PREV_QUESTION, prevQuestion);
 provide(NEXT_QUESTION_QUICKLY, nextQuestionQuickly);
 provide(PREV_QUESTION_QUICKLY, prevQuestionQuickly);
 //
+const showSwiperTip = ref(false);
 const guideShow = ref(false);
 const guideList = ref([
   {
     target: '#question-correct-btn',
     position: 'top',
-    msg: '这是第一步'
+    msg: '[题目纠错]\n点击题目纠错,帮助我们改进题目'
   },
   {
     target: '#question-favorite-btn',
     position: 'top',
-    msg: '这是第二步'
+    msg: '[题目收藏]\n收藏的题目可以在收藏夹查看'
   },
   {
     target: '#question-mark-btn',
     position: 'top',
-    msg: '这是第三步'
+    msg: '[题目标记]\n标记的题目可以在答题卡中快速找到'
   },
   {
     target: '#question-calendar-btn',
     position: 'top',
-    msg: '这是第四步'
+    msg: '[答题卡]\n查看答题卡,掌握考试进度'
   }
 ]);
 const guideIndex = ref(0);
@@ -196,8 +201,12 @@ const hanadleNavigate = (index: number) => {
 /// 问题纠错
 const questionCorrectPopupRef = ref();
 const handleCorrect = () => {
+  stopTime();
   questionCorrectPopupRef.value.open(currentQuestion.value.id);
 }
+const handleCorrectClose = () => {
+  startTime();
+}
 const handleFavorite = async () => {
   if (!currentQuestion.value.isFavorite) {
     await collectQuestion(currentQuestion.value.id);
@@ -268,6 +277,9 @@ const beforeSubmit = () => {
   });
 }
 
+/**
+ * 重新作答
+ */
 const handleReset = () => {
   if (doneCount.value <= 0) {
     return;
@@ -286,6 +298,9 @@ const handleReset = () => {
   });
 }
 
+/**
+ * 自动提交
+ */
 const autoSubmit = () => {
   if (isAllDone.value) {
     if (hasShowSubmitConfirm.value) {
@@ -296,6 +311,10 @@ const autoSubmit = () => {
   }
 }
 
+/**
+ * 提交试卷
+ * @param tempSave 是否临时保存
+ */
 const handleSubmit = (tempSave: boolean = false) => {
   console.log('handleSubmit', questionList.value)
   const msg = tempSave ? '保存中...' : '提交中...';
@@ -334,7 +353,6 @@ const restoreQuestion = (savedQuestion: Study.ExamineeQuestion[], fullQuestion:
   if (!savedQuestion) {
     return fullQuestion;
   }
-  console.log(savedQuestion, fullQuestion)
   for (const item of fullQuestion) {
     const savedQs = savedQuestion.find(q => q.id === item.id);
     if (savedQs) {
@@ -386,19 +404,35 @@ const combinePaperData = async (examinee: Study.Examinee, paperType: EnumPaperTy
       type: paperType,
       id: examinee.paperId
     });
-    console.log('试卷信息', res)
-    uni.$ie.hideLoading();
     paperData.value = res.data;
     paperData.value.questions = restoreQuestion(examinee.questions, res.data.questions);
     setQuestionList(paperData.value.questions);
     setDuration(examinee.duration || 0);
+    await nextTick();
     isReady.value = true;
-    startTime();
-    setTimeout(() => {
-      guideShow.value = true;
-    }, 500);
+    await nextTick();
+    console.log('试卷信息', res)
+    if (!userStore.isExamGuideShow) {
+      setTimeout(() => {
+        uni.$ie.hideLoading();
+        setTimeout(() => {
+          showSwiperTip.value = true;
+        }, 100);
+      }, 300);
+    } else {
+      uni.$ie.hideLoading();
+      startTime();
+    }
   }
 }
+const handleSwiperTipNext = () => {
+  showSwiperTip.value = false;
+  guideShow.value = true;
+}
+const handleGuideClose = () => {
+  userStore.isExamGuideShow = true;
+  startTime();
+}
 const loadData = async () => {
   uni.$ie.showLoading();
   const { paperType } = prevData.value;

+ 2 - 2
src/pagesStudy/pages/study-history/components/exam-history-student.vue

@@ -1,7 +1,7 @@
 <template>
   <view class="px-30 pb-30">
     <view class="sibling-border-top px-20 py-30" v-for="(item, index) in dataList" :key="index">
-      <exam-record-item />
+      <exam-record-item :data="item" />
     </view>
   </view>
 </template>
@@ -21,7 +21,7 @@ const loadData = async (type: string) => {
   dataList.value = [];
   if (type === EnumExamRecordType.SIMULATED) {
     const { data } = await getSimulatedRecord();
-    // dataList.value = data;
+    dataList.value = data;
   } else {
 
 

+ 5 - 4
src/pagesSystem/components/content-card.vue

@@ -1,6 +1,9 @@
 <template>
   <view class="my-16 bg-white pt-18 px-42">
-    <view class="text-32 font-bold text-fore-title">{{ title }}</view>
+    <view class="flex items-center justify-between">
+      <text class="text-32 font-bold text-fore-title">{{ title }}</text>
+      <slot name="right"></slot>
+    </view>
     <view class="mt-16">
       <slot></slot>
     </view>
@@ -14,6 +17,4 @@ const props = defineProps({
   }
 });
 </script>
-<style lang="scss" scoped>
-
-</style>
+<style lang="scss" scoped></style>

+ 42 - 21
src/pagesSystem/pages/bind-profile/bind-profile.vue

@@ -9,30 +9,31 @@
           </uv-input>
         </uv-form-item>
         <uv-form-item label="所在省份" prop="location" borderBottom required>
-          <ie-picker ref="pickerRef" v-model="examTypeForm.location" :list="provinceList" placeholder="选择省份"
-            :custom-style="customStyle" key-label="dictLabel" key-value="dictValue" :disabled="isProvinceDisabled">
+          <ie-picker ref="pickerRef" v-model="examTypeForm.location" :list="provinceList"
+            :placeholder="pickerPlaceholder" :custom-style="customStyle" key-label="dictLabel" key-value="dictValue"
+            :disabled="isProvinceDisabled">
             <template v-if="isProvinceDisabled" #right>
-              <ie-image src="/static/image/icon/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
+              <ie-image src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
             </template>
           </ie-picker>
         </uv-form-item>
         <uv-form-item label="考生类别" prop="examType" borderBottom required>
           <ie-picker ref="pickerRef" v-model="examTypeForm.examType" :list="examTypeList" :disabled="isExamTypeDisabled"
-            placeholder="选择考生类别" :custom-style="customStyle" key-label="dictLabel" key-value="dictValue">
+            :placeholder="pickerPlaceholder" :custom-style="customStyle" key-label="dictLabel" key-value="dictValue">
             <template v-if="isExamTypeDisabled" #right>
-              <ie-image src="/static/image/icon/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
+              <ie-image src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
             </template>
           </ie-picker>
         </uv-form-item>
         <uv-form-item v-if="examTypeForm.examType === 'VHS'" label="专业类别" prop="majorType" borderBottom required>
           <ie-picker ref="pickerRef" v-model="examTypeForm.majorType" :list="examMajorList"
-            :disabled="!examTypeForm.examType" placeholder="选择专业类别" :custom-style="customStyle" key-label="dictLabel"
-            key-value="dictValue"></ie-picker>
+            :disabled="!examTypeForm.examType" :placeholder="pickerPlaceholder" :custom-style="customStyle"
+            key-label="dictLabel" key-value="dictValue"></ie-picker>
         </uv-form-item>
         <uv-form-item label="毕业年份" prop="year" required>
           <ie-picker ref="pickerRef" v-model="examTypeForm.endYear" :list="endYearList"
-            :disabled="!examTypeForm.examType" placeholder="选择毕业年份" :custom-style="customStyle" key-label="dictLabel"
-            key-value="dictValue"></ie-picker>
+            :disabled="!examTypeForm.examType" :placeholder="pickerPlaceholder" :custom-style="customStyle"
+            key-label="dictLabel" key-value="dictValue"></ie-picker>
         </uv-form-item>
 
       </content-card>
@@ -45,48 +46,51 @@
       </content-card>
       <content-card v-if="showCulture" title="文化素质">
         <uv-form-item label="语文" prop="form.scores.chinese" borderBottom :required="isBindMode">
-          <uv-input v-model.number="scoresForm.chinese" border="none" type="number" placeholder="请输入" font-size="30rpx"
-            :custom-style="customStyle">
+          <uv-input v-model.number="scoresForm.chinese" border="none" type="number" :placeholder="inputPlaceholder"
+            font-size="30rpx" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
         <uv-form-item label="数学" prop="form.score.mathematics" borderBottom :required="isBindMode">
-          <uv-input v-model.number="scoresForm.mathematics" border="none" type="number" placeholder="请输入"
+          <uv-input v-model.number="scoresForm.mathematics" border="none" type="number" :placeholder="inputPlaceholder"
             font-size="30rpx" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
         <uv-form-item label="外语" prop="form.scores.foreign" borderBottom :required="isBindMode">
-          <uv-input v-model.number="scoresForm.foreign" border="none" type="number" placeholder="请输入" font-size="30rpx"
-            :custom-style="customStyle">
+          <uv-input v-model.number="scoresForm.foreign" border="none" type="number" :placeholder="inputPlaceholder"
+            font-size="30rpx" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
         <uv-form-item label="物理" prop="form.scores.physics" borderBottom :required="isBindMode">
-          <uv-input v-model.number="scoresForm.physics" border="none" type="number" placeholder="请输入" font-size="30rpx"
-            :custom-style="customStyle">
+          <uv-input v-model.number="scoresForm.physics" border="none" type="number" :placeholder="inputPlaceholder"
+            font-size="30rpx" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
         <uv-form-item label="政治" prop="form.scores.political" :required="isBindMode">
-          <uv-input v-model.number="scoresForm.political" border="none" type="number" placeholder="请输入"
+          <uv-input v-model.number="scoresForm.political" border="none" type="number" :placeholder="inputPlaceholder"
             font-size="30rpx" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
       </content-card>
       <content-card v-if="isBindMode" title="学校信息">
+        <template #right>
+          <view class="text-26 text-primary underline" @click="handleNoSchool">没有我的学校班级?</view>
+        </template>
         <uv-form-item label="学校名称" prop="form.name" borderBottom :required="isBindMode">
-          <ie-picker ref="pickerRef" v-model="form.schoolName" disabled placeholder="请选择就读学校"
+          <ie-picker ref="pickerRef" v-model="form.schoolName" disabled :placeholder="pickerPlaceholder"
             :custom-style="customStyle" :custom-label="form.schoolName" @click="handleSchoolSelect">
             <template v-if="isSchoolDisabled" #right>
-              <ie-image src="/static/image/icon/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
+              <ie-image src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
             </template>
           </ie-picker>
         </uv-form-item>
         <uv-form-item label="所在班级" prop="form.name" :required="isBindMode">
           <ie-picker ref="pickerRef" v-model="form.classId" :list="classList" :disabled="!form.schoolId" title="选择班级"
-            placeholder="请选择所在班级" :custom-style="customStyle" key-label="name" key-value="classId"></ie-picker>
+            placeholder="请选择" :custom-style="customStyle" key-label="name" key-value="classId"></ie-picker>
         </uv-form-item>
       </content-card>
     </uv-form>
     <ie-safe-toolbar :height="84" :shadow="false">
-      <view class="px-30 py-16">
+      <view class="px-46 pt-24">
         <ie-button @click="handleSubmit">确认提交</ie-button>
       </view>
     </ie-safe-toolbar>
@@ -128,11 +132,28 @@ const isSchoolDisabled = computed(() => isBindMode.value && prevData.value.cardI
 const isProvinceDisabled = computed(() => isBindMode.value && prevData.value.cardInfo.assignLocation);
 const isExamTypeDisabled = computed(() => (isBindMode.value && prevData.value.cardInfo.assignExamType) || !examTypeForm.value.location);
 
+const inputPlaceholder = computed(() => {
+  return isBindMode.value ? '请输入(提交后不可修改)' : '请输入';
+});
+const pickerPlaceholder = computed(() => {
+  return isBindMode.value ? '请选择(提交后不可修改)' : '请选择';
+});
 
 const classList = ref<ClassItem[]>([]);
 const showCulture = computed(() => {
   return examTypeForm.value.examType === EnumExamType.OHS;
 });
+const handleNoSchool = () => {
+  uni.showActionSheet({
+    title: '联系客服处理',
+    itemList: ['拨打电话:400-1797-985'],
+    success: (res) => {
+      uni.makePhoneCall({
+        phoneNumber: '400-1797-985'
+      });
+    }
+  });
+}
 const handleSchoolSelect = () => {
   if (isSchoolDisabled.value) {
     return;

+ 2 - 2
src/pagesSystem/pages/card-verify/card-verify.vue

@@ -22,8 +22,8 @@ import { useUserStore } from '@/store/userStore';
 const { transferTo } = useTransferPage();
 const userStore = useUserStore();
 const form = ref({
-  cardNo: '',
-  password: ''
+  cardNo: '', // 60005001
+  password: '', // 719615
 });
 const handleSubmit = async () => {
   const { cardNo, password } = form.value;

+ 9 - 9
src/pagesSystem/pages/edit-student-profile/edit-student-profile.vue

@@ -19,21 +19,21 @@
             <uv-input v-model="form.location" border="none" placeholder="" placeholderClass="text-30" font-size="30rpx"
               :custom-style="customStyle" readonly>
             </uv-input>
-            <ie-image slot="right" src="/static/image/icon/icon-lock.png" custom-class="w-24 h-30"
+            <ie-image slot="right" src="/static/image/icon-lock.png" custom-class="w-24 h-30"
               mode="aspectFill" />
           </uv-form-item>
           <uv-form-item label="考试类别" prop="name" borderBottom>
             <view class="flex-1 pl-[26px]">
               <ie-dict :dictName="EnumDictName.EXAM_TYPE" :dictValue="form.examType" />
             </view>
-            <ie-image slot="right" src="/static/image/icon/icon-lock.png" custom-class="w-24 h-30"
+            <ie-image slot="right" src="/static/image/icon-lock.png" custom-class="w-24 h-30"
               mode="aspectFill" />
           </uv-form-item>
           <uv-form-item label="毕业年份" prop="name">
             <uv-input v-model="form.endYear" border="none" placeholder="" placeholderClass="text-30" font-size="30rpx"
               :custom-style="customStyle" readonly>
             </uv-input>
-            <ie-image slot="right" src="/static/image/icon/icon-lock.png" custom-class="w-24 h-30"
+            <ie-image slot="right" src="/static/image/icon-lock.png" custom-class="w-24 h-30"
               mode="aspectFill" />
           </uv-form-item>
         </content-card>
@@ -44,21 +44,21 @@
               font-size="30rpx" :custom-style="customStyle" :readonly="form.examType === EnumExamType.OHS">
             </uv-input>
             <ie-image v-if="form.examType === EnumExamType.OHS" slot="right"
-              src="/static/image/icon/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
+              src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
           </uv-form-item>
           <uv-form-item label="数学" prop="name" borderBottom>
             <uv-input v-model="scores.mathematics" border="none" placeholder="请输入" placeholderClass="text-30"
               font-size="30rpx" :custom-style="customStyle" :readonly="form.examType === EnumExamType.OHS">
             </uv-input>
             <ie-image v-if="form.examType === EnumExamType.OHS" slot="right"
-              src="/static/image/icon/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
+              src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
           </uv-form-item>
           <uv-form-item label="外语" prop="name" :borderBottom="form.examType === EnumExamType.OHS">
             <uv-input v-model="scores.foreign" border="none" placeholder="请输入" placeholderClass="text-30"
               font-size="30rpx" :custom-style="customStyle" :readonly="form.examType === EnumExamType.OHS">
             </uv-input>
             <ie-image v-if="form.examType === EnumExamType.OHS" slot="right"
-              src="/static/image/icon/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
+              src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
           </uv-form-item>
           <block v-if="[EnumExamType.OHS].includes(form.examType)">
             <uv-form-item label="物理" prop="name" borderBottom>
@@ -66,14 +66,14 @@
                 font-size="30rpx" :custom-style="customStyle" :readonly="form.examType === EnumExamType.OHS">
               </uv-input>
               <ie-image v-if="form.examType === EnumExamType.OHS" slot="right"
-                src="/static/image/icon/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
+                src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
             </uv-form-item>
             <uv-form-item label="政治" prop="name">
               <uv-input v-model="scores.political" border="none" placeholder="请输入" placeholderClass="text-30"
                 font-size="30rpx" :custom-style="customStyle" :readonly="form.examType === EnumExamType.OHS">
               </uv-input>
               <ie-image v-if="form.examType === EnumExamType.OHS" slot="right"
-                src="/static/image/icon/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
+                src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
             </uv-form-item>
           </block>
         </content-card>
@@ -92,7 +92,7 @@
             <uv-input v-model="form.schoolName" border="none" placeholder="" placeholderClass="text-30"
               font-size="30rpx" :custom-style="customStyle" readonly>
             </uv-input>
-            <ie-image slot="right" src="/static/image/icon/icon-lock.png" custom-class="w-24 h-30"
+            <ie-image slot="right" src="/static/image/icon-lock.png" custom-class="w-24 h-30"
               mode="aspectFill" />
           </uv-form-item>
           <uv-form-item label="所在班级" prop="form.name">

+ 6 - 4
src/pagesSystem/pages/school-select/school-select.vue

@@ -6,12 +6,14 @@
           <ie-navbar title="选择学校" />
           <view class="bg-white px-30 py-20">
             <uv-input placeholder="请输入关键字" border="surround" shape="circle" prefixIcon="search"
-              prefixIconStyle="font-size: 22px;color: #909399" v-model="keyword" @confirm="handleConfirm"></uv-input>
+              :customStyle="{ backgroundColor: '#f8fcff' }" prefixIconStyle="font-size: 22px;color: #909399" clearable
+              v-model="keyword" @confirm="handleConfirm" @clear="handleConfirm"></uv-input>
           </view>
         </view>
       </template>
-      <view class="mt-16">
-        <view class="p-20 bg-white" v-for="item in list" :key="item.id" @click="handleItemClick(item)">
+      <view class="mt-16 px-20 bg-white ">
+        <view class="py-24 border-0 border-b border-solid border-[#EFEFEF]" v-for="item in list" :key="item.id"
+          @click="handleItemClick(item)">
           {{ item.name }}
         </view>
       </view>
@@ -34,7 +36,7 @@ const handleQuery = (pageNum: number, pageSize: number) => {
     pageNum,
     pageSize
   }).then(res => {
-    paging.value.complete(res.rows, res.total);
+    paging.value.completeByTotal(res.rows, res.total);
   }).catch(e => {
     paging.value.complete(false);
   }).finally(() => {

+ 1 - 0
src/store/userStore.ts

@@ -25,6 +25,7 @@ export const useUserStore = defineStore('ie-user', {
     card: null,
     isDefaultModifyPwd: false,
     isPasswordExpired: false,
+    isExamGuideShow: false,
     tempInfo: {
       location: '',
       examType: '',

+ 1 - 0
src/types/index.ts

@@ -79,6 +79,7 @@ export interface UserStoreState {
   isDefaultModifyPwd?: boolean;
   isPasswordExpired?: boolean;
   card: VipCardInfo | null;
+  isExamGuideShow: boolean;
   tempInfo?: {
     location: string;
     examType: string;

+ 80 - 23
src/uni_modules/fast-guide/components/fast-guide/fast-guide.vue

@@ -2,7 +2,8 @@
   <view v-if="show" @click="focusTap" @touchmove.stop.prevent :style="{ '--path': path, '--duration': duration + 'ms' }"
     class="clip-container">
     <view @click.stop="maskTap" class="clip-box"></view>
-    <view @click.stop class="guide-box animate__animated" :class="[contentVisible ? 'opacity-100' : 'opacity-0']" :style="[msgStyles]">
+    <view @click.stop class="guide-box animate__animated" :class="[contentVisible ? 'opacity-100' : 'opacity-0']"
+      :style="[msgStyles]">
       <view v-if="$slots.message" class="">
         <slot name="message" :msg="list[index].msg"></slot>
       </view>
@@ -11,10 +12,10 @@
       </view>
 
       <view class="step-box">
-        <view v-if="index > 0" @click="lastStep" class="step-btn">
+        <view @click="lastStep" class="step-btn" :class="{ 'opacity-0': index === 0 }">
           上一步
         </view>
-        <view @click="nextStep" class="step-btn">
+        <view @click="nextStep" class="step-btn next-btn">
           下一步
         </view>
         <view @click="skipStep" class="step-btn">
@@ -96,7 +97,7 @@ export default {
     },
     // 动画时长
     duration: {
-      default: 350
+      default: 500
     },
     // 换算单位
     unit: {
@@ -139,6 +140,8 @@ export default {
       return val === null || val === undefined || val === ''
     },
     async getCurrentPath() {
+      let maxWidth
+      // 优化6: 使用requestAnimationFrame确保在正确的时机执行动画
       await this.$nextTick(() => { })
 
       let {
@@ -161,7 +164,7 @@ export default {
       let x1, x2, y1, y2
 
       if (target) {
-        let maxWidth
+
         uni.getSystemInfo({
           success(res) {
             // #ifndef H5
@@ -221,12 +224,29 @@ export default {
         y1 = !this.isEmpty(top) ? `${this.addUnit(top)}` : `calc(100% - ${this.addUnit(bottom)} - ${this.addUnit(height)})`
         y2 = !this.isEmpty(top) ? `calc(${this.addUnit(top)} + ${this.addUnit(height)})` : `calc(100% - ${this.addUnit(bottom)})`
       }
-      // 延时,解决动画丢失的问题
+
+      // 优化7: 使用requestAnimationFrame替代setTimeout,确保动画在浏览器重绘前执行
       await new Promise((resolve) => {
+        // #ifdef H5
+        if (typeof requestAnimationFrame !== 'undefined') {
+          requestAnimationFrame(() => {
+            requestAnimationFrame(() => {
+              resolve()
+            })
+          })
+        } else {
+          setTimeout(() => {
+            resolve()
+          }, 50)
+        }
+        // #endif
+        // #ifndef H5
         setTimeout(() => {
           resolve()
         }, 50)
+        // #endif
       })
+
       this.path = `
 					polygon(
 						0% 0%,
@@ -242,8 +262,6 @@ export default {
 					)
 				`
       // console.log(this.path,'path.value')
-
-
       //设置msg样式
       const msgDom = await new Promise((resolve, reject) => {
         uni.createSelectorQuery().in(this).select('.guide-box').boundingClientRect(data => {
@@ -300,22 +318,38 @@ export default {
         }
 
       }
+      let boxLeft = left;
+      let boxRight = right;
+      if (!boxLeft) {
+        boxLeft = maxWidth - right - msgDom.width
+      }
+      if (boxLeft < 10) {
+        boxLeft = 10; // 和边界留出10px的距离
+      }
+      if (!boxRight) {
+        boxRight = maxWidth - left - msgDom.width
+      }
+      if (boxRight > maxWidth - 10) {
+        boxRight = maxWidth - 10; // 和边界留出10px的距离
+      }
       left = target ? this.addUnit(left, 'px') : this.addUnit(left)
       right = target ? this.addUnit(right, 'px') : this.addUnit(right)
-
+      // 优化8: 明确指定需要过渡的属性
       this.msgStyles = {
         'top': top,
-        'left': left,
-        'right': right,
-        // 'transition': `all ${this.duration}ms`,
+        'left': this.addUnit(boxLeft, 'px'),
+        'right': this.addUnit(boxRight, 'px'),
+        'transition': `all ${this.duration}ms`,
         'animation-name': animationName,
         '-webkit-animation-name': animationName,
 
         ...msgStyles
       }
-      setTimeout(() => {
-        this.contentVisible = true;
-      }, 300);
+      if (this.contentVisible === false) {
+        setTimeout(() => {
+          this.contentVisible = true;
+        }, 600);
+      }
     },
     nextStep() {
       if (this.list[this.index + 1]) {
@@ -331,6 +365,7 @@ export default {
       }
     },
     lastStep() {
+      this.$emit('update:index', this.index - 1)
       this.$emit('last', this.callBackData())
     },
     skipStep() {
@@ -369,7 +404,7 @@ export default {
 .clip-container {
   --path: '';
   --duration: '';
-  --color: #1676ff;
+  --color: #31A0FC;
 
   position: absolute;
   /* #ifdef H5 */
@@ -390,17 +425,28 @@ export default {
   box-sizing: border-box;
   width: 100%;
   height: 100vh;
-  transition: all var(--duration);
+  /* 优化1: 只对clip-path做过渡,避免transition: all */
+  transition: clip-path var(--duration);
+
+  /* 优化2: 提示浏览器即将变化的属性,提前优化 */
+  will-change: clip-path;
 
   clip-path: var(--path);
 
-  background-color: rgba(0, 0, 0, 0.5);
+  background-color: rgba(0, 0, 0, 0.4);
+
+  /* 优化3: 强制开启硬件加速(如果浏览器支持) */
+  transform: translateZ(0);
+  -webkit-transform: translateZ(0);
 
 }
 
 .guide-box {
-  width: 50%;
-  transition: all var(--duration);
+  // width: 50%;
+  width: fit-content;
+  max-width: 80%;
+  /* 优化4: 明确指定需要过渡的属性,避免all */
+  transition: left var(--duration), right var(--duration), top var(--duration), bottom var(--duration), opacity var(--duration);
   position: absolute;
   color: var(--color);
   background-color: #fff;
@@ -411,10 +457,16 @@ export default {
 
   display: flex;
   flex-direction: column;
+
+  /* 优化5: 开启硬件加速 */
+  transform: translateZ(0);
+  -webkit-transform: translateZ(0);
+  will-change: top, left, right, bottom, opacity;
 }
 
 .msg-label {
   font-size: 28rpx;
+  white-space: pre;
 }
 
 .step-box {
@@ -430,11 +482,16 @@ export default {
 .step-btn {
   margin-left: 20rpx;
   box-shadow: 2rpx 2rpx 12rpx #ddd;
-  padding: 6rpx 16rpx;
-  border-radius: 8rpx;
-  font-size: 26rpx;
+  padding: 12rpx 30rpx;
+  border-radius: 4px;
+  font-size: 24rpx;
+  background-color: white;
 }
 
+.next-btn {
+  color: white;
+  background-color: var(--color);
+}
 
 @-webkit-keyframes backInDown {
   0% {

+ 4 - 2
src/uni_modules/uv-input/components/uv-input/uv-input.vue

@@ -149,7 +149,7 @@
 			// 是否显示清除控件
 			isShowClear() {
 				const { clearable, readonly, focused, innerValue } = this;
-				return !!clearable && !readonly && !!focused && innerValue !== "";
+				return !!clearable && !readonly && innerValue !== "";
 			},
 			// 组件的类名
 			inputClass() {
@@ -262,8 +262,10 @@
 					this.isClear = false;
 				})
 				this.$nextTick(() => {
-					this.$emit("clear");
 					this.valueChange();
+          setTimeout(() => {
+            this.$emit("clear");
+          }, 0);
 				});
 			},
 			/**