unknown
2024-06-03 99d22ddc34a26490f27b77249a1fb7ac07c4d1c6
Merge branch 'master' of http://182.92.203.7:2001/r/testbookLayout
3个文件已修改
1个文件已添加
612 ■■■■■ 已修改文件
src/App.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/books/English/view/components/header.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/books/childHealth/view/content/index.vue 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/matching/matching.vue 338 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue
@@ -70,7 +70,7 @@
        // embedded
        // english
        // artAndDance
        this.config.resourceCtx + "sportsAndHealth"
        this.config.resourceCtx + "english"
      );
      // 测试试读30页
      // this.activeBook.tryPageCount = 10;
src/books/English/view/components/header.vue
@@ -1,5 +1,8 @@
<template>
  <div class="chapter" num="1">
    <!-- <div class="page-box">
      <matching :rawData="rawData" :item="question" :value="value"></matching>
    </div> -->
    <!--  -->
    <div class="page-box mt-20" page="1">
      <div v-if="showPageList.indexOf(1) > -1">
@@ -88,7 +91,9 @@
            《新标准通用职场英语》系列教材全面对标《高等职业教育专科英语课程标准(2021年版)》,充分突出高职英语课程的思想性、科学性、职业性、时代性,关注各学段的衔接性,实现价值引领,培养学生的必备能力和关键能力。
          </p>
          <p>
            <span class="kaiti ">2.全程融入课程思政,彰显语言课程的育人功能</span>
            <span class="kaiti"
              >2.全程融入课程思政,彰显语言课程的育人功能</span
            >
          </p>
          <p>
            教材从单元主题、素材选取、练习设置等各方面综合设计,紧密联系中国社会和文化,弘扬正能量。在提升学生核心素养的同时,引导学生关注社会,关注他人,潜移默化地培养学生的家国情怀和人文素养,增强学生在多元文化交流环境中讲述中国故事和推介中国文化的能力。教材以“立德树人”为根本任务,立足新时代中国职业教育大背景,以职业为关键词,选取职业与个人、职业与社会、职业与环境主题的语言材料,在助力语言教学的同时,引导学生贡献社会、关心社会、爱岗敬业,实现公共英语课程培根铸魂、启智增慧的功能,促进学生全面发展。
@@ -103,8 +108,11 @@
    <!-- 4 -->
    <div class="page-box" page="5">
      <div v-if="showPageList.indexOf(5) > -1">
        <div class="mb-20" style="padding-right: 20px;">
          <div class="primary-bc fl al-end" style="height: 100px;padding-left: 40px;">
        <div class="mb-20" style="padding-right: 20px">
          <div
            class="primary-bc fl al-end"
            style="height: 100px; padding-left: 40px"
          >
            <div class="preface-header-box y-bc">
              <span class="l-text">新标准通用职场英语</span>
              <span class="g-text g-color">基础模块一</span>
@@ -187,13 +195,195 @@
</template>
<script>
import matching from "@/components/matching/matching.vue";
export default {
  name: "page-header",
  components: { matching },
  props:{
    showPageList:{
      type:Array
    }
  }
      type: Array,
    },
  },
  data() {
    return {
      rawData: {
        left: [
          {
            oldId: "FB34",
            txt: "1",
          },
          {
            oldId: "64D6",
            txt: "2",
          },
          {
            oldId: "2ED4",
            txt: "3",
          },
          {
            oldId: "44DE",
            txt: "4",
          },
          {
            oldId: "A701",
            txt: "5",
          },
          {
            oldId: "A865",
            txt: "6",
          },
          {
            oldId: "D2A3",
            txt: "7",
          },
        ],
        right: [
          {
            oldId: "64D6",
            txt: "B",
          },
          {
            oldId: "FB34",
            txt: "A",
          },
          {
            oldId: "2ED4",
            txt: "C",
          },
          {
            oldId: "44DE",
            txt: "D",
          },
          {
            oldId: "A701",
            txt: "E",
          },
          {
            oldId: "D2A3",
            txt: "G",
          },
          {
            oldId: "A865",
            txt: "F",
          },
        ],
      },
      value: [],
      question: {
        KnowledgePoint: "123",
        analysis: "123",
        answer: [
          {
            id: "FB34",
            linkValue: "A",
            value: "1",
          },
          {
            id: "64D6",
            linkValue: "B",
            value: "2",
          },
          {
            id: "2ED4",
            linkValue: "C",
            value: "3",
          },
          {
            id: "44DE",
            linkValue: "D",
            value: "4",
          },
          {
            id: "A701",
            linkValue: "E",
            value: "5",
          },
          {
            id: "A865",
            linkValue: "F",
            value: "6",
          },
          {
            id: "D2A3",
            linkValue: "G",
            value: "7",
          },
        ],
        optionStyle:undefined,
        id: 489306,
        options: {
          linkValues: [
            {
              oldId: "64D6",
              txt: "B",
            },
            {
              oldId: "FB34",
              txt: "A",
            },
            {
              oldId: "2ED4",
              txt: "C",
            },
            {
              oldId: "44DE",
              txt: "D",
            },
            {
              oldId: "A701",
              txt: "E",
            },
            {
              oldId: "D2A3",
              txt: "G",
            },
            {
              oldId: "A865",
              txt: "F",
            },
          ],
          values:[
          {
            oldId: "FB34",
            txt: "1",
          },
          {
            oldId: "64D6",
            txt: "2",
          },
          {
            oldId: "2ED4",
            txt: "3",
          },
          {
            oldId: "44DE",
            txt: "4",
          },
          {
            oldId: "A701",
            txt: "5",
          },
          {
            oldId: "A865",
            txt: "6",
          },
          {
            oldId: "D2A3",
            txt: "7",
          },
          ]
        },
        questionType: "matching",
        stem:{
          stemTxt: "按顺序连线"
        },
        stemStyle: undefined,
        titleDescription: "1",
        userChoise:[],
        value:[]
      },
    };
  },
};
</script>
src/books/childHealth/view/content/index.vue
@@ -8,7 +8,7 @@
      :style="{
        fontSize: fontSize ? fontSize + 'px' : '16px',
        transform: `scale(${pageZoom ? pageZoom : 1})`,
        transformOrigin: 'center top'
        transformOrigin: 'center top',
      }"
    >
      <pageHeader
@@ -122,7 +122,7 @@
      loadPageList: [],
      questionDataMap: {},
      renderSignMap: {},
      highlightData: null
      highlightData: null,
    };
  },
  computed: {
@@ -131,7 +131,7 @@
    },
    pageZoom() {
      return this.$store.state.qiankun.scale / 100;
    }
    },
  },
  watch: {
    showCatalogList: {
@@ -142,7 +142,7 @@
        ) {
          // 调用父层方法
          this.$store.state.qiankun.catalogChange({
            showCatalogList: newVal
            showCatalogList: newVal,
          });
        }
        // 启动页码观察
@@ -150,7 +150,7 @@
          this.initObservation();
          this.initThemeColor();
        }, 500);
      }
      },
    },
    loadPageList: {
      handler(newVal, oldVal) {
@@ -158,7 +158,7 @@
          this.initSwiper();
          this.initViewer();
        }, 200);
      }
      },
    },
    pageZoom: {
      handler(newVal, oldVal) {
@@ -166,8 +166,8 @@
          this.container ? this.container : document
        ).querySelector(".page-main");
        scrollBox.scrollTop = (scrollBox.scrollTop / oldVal) * newVal;
      }
    }
      },
    },
  },
  mounted() {
    // 默认加载章节
@@ -202,7 +202,7 @@
        // 跳转检索结果位置
        jumpSearchItem: (data) => {
          this.searchItemLocation(data);
        }
        },
      });
    }
@@ -211,13 +211,13 @@
    this.observer = new IntersectionObserver(this.pageChangeCallback, {
      root: null, // 指定根元素,这里设为 null,表示选取整个视窗作为根元素。
      rootMargin: "0px", // 指定根元素的边界,这里设为 "0px",表示根元素的边界和视窗的边界重合
      threshold: 0.5 // 指定交叉比例,这里设为 0.5,表示当目标元素一半或更多显示在视窗中时触发回调函数。
      threshold: 0.5, // 指定交叉比例,这里设为 0.5,表示当目标元素一半或更多显示在视窗中时触发回调函数。
    });
    this.loadPageObserver = new IntersectionObserver(this.loadPageCallback, {
      root: null, // 指定根元素,这里设为 null,表示选取整个视窗作为根元素。
      rootMargin: "0px", // 指定根元素的边界,这里设为 "0px",表示根元素的边界和视窗的边界重合
      threshold: 0 // 指定交叉比例,这里设为 0.5,表示当目标元素一半或更多显示在视窗中时触发回调函数。
      threshold: 0, // 指定交叉比例,这里设为 0.5,表示当目标元素一半或更多显示在视窗中时触发回调函数。
    });
    // 启动页码观察
@@ -328,7 +328,7 @@
          this.showCatalogList = [
            this.catalogLength - 2,
            this.catalogLength - 1,
            this.catalogLength
            this.catalogLength,
          ];
        } else {
          this.showCatalogList = [catalog - 1, catalog, catalog + 1];
@@ -378,9 +378,7 @@
          this.container ? this.container : document
        ).querySelector(`[page="${data.page}"]`);
        // 创建 createTreeWalker 迭代器,用于遍历文本节点,保存到一个数组
        const treeWalker = (
          this.container ? this.container : document
        ).createTreeWalker(pageDom, NodeFilter.SHOW_TEXT);
        const treeWalker = document.createTreeWalker(pageDom, NodeFilter.SHOW_TEXT);
        const allTextNodes = [];
        let currentNode = treeWalker.nextNode();
        while (currentNode) {
@@ -586,7 +584,7 @@
            this.$store.state.qiankun.pageChange({
              page: page,
              catalog: catalog,
              text
              text,
            });
          // const sections = Array.from(document.querySelectorAll(".section"));
          //sections:获取所有具有 .section 类名的元素,并转换为数组。
@@ -645,9 +643,7 @@
              // 高亮行
              setTimeout(() => {
                // 获取页面所有text节点
                const pageTextList = (
                  this.container ? this.container : document
                ).createTreeWalker(target, NodeFilter.SHOW_TEXT);
                const pageTextList = document.createTreeWalker(target, NodeFilter.SHOW_TEXT);
                // 匹配关键字
                const allPageTextNodes = [];
                let currentNode = pageTextList.nextNode();
@@ -691,7 +687,7 @@
          autoplay: {
            //自动开始
            delay: 3000, //时间间隔
            disableOnInteraction: false //*手动操作轮播图后不会暂停*
            disableOnInteraction: false, //*手动操作轮播图后不会暂停*
          },
          paginationClickable: true,
          slidesPerView: 1, // 一组三个
@@ -703,11 +699,11 @@
            ),
            prevEl: (this.container ? this.container : document).querySelector(
              ".swiper-button-prev"
            )
            ),
          },
          // 窗口变化,重新init,针对F11全屏和放大缩小,必须加
          observer: true,
          observeParents: true
          observeParents: true,
          // // 如果需要分页器
          // pagination: {
          //   el: (this.container ? this.container : document).querySelector(
@@ -735,7 +731,7 @@
            ),
            prevEl: (this.container ? this.container : document).querySelector(
              ".swiper-button-prev"
            )
            ),
          },
          // 窗口变化,重新init,针对F11全屏和放大缩小,必须加
          observer: true,
@@ -754,8 +750,8 @@
              var paginationInfoEl = dom.querySelector(".pageBox");
              if (paginationInfoEl)
                paginationInfoEl.textContent = currentPage + "/" + totalPages;
            }
          }
            },
          },
        });
      }
    },
@@ -771,7 +767,7 @@
            : "body",
          navbar: true, // 显示导航栏
          toolbar: true, // 显示工具栏
          title: true // 显示标题
          title: true, // 显示标题
        });
      }
    },
@@ -794,7 +790,7 @@
        chapterTen,
        chapterEleven,
        chapterTwelve,
        chapterThirteen
        chapterThirteen,
      };
      // 遍历所有章节文件
      for (const key in pageData) {
@@ -805,8 +801,8 @@
        pageExample = new pageComponent({
          propsData: {
            showPageList: [],
            questionData: {}
          }
            questionData: {},
          },
        });
        pageExample.$mount(
          (this.container ? this.container : document).querySelector(
@@ -836,8 +832,8 @@
            pageExample = new pageComponent({
              propsData: {
                showPageList: [pageNum],
                questionData: {}
              }
                questionData: {},
              },
            });
            pageExample.$mount(
              (this.container ? this.container : document).querySelector(
@@ -850,9 +846,7 @@
              .querySelector(`[page="${pageNum}"]`);
            if (thisPageDom) {
              // 获取页面所有text节点
              const pageTextList = (
                this.container ? this.container : document
              ).createTreeWalker(thisPageDom, NodeFilter.SHOW_TEXT);
              const pageTextList = document.createTreeWalker(thisPageDom, NodeFilter.SHOW_TEXT);
              // 匹配关键字
              const allPageTextNodes = [];
              let currentNode = pageTextList.nextNode();
@@ -869,7 +863,7 @@
                    page: pageNum,
                    catalog: catalogIndex,
                    txt: textDom.textContent,
                    txtIndex: txtIndex
                    txtIndex: txtIndex,
                  });
                }
              }
@@ -892,7 +886,7 @@
      this.highlightData = data;
      // 跳转
      this.gotoPage(data.catalog, data.page, () => {});
    }
    },
  },
  components: {
    pageHeader,
@@ -908,8 +902,8 @@
    chapterTen,
    chapterEleven,
    chapterTwelve,
    chapterThirteen
  }
    chapterThirteen,
  },
};
</script>
src/components/matching/matching.vue
New file
@@ -0,0 +1,338 @@
<template>
  <div class="connect" id="connect" ref="connect" @mouseup="mouseup">
    <div class="answer"    @mousemove="mousemove">
      <div class="answer-box">
        <div
          class="answer-box-item"
          v-for="(item, index) in leftArr"
          :key="index"
          ref="left"
          @mousedown="(e) => touchstart(e, item, index)"
        >
          {{ item.label.txt }}
        </div>
      </div>
      <div class="answer-box">
        <div
          class="answer-box-item"
          v-for="(item, index) in rightArr"
          :key="index"
          ref="right"
          @mouseup="(e) => touchend(e, item, index)"
        >
          {{ item.label.txt }}
        </div>
      </div>
    </div>
    <canvas
      class="connect-canvasA"
      :width="clientWidth"
      :height="clientHeight"
      ref="canvasA"
    ></canvas>
    <canvas
      class="connect-canvasB"
      :width="clientWidth"
      :height="clientHeight"
      ref="canvasB"
    ></canvas>
  </div>
</template>
<script>
export default {
  data() {
    return {
      isDragging: false,
      leftArr: [],
      rightArr: [],
      location: [],
      canvasA: null,
      canvasB: null,
      leftDom: [],
      rightDom: [],
      clientWidth: 0,
      clientHeight: 0,
      scrollTop: 0,
      debounce: false,
      checkItem: null,
    };
  },
  props: {
    rawData: {
      type: Object,
      default: () => {
        return {
          left: [],
          right: [],
        };
      },
    },
    value: {
      type: Array,
      default: () => {
        return [];
      },
    },
    item: {
      type: Object,
      default: () => {
        return [];
      },
    },
  },
  watch: {
    rawData: {
      immediate: true,
      handler(val) {
        if (val.left && val.left.length) this.init();
      },
    },
  },
  mounted() {
    // 添加滚动事件 监听 解决因为滚动引起的拖动线不对的问题
    window.addEventListener(
      "scroll",
      (e) => {
        // 加个防抖
        if (this.debounce) clearTimeout(this.debounce);
        this.debounce = setTimeout(() => {
          this.debounce = false;
          this.scrollTop = e.target.scrollTop;
        }, 500);
      },
      true
    );
    let connect = this.$refs.connect;
    this.clientWidth = connect.clientWidth;
    this.clientHeight = connect.clientHeight;
    this.canvasA = this.$refs.canvasA.getContext("2d");
    this.canvasB = this.$refs.canvasB.getContext("2d");
    this.$nextTick(() => {
      this.drawing();
    });
  },
  methods: {
    init() {
      this.leftArr = this.rawData.left.map((r) => {
        return {
          label: r,
          line: [],
          value: [],
        };
      });
      this.rightArr = this.rawData.right.map((r) => {
        return {
          label: r,
        };
      });
      // 等dom 渲染完成
      this.$nextTick(() => {
        this.leftDom = this.$refs.left.map((r, i) => {
          return {
            bom: r,
            index: i,
          };
        });
        this.rightDom = this.$refs.right.map((r, i) => {
          return {
            bom: r,
            index: i,
          };
        });
        this.value.map((r) => {
          this.leftArr[r.left].line = this.attachment(r.left, r.right);
          this.leftArr[r.left].value = [r.right];
        });
        this.drawing();
      });
    },
    // 触摸结束
    touchend(e, item, index) {
      console.log("抬起", e,item);
      this.isDragging = false;
      if (this.item.showAnswer) {
        return false;
      }
      // let event = e.changedTouches[0];
      // document.elementFromPoint 重点,根据x,y坐标 取当前元素 所有能运行的逻辑 都依托于这里。
      let dom = document.elementFromPoint(e.pageX, e.pageY);
      // 右边的dom是哪个
      let right = this.rightDom.find((r) => r.bom === dom);
      // 不管是哪个都清除掉 底部的线
      this.canvasB.clearRect(0, 0, this.clientWidth, this.clientHeight);
      // 如果不是右边的dom 直接把 线 干掉 -- 证明不是 没有拖到右边上
      if (!right) {
        item.line = [];
        return;
      }
      // 如果已有的不是我自己 直接替换掉上一个的
      if (item.value[0] !== right.index) {
        let model = this.leftArr.find((r) => r.value[0] === right.index);
        if (model) {
          model.value = [];
          model.line = [];
        }
        item.value = [right.index];
      }
      // 重新赋值 线的 x y 轴
      item.line = this.attachment(index, right.index);
      this.drawing();
      let model = this.leftArr
        .map((r, i) => {
          return {
            left: i,
            right: r.value[0],
          };
        })
        .filter((r) => r.right !== undefined);
      this.$emit("input", model);
      this.item.userChoise = model;
      console.log(JSON.stringify(model));
    },
    // 触摸开始
    touchstart(e, item) {
      this.isDragging = true;
      console.log("按下", e);
      this.checkItem = item
      e.stopPropagation();
      // let event = e.targetTouches[0];
      item.line = [
        e.pageX,
        e.pageY - this.$refs.connect.getBoundingClientRect().y + this.scrollTop,
      ];
    },
    // // 触摸中
    // touchmove(e, item) {
    //     if(!this.isDragging) return false
    //     console.log('移动',e);
    //     if (this.item.showAnswer) {
    //         return false;
    //     }
    //     // let event = e.targetTouches[0];
    //     item.line[2] = e.pageX;
    //     item.line[3] = e.pageY - this.$refs.connect.getBoundingClientRect().y + this.scrollTop;
    //     this.backstrockline(item.line);
    // },
    // 移动中
    mousemove(e) {
      if (!this.isDragging) return false;
      console.log("移动", e);
      if (this.item.showAnswer) {
        return false;
      }
      // let event = e.targetTouches[0];
      this.checkItem.line[2] = e.pageX;
      this.checkItem.line[3] =
        e.pageY - this.$refs.connect.getBoundingClientRect().y + this.scrollTop;
      this.backstrockline(this.checkItem.line);
    },
    // 拖动的时候画线
    backstrockline(val) {
      let canvasB = this.canvasB;
      canvasB.clearRect(0, 0, this.clientWidth, this.clientHeight);
      canvasB.save();
      canvasB.beginPath();
      canvasB.lineWidth = 2;
      canvasB.moveTo(val[0], val[1]);
      canvasB.lineTo(val[2], val[3]);
      canvasB.strokeStyle = "#0C6";
      canvasB.stroke();
      canvasB.restore();
    },
    // 渲染出拖动之后的线
    drawing() {
      let canvasA = this.canvasA;
      this.canvasA.clearRect(0, 0, this.clientWidth, this.clientHeight);
      canvasA.beginPath();
      canvasA.lineWidth = 2;
      for (let i = 0; i < this.leftArr.length; i++) {
        const line = this.leftArr[i].line;
        console.log(line);
        console.log(this.leftArr[i]);
        if (line.length) {
          canvasA.moveTo(line[0], line[1]);
          canvasA.lineTo(line[2], line[3]);
        }
      }
      canvasA.strokeStyle = "#0C6";
      canvasA.stroke();
    },
    // 根据 左边 和右边的 index,换算出 左右的X,Y轴坐标
    attachment(index, rightIndex) {
      let leftEvent = this.leftDom[index].bom;
      let rightEvent = this.rightDom[rightIndex].bom;
      // 为了让线都在中间 x轴不用改 最简单
      let leftX = leftEvent.clientWidth + leftEvent.offsetLeft;
      let rightX = rightEvent.offsetLeft;
      let leftY = leftEvent.offsetTop + leftEvent.clientHeight / 2;
      let rightY = rightEvent.offsetTop + rightEvent.clientHeight / 2;
      return [leftX, leftY, rightX, rightY];
    },
    mouseup() {
      console.log("大盒子抬起", this.isDragging);
      this.isDragging = false;
    },
  },
};
</script>
<style lang="less" scoped>
.connect {
  position: relative;
  padding: 10px;
  &-canvasA {
    position: absolute;
    left: 0px;
    top: 0px;
    z-index: 1;
  }
  &-canvasB {
    position: absolute;
    left: 0px;
    top: 0px;
    z-index: 0;
  }
}
.answer {
  width: 100%;
  display: flex;
  justify-content: space-between;
  &-box {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    width: 40%;
    text-align: center;
    &-item {
      z-index: 2;
      // display: inline-flex;
      padding: 10px;
      border-radius: 4px;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      margin-bottom: 20px;
      line-height: 40px;
      padding: 20px 0;
    }
    &-item:last-child {
      margin-bottom: 0;
    }
  }
}
.connect {
  -webkit-user-select: none; /* Safari */
  -moz-user-select: none; /* Firefox */
  -ms-user-select: none; /* IE10+/Edge */
  user-select: none; /* 标准语法 */
}
</style>