闫增涛
2024-12-16 1fa2461678d7f93b88f5666c4898e5b6c72080f3
packageBookService/pages/bookServices/examination/examination.js
@@ -1,6 +1,9 @@
import {
  getPublicImage
} from "../../../../assets/js/middleGround/tool";
import {
  loginInfo
} from '../../../../assets/js/login';
const app = getApp();
Page({
  /**
@@ -14,6 +17,8 @@
    countdownInterval: null, // 计时器
    isCountdownRunning: true, // 是否倒计时
    countdownTime: 0, // 倒计时时间
    storeInfo: '',
    jslx: '',
    bookId: "",
    productLinkPath: "",
    rootCmsItemId: "",
@@ -47,7 +52,12 @@
    sliderValue: 0, // 字体滑块
    startTime: "", //进入页面当前时间
    pauseTime: 0, //暂停时间
    showDialog: false, // 未提交退出拦截弹窗
    showId: '',
    isShowDialog: false, // 测试报告弹窗是否显示
    joinGroup: false, // 是否加入班级
    visible: false, // 加入班级弹窗是否打开
    classList: [] // 班级列表
  },
  /**
@@ -67,15 +77,33 @@
      rootCmsItemId: options.rootCmsItemId,
      idPathList: options.idPathList ? JSON.parse(options.idPathList) : [],
      answerType: options.answerType,
      storeInfo: options.storeInfo,
      jslx: options.jslx,
    });
    wx.setNavigationBarTitle({
      title: options.answerTitle,
    })
    if (this.data.answerType == "mock") {
      this.setData({
        uuid: options.uuid,
        mockid: options.mockid,
      });
    }
    this.init();
    console.log("传参", options);
    const token = wx.getStorageSync(app.config.tokenKey)
    if (!token) {
      loginInfo(app, (data) => {
        if (data) {
          this.init();
        } else {
          this.init();
        }
      })
    } else {
      this.init()
    }
  },
  /**
@@ -178,6 +206,7 @@
   * 用户点击右上角分享
   */
  onShareAppMessage() {},
  onShareTimeline() {},
  // 监听watch
  watch(context, variableName, callback) {
@@ -196,20 +225,34 @@
      },
    });
  },
  // 修改nav颜色
  changeNavBarColor(e) {
    if (type == 'night') {
      wx.setNavigationBarColor({
        backgroundColor: '#000000',
        frontColor: '#ffffff',
      })
    } else {
      wx.setNavigationBarColor({
        backgroundColor: '#ffffff',
        frontColor: '#000000',
      })
    }
  },
  // 正则找出听力src
  extractSourceSrc(htmlString) {
    // 正则表达式匹配<source>标签中的src属性值  
    var srcRegex = /<source\s+src="([^"]+)"/i;
    var srcTwo = /<audio\s+src="([^"]+)"/i;
    // 执行正则匹配  
    var match = srcRegex.exec(htmlString);
    const local = srcTwo.exec(htmlString)
    // 如果匹配成功,返回第一个捕获组的内容(src属性的值)  
    if (match && match[1]) {
      return match[1];
      return match[1].replace('../file', app.config.requestCtx + '/file');
    } else if (local && local[1]) {
      return local[1]
      return local[1].replace('../file', app.config.requestCtx + '/file')
    } else {
      // 如果没有匹配到,返回null  
      return null;
@@ -232,38 +275,55 @@
  },
  // 返回拦截
  beforeleave() {
    wx.showModal({
      title: "提示",
      content: "未提交,是否退出答题",
      confirmColor: "#ff6c00",
      cancelColor: "#949494",
      complete: (res) => {
        if (res.cancel) {}
        if (res.confirm) {
          this.setData({
            submitStatus: true,
          });
          wx.navigateBack();
        }
      },
    });
    if ((this.data.answerType == 'option' || this.data.answerType == 'mock') && !this.data.submitStatus) {
      wx.showModal({
        title: "提示",
        content: "未提交,是否退出答题",
        confirmColor: "#ff6c00",
        cancelColor: "#949494",
        complete: (res) => {
          if (res.cancel) {
            this.setData({
              showDialog: true
            })
          }
          if (res.confirm) {
            this.setData({
              submitStatus: true,
              showDialog: false
            });
            wx.navigateBack();
          }
        },
      });
    }
  },
  onChangeSlider(e) {
    this.setData({
      sliderValue: e.detail.value,
    });
    console.log(e.detail.value);
  },
  // 返回
  goBack() {
    console.log(this.data.submitStatus);
    wx.navigateBack();
  },
  //设置背景色
  changeBGColor(e) {
    const flag = e.detail.value
    this.setData({
      isNight: e.detail.value,
      isNight: flag,
    });
    if (flag) {
      wx.setNavigationBarColor({
        backgroundColor: '#000000',
        frontColor: '#ffffff',
      })
    } else {
      wx.setNavigationBarColor({
        backgroundColor: '#ffffff',
        frontColor: '#000000',
      })
    }
  },
  // 获取保存的倒计时时间
  getSavedTime() {
@@ -321,11 +381,13 @@
  },
  // 切换题目
  changeSwiper(e) {
    this.setData({
      currentIndex: e.detail.index,
    });
    let index = e.detail.index - 1 >= 0 ? e.detail.index - 1 : 0;
    const item = this.data.questionDataList[index];
    const lastItem = this.data.questionDataList[index + 1];
    this.setData({
      currentIndex: e.detail.index,
      showId: lastItem.id
    });
    if (
      (this.data.answerType == "collectQuestion" ||
        this.data.answerType == "errorQuestion") &&
@@ -424,7 +486,6 @@
    const inputData = e.detail.value.detail.value;
    const id = e.detail.value.currentTarget.dataset.id;
    const index = Number(e.detail.value.currentTarget.dataset.index);
    console.log(index);
    const questionList = this.data.questionDataList;
    questionList.forEach((item) => {
      if (item.id == id) {
@@ -491,11 +552,13 @@
      submitStatus: true,
      loading: true,
    });
    const child = this.selectComponent("#question-options");
    const child = this.selectComponent('#question-options');
    if (
      this.data.answerType == "option" ||
      this.data.answerType == "errorQuestion" ||
      this.data.answerType == "mock"
      this.data.answerType == "mock" ||
      this.data.answerType == 'interaction'
    ) {
      // 先遍历所有题目,将未批改的题目批改
      const qustionList = this.data.questionDataList;
@@ -507,7 +570,11 @@
    if (this.data.answerType == "option") {
      this.toggleCountdown();
      this.recordAnswerData();
      child.openTestReportDialog();
      // this.selectComponent 拿不到 组件了, 改为监听组件传值 打开弹窗
      // child.openTestReportDialog();
      this.setData({
        isShowDialog: true
      })
    } else if (
      this.data.answerType == "collectQuestion" ||
      this.data.answerType == "errorQuestion"
@@ -550,10 +617,17 @@
          }),
        }, ],
      });
      child.openTestReportDialog();
      // child.openTestReportDialog();
      this.setData({
        isShowDialog: true
      })
    } else if (this.data.answerType == 'interaction') {
      this.toggleCountdown();
      this.handleClassQuestion()
    }
    this.setData({
      loading: false,
      showDialog: false,
    });
  },
  // 初始化函数
@@ -566,13 +640,19 @@
    });
    if (this.data.answerType == "option") {
      if (this.data)
        // this.startCountdown()
        this.setData({
          countdownTime: 2 * 60 * 60 * 1000,
        });
      // 测试答题
      await this.getCollectIdList(); // 获取收藏id列表
      await this.getErrorList(); // 获取错题id列表
    } else if (this.data.answerType == "interaction") {
      this.setData({
        countdownTime: 2 * 60 * 60 * 1000,
      });
      this.getCurrentClassList()
      this.getinteractionInfo()
      // 教学互动
    } else if (this.data.answerType == "collectQuestion") {
      this.setData({
        submitStatus: true,
@@ -630,6 +710,9 @@
            oldMockData.state == "2"
          ) {
            this.startCountdown();
            this.setData({
              showDialog: true
            })
          }
          if (oldMockData.state == "3") {
            this.setData({
@@ -651,6 +734,7 @@
      subjectiveNum: 0,
      currentIndex: 0,
      submitStatus: false,
      showDialog: true
    });
    if (this.data.answerType == "option") {
      this.setData({
@@ -729,6 +813,9 @@
              await this.getQuestionList(value.dataList);
            } else {
              await this.getQuestionList(); // 获取题库题目
              this.setData({
                showDialog: true
              })
            }
          });
        }
@@ -792,10 +879,10 @@
          size: 999,
        },
      };
      if (this.data.storeInfo) {
        query.storeInfo = this.data.storeInfo
      }
      await app.MG.store.getProductDetail(query).then((res) => {
        if (!res.datas.cmsDatas[0].datas.length) return this.setData({
          noData: true
        })
        this.setData({
          total: res.datas.cmsDatas[0].datas.length,
        });
@@ -806,11 +893,21 @@
          oldList = oldData.find(
            (item) => item.path == pathitem.productLinkPath
          ).infoList;
          this.setData({
            submitStatus: true,
          });
        }
        res.datas.cmsDatas[0].datas.forEach((item, index) => {
          if (this.data.storeInfo || this.data.jslx) {
            if (item.Embedded_QuestionBank_QuestionType == 'singleChoice') {
              pathitem.name = "单选题"
            } else if (item.Embedded_QuestionBank_QuestionType == 'shortAnswer') {
              pathitem.name = "简答题"
            } else if (item.Embedded_QuestionBank_QuestionType == "completion") {
              pathitem.name = "填空题";
            } else if (item.Embedded_QuestionBank_QuestionType == "multipleChoice") {
              pathitem.name = "多选题";
            } else if (item.Embedded_QuestionBank_QuestionType == "judge") {
              pathitem.name = "判断题";
            }
          }
          let oldObj = "";
          if (oldList)
            oldObj = oldList.find((oldItem) => oldItem.id == item.id);
@@ -846,7 +943,8 @@
            questionObj.questionType == "multipleChoice"
          ) {
            try {
              questionObj.answer = JSON.parse(questionObj.answer).toString();
              // questionObj.answer = JSON.parse(questionObj.answer).toString();
              questionObj.answer = JSON.parse(questionObj.answer)
            } catch (error) {
              questionObj.answer = item.Embedded_QuestionBank_Answer;
            }
@@ -874,7 +972,7 @@
                /\<img/gi,
                '<img style="max-width: 300rpx !important;object-fit: contain;" class="stem-rich-img" '
              )
              .replace(/\<p/gi, '<p class="stem-rich-p"');
              .replace(/\<p/gi, '<p class="stem-rich-p"').replace('../file', app.config.requestCtx + '/file');
          }
          // 选项富文本处理
          if (
@@ -887,7 +985,7 @@
              if (item.txt)
                item.txt = item.txt
                .replace(/\<img/gi, '<img class="option-rich-img"')
                .replace(/\<p/gi, '<p class="stem-rich-p"');
                .replace(/\<p/gi, '<p class="stem-rich-p"').replace('../file', app.config.requestCtx + '/file');
            });
          }
          // 解析富文本处理
@@ -906,7 +1004,6 @@
            if (src) {
              questionObj.src = src
              questionObj.stem.stemTxt = this.removeVideoAndAudioTags(questionObj.stem.stemTxt)
              console.log('题干', questionObj.stem.stemTxt);
            }
          }
          // 获取图片
@@ -983,14 +1080,25 @@
            questionDataList: questionList,
            cardList: cardUpdatedList,
          });
          console.log(
            '题目', this.data.questionDataList
          );
        });
      });
    }
    // 有题目再开始倒计时
    if (this.data.questionDataList.length) this.startCountdown();
    this.setData({
      loading: false,
    });
    if (this.data.questionDataList.length) {
      this.startCountdown();
      this.setData({
        loading: false,
        showId: this.data.questionDataList[0].id
      })
    } else {
      this.setData({
        noData: true,
        loading: false,
      })
    }
  },
  // 批改题目 (练习,我的错题,我的收藏,,组卷)
  handleQuestion(index) {
@@ -1023,7 +1131,7 @@
      // 简答 翻译
      questionList[index].isRight = null;
    } else if (item.questionType == "completion") {
      if (item.answer == "string") {
      if (typeof item.answer == "string") {
        item.isRight = item.answer == item.userAnswer[0];
      } else {
        if (item.answer.length != item.userAnswer.length) {
@@ -1181,7 +1289,6 @@
        }
      }
    }
    this.setAnswerInfo(setInfoData);
  },
  // 提交答题数据
@@ -1309,6 +1416,9 @@
          Embedded_QuestionBank_Difficulty: [],
        },
      };
      if (this.data.storeInfo) {
        query.storeInfo = this.data.storeInfo
      }
      await app.MG.store.getProductDetail(query).then((res) => {
        let questionArr = [];
        res.datas.cmsDatas[0].datas.forEach((item, index) => {
@@ -1340,6 +1450,7 @@
            questionObj.questionType == "completion" ||
            questionObj.questionType == "multipleChoice"
          ) {
            console.log(questionObj.answer, "111")
            try {
              questionObj.answer = JSON.parse(questionObj.answer).toString();
            } catch (error) {
@@ -1388,7 +1499,7 @@
                /\<img/gi,
                '<img style="max-width: 300rpx !important;object-fit: contain;" class="stem-rich-img" '
              )
              .replace(/\<p/gi, '<p class="stem-rich-p"');
              .replace(/\<p/gi, '<p class="stem-rich-p"').replace('../file', app.config.requestCtx + '/file');
          }
          // 选项富文本处理
          if (
@@ -1401,7 +1512,7 @@
              if (item.txt)
                item.txt = item.txt
                .replace(/\<img/gi, '<img class="option-rich-img"')
                .replace(/\<p/gi, '<p class="stem-rich-p"');
                .replace(/\<p/gi, '<p class="stem-rich-p"').replace('../file', app.config.requestCtx + '/file');
            });
          }
          // 解析富文本处理
@@ -1413,6 +1524,14 @@
              /\<img/gi,
              '<img style="max-width: 300rpx !important;object-fit: contain;" class="stem-rich-img" '
            );
          }
          // 听力题修改
          if (questionObj.questionType == 'singleChoice') {
            const src = this.extractSourceSrc(questionObj.stem.stemTxt)
            if (src) {
              questionObj.src = src
              questionObj.stem.stemTxt = this.removeVideoAndAudioTags(questionObj.stem.stemTxt)
            }
          }
          if (item.Embedded_QuestionBank_QuestionType == "judge") {
            questionObj.type = "判断题";
@@ -1455,6 +1574,7 @@
    }
    this.setData({
      questionDataList: questionArr,
      showId: questionArr[0].id,
      cardList: cardList,
      loading: false,
    });
@@ -1547,6 +1667,9 @@
        Embedded_QuestionBank_Difficulty: [],
      },
    };
    if (this.data.storeInfo) {
      query.storeInfo = this.data.storeInfo
    }
    await app.MG.store.getProductDetail(query).then((res) => {
      let questionArr = [];
      res.datas.cmsDatas[0].datas.forEach((item, index) => {
@@ -1628,7 +1751,7 @@
              /\<img/gi,
              '<img style="max-width: 300rpx !important;object-fit: contain;" class="stem-rich-img" '
            )
            .replace(/\<p/gi, '<p class="stem-rich-p"');
            .replace(/\<p/gi, '<p class="stem-rich-p"').replace('../file', app.config.requestCtx + '/file');
        }
        // 选项富文本处理
        if (
@@ -1641,7 +1764,7 @@
            if (item.txt)
              item.txt = item.txt
              .replace(/\<img/gi, '<img class="option-rich-img"')
              .replace(/\<p/gi, '<p class="stem-rich-p"');
              .replace(/\<p/gi, '<p class="stem-rich-p"').replace('../file', app.config.requestCtx + '/file');
          });
        }
        // 解析富文本处理
@@ -1653,6 +1776,15 @@
            /\<img/gi,
            '<img style="max-width: 300rpx !important;object-fit: contain;" class="stem-rich-img" '
          );
        }
        // 听力题修改
        if (questionObj.questionType == 'singleChoice') {
          const src = this.extractSourceSrc(questionObj.stem.stemTxt)
          if (src) {
            questionObj.src = src
            questionObj.stem.stemTxt = this.removeVideoAndAudioTags(questionObj.stem.stemTxt)
            console.log('题干', questionObj.stem.stemTxt);
          }
        }
        if (item.Embedded_QuestionBank_QuestionType == "judge") {
          questionObj.type = "判断题";
@@ -1694,11 +1826,12 @@
      }
      this.setData({
        questionDataList: questionArr,
        showId: questionArr[0].id,
        cardList: cardList,
        loading: false,
      });
      console.log(this.data.questionDataList, "questionDataList");
    });
    // loadings.value = false
  },
  // 获取组卷结果
  async getEduQuizConfig() {
@@ -1823,6 +1956,9 @@
          Embedded_QuestionBank_Difficulty: [],
        },
      };
      if (this.data.storeInfo) {
        query.storeInfo = this.data.storeInfo
      }
      await app.MG.store.getProductDetail(query).then((res) => {
        res.datas.cmsDatas[0].datas.forEach((item, index) => {
          // 循环questionList,给每题赋值分数
@@ -1889,7 +2025,7 @@
            questionObj.stem.stemTxt = questionObj.stem.stemTxt.replace(
              /\<img/gi,
              '<img style="max-width: 300rpx !important;object-fit: contain;" class="stem-rich-img"'
            );
            ).replace(/\<p/gi, '<p class="stem-rich-p"').replace('../file', app.config.requestCtx + '/file');
          }
          // 选项富文本处理
          if (
@@ -1903,8 +2039,16 @@
                item.txt = item.txt.replace(
                  /\<img/gi,
                  '<img class="option-rich-img"'
                );
                ).replace(/\<p/gi, '<p class="stem-rich-p"').replace('../file', app.config.requestCtx + '/file');
            });
          }
          // 听力题修改
          if (questionObj.questionType == 'singleChoice') {
            const src = this.extractSourceSrc(questionObj.stem.stemTxt)
            if (src) {
              questionObj.src = src
              questionObj.stem.stemTxt = this.removeVideoAndAudioTags(questionObj.stem.stemTxt)
            }
          }
          // 获取图片
          if (
@@ -1969,6 +2113,7 @@
    }
    this.setData({
      loading: false,
      showId: this.data.questionDataList[0].id
    });
  },
  // 获取组卷数据
@@ -2029,11 +2174,12 @@
      })
      .then((res) => {
        if (res[0]) {
          // 这里的 countdownTime 赋值:如果是时间到了提交,记录的剩余时间就是0,所以:如果是0的话赋值1秒,防止监听到时间为0再次提交
          this.setData({
            currentIndex: JSON.parse(res[0].value).currentIndex,
            "mockData.time": JSON.parse(res[0].value).time,
            countdownTime: JSON.parse(res[0].value).time ?
              JSON.parse(res[0].value).time : this.data.mockData.sumTime,
            countdownTime: JSON.parse(res[0].value).time > 0 ?
              JSON.parse(res[0].value).time : 1000,
            "mockData.answer": JSON.parse(res[0].value).answerData,
          });
          console.log(JSON.parse(res[0].value));
@@ -2097,7 +2243,6 @@
  // 富文本处理
  formatRichText(html) {
    console.log(html);
    let newContent = html.replace(/<img[^>]*>/gi, function (match, capture) {
      match = match
        .replace(/style="[^"]+"/gi, "")
@@ -2131,4 +2276,206 @@
    );
    return newContent;
  },
  // 教学互动模式相关
  // 获取班级列表
  getCurrentClassList() {
    const query = {
      start: 0,
      size: 999,
      filterList: [],
    }
    app.MG.identity.joinedGroupByList(query).then((res) => {
      res.datas.forEach(async item => {
        item.topicId = null
        const data = await this.getTopicInfo(item.id)
        if (data) {
          item.topicId = data.id
        }
      })
      if (res.datas.length) {
        this.setData({
          joinGroup: true,
          classList: res.datas,
        })
      } else {
        // 未加入班级,唤起加入班级弹窗
        this.setData({
          joinGroup: false,
          visible: true
        })
      }
    })
  },
  // 加入班级
  joinClass(e) {
    const data = {
      refCode: e.detail.value
    }
    app.MG.identity.joinGroupByRefCode(data).then((res) => {
      if (res == '组不存在') {
        wx.showToast({
          icon: 'error',
          title: '无效的班级',
        })
      } else if (res == '组成员数量已最大,不能加入') {
        wx.showToast({
          icon: 'error',
          title: '班级成员数量已最大,不能加入',
        })
      } else if (res == '已经申请过加入此组') {
        wx.showToast({
          icon: 'error',
          title: '已经申请过加入此班级',
        })
      } else {
        wx.showToast({
          icon: "success",
          title: '已成功,等待审核中...',
        })
        this.setData({
          visible: false
        })
        this.getCurrentClassList()
      }
    })
  },
  // 获取班级topic
  async getTopicInfo(classId) {
    let query = {
      classId,
      refCodes: ["TeachInteraction"]
    }
    const res = await app.MG.edu.getClassTopic(query)
    return res[0] ?? null
  },
  // 获取旧教学互动答题数据
  getinteractionInfo() {
    app.MG.identity
      .getUserKey({
        domain: "interactionData",
        keys: [this.data.productLinkPath],
      })
      .then((res) => {
        if (res.length) {
          let value = JSON.parse(res[0].value);
          this.setData({
            submitStatus: value.submitStatus,
            currentIndex: value.currentIndex,
          });
          // 携带答题记录 获取题目
          this.getQuestionList(value.dataList);
        } else {
          this.getQuestionList(); // 获取题库题目
          this.setData({
            showDialog: true
          })
        }
      });
  },
  // 提交教学互动答题数据
  setinteractionInfo(submitStatus) {
    const list = []
    this.data.cardList.forEach(item => {
      list.push({
        catalogName: item.catalogName,
        path: item.path,
        infoList: item.infoList.map((citem) => ({
          id: citem.id,
          userAnswer: citem.userAnswer
        }))
      })
    })
    console.log('提交数据', list);
    app.MG.identity
      .setUserKey({
        setKeyRequests: [{
          domain: "interactionData",
          key: this.data.productLinkPath,
          value: JSON.stringify({
            submitStatus,
            currentIndex: this.data.currentIndex,
            dataList: list
          }),
        }, ],
      })
      .then((res) => {});
  },
  // 处理教学互动答题
  handleClassQuestion() {
    debugger
    const flag = this.data.questionDataList.some(item => !item.userAnswer)
    if (flag) {
      // 没做完,保存即可
      const isAnswer = this.data.questionDataList.some(item => item.userAnswer)
      if (isAnswer) this.setinteractionInfo(false)
    } else {
      // 做完了,提交到message
      this.setinteractionInfo(true)
      if (this.data.classList.length) {
        this.data.classList.forEach(item => {
          this.newTopicMessage(item.topicId)
        })
      }
    }
    this.setData({
      submitStatus: true
    })
  },
  // 新建topicMessage
  newTopicMessage(topicId) {
    let content = []
    for (let cindex = 0; cindex < this.data.questionDataList.length; cindex++) {
      const citem = this.data.questionDataList[cindex];
      content.push({
        cmsItemId: citem.id,
        answer: citem.userAnswer,
        state: citem.questionType == 'shortAnswer' ? 'none' : citem.isRight,
        type: citem.questionType
      })
    }
    const data = {
      description: '',
      icon: '',
      state: 'Normal',
      topicIdOrRefCode: String(topicId),
      name: this.data.answerTitle,
      content: JSON.stringify({
        bookId: this.data.bookId,
        userName: JSON.parse(wx.getStorageSync(app.config.userInfoKey)).name,
        path: this.data.productLinkPath,
        content
      }),
      type: 'Normal',
      cmsTypeRefCode: '',
      newDataListRequest: []
    }
    app.MG.ugc.newTopicMessage(data).then((res) => {
      if (res) {
        this.setData({
          isShowDialog: true
        })
      }
    })
  },
  // 新建子topicMessage
  // newTopicSubMessage(parentId,topicId) {
  //   const data = {
  //     description: '',
  //     icon: '',
  //     parentId,
  //     state: 'Normal',
  //     topicIdOrRefCode: String(topicId),
  //     name: this.data.answerTitle,
  //     content: '',
  //     type: 'Normal',
  //     cmsTypeRefCode: '',
  //     newDataListRequest: []
  //   }
  //   MG.ugc.newTopicMessage(data).then((res) => {
  //     if (res) {
  //     }
  //   })
  // },
});