zhangjie 5 年之前
父节点
当前提交
2039193387

+ 53 - 17
src/assets/styles/card-design.scss

@@ -213,14 +213,39 @@
   }
 }
 .design-steps {
-  padding: 10px 0 30px;
+  margin: 10px 0 30px;
   text-align: center;
-  white-space: nowrap;
+  position: relative;
+  height: 28px;
+
+  &::after {
+    content: "";
+    position: absolute;
+    width: 100%;
+    left: 0;
+    top: 14px;
+    border-bottom: 1px dashed #999;
+    z-index: 2;
+  }
 
   .step-item {
-    display: inline-block;
-    vertical-align: top;
+    position: absolute;
+    top: 0;
+    z-index: 8;
+    padding: 0 10px;
+
+    &::after {
+      content: "";
+      position: absolute;
+      width: 100%;
+      left: 0;
+      top: 14px;
+      border-bottom: 1px solid #f5f5f5;
+      z-index: 5;
+    }
+
     > i {
+      position: relative;
       display: inline-block;
       vertical-align: middle;
       height: 28px;
@@ -230,23 +255,37 @@
       color: $--color-primary;
       line-height: 24px;
       font-weight: bold;
+      z-index: 8;
     }
     > span {
+      position: relative;
       display: inline-block;
       vertical-align: middle;
       margin-left: 14px;
       font-weight: bold;
       color: #999;
+      z-index: 8;
     }
-    &:not(:last-child) {
-      &::after {
-        content: "";
-        display: inline-block;
-        vertical-align: middle;
-        width: 200px;
-        margin: 0 20px;
-        border-bottom: 1px dashed #999;
-      }
+
+    &:first-child {
+      left: 0;
+      padding-left: 0;
+    }
+    &:last-child {
+      right: 0;
+      padding-right: 0;
+    }
+    &:nth-of-type(2) {
+      left: 25%;
+      transform: translateX(-50%);
+    }
+    &:nth-of-type(3) {
+      left: 50%;
+      transform: translateX(-50%);
+    }
+    &:nth-of-type(4) {
+      left: 75%;
+      transform: translateX(-50%);
     }
   }
 }
@@ -599,10 +638,7 @@
       }
     }
     .design-steps {
-      padding: 10px 0 10px;
-      .step-item:not(:last-child)::after {
-        width: 160px;
-      }
+      margin: 10px 0;
     }
     .design-body {
       padding: 140px 30px 30px 250px;

+ 36 - 28
src/assets/styles/card-preview.scss

@@ -40,40 +40,42 @@
 
     &-3 {
       .page-column {
-        &:first-child {
-          width: 430px;
-        }
-        &:not(:first-child) {
-          width: 508.5px;
-        }
+        width: 33.33%;
+        // &:first-child {
+        //   width: 430px;
+        // }
+        // &:not(:first-child) {
+        //   width: 508.5px;
+        // }
       }
     }
     &-4 {
       .page-column {
-        &:first-child {
-          width: 430px;
-        }
-        &:not(:first-child) {
-          width: 335.5px;
-        }
+        width: 25%;
+        // &:first-child {
+        //   width: 420px;
+        // }
+        // &:not(:first-child) {
+        //   width: 340.5px;
+        // }
       }
     }
   }
 
-  &-1 {
-    .page-main {
-      &-3 {
-        .page-column {
-          width: 33.33% !important;
-        }
-      }
-      &-4 {
-        .page-column {
-          width: 25% !important;
-        }
-      }
-    }
-  }
+  // &-1 {
+  //   .page-main {
+  //     &-3 {
+  //       .page-column {
+  //         width: 33.33% !important;
+  //       }
+  //     }
+  //     &-4 {
+  //       .page-column {
+  //         width: 25% !important;
+  //       }
+  //     }
+  //   }
+  // }
 }
 // 分栏间距,默认20px
 // page-main-inner
@@ -175,6 +177,12 @@
         margin-top: 10px;
         border-top: 1px solid #333;
       }
+      &-fill-question {
+        border-bottom: 0;
+      }
+      &-type-last {
+        border-bottom: 1px solid #333;
+      }
     }
   }
 }
@@ -874,14 +882,14 @@
 .elem-fill-question {
   white-space: normal;
   .elem-body {
-    padding: 10px 0 10px 20px;
+    padding: 10px 0 10px 16px;
   }
 
   .group-item {
     display: inline-block;
     vertical-align: top;
     font-size: 0;
-    margin-bottom: 20px;
+    // margin-bottom: 20px;
   }
   .question-item {
     font-size: 0;

+ 11 - 5
src/modules/card/components/PagePropEdit.vue

@@ -115,16 +115,17 @@ export default {
         if (val.hasOwnProperty("aOrBSystem")) {
           this.form.aOrB = val.aOrBSystem;
         }
+        this.columnOptions[2].disabled = val.examNumberStyle === "fill";
       }
     }
   },
   mounted() {},
   methods: {
-    ...mapMutations("card", ["setCurElement", "setCardConfig"]),
+    ...mapMutations("card", ["setPages", "setCurElement", "setCardConfig"]),
     ...mapActions("card", ["rebuildPages", "resetElementProp"]),
     modifyColumnNum(item) {
       this.$confirm(
-        "此操作可能会导致当前题卡所有元素位置变动, 是否继续?",
+        "此操作会导致当前题卡编辑的所有元素清空, 是否继续?",
         "提示",
         {
           confirmButtonText: "确定",
@@ -133,17 +134,22 @@ export default {
         }
       )
         .then(() => {
-          this.form.columnNumber = item.value;
-          this.configChange();
+          this.columnNumChange(item.value);
         })
         .catch(() => {});
     },
+    columnNumChange(val) {
+      this.form.columnNumber = val;
+      this.setCardConfig(this.form);
+      this.setPages([]);
+      this.$emit("init-page");
+    },
     configChange() {
+      // TIPS:暂时不用到
       this.setCardConfig(this.form);
       this.$nextTick(() => {
         this.rebuildPages();
         this.setCurElement({});
-        // TODO:重排之后,元素宽度变化 印象了拖动
         this.$nextTick(() => {
           this.resetElementProp(true);
         });

+ 1 - 0
src/modules/card/components/TopicElementEdit.vue

@@ -76,6 +76,7 @@ export default {
         "topic-design",
         "element-item",
         `element-item-${this.elementName}`,
+        this.data["isLast"] ? `element-item-type-last` : "",
         {
           "topic-design-act": this.curElement.id === this.data.id
         }

+ 9 - 5
src/modules/card/components/common/ElementResize.vue

@@ -162,6 +162,7 @@ export default {
       this.initOver = true;
     },
     checkValidSizePos(sizePos) {
+      // TODO:设置校验模式,w or h,改变高度只校验高度,改变宽高校验所有
       if (
         sizePos.w < this.minWidth ||
         (this.maxWidth !== 0 && sizePos.w > this.maxWidth)
@@ -185,11 +186,14 @@ export default {
       if (this.fitParent) {
         if (sizePos.x < 0 || elOffsetTop < 0) return false;
 
-        if (
-          sizePos.x + sizePos.w > this.parentNodeSize.w ||
-          elOffsetTop + sizePos.h > this.parentNodeSize.h
-        )
-          return false;
+        if (this.positionType === "relative") {
+          return elOffsetTop + sizePos.h <= this.parentNodeSize.h;
+        } else {
+          return (
+            sizePos.x + sizePos.w <= this.parentNodeSize.w &&
+            elOffsetTop + sizePos.h <= this.parentNodeSize.h
+          );
+        }
       }
 
       return true;

+ 5 - 3
src/modules/card/components/elementPreview/FillQuestion.vue

@@ -1,12 +1,14 @@
 <template>
   <div :class="classes">
-    <div class="elem-title" v-if="data.topicName">{{ data.topicName }}</div>
+    <div class="elem-title" v-if="data.startNumber === data.parent.startNumber">
+      {{ data.parent.topicName }}
+    </div>
     <div class="elem-body">
       <ul
         class="group-item"
         v-for="(group, gindex) in questions"
         :key="gindex"
-        :style="groupGapStyles"
+        :style="gindex !== questions.length - 1 ? groupGapStyles : null"
       >
         <li
           class="question-item"
@@ -87,7 +89,7 @@ export default {
       this.questions = questions;
     },
     getChoiceList(num, isFill) {
-      const options = !isFill ? "abcdefghijklmn" : "√×";
+      const options = !isFill ? "abcdefghijklmnopqrstuv" : "√×";
       return options
         .toUpperCase()
         .slice(0, num)

+ 30 - 0
src/modules/card/components/elementPropEdit/EditComposition.vue

@@ -49,6 +49,7 @@
 <script>
 const initModalForm = {
   id: "",
+  topicNo: null,
   topicName: "",
   lineCount: 10
 };
@@ -61,9 +62,32 @@ export default {
       default() {
         return {};
       }
+    },
+    topicNos: {
+      type: Array,
+      default() {
+        return [];
+      }
     }
   },
   data() {
+    const topicNoValidater = (rule, value, callback) => {
+      if (this.instance.topicNo === 0) {
+        // 新增题目
+        if (this.topicNos.includes(value)) {
+          callback(new Error("当前大题题号已经存在,请重新输入"));
+        } else {
+          callback();
+        }
+      } else {
+        // 修改题目
+        if (value !== this.instance.topicNo && this.topicNos.includes(value)) {
+          callback(new Error("当前大题题号已经存在,请重新输入"));
+        } else {
+          callback();
+        }
+      }
+    };
     return {
       dialogIsShow: false,
       modalForm: { ...initModalForm },
@@ -74,6 +98,12 @@ export default {
             message: "请输入题目名称",
             trigger: "change"
           }
+        ],
+        topicNo: [
+          {
+            validate: topicNoValidater,
+            trigger: "change"
+          }
         ]
       }
     };

+ 38 - 7
src/modules/card/components/elementPropEdit/EditExplain.vue

@@ -59,6 +59,7 @@
 <script>
 const initModalForm = {
   id: "",
+  topicNo: null,
   topicName: "",
   startNumber: 1,
   endNumber: 4,
@@ -73,6 +74,12 @@ export default {
       default() {
         return {};
       }
+    },
+    topicNos: {
+      type: Array,
+      default() {
+        return [];
+      }
     }
   },
   data() {
@@ -84,17 +91,41 @@ export default {
       }
     };
 
+    const topicNoValidater = (rule, value, callback) => {
+      if (this.instance.topicNo === 0) {
+        // 新增题目
+        if (this.topicNos.includes(value)) {
+          callback(new Error("当前大题题号已经存在,请重新输入"));
+        } else {
+          callback();
+        }
+      } else {
+        // 修改题目
+        if (value !== this.instance.topicNo && this.topicNos.includes(value)) {
+          callback(new Error("当前大题题号已经存在,请重新输入"));
+        } else {
+          callback();
+        }
+      }
+    };
+
     return {
       dialogIsShow: false,
       modalForm: { ...initModalForm },
       rules: {
-        // topicName: [
-        //   {
-        //     required: true,
-        //     message: "请输入题目名称",
-        //     trigger: "change"
-        //   }
-        // ],
+        topicName: [
+          {
+            required: true,
+            message: "请输入题目名称",
+            trigger: "change"
+          }
+        ],
+        topicNo: [
+          {
+            validate: topicNoValidater,
+            trigger: "change"
+          }
+        ],
         startEnd: [
           {
             validate: numberValidater,

+ 31 - 0
src/modules/card/components/elementPropEdit/EditFillLine.vue

@@ -90,6 +90,7 @@
 <script>
 const initModalForm = {
   id: "",
+  topicNo: null,
   topicName: "",
   startNumber: 1,
   endNumber: 2,
@@ -107,6 +108,12 @@ export default {
       default() {
         return {};
       }
+    },
+    topicNos: {
+      type: Array,
+      default() {
+        return [];
+      }
     }
   },
   data() {
@@ -118,10 +125,34 @@ export default {
       }
     };
 
+    const topicNoValidater = (rule, value, callback) => {
+      if (this.instance.topicNo === 0) {
+        // 新增题目
+        if (this.topicNos.includes(value)) {
+          callback(new Error("当前大题题号已经存在,请重新输入"));
+        } else {
+          callback();
+        }
+      } else {
+        // 修改题目
+        if (value !== this.instance.topicNo && this.topicNos.includes(value)) {
+          callback(new Error("当前大题题号已经存在,请重新输入"));
+        } else {
+          callback();
+        }
+      }
+    };
+
     return {
       dialogIsShow: false,
       modalForm: { ...initModalForm },
       rules: {
+        topicNo: [
+          {
+            validate: topicNoValidater,
+            trigger: "change"
+          }
+        ],
         startEnd: [
           {
             validate: numberValidater,

+ 67 - 5
src/modules/card/components/elementPropEdit/EditFillQuestion.vue

@@ -19,6 +19,17 @@
       :key="modalForm.id"
       label-width="100px"
     >
+      <el-form-item prop="topicNo" label="大题题号:">
+        <el-input-number
+          style="width:125px;"
+          v-model="modalForm.topicNo"
+          :min="1"
+          :max="20"
+          :step="1"
+          step-strictly
+          :controls="false"
+        ></el-input-number>
+      </el-form-item>
       <el-form-item prop="topicName" label="题目名称:">
         <el-input
           v-model.trim="modalForm.topicName"
@@ -27,7 +38,7 @@
           clearable
         ></el-input>
       </el-form-item>
-      <el-form-item prop="startEnd" label="起止题号:">
+      <el-form-item prop="endNumber" label="起止题号:">
         <el-input-number
           style="width:40px;"
           v-model="modalForm.startNumber"
@@ -41,7 +52,7 @@
         <el-input-number
           style="width:40px;"
           v-model="modalForm.endNumber"
-          :min="0"
+          :min="modalForm.startNumber"
           :max="100"
           :step="1"
           step-strictly
@@ -53,7 +64,7 @@
           style="width:125px;"
           v-model="modalForm.optionCount"
           :min="2"
-          :max="15"
+          :max="22"
           :step="1"
           step-strictly
           :controls="false"
@@ -84,6 +95,7 @@
 <script>
 const initModalForm = {
   id: "",
+  topicNo: null,
   topicName: "",
   startNumber: 1,
   endNumber: 5,
@@ -101,6 +113,12 @@ export default {
       default() {
         return {};
       }
+    },
+    topicNos: {
+      type: Array,
+      default() {
+        return [];
+      }
     }
   },
   data() {
@@ -112,12 +130,55 @@ export default {
       }
     };
 
+    const topicNoValidater = (rule, value, callback) => {
+      if (!this.instance.topicNo) {
+        // 新增题目
+        if (this.topicNos.includes(value)) {
+          callback(new Error("当前大题题号已经存在,请重新输入"));
+        } else {
+          callback();
+        }
+      } else {
+        // 修改题目
+        if (value !== this.instance.topicNo && this.topicNos.includes(value)) {
+          callback(new Error("当前大题题号已经存在,请重新输入"));
+        } else {
+          callback();
+        }
+      }
+    };
+
     return {
       dialogIsShow: false,
       modalForm: { ...initModalForm },
       rules: {
-        startEnd: [
+        topicName: [
+          {
+            required: true,
+            message: "请输入题目名称",
+            trigger: "change"
+          }
+        ],
+        topicNo: [
+          {
+            required: true,
+            message: "请输入大题题号",
+            trigger: "change"
+          },
+          {
+            type: "number",
+            validate: topicNoValidater,
+            trigger: "change"
+          }
+        ],
+        endNumber: [
+          {
+            required: true,
+            message: "请输入起止题号",
+            trigger: "change"
+          },
           {
+            type: "number",
             validate: numberValidater,
             trigger: "change"
           }
@@ -127,7 +188,8 @@ export default {
   },
   methods: {
     initData(val) {
-      this.modalForm = { ...val };
+      const valInfo = val.parent || val;
+      this.modalForm = { ...valInfo };
       this.modalForm.endNumber =
         this.modalForm.startNumber + this.modalForm.questionsCount - 1;
     },

+ 23 - 2
src/modules/card/components/elementPropEdit/ElementPropEdit.vue

@@ -2,24 +2,28 @@
   <div class="element-prop-edit">
     <edit-composition
       :instance="curElement"
+      :topicNos="topicNos"
       @modified="modified"
       @closed="closed"
       ref="CompositionDialog"
     ></edit-composition>
     <edit-explain
       :instance="curElement"
+      :topicNos="topicNos"
       @modified="modified"
       @closed="closed"
       ref="ExplainDialog"
     ></edit-explain>
     <edit-fill-line
       :instance="curElement"
+      :topicNos="topicNos"
       @modified="modified"
       @closed="closed"
       ref="FillLineDialog"
     ></edit-fill-line>
     <edit-fill-question
       :instance="curElement"
+      :topicNos="topicNos"
       @modified="modified"
       @closed="closed"
       ref="FillQuestionDialog"
@@ -85,16 +89,33 @@ export default {
     }
   },
   computed: {
-    ...mapState("card", ["curElement", "openElementEditDialog"])
+    ...mapState("card", ["curElement", "openElementEditDialog", "topicNos"])
   },
   methods: {
-    ...mapMutations("card", ["setOpenElementEditDialog"]),
+    ...mapMutations("card", ["setOpenElementEditDialog", "setTopicNos"]),
     ...mapActions("card", [
       "modifyElement",
       "modifyElementChild",
       "rebuildPages"
     ]),
     modified(element) {
+      // 修改大题号列表
+      if (element["topicNo"]) {
+        let topicNos = [...this.topicNos];
+        if (!this.curElement.topicNo) {
+          // 新增题目,直接添加
+          topicNos.push(element["topicNo"]);
+        } else {
+          // 编辑题目,删除旧的,新增新的
+          // newTopicNo: element['topicNo']
+          // oldTopicNo: this.curElement.topicNo
+          const pos = topicNos.indexOf(this.curElement.topicNo);
+          topicNos.splice(pos, 1, element["topicNo"]);
+        }
+        this.setTopicNos(topicNos);
+      }
+      // 编辑试题
+      // 属性存在的条件:parent:大题的小题,container:题目内的子元素
       if (element["container"]) {
         this.modifyElementChild(element);
       } else {

+ 37 - 2
src/modules/card/elementModel.js

@@ -154,16 +154,17 @@ const FILL_QUESTION_PROP = {
   x: 0,
   y: 0,
   w: 0,
-  h: 230,
+  h: 112,
   sign: "objective",
   topicName: "",
+  topicNo: null,
   startNumber: 1,
   questionsCount: 10,
   optionCount: 4,
   questionCountPerGroup: 5,
   optionDirection: "horizontal",
   questionGap: 8,
-  groupGap: 22,
+  groupGap: 20,
   optionGap: 8,
   isFill: false,
   isMultiply: false,
@@ -192,6 +193,7 @@ const FILL_LINE_PROP = {
   h: 170,
   sign: "subjective",
   topicName: "",
+  topicNo: null,
   startNumber: 1,
   questionsCount: 4,
   questionNumberPerLine: 2,
@@ -204,6 +206,7 @@ const FILL_LINE_PROP = {
 const EXPLAIN_PROP = {
   type: "EXPLAIN",
   sign: "subjective",
+  topicNo: null,
   topicName: "",
   startNumber: 1,
   questionsCount: 1
@@ -234,6 +237,7 @@ const COMPOSITION_PROP = {
   h: 350,
   sign: "subjective",
   topicName: "",
+  topicNo: null,
   lineCount: 5,
   // 每一个作文题都可以包含其他基础元件,但这些基础元件都用相对定位
   elements: []
@@ -357,6 +361,36 @@ const getTopicHead = (content, type) => {
   return element;
 };
 
+const getFillQuesitons = (model, columnNumber) => {
+  const parent = { ...model };
+  const numberPerChildren = {
+    2: [0, 0, 7, 5, 4, 4, 3, 3, 2, 2, 2, 2, 1],
+    3: [0, 0, 4, 3, 2, 2, 2, 2, 1],
+    4: [0, 0, 3, 2, 2, 2, 1]
+  };
+  const numList = numberPerChildren[columnNumber];
+  const groupPerLine =
+    model.optionCount > numList.length
+      ? numList.pop()
+      : numList[model.optionCount];
+  const numPerLine = groupPerLine * model.questionCountPerGroup;
+  const total = Math.ceil(model.questionsCount / numPerLine);
+  let elements = [];
+  for (var i = 0; i < total; i++) {
+    let child = Object.assign(deepCopy(FILL_QUESTION_PROP), parent);
+    child.id = getElementId();
+    child.h = i ? parent.h : parent.h + 34;
+    child.startNumber = model.startNumber + i * numPerLine;
+    child.questionsCount =
+      i === total - 1 ? model.questionsCount - numPerLine * i : numPerLine;
+    child.parent = parent;
+    child.isLast = i === total - 1;
+
+    elements[i] = child;
+  }
+  return elements;
+};
+
 /**
  *
  * @param {Object} explainModel 解答题model
@@ -410,6 +444,7 @@ export {
   getTopicHead,
   getTopicModel,
   getExplainChildren,
+  getFillQuesitons,
   getElementId,
   ELEMENT_LIST,
   TOPIC_LIST

+ 63 - 3
src/modules/card/store.js

@@ -1,5 +1,6 @@
 import {
   getExplainChildren,
+  getFillQuesitons,
   getNewPage,
   getTopicHead,
   getElementId
@@ -11,6 +12,7 @@ const state = {
   curDragElement: {},
   curPageNo: 0,
   pages: [],
+  topicNos: [],
   cardConfig: {},
   openElementEditDialog: false
 };
@@ -25,6 +27,9 @@ const mutations = {
   setPages(state, pages) {
     state.pages = pages;
   },
+  setTopicNos(state, topicNos) {
+    state.topicNos = topicNos;
+  },
   setCardConfig(state, cardConfig) {
     state.cardConfig = Object.assign({}, state.cardConfig, cardConfig);
   },
@@ -40,6 +45,10 @@ const mutations = {
   setOpenElementEditDialog(state, openElementEditDialog) {
     state.openElementEditDialog = openElementEditDialog;
   },
+  initTopicNos(state) {
+    state.topicNos = getPageTopicNos(state.pages);
+    console.log(state.topicNos);
+  },
   initState(state) {
     state.curElement = {};
     state.curDragElement = {};
@@ -47,6 +56,7 @@ const mutations = {
     state.pages = [];
     state.cardConfig = {};
     state.openElementEditDialog = false;
+    state.topicNos = [];
   }
 };
 
@@ -100,6 +110,19 @@ const fetchFirstSubjectiveTopicPositionInfo = pages => {
   }
 };
 
+const getPageTopicNos = pages => {
+  let topicNos = [];
+  pages.forEach(page => {
+    page.columns.forEach(column => {
+      column.elements.forEach(element => {
+        if (element["topicNo"] && !topicNos.includes(element["topicNo"]))
+          topicNos.push(element["topicNo"]);
+      });
+    });
+  });
+  return topicNos;
+};
+
 const fetchPageLastColumnPositionInfo = pages => {
   return {
     _pageNo: pages.length - 1,
@@ -157,6 +180,34 @@ const actions = {
       } else {
         dispatch("addElement", element);
       }
+    } else if (element.type === "FILL_QUESTION") {
+      const positionInfos = fetchAllRelateParentElementPositionInfos(
+        element,
+        state.pages
+      );
+      if (positionInfos.length) {
+        // 删除所有相关选择题
+        positionInfos.reverse().forEach(pos => {
+          const elems =
+            state.pages[pos._pageNo].columns[pos._columnNo].elements;
+          elems.splice(pos._elementNo, 1);
+        });
+        // 创建新的选择题元素
+        const newElements = getFillQuesitons(
+          element,
+          state.cardConfig.columnNumber
+        );
+        const pos = positionInfos.pop();
+        newElements.forEach((newElement, index) => {
+          state.pages[pos._pageNo].columns[pos._columnNo].elements.splice(
+            pos._elementNo + index,
+            0,
+            newElement
+          );
+        });
+      } else {
+        dispatch("addElement", element);
+      }
     } else {
       const positionInfos = fetchElementPositionInfos(element, state.pages);
       if (positionInfos.length) {
@@ -182,8 +233,14 @@ const actions = {
     }
 
     const elements = state.pages[pos._pageNo].columns[pos._columnNo].elements;
-    const preElements =
-      element.type === "EXPLAIN" ? getExplainChildren(element) : [element];
+    let preElements = [];
+    if (element.type === "EXPLAIN") {
+      preElements = getExplainChildren(element);
+    } else if (element.type === "FILL_QUESTION") {
+      preElements = getFillQuesitons(element, state.cardConfig.columnNumber);
+    } else {
+      preElements = [element];
+    }
     preElements.forEach(preElement => {
       elements.push(preElement);
     });
@@ -195,7 +252,10 @@ const actions = {
   },
   removeElement({ state, commit }, element) {
     // 解答题时,删除所有小题。
-    if (element.type === "EXPLAIN_CHILDREN") {
+    if (
+      element.type === "EXPLAIN_CHILDREN" ||
+      element.type === "FILL_QUESTION"
+    ) {
       const positionInfos = fetchAllRelateParentElementPositionInfos(
         element.parent,
         state.pages

+ 3 - 1
src/modules/card/views/CardDesign.vue

@@ -46,7 +46,7 @@
         <div class="action-part">
           <div class="action-part-title"><h2>基本设置</h2></div>
           <div class="action-part-body">
-            <page-prop-edit></page-prop-edit>
+            <page-prop-edit @init-page="initPageData"></page-prop-edit>
           </div>
         </div>
         <div class="action-part">
@@ -317,6 +317,7 @@ export default {
       "setOpenElementEditDialog",
       "setCurDragElement",
       "setPages",
+      "initTopicNos",
       "initState"
     ]),
     ...mapActions("card", [
@@ -346,6 +347,7 @@ export default {
         this.cardDetailId = tempData.id;
         this.setPages(cont.pages);
         this.setCardConfig(cont.cardConfig);
+        this.initTopicNos();
       } else {
         // 没有题卡内容时,直接创建新的内容
         this.setCardConfig({ cardName: detData.title });

+ 12 - 4
src/plugins/formRules.js

@@ -57,18 +57,26 @@ const smscode = [
   }
 ];
 
-const numberValidator = message => {
+const numberValidator = ({ prop, min = 3, max = 20 }) => {
   return [
     {
       required: true,
       validator: (rule, value, callback) => {
         if (!value && value !== 0) {
-          callback(new Error(message));
+          return callback(new Error(`${prop}不能为空`));
+        }
+
+        if (!Number.isInteger(value)) {
+          callback(new Error("请输入数字值"));
         } else {
-          callback();
+          if (value < min || value > max) {
+            callback(new Error(`${prop}的大小只能介于${min}-${max}之间。`));
+          } else {
+            callback();
+          }
         }
       },
-      trigger: "change"
+      trigger: "blur"
     }
   ];
 };