闫增涛
2024-06-24 be7eb48ee79b368139cf517f731717a3d63b8320
拖拽题控件
3个文件已修改
1个文件已添加
642 ■■■■■ 已修改文件
src/books/mathBook/view/components/chapter001.vue 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/books/mathBook/view/components/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/dragQuestion/index.vue 518 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/examinations/index.vue 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/books/mathBook/view/components/chapter001.vue
@@ -575,7 +575,9 @@
        </div>
      </div>
    </div>
    <!-- <div class="page-box padding-116" page="10">
      <drag :question="dragQuestion" :page="10"/>
    </div> -->
    <!-- 函数控件弹窗 -->
    <el-dialog
      :visible.sync="dialogVisible"
@@ -820,9 +822,10 @@
import examinations from "@/components/examinations/index.vue";
import { getResourcePath } from "@/assets/methods/resources";
import { getCollectResource,setCollectResource } from "@/assets/methods/resources";
import drag from '@/components/dragQuestion/index.vue'
export default {
  name: "chapter-one",
  components: { examinations },
  components: { examinations,drag },
  props: {
    showPageList: {
      type: Array,
@@ -886,6 +889,80 @@
          isShow: false,
        },
      ],
      dragQuestion:[
          {
          analysisCon: null,
          answer: ['A','B','C'],
          difficulty: 0,
          id: "7BC7B760",
          isCollect: false,
          isComplete: false,
          isRight: null,
          isUnfold: "",
          isUserAnswer: false,
          number: 1,
          option: [
            {
              img: "",
              index: "010311",
              txt: "胆小的",
              value: "A",
              isShow:true
            },
            {
              img: "",
              index: "010312",
              txt: "善良的",
              value: "B",
              isShow:true
            },
            {
              img: "",
              index: "010313",
              txt: "沉稳的",
              value: "C",
              isShow:true
            },
          ],
          optionStyle: "Txt",
          questionType: "drag",
          score: 2,
          stem: {
            0: "蚂蚁队长走路昂首挺胸、步伐坚定,它是一只(",
            1:{
              data: "span",
              num: 0
            },
            2: ")蚂蚁;小蚂蚁走起路来小心翼翼,眼神飘忽不定,它是一只(",
            3:{
              data:"span",
              num:1
            },
            4:")蚂蚁;蚂蚁小妹面带微笑,时刻愿意帮助大家,它是一只(",
            5:{
              data:"span",
              num:2,
            },
            6:" )蚂蚁"
          },
          stemStyle: "RichTxt",
          type: "拖拽题",
          userAnswer:[
            {
              vlaue:'',
              txt:''
            },
            {
              vlaue:'',
              txt:''
            },
            {
              vlaue:'',
              txt:''
            },
          ]
        },
      ]
    };
  },
  methods: {
src/books/mathBook/view/components/index.vue
@@ -162,8 +162,8 @@
    }, 500);
    // 测试页面跳转
    // setTimeout(() => {
    //   this.gotoPage(1, 10);
    setTimeout(() => {
      this.gotoPage(2, 10);
    //   setTimeout(() => {
    //     this.renderSign("Highlight", {
    //       id: "2ACA9359",
@@ -191,7 +191,7 @@
    //   txt: " 运动系统是由骨、骨连结和骨骼肌三部分组成的。全身的骨通过骨连结组成人体骨骼(见图1-1)。骨骼是人体的支架,具有保护内脏器官、供肌肉附着和作为肌肉运动的杠杆等作用。在神经系统的支配下,肌肉收缩牵动所附着的骨绕着关节转动,使身体产生各种动作。所以,运动系统具有运动、支持和保护等功能,幼年时期的骨骼还具有造血功能。 ",
    //   txtIndex: 57
    // });
    // }, 5000);
    }, 500);
    // 获取题目id列表
    this.getQuestionId();
src/components/dragQuestion/index.vue
New file
@@ -0,0 +1,518 @@
<template>
  <div class="drag-box">
    <div
      v-for="(item, index) in drageQuestion"
      :key="item.id"
      @mousemove="mousemove"
      @mouseup="mouseup"
      :num="index"
      class="question-box"
    >
      <!-- 题干 -->
      <div>
        <span v-for="(ditem, dindex) in item.stem" :key="dindex">
          <span v-if="typeof ditem == 'string'">
            {{ ditem }}
          </span>
          <span class="space" v-else>{{ item.userAnswer[ditem.num].txt }}</span>
        </span>
      </div>
      <!-- 选项 -->
      <ul class="option-box">
        <li v-for="(citem, cindex) in item.option" :key="cindex">
          <span class="drag-option" @mousedown="mousedown" v-show="item.userAnswer.findIndex(eitem => eitem.value == citem.value) == -1"
            >{{ citem.value }}、{{ citem.txt }}</span
          >
        </li>
      </ul>
      <!-- 提交后解析 -->
      <div class="analysis" v-if="item.isComplete">
        <el-collapse
          v-model="item.isUnfold"
          @change="handleChange(item)"
          accordion
          v-if="item.questionType != 'shortAnswer'"
        >
          <el-collapse-item :name="item.id" class="objective">
            <template #title>
              <div class="headerBox">
                <div class="headerConent">
                  <p class="correct" :title="arrayToString(item.answer)">
                    <span>正确答案:</span>
                    <span
                      v-html="arrayToString(item.answer)"
                      class="correctBox"
                    ></span>
                  </p>
                  <p
                    :class="
                      item.isRight
                        ? 'correct textOverFlow'
                        : 'error textOverFlow'
                    "
                    :title="arrayToString(item.userAnswer)"
                    style="margin-left: 20px"
                  >
                    <span>您的答案:</span>
                    <span
                      class="errorBox"
                      v-if="item.userAnswer.length"
                      >
                      <span v-for="(answerItem,answerIdnex) in item.userAnswer" :key="answerIdnex">{{answerItem.value}}<span v-if="answerIdnex !== item.userAnswer.length - 1 && answerItem.value">,</span></span>
                      </span
                    >
                  </p>
                </div>
                <p class="difficulty" v-if="item.difficulty">
                  <span style="color: #333">难度等级:</span>
                  <el-rate
                    v-model="item.difficulty"
                    :max="3"
                    size="large"
                    disabled
                    disabled-void-color="#949494"
                  />
                </p>
                <!-- 正确错误图标 -->
                <span class="mr-10">
                  <svg
                    v-if="item.isRight"
                    t="1716986419862"
                    class="icon"
                    viewBox="0 0 1820 1024"
                    version="1.1"
                    xmlns="http://www.w3.org/2000/svg"
                    p-id="18767"
                    xmlns:xlink="http://www.w3.org/1999/xlink"
                    width="40"
                    height="20"
                  >
                    <path
                      d="M1439.374222 216.007111s-169.472 56.490667-367.179852 282.443852C888.604444 703.222519 846.241185 787.949037 775.632593 900.93037 768.568889 893.866667 662.651259 689.095111 380.207407 540.814222l148.290371-141.226666s134.162963 91.790222 225.953185 261.262222c0 0 233.016889-360.116148 684.923259-536.642371v91.799704z m0 0"
                      fill="#1AFA29"
                      p-id="18768"
                    ></path>
                  </svg>
                  <svg
                    v-if="item.isRight == false"
                    t="1716987085767"
                    class="icon"
                    viewBox="0 0 1024 1024"
                    version="1.1"
                    xmlns="http://www.w3.org/2000/svg"
                    p-id="25745"
                    xmlns:xlink="http://www.w3.org/1999/xlink"
                    width="20"
                    height="20"
                  >
                    <path
                      d="M116.579135 38.64349531L38.703935 103.74399781c138.82075969 102.96027281 268.24660875 221.31426938 381.68489719 339.96758156C246.29374906 618.40145938 109.95003031 790.19602344 38.10817906 859.25288281l148.35573469 123.62658094c52.61360812-108.17625656 167.23381594-272.86683656 320.56281844-445.01635875 153.50744156 173.21056312 268.36844625 338.43166313 321.38977781 447.49243969 0 0 144.5682225-152.96636906 157.47435281-129.29729625-55.80632344-62.49011156-191.37776625-244.16501625-374.17990593-430.27403438 104.68422375-107.1132975 222.15274031-213.10127719 347.60304468-306.24740437L925.17746562 56.03842156C782.85412063 126.51895625 647.69328031 231.09093594 526.07845437 342.39755 403.34886594 226.82662719 264.46095125 116.16373719 116.579135 38.64349531L116.579135 38.64349531zM116.579135 38.64349531"
                      fill="#d81e06"
                      p-id="25746"
                    ></path>
                  </svg>
                </span>
                <div class="headerConent sitgBox">
                  <p v-if="!item.isUnfold">
                    <span class="analysisColor">展开解析</span><el-image />
                  </p>
                  <p v-else>
                    <span class="analysisColor">收起解析</span><el-image />
                  </p>
                </div>
              </div>
            </template>
            <!-- 解析 -->
            <div v-if="item.analysisCon" v-html="item.analysisCon"></div>
            <div v-else>暂无数据</div>
          </el-collapse-item>
          <!-- 主观题 -->
        </el-collapse>
      </div>
    </div>
    <div class="drag-bottom-btn">
      <el-button @click="saveData">保存</el-button>
      <el-button @click="submitData">提交</el-button>
      <el-button @click="redio">重做</el-button>
      <el-button @click="seeAnswer">查看答案</el-button>
    </div>
  </div>
</template>
<script>
export default {
  name: "drag",
  props: {
    question: {
      type: Array,
      default: [],
    },
    page: {
      type: Number,
    },
  },
  watch: {
    question: {
      handler(newValue, oldValue) {
        console.log("监听传值", newValue);
        let oldAnswer = localStorage.getItem(
          this.config.activeBook.name + "-drag-" + this.page
        );
        if (oldAnswer) {
          oldAnswer = JSON.parse(oldAnswer);
          for (let index = 0; index < newValue.length; index++) {
            // 旧答案赋值
            const item = newValue[index];
            const oldItem = oldAnswer.find((citem) => citem.id == item.id);
            item.userAnswer = oldItem.userAnswer;
            // 隐藏旧答案里的选项
            // for (let cindex = 0; cindex < item.option.length; cindex++) {
            //   const citem = item.option[cindex];
            //   if(item.userAnswer.findIndex(ditem => ditem.value == citem.value) > -1) {
            //     citem.isShow = false
            //   }
            // }
          }
        }
        this.drageQuestion = newValue;
      },
      immediate: true,
    },
  },
  data() {
    return {
      questionIndex: null,
      drageQuestion: [],
      moveDom: null,
      parentDom: null,
      parentX: null, // 父盒子在页面的位置
      parentY: null,
      maxX: null,
      maxY: null,
      spaceList: [],
    };
  },
  mounted() {
    console.log("传值", this.question);
  },
  methods: {
    // 1.选项拖拽
    // 2.限制拖拽移动只能在题范围内
    // 3.限制鼠标松开要在空格的范围内
    mousedown(e) {
      e.preventDefault();
      console.log("鼠标按下", e);
      this.moveDom = e.toElement;
      this.parentDom = this.getParentWithClass(e.toElement, "question-box");
      this.questionIndex = this.parentDom.getAttribute("num");
      this.getSpaceInfo(this.parentDom);
      const parentInfo = this.parentDom.getBoundingClientRect();
      this.parentX = parentInfo.x;
      this.parentY = parentInfo.y;
      this.maxX = parentInfo.x + this.parentDom.clientWidth;
      this.maxY = parentInfo.y + this.parentDom.clientHeight;
      console.log("父盒子", parentInfo);
    },
    // 鼠标移动
    mousemove(e) {
      if (!this.moveDom) return false;
      this.moveDom.style.position = "absolute";
      // 限制在此题范围内拖动
      if (e.x <= this.maxX && e.y < this.maxY) {
        const moveX = e.x - this.parentX;
        const moveY = e.y - this.parentY;
        this.moveDom.style.left = moveX + "px";
        this.moveDom.style.top = moveY + "px";
        // 如果移动到空格范围内,将答案填入空格
        if (this.spaceList.length) {
          for (let index = 0; index < this.spaceList.length; index++) {
            const item = this.spaceList[index];
            if (
              e.x >= item.minX &&
              e.x <= item.maxX &&
              e.y >= item.minY &&
              e.y <= item.maxY
            ) {
              this.$set(
                this.drageQuestion[this.questionIndex].userAnswer,
                index,
                {
                  value:this.moveDom.textContent.charAt(0),
                  txt:this.moveDom.textContent.slice(2)
                }
              );
              this.moveDom.style.display = "none";
            }
          }
        }
      }
    },
    // 鼠标抬起
    mouseup(e) {
      if (this.moveDom) {
        this.moveDom = null;
      }
    },
    // 获取题目空格坐标
    getSpaceInfo(parentDom) {
      let arr = [];
      const list = parentDom.querySelectorAll(".space");
      for (let index = 0; index < list.length; index++) {
        const itemInfo = list[index].getBoundingClientRect();
        arr.push({
          minX: itemInfo.x,
          maxX: itemInfo.x + itemInfo.width,
          minY: itemInfo.y,
          maxY: itemInfo.y + itemInfo.height,
        });
      }
      this.spaceList = arr;
      console.log("空格范围", arr);
    },
    // 获取父元素
    getParentWithClass(element, className) {
      while (element.parentElement) {
        element = element.parentElement;
        if (element.classList.contains(className)) {
          return element;
        }
      }
    },
    // 保存答案
    saveData(e) {
      let answerArr = [];
      for (let index = 0; index < this.drageQuestion.length; index++) {
        const item = this.drageQuestion[index];
        answerArr.push({
          id: item.id,
          userAnswer: item.userAnswer,
        });
      }
      localStorage.setItem(
        this.config.activeBook.name + "-drag-" + this.page,
        JSON.stringify(answerArr)
      );
    },
    // 提交
    submitData() {
      let arr = [];
      const data = this.drageQuestion;
      for (let index = 0; index < data.length; index++) {
        const item = data[index];
        for (let cindex = 0; cindex < item.userAnswer.length; cindex++) {
          let citem = item.userAnswer[cindex];
          arr[cindex] = citem.value
        }
        item.isRight = arr == item.answer
      }
      console.log(arr,this.drageQuestion[0]);
    },
    redio() {
      localStorage.removeItem(
        this.config.activeBook.name + "-drag-" + this.page
      );
      let arr = []
      // const data = []
      for (let index = 0; index < this.drageQuestion.length; index++) {
        const item = this.drageQuestion[index];
        for (let cindex = 0; cindex < item.option.length; cindex++) {
          const citem = item.option[cindex];
          arr.push(
            {
              txt:'',
              value:''
            }
          )
        }
        item.userAnswer = arr
      }
      console.log(this.drageQuestion);
      const optionList = (
        this.container ? this.container : document
      ).querySelectorAll(".drag-option");
      for (let index = 0; index < optionList.length; index++) {
        const item = optionList[index];
        item.style.position = null
        item.style.top = null
        item.style.left = null
      }
    },
    seeAnswer() {
      for (let index = 0; index < this.drageQuestion.length; index++) {
        const item = this.drageQuestion[index];
        item.isComplete = true;
      }
    },
    // 数组转为字符串方法
    arrayToString(data) {
      // 检查是否为数组
      if (Array.isArray(data)) {
        // 使用 join 方法将数组转换为字符串,默认使用逗号分隔
        return data.join(",").replace(/<[^>]*>/g, "");
      } else {
        // 如果不是数组,直接返回原始值
        return data.replace(/<[^>]*>/g, "");
      }
    },
    isHaveAnswer(data) {
      if (typeof data == "string") {
        data = data
          .replace(/<[^>]*>/g, "")
          .replace(/&nbsp;/g, "")
          .trim();
        if (data.length) {
          return true;
        } else {
          return false;
        }
      } else {
        const answer = data.find((item) => item.length > 0);
        if (answer) {
          return true;
        } else {
          return false;
        }
      }
    },
  },
};
</script>
<style lang="less" scoped>
p {
  text-indent: 0 !important;
}
.drag-box {
  position: relative;
}
.space {
  display: inline-block;
  text-align: center;
  min-width: 60px !important;
  min-height: 15px !important;
}
.option-box {
  display: flex;
  justify-content: space-evenly;
}
.drag-option {
  cursor: pointer;
}
.drag-bottom-btn {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  .el-button {
    height: 30px;
    width: 78px;
    padding: 4px 10px;
  }
}
.analysis {
  margin: 20px 0;
  width: 94%;
  // margin-left: 12px;
}
.el-collapse {
  width: 100%;
}
/** 解析 */
.objective {
  /deep/ .el-collapse-item__header {
    min-height: 48px;
    height: min-content;
    padding: 0 20px;
    font-size: 16px;
    background-color: #f4f4f4;
    .headerBox {
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: space-between;
      align-items: center;
      flex-wrap: wrap;
      .headerConent {
        height: 100%;
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        p {
          margin-bottom: 0;
        }
        .el-image {
          width: 9px;
          height: 9px;
        }
        .correct {
          color: #1fbc1f;
          width: 180px;
          text-align: left;
          display: flex;
          span:nth-child(1) {
            display: inline-block;
            text-indent: 0;
            width: 82px;
          }
        }
        .correctBox {
          width: 100px;
          height: min-content;
          word-break: break-all;
          text-overflow: ellipsis;
          display: -webkit-box;
          -webkit-box-orient: vertical;
          -webkit-line-clamp: 1; /* 这里是超出几行省略 */
          overflow: hidden;
        }
        .error {
          display: flex;
          text-align: left;
          width: 170px;
          color: #ee1818;
          span {
            height: min-content;
            width: 100px;
          }
          .errorBox {
            width: 100px;
            // height: 48px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            ::v-deep {
              img {
                max-height: 48px;
              }
            }
          }
        }
      }
    }
    .checkAnalysis {
      cursor: pointer;
      height: 100%;
      display: flex;
      align-items: center;
    }
  }
}
/deep/ .el-collapse-item__header:focus:not(:hover) {
  color: #333;
}
/deep/ .el-collapse-item__content {
  width: 93%;
  padding: 0 20px;
  background-color: #f4f4f4;
  font-size: 16px;
  color: #333;
}
/deep/ .el-collapse-item__arrow {
  display: none;
}
</style>
src/components/examinations/index.vue
@@ -561,7 +561,7 @@
  },
  mounted() {
    this.getCollectIdList();
    this.getErrorList()
    this.getErrorList();
  },
  methods: {
    // 数组转为字符串方法
@@ -621,7 +621,7 @@
    },
    // 批改题目  (练习,我的做题,我的收藏模式下)
    handleQuestion() {
      let errorId = []
      let errorId = [];
      const list = this.cardData;
      for (let index = 0; index < list.length; index++) {
        const item = list[index];
@@ -665,36 +665,38 @@
              }
            }
          }
          if(citem.isRight == false) {
            errorId.push(citem.id)
          if (citem.isRight == false) {
            errorId.push(citem.id);
          }
        }
      }
      this.cardData = list;
      let oldErrodId = this.allError.find(item => item.type == this.sourceType).errorList
      let oldErrodId = this.allError.find(
        (item) => item.type == this.sourceType
      ).errorList;
      for (let index = 0; index < errorId.length; index++) {
        const item = errorId[index];
        if(oldErrodId.indexOf(item == -1)) {
          oldErrodId.push(item)
        if (oldErrodId.indexOf(item == -1)) {
          oldErrodId.push(item);
        }
      }
      for (let cindex = 0; cindex < this.allError.length; cindex++) {
        const citem = this.allError[cindex];
        if(citem.type == this.sourceType) citem.errorList = oldErrodId
        if (citem.type == this.sourceType) citem.errorList = oldErrodId;
      }
      this.MG.identity
        .setUserKey({
          setKeyRequests: [
            {
              domain: 'errorData',
              domain: "errorData",
              key: this.config.activeBook.bookId,
              value: JSON.stringify(this.allError)
            }
          ]
              value: JSON.stringify(this.allError),
            },
          ],
        })
        .then((res) => {
          console.log('错题已保存',this.allError)
        })
          console.log("错题已保存", this.allError);
        });
    },
    getParentWithClass(element, className) {
      while (element.parentElement) {
@@ -792,6 +794,8 @@
    },
    // 获取收藏id列表
    getCollectIdList() {
      const token = localStorage.getItem("token");
      if (!token) return false;
      this.MG.identity
        .getUserKey({
          domain: "collectData",
@@ -821,6 +825,8 @@
    },
    // 获取错题id列表
    getErrorList() {
      const token = localStorage.getItem("token");
      if (!token) return false;
      this.MG.identity
        .getUserKey({
          domain: "errorData",
@@ -841,7 +847,8 @@
              ).errorList;
            }
          } catch (error) {}
        });
        })
        .catch(() => {});
    },
  },
};