natasha 2 lat temu
rodzic
commit
4749007989

BIN
src/assets/teacherdev/Undo-16-disable-Black.png


BIN
src/assets/teacherdev/Undo-16-normal-Black.png


BIN
src/assets/teacherdev/thick-pen-active.png


BIN
src/assets/teacherdev/thick-pen.png


BIN
src/assets/teacherdev/thicks-pen-active.png


BIN
src/assets/teacherdev/thicks-pen.png


BIN
src/assets/teacherdev/thin-pen-active.png


BIN
src/assets/teacherdev/thin-pen.png


+ 267 - 0
src/components/corpus/FreeWriteQP.vue

@@ -0,0 +1,267 @@
+<template>
+  <canvas ref="canvas" id="panel1"></canvas>
+</template>
+
+<script>
+export default {
+  props: {
+    width: {
+      type: Number,
+      default: 38,
+    },
+    height: {
+      type: Number,
+      default: 38,
+    },
+    lineWidth: {
+      type: Number,
+      default: 4,
+    },
+    lineColor: {
+      type: String,
+      default: "#000000",
+    },
+    bgColor: {
+      type: String,
+      default: "",
+    },
+    isCrop: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      hasDrew: false,
+      resultImg: "",
+      canvasTxt: null,
+      canvas: null,
+      redrawCanvas: null,
+      isMouseDown: false,
+      lastLoc: { x: 0, y: 0 },
+      history: [],
+      sratio: 1,
+    };
+  },
+  computed: {
+    ratio() {
+      return this.height / this.width;
+    },
+    stageInfo() {
+      return this.$refs.canvas.getBoundingClientRect();
+    },
+    myBg() {
+      return this.bgColor ? this.bgColor : "rgba(255, 255, 255, 0)";
+    },
+    context() {
+      return this.$refs.canvas.getContext("2d");
+    },
+    redrawCxt() {
+      return this.$refs.canvas.getContext("2d");
+    },
+  },
+  watch: {
+    myBg: function (newVal) {
+      this.$refs.canvas.style.background = newVal;
+    },
+  },
+  beforeMount() {
+    window.addEventListener("resize", this.$_resizeHandler);
+  },
+  beforeDestroy() {
+    window.removeEventListener("resize", this.$_resizeHandler);
+  },
+  mounted() {
+    const canvas = this.$refs.canvas;
+    canvas.height = this.height;
+    canvas.width = this.width;
+    canvas.style.background = this.myBg;
+    this.$_resizeHandler();
+    // 在画板以外松开鼠标后冻结画笔
+    document.onmouseup = () => {
+      this.isMouseDown = false;
+    };
+    this.canvas = canvas;
+    this.redrawCanvas = canvas;
+    this.init();
+  },
+  methods: {
+    reload() {
+      this.reset();
+      this.redraw(this.redrawCxt);
+    },
+    init() {
+      this.canvas.onmousedown = (e) => {
+        this.isMouseDown = true;
+        this.hasDrew = true;
+        this.lastLoc = this.window2Canvas(e.clientX, e.clientY);
+      };
+      this.canvas.onmouseout = (e) => {
+        this.isMouseDown = false;
+      };
+      this.canvas.onmousemove = (e) => {
+        if (this.isMouseDown) {
+          let curLoc = this.window2Canvas(e.clientX, e.clientY); // 获得当前坐标
+          this.draw(this.context, this.lastLoc, curLoc);
+          this.history.push([this.lastLoc, curLoc]);
+          this.lastLoc = Object.assign({}, curLoc); // U know what I mean.
+        }
+      };
+      this.canvas.onmouseup = (e) => {
+        this.isMouseDown = false;
+        if (history.length) {
+          localStorage.setItem("history", JSON.stringify(this.history));
+        }
+      };
+    },
+    window2Canvas(x, y) {
+      let bbox = this.canvas.getBoundingClientRect();
+      return { x: Math.round(x - bbox.left), y: Math.round(y - bbox.top) };
+    },
+    draw(context, lastLoc, curLoc) {
+      if (context) {
+        context.lineWidth = 5;
+        context.beginPath();
+        context.moveTo(lastLoc.x, lastLoc.y);
+        context.lineTo(curLoc.x, curLoc.y);
+        context.strokeStyle = "#000";
+        context.lineCap = "round";
+        context.lineJoin = "round";
+        context.stroke();
+      } else {
+        this.redrawCxt.lineWidth = 5;
+        this.redrawCxt.beginPath();
+        this.redrawCxt.moveTo(lastLoc.x, lastLoc.y);
+        this.redrawCxt.lineTo(curLoc.x, curLoc.y);
+        this.redrawCxt.strokeStyle = "#000";
+        this.redrawCxt.lineCap = "round";
+        this.redrawCxt.lineJoin = "round";
+        this.redrawCxt.stroke();
+      }
+    },
+    redraw(context) {
+      if (localStorage.getItem("history")) {
+        let history = JSON.parse(localStorage.getItem("history"));
+        const len = history.length;
+        let i = 0;
+        const runner = () => {
+          i++;
+          if (i < len) {
+            this.draw(context, history[i][0], history[i][1]);
+            requestAnimationFrame(runner);
+          }
+        };
+        requestAnimationFrame(runner);
+      }
+    },
+
+    $_resizeHandler() {
+      const canvas = this.$refs.canvas;
+      canvas.style.width = this.width + "px";
+      const realw = parseFloat(window.getComputedStyle(canvas).width);
+      canvas.style.height = this.ratio * realw + "px";
+      this.canvasTxt = canvas.getContext("2d");
+      this.canvasTxt.scale(1 * this.sratio, 1 * this.sratio);
+      this.sratio = realw / this.width;
+      this.canvasTxt.scale(1 / this.sratio, 1 / this.sratio);
+    },
+    // 操作
+    generate() {
+      const pm = new Promise((resolve, reject) => {
+        if (!this.hasDrew) {
+          reject(`Warning: Not Signned!`);
+          return;
+        }
+        var resImgData = this.canvasTxt.getImageData(
+          0,
+          0,
+          this.$refs.canvas.width,
+          this.$refs.canvas.height
+        );
+        this.canvasTxt.globalCompositeOperation = "destination-over";
+        this.canvasTxt.fillStyle = this.myBg;
+        this.canvasTxt.fillRect(
+          0,
+          0,
+          this.$refs.canvas.width,
+          this.$refs.canvas.height
+        );
+        this.resultImg = this.$refs.canvas.toDataURL();
+        var resultImg = this.resultImg;
+        this.canvasTxt.clearRect(
+          0,
+          0,
+          this.$refs.canvas.width,
+          this.$refs.canvas.height
+        );
+        this.canvasTxt.putImageData(resImgData, 0, 0);
+        this.canvasTxt.globalCompositeOperation = "source-over";
+        if (this.isCrop) {
+          const crop_area = this.getCropArea(resImgData.data);
+          var crop_canvas = document.createElement("canvas");
+          const crop_ctx = crop_canvas.getContext("2d");
+          crop_canvas.width = crop_area[2] - crop_area[0];
+          crop_canvas.height = crop_area[3] - crop_area[1];
+          const crop_imgData = this.canvasTxt.getImageData(...crop_area);
+          crop_ctx.globalCompositeOperation = "destination-over";
+          crop_ctx.putImageData(crop_imgData, 0, 0);
+          crop_ctx.fillStyle = this.myBg;
+          crop_ctx.fillRect(0, 0, crop_canvas.width, crop_canvas.height);
+          resultImg = crop_canvas.toDataURL();
+          crop_canvas = null;
+        }
+        resolve(resultImg);
+      });
+      return pm;
+    },
+    reset() {
+      this.canvasTxt.clearRect(
+        0,
+        0,
+        this.$refs.canvas.width,
+        this.$refs.canvas.height
+      );
+      this.$emit("update:bgColor", "");
+      this.$refs.canvas.style.background = "rgba(255, 255, 255, 0)";
+      this.history = [];
+      this.hasDrew = false;
+      this.resultImg = "";
+    },
+    getCropArea(imgData) {
+      var topX = this.$refs.canvas.width;
+      var btmX = 0;
+      var topY = this.$refs.canvas.height;
+      var btnY = 0;
+      for (var i = 0; i < this.$refs.canvas.width; i++) {
+        for (var j = 0; j < this.$refs.canvas.height; j++) {
+          var pos = (i + this.$refs.canvas.width * j) * 4;
+          if (
+            imgData[pos] > 0 ||
+            imgData[pos + 1] > 0 ||
+            imgData[pos + 2] ||
+            imgData[pos + 3] > 0
+          ) {
+            btnY = Math.max(j, btnY);
+            btmX = Math.max(i, btmX);
+            topY = Math.min(j, topY);
+            topX = Math.min(i, topX);
+          }
+        }
+      }
+      topX++;
+      btmX++;
+      topY++;
+      btnY++;
+      const data = [topX, topY, btmX, btnY];
+      return data;
+    },
+  },
+};
+</script>
+
+<style scoped>
+canvas {
+  max-width: 100%;
+  display: block;
+}
+</style>

+ 583 - 0
src/components/corpus/FreewriteLettle.vue

@@ -0,0 +1,583 @@
+<!--  -->
+<template>
+  <div class="practice practiceSingleNPC">
+    <!-- <img @click="changePraShow()" class="close-icon" /> -->
+    <a class="close-icon"><svg-icon
+      icon-class="close"
+      @click="changePraShow()"
+    ></svg-icon></a>
+
+    <div class="right-content">
+      <div class="right-content-box">
+        <div class="right-strockred">
+          <template v-if="!hasPlay && data && data.strokes_image_url">
+            <img class="img" :src="data.strokes_image_url" alt="" />
+          </template>
+          <div class="vueEsign-box">
+            <FreeWriteQP
+              :bgColor.sync="bgColor"
+              :height="height"
+              :isCrop="isCrop"
+              :lineColor="hanzicolor"
+              :lineWidth="hanziweight"
+              :width="width"
+              class="vueEsign"
+              ref="esign"
+              id="esign"
+            />
+          </div>
+          <div class="tian-bg">
+            <svg-icon
+                icon-class="tian"
+                v-if="BoxbgType==0"
+                :style="{color:'#DEDEDE'}"
+            />
+            <svg-icon
+                icon-class="mi"
+                v-if="BoxbgType==1"
+                :style="{color:'#DEDEDE'}"
+            />
+          </div>
+          
+          <a @click="resetHuahua" class="clean-btn"></a>
+        </div>
+      </div>
+      <ul class="nav-list">
+        <li @click="play()">
+            播放
+        </li>
+        <li @click="handleWriteImg">
+            保存
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
+
+<script>
+import FreeWriteQP from "./FreeWriteQP.vue";
+
+export default {
+  components: {
+    FreeWriteQP,
+  },
+  props: [
+    "cur",
+    "changePraShow",
+    "themeColor",
+    "currentTreeID",
+    "currentHz",
+    "currenHzData",
+    "closeifFreeShow",
+    "rowIndex",
+    "colIndex",
+    "BoxbgType"
+  ],
+  data() {
+    return {
+      width: 256,
+      height: 256,
+      bgColor: "",
+      isCrop: false,
+      //   learn_mode: "",
+      playStorkes: false,
+      navIndex: 0,
+      colorsList: ["#404040", "#f65d4d", "#19b068", "#52a1ea", "#ff8c49"],
+      weightList: [3, 6, 10],
+      colorIndex: 0,
+      penIndex: 0,
+      hanzicolor: "",
+      hanziweight: "",
+      thinpen: require("../../assets/teacherdev/thin-pen.png"), //细笔
+      thinpenActive: require("../../assets/teacherdev/thin-pen-active.png"),
+      thickpen: require("../../assets/teacherdev/thick-pen.png"),
+      thickpenActive: require("../../assets/teacherdev/thick-pen-active.png"),
+      thicskpen: require("../../assets/teacherdev/thicks-pen.png"),
+      thicskpenActive: require("../../assets/teacherdev/thicks-pen-active.png"),
+      collectFlag: false, // 是否收藏
+      imgarr: [],
+      imgOrCans: false,
+      hasPlay: false,
+      data: null,
+    };
+  },
+  computed: {},
+  watch: {},
+  //方法集合
+  methods: {
+    play(index) {
+      let _this = this;
+      if (
+        (_this.currenHzData &&
+          _this.currenHzData.history &&
+          _this.currenHzData.history.length > 0) ||
+        (_this.$refs.esign.history && _this.$refs.esign.history.length > 0)
+      ) {
+        if (_this.hasPlay) {
+          _this.$message.warning("请等待播放完成");
+          return;
+        }
+        //this.$refs.esign.reset();
+        _this.hasPlay = true;
+        let c = document.getElementById("esign");
+        let cxt = document.getElementById("esign").getContext("2d");
+        cxt.clearRect(0, 0, c.width, c.height);
+        let history = null;
+        history =
+          _this.$refs.esign.history && _this.$refs.esign.history.length > 0
+            ? _this.$refs.esign.history
+            : _this.currenHzData.history;
+        const len = history.length;
+        let i = 0;
+        const runner = () => {
+          i++;
+          if (i < len) {
+            _this.$refs.esign.draw(null, history[i][0], history[i][1]);
+            requestAnimationFrame(runner);
+          } else {
+            console.log("播放完成");
+            _this.hasPlay = false;
+          }
+        };
+        requestAnimationFrame(runner);
+      } else {
+        _this.$message.warning("请先绘制图形");
+      }
+    },
+
+    changeNav(index) {
+      this.navIndex = index;
+    },
+    changeColor(index) {
+      let _this = this;
+      _this.colorIndex = index;
+      let color = _this.colorsList[index];
+      _this.hanzicolor = color;
+    },
+    // changePen(index) {
+    //   let _this = this;
+    //   _this.penIndex = index;
+    //   _this.hanziweight = _this.weightList[_this.penIndex];
+    // },
+    changeLearnMode(mode) {
+      this.learn_mode = mode;
+    },
+    resetHuahua() {
+      let _this = this;
+      if (this.hasPlay) {
+        this.$message.warning("请等待播放完成");
+        return;
+      }
+      this.imgOrCans = false;
+      this.$refs.esign.reset();
+      if (this.data) {
+        this.data.strokes_image_url = "";
+      }
+      this.$emit(
+          "ExerciseChangeCurQue",
+          {
+            history: null,
+            strokes_image_url: null,
+          },
+          this.rowIndex,
+          this.colIndex
+        );
+    },
+    //不保存到记录列表
+    handleWriteImg() {
+      if (this.TaskModel == "ANSWER") {
+        return;
+      }
+      if (this.hasPlay) {
+          this.$message.warning("请等待播放完成");
+          return;
+        }
+      this.$refs.esign.generate().then((res) => {
+        let Book_img = res.replace("data:image/png;base64,", "");
+        let write_img = "data:image/png;base64," + Book_img;
+        let answer = {};
+        answer = {
+          hz: this.currentHz,
+          strokes_content: JSON.stringify(this.$refs.esign.history),
+          strokes_image_url: write_img,
+        };
+        let obj = {
+          history: this.$refs.esign.history,
+          strokes_image_url: write_img,
+        };
+        this.$emit("ExerciseChangeCurQue", obj, this.rowIndex, this.colIndex);
+
+        this.closeifFreeShow(obj, this.rowIndex, this.colIndex);
+        // this.$message.warning("请先书写在保存");
+      });
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    let _this = this;
+    let color = _this.colorsList[_this.colorIndex];
+    _this.hanzicolor = color;
+    _this.hanziweight = 6;
+    if (this.currenHzData && this.currenHzData.strokes_image_url) {
+      this.imgOrCans = true;
+    }
+    this.data = JSON.parse(JSON.stringify(this.currenHzData));
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='scss' scoped>
+.tian-bg {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  left: 0;
+  top: 0;
+}
+.practice {
+  width: 320px;
+  // max-height: 400px;
+  margin: 0 auto;
+  background: #f3f3f3;
+  box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.15);
+  border-radius: 8px;
+  position: relative;
+  .clean-btn {
+    position: absolute;
+    right: 8px;
+    bottom: 8px;
+    z-index: 999;
+    width: 16px;
+    height: 16px;
+    margin: 0 4px;
+    cursor: pointer;
+    background: url("../../assets/teacherdev/Undo-16-disable-Black.png") center
+      no-repeat;
+    background-size: cover;
+    display: block;
+    &:hover {
+      background: url("../../assets/teacherdev/Undo-16-normal-Black.png") center
+        no-repeat;
+      background-size: cover;
+    }
+  }
+
+  .close-icon {
+    position: absolute;
+    top: 6px;
+    right: 8px;
+    width: 20px;
+    height: 20px;
+    padding: 8px;
+    cursor: pointer;
+    z-index: 2;
+  }
+  .Book_content {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    box-sizing: border-box;
+    position: relative;
+    align-items: flex-start;
+  }
+  .left-content {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    width: 144px;
+    .left-content-pra {
+      height: 162px;
+    }
+  }
+  .right-content {
+    position: relative;
+    width: 288px;
+    // height: 360px;
+    background: #f3f3f3;
+    border-radius: 16px;
+    box-sizing: border-box;
+    padding: 30px 16px 30px;
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+    align-items: center;
+    margin: 0 auto;
+    .nav-list {
+      width: 100%;
+      height: 34px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 0;
+      list-style: none;
+      margin-top: 16px;
+      > li {
+        height: 34px;
+        width: 124px;
+        text-align: center;
+        font-style: normal;
+        font-weight: bold;
+        font-size: 14px;
+        line-height: 34px;
+        color: #fff;
+        cursor: pointer;
+        border-radius: 8px;
+        background: #DE4444;
+        &:hover {
+          background: #f76565;
+        }
+        &:active {
+          background: #c43c3c;
+        }
+        &.disabled {
+          color: #fff;
+          background-color: #c8c9cc;
+          border-color: #c8c9cc;
+          cursor: not-allowed;
+          background-image: none;
+        }
+      }
+    }
+    &-box {
+      width: 288px;
+      height: 288px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      border-radius: 16px;
+    }
+    .right-strockred {
+      position: relative;
+      width: 256px;
+      height: 256px;
+      position: relative;
+      overflow: hidden;
+      box-sizing: border-box;
+      background: #fff;
+      .img {
+        position: absolute;
+        z-index: 1;
+      }
+      .tian-bg {
+        width: 256px;
+        height: 256px;
+        position: absolute;
+        left: 0;
+        top: 0;
+        z-index: 0;
+        svg{
+            width: 100%;
+            height: 100%;
+        }
+      }
+      .vueEsign {
+        width: 256px;
+        height: 256px;
+        position: absolute;
+        left: 0;
+        top: 0;
+        z-index: 99;
+      }
+    }
+    .footer {
+      position: absolute;
+      bottom: 80px;
+      width: 100%;
+      padding-right: 40px;
+      display: flex;
+      justify-content: flex-end;
+      align-items: center;
+      .pen-colors {
+        display: flex;
+        justify-content: flex-start;
+        align-items: center;
+        .write-icon-3 {
+          width: 20px;
+          height: 20px;
+          margin-right: 12px;
+        }
+        .colors-list {
+          display: flex;
+          justify-content: flex-start;
+          align-items: center;
+          margin: 0;
+          padding: 0;
+          > li {
+            width: 20px;
+            height: 20px;
+            border: 2px solid #fff;
+            box-sizing: border-box;
+            background: #fff;
+            margin: 0 4px;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            border-radius: 50%;
+            cursor: pointer;
+            > span {
+              width: 14px;
+              height: 14px;
+              border-radius: 100%;
+              &.color-item0 {
+                background: #404040;
+              }
+              &.color-item1 {
+                background: #f65d4d;
+              }
+              &.color-item2 {
+                background: #19b068;
+              }
+              &.color-item3 {
+                background: #52a1ea;
+              }
+              &.color-item4 {
+                background: #ff8c49;
+              }
+            }
+
+            &.color-item-active0 {
+              border: 2px solid #404040;
+            }
+            &.color-item-active1 {
+              border: 2px solid #f65d4d;
+            }
+            &.color-item-active2 {
+              border: 2px solid #19b068;
+            }
+            &.color-item-active3 {
+              border: 2px solid #52a1ea;
+            }
+            &.color-item-active4 {
+              border: 2px solid #ff8c49;
+            }
+          }
+        }
+      }
+      .pen {
+        display: flex;
+        justify-content: flex-start;
+        align-items: center;
+        > img {
+          width: 21px;
+          height: 19px;
+          margin-left: 4px;
+          cursor: pointer;
+        }
+      }
+    }
+  }
+}
+.strockplay {
+  width: 144px;
+  height: 144px;
+  border: 2px solid #de4444;
+  border-radius: 8px;
+  box-sizing: border-box;
+  overflow: hidden;
+  .strockplayRedInner {
+    width: 100%;
+    height: 100%;
+  }
+}
+.left-content .footer {
+  width: 100%;
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+  .bg-box {
+    width: 76px;
+    height: 32px;
+    text-align: center;
+    padding: 4px 8px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    background: #ffffff;
+    border: 1px solid rgba(0, 0, 0, 0.1);
+    box-sizing: border-box;
+    border-radius: 4px;
+    font-size: 16px;
+    line-height: 150%;
+    color: #000;
+    // &:nth-child(2) {
+    //   margin: 0 24px;
+    // }
+    img {
+      width: 24px;
+      height: 24px;
+      margin: 0;
+    }
+  }
+  .practice-icon {
+    height: 36px;
+    margin-top: 12px;
+  }
+  > span {
+    margin-bottom: 9px;
+    font-weight: 600;
+    font-family: "FZJCGFKTK";
+    font-size: 24px;
+    line-height: 34px;
+    /* identical to box height */
+
+    text-align: center;
+
+    color: #ba7d21;
+  }
+}
+.el-tabs {
+  width: 100%;
+}
+</style>
+<style lang="scss">
+.practiceSingleNPC {
+  .el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active {
+    color: #000;
+  }
+  .el-tabs--border-card
+    > .el-tabs__header
+    .el-tabs__item:not(.is-disabled):hover {
+    color: #000;
+  }
+  .el-tabs__item,
+  .el-tabs--border-card > .el-tabs__header .el-tabs__item {
+    color: #000;
+    font-size: 16px;
+    line-height: 150%;
+    line-height: 48px;
+    height: 48px;
+    width: 170px;
+    text-align: center;
+    font-weight: normal;
+    border: none;
+  }
+  .el-tabs--border-card > .el-tabs__header {
+    background: #f3f3f3;
+    border: none;
+  }
+  .el-tabs--border-card > .el-tabs__content {
+    padding: 0px;
+  }
+  .el-tab-pane {
+    display: flex;
+  }
+}
+.NPC-Big-Book-preview-green {
+  .strockplay {
+    border-color: #24b99e;
+  }
+}
+.NPC-Big-Book-preview-brown {
+  .strockplay {
+    border-color: #bd8865;
+  }
+}
+</style>

+ 2 - 4
src/components/corpus/Strockplayredline.vue

@@ -167,11 +167,9 @@ export default {
 .strockplayRedInner {
   position: relative;
 
-  width: 62px; //444px
-  height: 62px; //480px
+  width: 100%; //444px
+  height: 100%; //480px
 }
-
-
 .character-target-div {
   width: 100%;
   height: 100%;

+ 3 - 0
src/icons/svg/close.svg

@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0.283961 10.2901C-0.0872752 10.6613 -0.104953 11.324 0.2928 11.704C0.672875 12.1016 1.34464 12.0839 1.71587 11.7128L6.00277 7.4271L10.2897 11.7128C10.6697 12.0928 11.3238 12.1016 11.7039 11.704C12.1016 11.324 12.0928 10.6613 11.7127 10.2813L7.42584 5.99558L11.7127 1.7187C12.0928 1.3299 12.1016 0.675994 11.7039 0.296024C11.3238 -0.10162 10.6697 -0.0927835 10.2897 0.287187L6.00277 4.5729L1.71587 0.287187C1.34464 -0.083947 0.672875 -0.10162 0.2928 0.296024C-0.104953 0.675994 -0.0872752 1.33873 0.283961 1.70987L4.57086 5.99558L0.283961 10.2901Z" fill="currentColor"/>
+</svg>

+ 23 - 16
src/views/wordcard/cread.vue

@@ -78,7 +78,7 @@
               <div style="margin-right: 16px">
                 <span class="title">书写格</span>
                 <el-input
-                  style="width: 60px"
+                  style="width: 60px;text-align:center"
                   v-model="from.writeBoxNumber"
                 ></el-input>
                 <span style="margin-left: 8px">{{
@@ -88,7 +88,7 @@
               <div style="margin-right: 16px">
                 <span class="title">描红</span>
                 <el-input
-                  style="width: 60px"
+                  style="width: 60px;text-align:center"
                   v-model="from.miaoRedBoxNumber"
                 ></el-input>
                 <span style="margin-left: 8px">{{
@@ -98,7 +98,7 @@
               <div>
                 <span class="title">文末空行</span>
                 <el-input
-                  style="width: 60px"
+                  style="width: 60px;text-align:center"
                   v-model="from.lastNullrow"
                 ></el-input>
                 <span style="margin-left: 8px">行</span>
@@ -184,11 +184,12 @@ export default {
     },
     // 生成
     creadEvent() {
+      this.writeTableData = null
       if (this.from.content == "") {
         this.$message.warning("请先输入内容");
         return;
       }
-      if(!(this.from.writeBoxNumber!=''&&this.from.miaoRedBoxNumber!=''&&this.from.lastNullrow!='')){
+      if(!(this.from.writeBoxNumber||this.from.miaoRedBoxNumber||this.from.lastNullrow)){
         this.$message.warning("请先输入配置内容");
         return;
       }
@@ -238,13 +239,14 @@ export default {
                 };
                 data.option.push(obj);
             }
-            
         }else{
             for(let m=0;m<contentArr[i].length;m++){
-                let obj = {
-                    con: contentArr[i][m],
-                };
-                data.option.push(obj);
+                if(/^[\u4e00-\u9fa5]/.test(contentArr[i][m])){
+                    let obj = {
+                        con: contentArr[i][m],
+                    };
+                    data.option.push(obj);
+                }
             }
         }
       }
@@ -284,13 +286,15 @@ export default {
                 arr.push({
                   con: item.con,
                 });
-                item.hzDetail.hz_json.medians.forEach((items, indexs) => {
-                  arr.push({
-                    con: item.con,
-                    answer: indexs + 1,
-                    hzDetail: JSON.parse(JSON.stringify(item.hzDetail.hz_json)),
-                  });
-                });
+                if(item.hzDetail&&item.hzDetail.hz_json&&item.hzDetail.hz_json.medians){
+                    item.hzDetail.hz_json.medians.forEach((items, indexs) => {
+                        arr.push({
+                            con: item.con,
+                            answer: indexs + 1,
+                            hzDetail: JSON.parse(JSON.stringify(item.hzDetail.hz_json)),
+                        });
+                    });
+                }
                 // 如果不满一行则补满
                 let newarr = [];
                 if (arr.length % data.rowNumber != 0) {
@@ -672,6 +676,9 @@ export default {
     .el-switch__label.is-active {
       color: #000000;
     }
+    .el-input__inner{
+        text-align: center;
+    }
   }
 }
 </style>

+ 76 - 8
src/views/wordcard/writeTable.vue

@@ -44,10 +44,7 @@
                         :targetDiv="'write-item-' + pageNumber + '-' + indexR + '-' + indexI"
                      />
                 </template>
-                <template v-else-if="itemI&&itemI.write">
-                    {{123}}
-                </template>
-                <div v-else class="tian-div">
+                <div v-else class="tian-div" @click="freeWrite(itemI,indexR,indexI)">
                     <svg-icon
                         icon-class="tian"
                         className="tian"
@@ -60,6 +57,11 @@
                         v-if="dataConfig.BoxbgType==1"
                         :style="{color:'#DEDEDE'}"
                     />
+                    <img
+                        v-if="itemI.strokes_image_url"
+                        :src="itemI.strokes_image_url"
+                        alt=""
+                    />
                 </div>
             </div>
         </div>
@@ -69,6 +71,18 @@
         <b>{{pageNumber + '/' + totalNumber}}</b>
         <a>www.chinesedu.com</a>
     </div>
+    <div class="practiceBox practiceBoxStrock" v-if="ifFreeShow">
+      <FreewriteLettle
+        :changePraShow="changePraShow"
+        ref="freePaint"
+        :currenHzData="currenHzData"
+        :rowIndex="activeIndex"
+        :colIndex="activeColIndex"
+        :closeifFreeShow="closeifFreeShow"
+        @ExerciseChangeCurQue="ExerciseChangeCurQue"
+        :BoxbgType="dataConfig.BoxbgType"
+      />
+    </div>
   </div>
 </template>
 
@@ -77,13 +91,15 @@
 import Strockplayredline from "../../components/corpus/Strockplayredline.vue";
 import Strockplay from "../../components/corpus/Strockplay.vue"
 import Strockred from "../../components/corpus/Strockred.vue"
+import FreewriteLettle from "../../components/corpus/FreewriteLettle.vue"
 
 export default {
   //import引入的组件需要注入到对象中才能使用
   components: {
     Strockplayredline,
     Strockplay,
-    Strockred
+    Strockred,
+    FreewriteLettle
   },
   props: [
     "dataConfig",
@@ -94,7 +110,9 @@ export default {
   data() {
     //这里存放数据
     return {
-      
+        ifFreeShow: false,
+        activeIndex: null,
+        activeColIndex: null,
     };
   },
   //计算属性 类似于data概念
@@ -103,11 +121,35 @@ export default {
   watch: {},
   //方法集合
   methods: {
-    
+    changePraShow() {
+      this.ifFreeShow = false;
+    },
+    closeifFreeShow(data, rowIndex, colIndex) {
+      this.ifFreeShow = false;
+      this.$forceUpdate();
+    },
+    freeWrite(item, row, col) {
+      this.ifFreeShow = true;
+      this.activeIndex = row;
+      this.activeColIndex = col;
+    //   this.currentHz = this.curQue.option[indexs].rightOption[rightindex].con;
+      if(item){
+        this.currenHzData = item;
+      }else{
+        this.currenHzData = {};
+      }
+      
+    },
+    ExerciseChangeCurQue(answer, rowIndex, colIndex ) {
+      if (answer) {
+        this.data[rowIndex][colIndex].strokes_image_url = answer.strokes_image_url;
+        this.data[rowIndex][colIndex].history = answer.history
+        this.$forceUpdate();
+      }
+    },
   },
   //生命周期 - 创建完成(可以访问当前this实例)
   created() {
-    console.log(this.data)
   },
   //生命周期 - 挂载完成(可以访问DOM元素)
   mounted() {},
@@ -185,10 +227,36 @@ export default {
     .tian-div{
         width: 100%;
         height: 100%;
+        position: relative;
         .tian{
             width: 100%;
             height: 100%;
         }
+        img{
+            width: 100%;
+            height: 100%;
+            position: absolute;
+            left: 0;
+            top: 0;
+        }
+    }
+    .practiceBox {
+        position: fixed;
+        left: 0;
+        top: 0;
+        z-index: 100100;
+        width: 100%;
+        height: 100vh;
+        background: rgba(0, 0, 0, 0.19);
+        box-sizing: border-box;
+        overflow: hidden;
+        overflow-y: auto;
+        &.practiceBoxStrock {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            padding-top: 0px;
+        }
     }
 }
 </style>