瀏覽代碼

新增免费试用,修改路由逻辑

wyling 3 年之前
父節點
當前提交
c3cb2971e3

+ 26 - 1
src/hooks/index.ts

@@ -1,6 +1,6 @@
 import { computed } from "vue";
 import { useStore } from "vuex";
-import { useRoute } from "vue-router";
+import { useRoute, useRouter } from "vue-router";
 /**
  * 获取用户会员到期时间
  */
@@ -23,3 +23,28 @@ export const useRouteQuery = () => {
     query,
   };
 };
+
+/**
+ * 路由转发汇总class模式书写,需要注意this指向
+ * @returns
+ */
+export class RouterBus {
+  router;
+  route;
+  constructor() {
+    this.router = useRouter();
+    this.route = useRoute();
+  }
+  /**
+   * 会员购买页
+   */
+  goBuyVip = () => {
+    this.router.push("/buyVip");
+  };
+  /**
+   * 模拟考试页
+   */
+  goMockTest = () => {
+    this.router.push({ path: "/mockTest", query: this.route.query });
+  };
+}

+ 0 - 7
src/route/routerPush.ts

@@ -1,7 +0,0 @@
-import router from ".";
-
-/**
- * 会员购买页
- * @returns
- */
-export const goBuyVip = () => router.push("/buyVip");

+ 7 - 7
src/views/exercise/index.vue

@@ -1,9 +1,9 @@
 <template>
   <!-- 导航栏 -->
   <van-nav-bar
-    title="标题"
+    :title="query.vehicle + '>' + query.name"
     left-arrow
-    @click-left="onClickLeft"
+    @click-left="back"
     fixed
     placeholder
   >
@@ -276,13 +276,13 @@
 </template>
 
 <script lang="ts" setup>
-import { useRouter } from "vue-router";
 import { ref } from "vue";
 import { useTopicMode, useAudioSet, useSubjectShowLogic } from "./hooks";
-const router = useRouter();
-const onClickLeft = () => {
-  router.back();
-};
+import { RouterBus } from "@/hooks";
+const {
+  router: { back },
+  route: { query },
+} = new RouterBus();
 
 //答题模式选择逻辑
 const { answerTypeList, currentType, typeParams } = useTopicMode();

+ 273 - 0
src/views/exerciseFree/hooks.ts

@@ -0,0 +1,273 @@
+import {
+  ref,
+  watch,
+  onBeforeMount,
+  Ref,
+  computed,
+  nextTick,
+  ComputedRef,
+} from "vue";
+import * as API from "@/api";
+import { Howl, Howler } from "howler";
+import { useRoute } from "vue-router";
+
+//答题模式切换
+export function useTopicMode() {
+  const answerTypeList = ref([
+    { name: "顺序练习" },
+    { name: "随机练习" },
+    { name: "背题模式" },
+  ]);
+  const currentType = ref(0);
+  const typeParams = ref({
+    order: true, //顺序练习
+    answerShow: false, //背题模式
+  });
+  watch(currentType, (currentVal) => {
+    switch (currentVal) {
+      case 0:
+        typeParams.value.order = true;
+        typeParams.value.answerShow = false;
+        break;
+      case 1:
+        typeParams.value.order = false;
+        typeParams.value.answerShow = false;
+        break;
+      case 2:
+        typeParams.value.order = true;
+        typeParams.value.answerShow = true;
+        break;
+    }
+  });
+  return {
+    answerTypeList,
+    currentType,
+    typeParams,
+  };
+}
+
+//语音设置
+export function useAudioSet(currentSubject: ComputedRef<any>) {
+  const aotuPlayFlag = ref(false);
+
+  let sound: Howl;
+  /**
+   * 播放音频
+   * @param audioUrl
+   */
+  const audioPlay = (audioUrl: string | string[]) => {
+    audioPause();
+    sound = new Howl({
+      src: audioUrl,
+    });
+    sound.once("load", function () {
+      sound.play();
+    });
+    if (typeof audioUrl === "object") {
+      sound.once("end", () => {
+        sound = new Howl({
+          src: audioUrl[1],
+        });
+        sound.once("load", function () {
+          sound.play();
+        });
+      });
+    }
+  };
+
+  /**
+   * 读题
+   */
+  const subjectAudioPlay = (
+    type: "读题" | "读官方解释" | "读技巧解释" | "读题+答案"
+  ) => {
+    switch (type) {
+      case "读题":
+        audioPlay(currentSubject.value.issuemp3);
+        break;
+      case "读官方解释":
+        audioPlay(currentSubject.value.explainjsmp3);
+        break;
+      case "读技巧解释":
+        audioPlay(currentSubject.value.explainMp3);
+        break;
+      case "读题+答案":
+        audioPlay([currentSubject.value.issuemp3, currentSubject.value.answermp3]);
+        break;
+      default:
+        break;
+    }
+  };
+
+  /**
+   * 停止播放
+   */
+  const audioPause = () => {
+    sound && sound.pause();
+  };
+
+  //音频模块end
+  const aotuPlaySet = () => {
+    aotuPlayFlag.value = !aotuPlayFlag.value;
+    aotuPlayFlag.value ? subjectAudioPlay("读题") : audioPause();
+  };
+
+  //自动读题
+  watch(currentSubject, () => {
+    if (aotuPlayFlag.value) subjectAudioPlay("读题"); //自动读题
+  });
+
+  return {
+    aotuPlayFlag,
+    aotuPlaySet,
+    subjectAudioPlay
+  };
+}
+
+const useSubjectList = () => {
+  const subjectList = ref<any[]>([]); //题目列表
+  const subjectTotal = ref(0); //题目总数
+  const pageNum = ref(1); //当前请求页码
+  const pageSize = ref(100); //当前请求每页数据
+  const query = useRoute().query; //路由query参数
+  onBeforeMount(async () => {
+    const res = await API.getTopicList({
+      ...query,
+      pageNum: pageNum.value,
+      pageSize: pageSize.value,
+    });
+    subjectList.value = res.list;
+    subjectTotal.value = res.total;
+  });
+  //加载下一页数据
+  const loadNewSubject = async () => {
+    if (subjectList.value.length == subjectTotal.value) return;
+    pageNum.value++;
+    const res = await API.getTopicList({
+      ...query,
+      pageNum: pageNum.value,
+      pageSize: pageSize.value,
+    });
+    subjectList.value = subjectList.value.concat(res.list);
+  };
+  const currentSubjectIndex = ref(0); //当前题目下标
+  //当前题目内容
+  const currentSubject = computed(() => {
+    return subjectList.value[currentSubjectIndex.value];
+  });
+  return {
+    subjectList,
+    subjectTotal,
+    loadNewSubject,
+    currentSubject,
+    currentSubjectIndex,
+  };
+};
+
+const useSubjectCheck = (
+  currentSubject: ComputedRef<any>,
+  nextSubject: () => Promise<void>
+) => {
+  const trueNum = ref(0); //正确数量
+  const falseNum = ref(0); //错误数量
+  const isJumpNext = ref(false); //答对跳转下一题
+
+  /**
+   * 选择答案后进行校验
+   */
+  const userAnswerChange = () => {
+    currentSubject.value.optsBack = currentSubject.value.opts.map(
+      (val: String) => {
+        let status;
+        if (currentSubject.value.answer.includes(val)) {
+          status = 1;
+        } else {
+          status = 0;
+        }
+        if (currentSubject.value.userAnswer.includes(val)) {
+          status += 2;
+        }
+        return { opt: val, status };
+      }
+    );
+    if (
+      JSON.stringify(currentSubject.value.answer) ==
+      JSON.stringify(currentSubject.value.userAnswer)
+    ) {
+      console.log("答案正确");
+      currentSubject.value.isTrue = true;
+      trueNum.value++;
+      if (isJumpNext.value) {
+        nextTick(() => {
+          nextSubject();
+        });
+      }
+    } else {
+      console.log("错误");
+      currentSubject.value.isTrue = false;
+      falseNum.value++;
+    }
+  };
+
+  return {
+    trueNum,
+    falseNum,
+    isJumpNext,
+    userAnswerChange,
+  };
+};
+
+export const useSubjectShowLogic = () => {
+  const {
+    subjectList,
+    subjectTotal,
+    loadNewSubject,
+    currentSubject,
+    currentSubjectIndex,
+  } = useSubjectList(); //获取题目列表
+
+  const nextBtnState = ref(true); //下一题数据请求锁
+  /**
+   * 展示下一题
+   */
+  const nextSubject = async () => {
+    if (currentSubjectIndex.value < subjectList.value.length - 1) {
+      currentSubjectIndex.value++;
+    } else {
+      if (nextBtnState.value) {
+        //禁用下一题按钮
+        nextBtnState.value = false;
+        //题目数量不足加载数据
+        await loadNewSubject();
+        //启用按钮
+        nextBtnState.value = true;
+        nextSubject();
+      }
+    }
+  };
+  /**
+   * 展示上一题
+   */
+  const lastSubject = () => {
+    if (currentSubjectIndex.value > 0) {
+      currentSubjectIndex.value--;
+    }
+  };
+
+  const { trueNum, falseNum, isJumpNext, userAnswerChange } = useSubjectCheck(
+    currentSubject,
+    nextSubject
+  );
+
+  return {
+    currentSubject,
+    currentSubjectIndex,
+    subjectTotal,
+    nextSubject,
+    lastSubject,
+    trueNum,
+    falseNum,
+    isJumpNext,
+    userAnswerChange,
+  };
+};

+ 509 - 0
src/views/exerciseFree/index.vue

@@ -0,0 +1,509 @@
+<template>
+  <!-- 导航栏 -->
+  <van-nav-bar
+    :title="query.vehicle + '>' + query.name"
+    left-arrow
+    @click-left="back"
+    fixed
+    placeholder
+  >
+    <template #right>
+      <m-icon type="shezhi" @click="setShow = true" />
+    </template>
+  </van-nav-bar>
+  <!-- 导航栏end -->
+  <!-- 答题模式选择 -->
+  <div class="answerType">
+    <span
+      v-for="(answerType, index) in answerTypeList"
+      :key="index"
+      :class="{ selected: currentType == index }"
+      @click="currentType = index"
+      >{{ answerType.name }}</span
+    >
+    <span :class="{ selected: aotuPlayFlag }" @click="aotuPlaySet"
+      >自动读题</span
+    >
+  </div>
+  <!-- 答题模式选择end -->
+  <!-- 分割线 -->
+  <div class="divider" />
+  <!-- 题目模块 -->
+  <!-- 题目预加载 -->
+  <m-empty v-if="!currentSubject" />
+  <!-- 题目预加载end -->
+  <div class="problem-box" v-else>
+    <!-- 题目内容 -->
+    <div class="problem">
+      <span class="type">{{ currentSubject.type }}</span>
+      <span class="text">{{ currentSubject.explain }}</span>
+      <van-image
+        v-if="currentSubject.image"
+        :src="currentSubject.image"
+        class="img"
+      >
+        <template v-slot:loading>
+          <van-loading type="spinner" size="20" />
+        </template>
+      </van-image>
+    </div>
+    <!-- 背题模式展示 -->
+    <div v-if="typeParams.answerShow">
+      <div>
+        <div
+          class="answer-box"
+          v-for="(item, index) in currentSubject.opts"
+          :key="Number(index)"
+        >
+          <div class="choose-icon">
+            {{ String.fromCharCode(65 + Number(index)) }}
+          </div>
+          <span
+            class="answer-text"
+            :class="{ true: currentSubject.answer.includes(item) }"
+          >
+            {{ item }}
+          </span>
+        </div>
+      </div>
+      <div class="checkbox-answer">
+        答案: {{ currentSubject.answer.toString() }}
+      </div>
+    </div>
+    <!-- 背题模式展示end -->
+    <!-- 选择内容 -->
+    <div v-else-if="currentSubject.isTrue === null">
+      <!-- 单选 -->
+      <van-radio-group
+        v-model="currentSubject.userAnswer"
+        v-if="currentSubject.type != '多选题'"
+        @change="userAnswerChange"
+        icon-size="35px"
+      >
+        <van-radio
+          v-for="(item, index) in currentSubject.opts"
+          :key="Number(index)"
+          :name="item"
+          class="answer"
+          >{{ item }}
+          <template #icon="props">
+            <div class="choose-icon" :class="{ selected: props.checked }">
+              {{ String.fromCharCode(65 + Number(index)) }}
+            </div>
+          </template>
+        </van-radio>
+      </van-radio-group>
+      <!-- 多选 -->
+      <div v-else>
+        <van-checkbox-group
+          v-model="currentSubject.userAnswer"
+          icon-size="35px"
+        >
+          <van-checkbox
+            v-for="(item, index) in currentSubject.opts"
+            :key="Number(index)"
+            :name="item"
+            class="answer"
+            >{{ item }}
+            <template #icon="props">
+              <div class="choose-icon" :class="{ selected: props.checked }">
+                {{ String.fromCharCode(65 + Number(index)) }}
+              </div>
+            </template>
+          </van-checkbox>
+        </van-checkbox-group>
+        <van-button
+          round
+          type="primary"
+          class="checkbox-btn"
+          :disabled="currentSubject.userAnswer.length == 0"
+          @click="userAnswerChange"
+          >确定</van-button
+        >
+      </div>
+    </div>
+    <!-- 展示答题后选择内容 -->
+    <div v-else>
+      <div>
+        <div
+          v-for="(item, index) in currentSubject.optsBack"
+          :key="Number(index)"
+          class="answer-box"
+        >
+          <div
+            class="choose-icon"
+            :class="{ iconTrue: item.status % 2 !== 0 }"
+            v-if="item.status < 2"
+          >
+            {{ String.fromCharCode(65 + Number(index)) }}
+          </div>
+          <m-icon
+            v-else-if="item.status == 3"
+            type="dui"
+            size="30px"
+            style="margin-left: 5px"
+          />
+          <m-icon
+            v-else-if="item.status == 2"
+            size="30px"
+            type="cuo"
+            style="margin-left: 5px"
+          />
+          <span
+            class="answer-text"
+            :class="{ true: item.status % 2 !== 0, false: item.status == 2 }"
+          >
+            {{ item.opt }}
+          </span>
+        </div>
+      </div>
+      <div class="checkbox-answer">
+        答案: {{ currentSubject.answer.toString() }}
+      </div>
+    </div>
+    <!-- 展示答题后选择内容end -->
+  </div>
+  <!-- 选择内容End -->
+  <!-- 分割线 -->
+  <van-divider />
+  <!-- 功能选择列表 -->
+  <div class="function-list">
+    <div class="function-item">
+      <m-icon type="shoucanghui" size="25px" />
+      <span>收藏</span>
+    </div>
+    <div class="function-item" @click="subjectAudioPlay('读题+答案')">
+      <m-icon type="a-dtda" size="25px" />
+      <span>读题+答案</span>
+    </div>
+    <div class="function-item" @click="subjectAudioPlay('读题')">
+      <m-icon type="duti" size="25px" />
+      <span>读题</span>
+    </div>
+    <div class="function-item" @click="skillsShow = true">
+      <m-icon type="jqjj" size="25px" />
+      <span>技巧讲解</span>
+    </div>
+  </div>
+  <!-- 功能选择列表End -->
+  <!-- 技巧讲解 -->
+  <van-overlay :show="skillsShow" @click="skillsShow = false" z-index="10">
+    <div class="skills-box" @click.stop>
+      <div class="skills">
+        <div class="title">技巧讲解</div>
+        <img :src="currentSubject.explainGif" class="img" />
+        <van-divider class="divider">本题速记口诀</van-divider>
+        <div class="text">{{ currentSubject.explainJq }}</div>
+        <div class="btn">
+          <span @click="skillsShow = false">关闭</span>
+          <span @click="subjectAudioPlay('读技巧解释')">语音重播</span>
+        </div>
+      </div>
+    </div>
+  </van-overlay>
+  <!-- 技巧讲解end -->
+  <!-- 官方解释 -->
+  <van-overlay :show="officialShow" @click="officialShow = false" z-index="10">
+    <div class="skills-box" @click.stop>
+      <div class="skills">
+        <div class="title">官方解释</div>
+        <div class="text">
+          {{ currentSubject.explainJs }}
+        </div>
+        <div class="btn">
+          <span @click="officialShow = false">关闭</span>
+          <span @click="subjectAudioPlay('读官方解释')">语音重播</span>
+        </div>
+      </div>
+    </div>
+  </van-overlay>
+  <!-- 官方解释end -->
+  <!-- 题目模块end -->
+  <!-- 设置操作栏 -->
+  <van-popup v-model:show="setShow" position="bottom">
+    <van-cell center title="答对跳转下一题">
+      <template #right-icon>
+        <van-switch v-model="isJumpNext" size="24" />
+      </template>
+    </van-cell>
+    <van-cell center title="答题音效提示">
+      <template #right-icon>
+        <van-switch v-model="isSoundEffect" size="24" />
+      </template>
+    </van-cell>
+  </van-popup>
+  <!-- 设置操作栏end -->
+  <!-- 底部操作栏 -->
+  <van-tabbar placeholder route>
+    <van-tabbar-item @click="lastSubject"
+      >上一题
+      <template #icon>
+        <m-icon type="shangyiti" />
+      </template>
+    </van-tabbar-item>
+    <van-tabbar-item
+      >{{ trueNum }}
+      <template #icon>
+        <m-icon type="dui" />
+      </template>
+    </van-tabbar-item>
+    <van-tabbar-item
+      >{{ falseNum }}
+      <template #icon>
+        <m-icon type="cuo" />
+      </template>
+    </van-tabbar-item>
+    <van-tabbar-item
+      >{{ currentSubjectIndex + 1 }}/{{ subjectTotal }}
+      <template #icon>
+        <m-icon type="zongtishu" />
+      </template>
+    </van-tabbar-item>
+    <van-tabbar-item @click="officialShow = true"
+      >官方解释
+      <template #icon>
+        <m-icon type="gfjs" />
+      </template>
+    </van-tabbar-item>
+    <van-tabbar-item @click="nextSubject"
+      >下一题
+      <template #icon>
+        <m-icon type="xiayiti" />
+      </template>
+    </van-tabbar-item>
+  </van-tabbar>
+  <!-- 底部操作栏end -->
+</template>
+
+<script lang="ts" setup>
+import { ref } from "vue";
+import { useTopicMode, useAudioSet, useSubjectShowLogic } from "./hooks";
+import { RouterBus } from "@/hooks";
+const {
+  router: { back },
+  route: { query },
+} = new RouterBus();
+
+//答题模式选择逻辑
+const { answerTypeList, currentType, typeParams } = useTopicMode();
+
+const skillsShow = ref(false); //显示技巧讲解
+const officialShow = ref(false); //显示官方解释
+
+//设置操作栏
+const setShow = ref(false); //显示设置栏
+const isSoundEffect = ref(true); //答题音效
+
+//题目展示逻辑
+const {
+  currentSubject,
+  currentSubjectIndex,
+  subjectTotal,
+  nextSubject,
+  lastSubject,
+  trueNum,
+  falseNum,
+  isJumpNext,
+  userAnswerChange,
+} = useSubjectShowLogic();
+
+//音频模块
+const { aotuPlayFlag, subjectAudioPlay, aotuPlaySet } =
+  useAudioSet(currentSubject);
+</script>
+
+<style lang="scss" scoped>
+.parsing-img {
+  width: 100%;
+  margin-top: 10px;
+}
+.function-list {
+  width: 100%;
+  font-size: 13px;
+  display: flex;
+  justify-content: space-around;
+  padding: 15px;
+  box-sizing: border-box;
+  .function-item {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    font-size: 13px;
+    font-weight: 400;
+    color: #8a9099;
+    span {
+      margin-top: 5px;
+    }
+  }
+}
+.answerType {
+  width: 100%;
+  font-size: 13px;
+  display: flex;
+  justify-content: space-around;
+  padding: 15px;
+  box-sizing: border-box;
+  span {
+    border-radius: 20px;
+    padding: 3px 10px;
+    background-color: #b8c0cc;
+    color: #ffffff;
+  }
+  .selected {
+    background-color: #498ef5;
+  }
+}
+.divider {
+  width: 100%;
+  height: 10px;
+  background-color: #f2f3f5;
+}
+.problem-box {
+  font-size: 17px;
+  padding: 15px;
+  .problem {
+    .type {
+      width: 47px;
+      height: 24px;
+      background: #498ef5;
+      border-radius: 10px 10px 0px 10px;
+      font-size: 11px;
+      padding: 2px 7px;
+      margin-right: 5px;
+    }
+    .text {
+      font-family: PingFang SC;
+      font-weight: 400;
+      color: #0a1a33;
+      letter-spacing: 0.3px;
+    }
+    .img {
+      width: 100%;
+      margin-top: 10px;
+    }
+  }
+  .answer {
+    margin-top: 25px;
+  }
+  .answer-box {
+    display: flex;
+    margin-top: 25px;
+    align-items: center;
+    .iconTrue {
+      background-color: #01c18d;
+    }
+    .answer-text {
+      margin-left: 10px;
+    }
+    .true {
+      color: #01c18d;
+    }
+    .false {
+      color: #ff4d53;
+    }
+  }
+
+  .choose-icon {
+    width: 30px;
+    height: 30px;
+    border-radius: 50%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    font-size: 17px;
+    box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.16);
+    box-sizing: border-box;
+    margin-left: 5px;
+    margin-top: 1px;
+  }
+  .selected {
+    background-color: #498ef5;
+  }
+  .checkbox-btn {
+    width: 266px;
+    height: 40px;
+    margin: auto;
+    margin-top: 25px;
+    left: 50%;
+    transform: translateX(-50%);
+  }
+  .checkbox-answer {
+    padding: 8px 10px;
+    background-color: #f2f3f5;
+    margin-top: 25px;
+  }
+}
+.skills-box {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 100%;
+  .skills {
+    width: 290px;
+    background: #ffffff;
+    box-shadow: 0px 0px 8px rgba(124, 129, 136, 0.16);
+    border-radius: 10px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding: 20px 16px;
+    box-sizing: border-box;
+    .title {
+      font-size: 15px;
+      font-family: PingFang SC;
+      font-weight: bold;
+      line-height: 21px;
+      color: #0a1a33;
+    }
+    .img {
+      width: 258px;
+      height: 129px;
+      border: 1px solid #e8e8e8;
+      margin-top: 16px;
+    }
+    .divider {
+      margin-top: 20px;
+      color: #0a1a33;
+      background: #ffffff;
+    }
+    .text {
+      font-size: 13px;
+      font-family: PingFang SC;
+      font-weight: 400;
+      line-height: 19px;
+      color: #5c6066;
+      margin-top: 10px;
+    }
+    .btn {
+      width: 100%;
+      display: flex;
+      justify-content: space-between;
+      padding: 0 40px;
+      box-sizing: border-box;
+      margin-top: 20px;
+      span {
+        width: 76px;
+        height: 30px;
+        border-radius: 15px;
+        font-size: 13px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        &:active {
+          background-color: #afaaaa;
+          filter: brightness(50%);
+        }
+        &:nth-of-type(1) {
+          border: 1px solid #707070;
+          color: #5c6066;
+        }
+        &:nth-of-type(2) {
+          background: #498ef5;
+          border: 1px solid #498ef5;
+          color: #ffffff;
+        }
+      }
+    }
+  }
+}
+</style>

+ 10 - 11
src/views/home/children/test/components/sujectOne.vue

@@ -6,7 +6,7 @@
           class="icon-box"
           v-for="(item, index) in testObj.left"
           :key="index"
-          @click="gotoRoute(item.route)"
+          @click="push(item.route)"
         >
           <m-icon :type="item.icon" isSvg />
           <span>{{ item.name }}</span>
@@ -17,7 +17,7 @@
           class="icon-box"
           v-for="(item, index) in testObj.center"
           :key="index"
-          @click="gotoRoute(item.route)"
+          @click="push(item.route)"
         >
           <m-icon :type="item.icon" isSvg />
           <span>{{ item.name }}</span>
@@ -28,7 +28,7 @@
           class="icon-box"
           v-for="(item, index) in testObj.right"
           :key="index"
-          @click="gotoRoute(item.route)"
+          @click="push(item.route)"
         >
           <m-icon :type="item.icon" isSvg />
           <span>{{ item.name }}</span>
@@ -39,13 +39,12 @@
 </template>
 
 <script lang="ts" setup>
-import { useRouter } from "vue-router";
-import { defineProps } from "vue";
+import { RouterBus } from "@/hooks";
 const props = defineProps(["query"]);
-const router = useRouter();
-const gotoRoute = (obj: any) => {
-  router.push(obj);
-};
+const {
+  router: { push },
+} = new RouterBus();
+
 const testList = [
   {
     left: [
@@ -93,8 +92,8 @@ const testList = [
     left: [
       {
         icon: "真实考场模拟",
-        name: "考场模拟",
-        route: { name: "mockTest", query: { ...props.query } },
+        name: "免费试用",
+        route: { name: "exerciseFree", query: { ...props.query } },
       },
       {
         icon: "模拟成绩",

+ 2 - 2
src/views/home/children/test/components/userData.vue

@@ -16,12 +16,12 @@
 </template>
 
 <script lang="ts">
-import { useExpireTime } from "@/hooks";
+import { useExpireTime, RouterBus } from "@/hooks";
 </script>
 
 <script lang="ts" setup>
-import { goBuyVip } from "@/route/routerPush";
 const { expireTime } = useExpireTime();
+const { goBuyVip } = new RouterBus();
 </script>
 
 <style lang="scss" scoped>

+ 3 - 1
src/views/home/children/user/index.vue

@@ -19,6 +19,7 @@
         :value="expireTime ? expireTime : '开通会员'"
         is-link
         center
+        @click="goBuyVip"
       >
         <template #icon>
           <m-icon type="hyyxq" class="cell-icon" />
@@ -51,12 +52,13 @@
 </template>
 
 <script lang="ts">
-import { useExpireTime } from "@/hooks";
+import { useExpireTime, RouterBus } from "@/hooks";
 </script>
 
 <script lang="ts" setup>
 import { loopPrepareOrder } from "@/api";
 const { expireTime } = useExpireTime();
+const { goBuyVip } = new RouterBus();
 </script>
 
 <style scoped lang="scss">

+ 1 - 3
src/views/mockTest/components/initMockTest.vue

@@ -44,9 +44,7 @@ import { useRoute } from "vue-router";
 <script lang="ts" setup>
 import { defineEmits } from "vue";
 const emits = defineEmits(["next"]);
-const gotoNextPage = () => {
-  emits("next");
-};
+const gotoNextPage = () => void emits("next");
 const { query } = useRoute();
 </script>
 

+ 9 - 9
src/views/mockTest/components/mockTestEnd.vue

@@ -28,19 +28,23 @@
   </div>
   <div class="btn-box">
     <m-button class="btn1" text="错题重做" />
-    <m-button class="btn2" text="重新测试" />
+    <m-button @click="againTest" class="btn2" text="重新测试" />
   </div>
 </template>
 
 <script setup lang="ts">
-import { defineEmits, defineProps, computed } from "vue";
+import { computed } from "vue";
 import dayjs from "dayjs";
 import { createTestScores } from "@/api";
-import { useRoute } from "vue-router";
-
+import { RouterBus } from "@/hooks";
 const props = defineProps(["userTestData"]);
+const emits = defineEmits(["next"]);
+
+const {
+  route: { query },
+} = new RouterBus();
 
-console.log(props.userTestData);
+const againTest = () => void emits("next");
 
 //是否通过考试
 const testResult = computed(() => {
@@ -51,15 +55,11 @@ const useTime = computed(() => {
   return dayjs(props.userTestData.useTime).format("mm分ss秒");
 });
 
-const { query } = useRoute();
-
 //提交考试成绩
 createTestScores({
   type: query.vehicle as string,
   kskm: query.name as string,
   score: props.userTestData.testScores,
-}).then((res) => {
-  console.log(res);
 });
 </script>
 

+ 12 - 9
src/views/mockTest/components/startTest.vue

@@ -1,6 +1,12 @@
 <template>
   <!-- 导航栏 -->
-  <van-nav-bar title="标题" left-arrow @click-left="back" fixed placeholder>
+  <van-nav-bar
+    :title="query.vehicle + '>' + query.name"
+    left-arrow
+    @click-left="back"
+    fixed
+    placeholder
+  >
     <template #right>
       <m-icon type="shezhi" @click="setShow = true" />
     </template>
@@ -193,11 +199,14 @@
 </template>
 
 <script lang="ts" setup>
-import { useRoute, useRouter } from "vue-router";
 import { ref, defineEmits } from "vue";
 import { Dialog } from "vant";
 import { useSubjectShowLogic, useTopicMode, useAudioSet } from "./hooks";
-const { back } = useRouter();
+import { RouterBus } from "@/hooks";
+const {
+  route: { query },
+  router: { back },
+} = new RouterBus();
 
 //父级传参
 const props = defineProps(["userTestData"]);
@@ -213,12 +222,6 @@ const scoreCalc = () => {
   subjectList.value.forEach((item) => {
     userAnswerChange(item);
   });
-
-  console.log({
-    useTime: useTime.value,
-    testScores: trueNum.value,
-  });
-
   emits("update:userTestData", {
     useTime: useTime.value,
     testScores: trueNum.value,

+ 1 - 1
src/views/mockTest/index.vue

@@ -21,7 +21,7 @@ const userTestData = ref({
 const currentComponent = ref<any>(initMockTest);
 const comIndex = ref(0);
 const next = () => {
-  comIndex.value++;
+  comIndex.value = (comIndex.value + 1) % 3;
   switch (comIndex.value) {
     case 0:
       currentComponent.value = initMockTest;

+ 9 - 1
src/views/testScores/index.vue

@@ -12,7 +12,13 @@
           >
         </div>
       </div>
-      <m-button class="continue" width="90px" height="30px" text="继续考试" />
+      <m-button
+        @click="goMockTest"
+        class="continue"
+        width="90px"
+        height="30px"
+        text="继续考试"
+      />
     </div>
   </div>
   <div class="summary content-box">
@@ -59,6 +65,7 @@
 <script lang="ts">
 import { getTestScoresList, getTestScoresInfo } from "@/api";
 import { ref, onBeforeMount } from "vue";
+import { RouterBus } from "@/hooks";
 /**
  * 考试成绩数据结构
  */
@@ -111,6 +118,7 @@ const useTestScoresInfo = () => {
 <script lang="ts" setup>
 const { testScoresList } = useTestScoresList();
 const { testScoresInfo } = useTestScoresInfo();
+const { goMockTest } = new RouterBus();
 </script>
 
 <style scoped lang="scss">