|
@@ -0,0 +1,325 @@
|
|
|
|
+import {
|
|
|
|
+ ref,
|
|
|
|
+ watch,
|
|
|
|
+ onBeforeMount,
|
|
|
|
+ computed,
|
|
|
|
+ nextTick,
|
|
|
|
+ ComputedRef,
|
|
|
|
+} from "vue";
|
|
|
|
+import * as API from "@/api";
|
|
|
|
+import { Howl, Howler } from "howler";
|
|
|
|
+import { useRoute } from "vue-router";
|
|
|
|
+import { CollectionModel } from "@/dataModel/collection";
|
|
|
|
+import { RouterBus } from "@/hooks";
|
|
|
|
+import { Notify } from "vant";
|
|
|
|
+
|
|
|
|
+class Execrise {
|
|
|
|
+ constructor() {}
|
|
|
|
+
|
|
|
|
+ /** 答题模式切换 */
|
|
|
|
+ useTopicMode = () => {
|
|
|
|
+ const answerTypeList = ref([
|
|
|
|
+ { name: "顺序练习" },
|
|
|
|
+ { name: "随机练习" },
|
|
|
|
+ { name: "背题模式" },
|
|
|
|
+ ]);
|
|
|
|
+ const currentType = ref(0);
|
|
|
|
+ const typeParams = computed(() => {
|
|
|
|
+ switch (currentType.value) {
|
|
|
|
+ case 0:
|
|
|
|
+ return {
|
|
|
|
+ order: true, //顺序练习
|
|
|
|
+ answerShow: false, //背题模式
|
|
|
|
+ };
|
|
|
|
+ case 1:
|
|
|
|
+ return {
|
|
|
|
+ order: false, //顺序练习
|
|
|
|
+ answerShow: false, //背题模式
|
|
|
|
+ };
|
|
|
|
+ case 2:
|
|
|
|
+ return {
|
|
|
|
+ order: true, //顺序练习
|
|
|
|
+ answerShow: true, //背题模式
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ 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 audioPause = () => {
|
|
|
|
+ sound && sound.pause();
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 读题
|
|
|
|
+ */
|
|
|
|
+ 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;
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ //音频模块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 wrongModel = new CollectionModel("wrong");
|
|
|
|
+ const collectionModel = new CollectionModel("collection");
|
|
|
|
+ const {
|
|
|
|
+ route: { query },
|
|
|
|
+ } = new RouterBus();
|
|
|
|
+
|
|
|
|
+ /** 批量新增收藏 */
|
|
|
|
+ const addsCullection = async (ids: number[]) => {
|
|
|
|
+ const questionList = ids.map((id) => {
|
|
|
|
+ return {
|
|
|
|
+ carType: query.vehicle as CollectionAndWrongType.CarType,
|
|
|
|
+ km: query.name as CollectionAndWrongType.Km,
|
|
|
|
+ questionId: id,
|
|
|
|
+ };
|
|
|
|
+ });
|
|
|
|
+ collectionModel.adds(questionList);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ /** 收藏当前题目 */
|
|
|
|
+ const addCurrentQuestion = async () => {
|
|
|
|
+ const res = await collectionModel.adds([
|
|
|
|
+ {
|
|
|
|
+ carType: query.vehicle as CollectionAndWrongType.CarType,
|
|
|
|
+ km: query.name as CollectionAndWrongType.Km,
|
|
|
|
+ questionId: currentSubject.value.id,
|
|
|
|
+ },
|
|
|
|
+ ]);
|
|
|
|
+ if (res.data == 1) {
|
|
|
|
+ currentSubject.value.isCollection = true;
|
|
|
|
+ Notify({ type: "success", message: "收藏成功" });
|
|
|
|
+ } else {
|
|
|
|
+ currentSubject.value.isCollection = true;
|
|
|
|
+ Notify({ type: "primary", message: res.msg });
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ /**
|
|
|
|
+ * 选择答案后进行校验
|
|
|
|
+ */
|
|
|
|
+ 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)
|
|
|
|
+ ) {
|
|
|
|
+ //答案正确
|
|
|
|
+ currentSubject.value.isTrue = true;
|
|
|
|
+ trueNum.value++;
|
|
|
|
+ if (isJumpNext.value) {
|
|
|
|
+ nextTick(() => {
|
|
|
|
+ nextSubject();
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ //答案错误
|
|
|
|
+ wrongModel.adds([
|
|
|
|
+ {
|
|
|
|
+ carType: query.vehicle as CollectionAndWrongType.CarType,
|
|
|
|
+ km: query.name as CollectionAndWrongType.Km,
|
|
|
|
+ questionId: currentSubject.value.id,
|
|
|
|
+ },
|
|
|
|
+ ]);
|
|
|
|
+ currentSubject.value.isTrue = false;
|
|
|
|
+ falseNum.value++;
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ trueNum,
|
|
|
|
+ falseNum,
|
|
|
|
+ isJumpNext,
|
|
|
|
+ userAnswerChange,
|
|
|
|
+ addCurrentQuestion,
|
|
|
|
+ };
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+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;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ /** 展示上一题 */
|
|
|
|
+ const lastSubject = () => {
|
|
|
|
+ if (currentSubjectIndex.value > 0) {
|
|
|
|
+ currentSubjectIndex.value--;
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ const {
|
|
|
|
+ trueNum,
|
|
|
|
+ falseNum,
|
|
|
|
+ isJumpNext,
|
|
|
|
+ userAnswerChange,
|
|
|
|
+ addCurrentQuestion,
|
|
|
|
+ } = useSubjectCheck(currentSubject, nextSubject);
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ currentSubject,
|
|
|
|
+ currentSubjectIndex,
|
|
|
|
+ subjectTotal,
|
|
|
|
+ nextSubject,
|
|
|
|
+ lastSubject,
|
|
|
|
+ trueNum,
|
|
|
|
+ falseNum,
|
|
|
|
+ isJumpNext,
|
|
|
|
+ userAnswerChange,
|
|
|
|
+ addCurrentQuestion,
|
|
|
|
+ };
|
|
|
|
+};
|