zhangjie 2 anni fa
parent
commit
5b9a598d88
100 ha cambiato i file con 2296 aggiunte e 2305 eliminazioni
  1. 1 1
      .browserslistrc
  2. 17 10
      .eslintrc.js
  3. 0 5
      .prettierrc
  4. 0 5
      CHANGE.md
  5. 1 1
      babel.config.js
  6. 2 2
      card/api.js
  7. 1 1
      card/assets/styles/card-design.scss
  8. 0 0
      card/card.temp.json
  9. 14 16
      card/components/CardConfigPropEdit.vue
  10. 525 525
      card/components/CardDesign.vue
  11. 114 114
      card/components/CardView.vue
  12. 9 9
      card/components/ElementPropEdit.vue
  13. 6 6
      card/components/PageNumber.vue
  14. 207 207
      card/components/PagePropEdit.vue
  15. 6 6
      card/components/PageStructDialog.vue
  16. 33 36
      card/components/PaperParams.vue
  17. 18 20
      card/components/RightClickMenu.vue
  18. 10 10
      card/components/TopicElementEdit.vue
  19. 9 7
      card/components/TopicElementPreview.vue
  20. 5 5
      card/components/TopicSelectDialog.vue
  21. 21 24
      card/components/UploadButton.vue
  22. 7 7
      card/components/common/ColorSelect.vue
  23. 9 9
      card/components/common/DirectionSelect.vue
  24. 39 39
      card/components/common/ElementResize.vue
  25. 6 6
      card/components/common/FontFamilySelect.vue
  26. 7 7
      card/components/common/LineStyleSelect.vue
  27. 6 6
      card/components/common/LineWidthSelect.vue
  28. 6 6
      card/components/common/PopoverButton.vue
  29. 6 6
      card/components/common/RotationSelect.vue
  30. 5 5
      card/components/common/ShortcutKeySpin.vue
  31. 12 12
      card/components/common/SizeSelect.vue
  32. 3 3
      card/components/common/TopicNumber.vue
  33. 4 4
      card/directives/move-ele.js
  34. 187 187
      card/elementModel.js
  35. 13 13
      card/elements/barcode/EditBarcode.vue
  36. 5 5
      card/elements/barcode/ElemBarcode.vue
  37. 2 2
      card/elements/barcode/model.js
  38. 11 11
      card/elements/card-head/CardHead.vue
  39. 8 8
      card/elements/card-head/CardHeadBodyAutoResize.vue
  40. 2 2
      card/elements/card-head/CardHeadSample.vue
  41. 7 7
      card/elements/card-head/cardHeadSpin/HeadDynamic.vue
  42. 6 6
      card/elements/card-head/cardHeadSpin/HeadNotice.vue
  43. 10 10
      card/elements/card-head/cardHeadSpin/HeadStdinfo.vue
  44. 6 6
      card/elements/card-head/cardHeadSpin/HeadStdno.vue
  45. 2 2
      card/elements/card-head/model.js
  46. 11 11
      card/elements/composition/EditComposition.vue
  47. 4 4
      card/elements/composition/ElemComposition.vue
  48. 12 12
      card/elements/composition/ElemCompositionEdit.vue
  49. 7 7
      card/elements/composition/ElemCompositionElement.vue
  50. 12 12
      card/elements/composition/ElemCompositionElementEdit.vue
  51. 6 6
      card/elements/composition/model.js
  52. 16 16
      card/elements/explain/EditExplain.vue
  53. 4 4
      card/elements/explain/ElemExplain.vue
  54. 12 12
      card/elements/explain/ElemExplainEdit.vue
  55. 6 6
      card/elements/explain/ElemExplainElement.vue
  56. 11 11
      card/elements/explain/ElemExplainElementEdit.vue
  57. 5 5
      card/elements/explain/model.js
  58. 21 21
      card/elements/fill-field/EditFillField.vue
  59. 13 13
      card/elements/fill-field/ElemFillField.vue
  60. 2 2
      card/elements/fill-field/model.js
  61. 29 29
      card/elements/fill-line/EditFillLine.vue
  62. 8 8
      card/elements/fill-line/ElemFillLine.vue
  63. 7 7
      card/elements/fill-line/model.js
  64. 9 9
      card/elements/fill-number/EditFillNumber.vue
  65. 5 5
      card/elements/fill-number/ElemFillNumber.vue
  66. 2 2
      card/elements/fill-number/model.js
  67. 20 20
      card/elements/fill-pane/EditFillPane.vue
  68. 7 7
      card/elements/fill-pane/ElemFillPane.vue
  69. 2 2
      card/elements/fill-pane/model.js
  70. 28 28
      card/elements/fill-question/EditFillQuestion.vue
  71. 11 11
      card/elements/fill-question/ElemFillQuestion.vue
  72. 6 6
      card/elements/fill-question/model.js
  73. 17 17
      card/elements/fill-table/EditFillTable.vue
  74. 6 6
      card/elements/fill-table/ElemFillTable.vue
  75. 2 2
      card/elements/fill-table/model.js
  76. 10 10
      card/elements/grids/EditGrids.vue
  77. 7 7
      card/elements/grids/ElemGrids.vue
  78. 2 2
      card/elements/grids/model.js
  79. 12 12
      card/elements/image/EditImage.vue
  80. 5 5
      card/elements/image/ElemImage.vue
  81. 2 2
      card/elements/image/model.js
  82. 6 6
      card/elements/line/EditLine.vue
  83. 7 7
      card/elements/line/ElemLine.vue
  84. 4 4
      card/elements/line/model.js
  85. 9 9
      card/elements/lines/EditLines.vue
  86. 5 5
      card/elements/lines/ElemLines.vue
  87. 2 2
      card/elements/lines/model.js
  88. 21 21
      card/elements/page/EditPage.vue
  89. 78 78
      card/elements/page/model.js
  90. 6 6
      card/elements/pane/EditPane.vue
  91. 5 5
      card/elements/pane/ElemPane.vue
  92. 2 2
      card/elements/pane/model.js
  93. 15 15
      card/elements/text/EditText.vue
  94. 5 5
      card/elements/text/ElemText.vue
  95. 4 4
      card/elements/text/model.js
  96. 5 5
      card/elements/topic-head/TopicHead.vue
  97. 1 1
      card/elements/topic-head/model.js
  98. 23 23
      card/enumerate.js
  99. 1 1
      card/main.js
  100. 390 388
      card/mixins/exchange.js

+ 1 - 1
.browserslistrc

@@ -1,3 +1,3 @@
 > 1%
 last 2 versions
-not ie <= 8
+not dead

+ 17 - 10
.eslintrc.js

@@ -1,25 +1,32 @@
 module.exports = {
   root: true,
   env: {
-    node: true
+    node: true,
+  },
+  extends: [
+    "plugin:vue/essential",
+    "eslint:recommended",
+    "plugin:prettier/recommended",
+  ],
+  parserOptions: {
+    parser: "@babel/eslint-parser",
   },
-  extends: ["plugin:vue/essential", "@vue/prettier"],
   rules: {
-    "no-console": process.env.NODE_ENV === "production" ? "off" : "off",
+    "no-console": "off",
     "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
+    "vue/multi-word-component-names": "off",
+    "vue/no-mutating-props": "off",
     "no-unused-vars": [
       "error",
-      { vars: "all", args: "none", ignoreRestSiblings: false }
+      { vars: "all", args: "none", ignoreRestSiblings: false },
     ],
     "vue/no-parsing-error": [2, { "x-invalid-end-tag": false }],
     "vue/no-use-v-if-with-v-for": [
       "error",
       {
-        allowUsingIterationVar: true
-      }
-    ]
+        allowUsingIterationVar: true,
+      },
+    ],
   },
-  parserOptions: {
-    parser: "babel-eslint"
-  }
+  ignorePatterns: ["public/"],
 };

+ 0 - 5
.prettierrc

@@ -1,5 +0,0 @@
-{
-  "semi": true,
-  "singleQuote": false,
-  "jsxBracketSameLine": false
-}

+ 0 - 5
CHANGE.md

@@ -1,5 +0,0 @@
-
-
-# 0.1.0
-
-- 系统1.0

+ 1 - 1
babel.config.js

@@ -1,3 +1,3 @@
 module.exports = {
-  presets: ["@vue/app"]
+  presets: ["@vue/cli-plugin-babel/preset"],
 };

+ 2 - 2
card/api.js

@@ -26,7 +26,7 @@ export const cardConfigInfos = () => {
     subjectiveAttention: "测试题卡规则1",
     enable: true,
     remark: "测试题卡规则1",
-    orgIds: null
+    orgIds: null,
   });
 };
 export const cardDetail = () => {
@@ -34,7 +34,7 @@ export const cardDetail = () => {
   return Promise.resolve(cardData);
 };
 
-export const saveCard = datas => {
+export const saveCard = (datas) => {
   Vue.ls.set("cardData", datas);
   return Promise.resolve(randomCode());
 };

+ 1 - 1
card/assets/styles/card-design.scss

@@ -446,7 +446,7 @@
   .el-checkbox {
     color: $--color-text-dark-1;
   }
-  .el-form-item__label{
+  .el-form-item__label {
     padding-right: 10px;
   }
   .column-btn {

File diff suppressed because it is too large
+ 0 - 0
card/card.temp.json


+ 14 - 16
card/components/CardConfigPropEdit.vue

@@ -1,8 +1,6 @@
 <template>
   <div class="card-config-prop-edit">
-    <el-button @click="drawer = true" type="primary">
-      配置题卡信息
-    </el-button>
+    <el-button @click="drawer = true" type="primary"> 配置题卡信息 </el-button>
     <el-drawer
       title="配置题卡信息"
       :visible.sync="drawer"
@@ -82,26 +80,26 @@ export default {
       examNumberStyleOptions: [
         {
           label: "自动条码",
-          value: "auto"
+          value: "auto",
         },
         {
           label: "手动条码",
-          value: "empty"
+          value: "empty",
         },
         {
           label: "手动涂填",
-          value: "fill"
-        }
+          value: "fill",
+        },
       ],
       aOrBTypeOptions: [
         {
           label: "自动条码",
-          value: "auto"
+          value: "auto",
         },
         {
           label: "手动涂填",
-          value: "fill"
-        }
+          value: "fill",
+        },
       ],
       drawer: false,
       form: {
@@ -111,24 +109,24 @@ export default {
         aOrB: true,
         examAbsent: true,
         writeSign: true,
-        showForbidArea: true
-      }
+        showForbidArea: true,
+      },
     };
   },
   computed: {
-    ...mapState("card", ["cardConfig"])
+    ...mapState("card", ["cardConfig"]),
   },
   watch: {
     cardConfig(val) {
       this.form = objAssign(this.form, val);
-    }
+    },
   },
   methods: {
     ...mapMutations("card", ["setCardConfig"]),
     editChange() {
       this.setCardConfig({ ...this.form });
-    }
-  }
+    },
+  },
 };
 </script>
 

+ 525 - 525
card/components/CardDesign.vue

@@ -1,525 +1,525 @@
-<template>
-  <div class="card-design">
-    <div class="design-header">
-      <div class="design-steps">
-        <div class="step-item" v-for="(step, index) in steps" :key="index">
-          <i>{{ index + 1 }}</i>
-          <span>{{ step }}</span>
-        </div>
-      </div>
-    </div>
-
-    <!-- actions -->
-    <div class="design-action">
-      <div class="design-logo">
-        <h1>
-          <i class="el-icon-d-arrow-left" @click="toExit" title="退出"></i>
-          答题卡制作
-        </h1>
-      </div>
-
-      <div class="action-part">
-        <div class="action-part-title"><h2>基本设置</h2></div>
-        <div class="action-part-body">
-          <page-prop-edit @init-page="initPageData"></page-prop-edit>
-        </div>
-      </div>
-      <div class="action-part">
-        <div class="action-part-title"><h2>试题配置</h2></div>
-        <div class="action-part-body">
-          <div class="type-list">
-            <div
-              class="type-item"
-              v-for="(item, index) in TOPIC_LIST"
-              :key="index"
-            >
-              <el-button @click="addNewTopic(item)"
-                ><i class="el-icon-plus"></i>{{ item.name }}</el-button
-              >
-            </div>
-          </div>
-          <p class="tips-info">提示:点击创建试题</p>
-        </div>
-      </div>
-      <div class="action-part">
-        <div class="action-part-title"><h2>插入元素</h2></div>
-        <div class="action-part-body">
-          <div class="type-list">
-            <div
-              class="type-item"
-              v-for="(item, index) in ELEMENT_LIST"
-              :key="index"
-              draggable="true"
-              @dragstart="dragstart(item)"
-            >
-              <el-button><i class="el-icon-plus"></i>{{ item.name }}</el-button>
-            </div>
-            <p class="tips-info">提示:拖动插入元素</p>
-          </div>
-          <!-- Develop btns -->
-          <!-- <card-config-prop-edit></card-config-prop-edit> -->
-        </div>
-        <!-- <br /><br /> -->
-        <!-- <el-button @click="initCard">新建页面</el-button> -->
-      </div>
-      <!-- <div class="action-part">
-          <div class="action-part-title"><h2>阅卷参数</h2></div>
-          <div class="action-part-body">
-            <el-button type="primary" @click="modifyParams"
-              >上传阅卷参数<span class="color-danger"
-                >({{ paperParams["pageSumScore"] || 0 }}分)</span
-              ></el-button
-            >
-          </div>
-        </div> -->
-    </div>
-
-    <div class="design-main">
-      <!-- menus -->
-      <div class="design-control">
-        <div class="control-left tab-btns">
-          <el-button
-            v-for="(page, pageNo) in pages"
-            :key="pageNo"
-            :type="curPageNo === pageNo ? 'primary' : 'default'"
-            @click="swithPage(pageNo)"
-            >第{{ pageNo + 1 }}页</el-button
-          >
-        </div>
-        <div class="control-right">
-          <el-button
-            type="success"
-            :loading="isSubmit"
-            :disabled="!pages.length"
-            @click="toPreview"
-            >预览</el-button
-          >
-          <!-- <el-button
-            v-if="showSaveBtn"
-            type="primary"
-            :loading="isSubmit"
-            :disabled="canSave || !pages.length"
-            @click="toSave"
-            >暂存</el-button
-          > -->
-          <el-button type="primary" :loading="isSubmit" @click="toSubmit"
-            >提交</el-button
-          >
-        </div>
-      </div>
-
-      <!-- edit body -->
-      <div class="design-body">
-        <!-- 注意:后台要替换内容,改类名时,要注意 -->
-        <div
-          :class="[
-            'page-box',
-            `page-box-${cardConfig.pageSize}`,
-            `page-box-${curPageNo % 2}`,
-            { 'page-box-less': pages.length <= 2 }
-          ]"
-          v-if="curPage.locators"
-        >
-          <!-- locator -->
-          <div class="page-locator page-locator-top">
-            <div
-              v-for="elem in curPage.locators.top"
-              :key="elem.id"
-              :id="elem.id"
-              class="page-locator-item"
-            ></div>
-          </div>
-          <div class="page-locator page-locator-bottom">
-            <div
-              v-for="elem in curPage.locators.bottom"
-              :key="elem.id"
-              :id="elem.id"
-              class="page-locator-item"
-            ></div>
-          </div>
-          <!-- inner edit area -->
-          <div class="page-main-inner">
-            <div
-              :class="['page-main', `page-main-${curPage.columns.length}`]"
-              :style="{ margin: `0 -${curPage.columnGap / 2}px` }"
-            >
-              <div
-                class="page-column"
-                v-for="(column, columnNo) in curPage.columns"
-                :key="columnNo"
-                :style="{ padding: `0 ${curPage.columnGap / 2}px` }"
-              >
-                <div
-                  class="page-column-main"
-                  :id="[`column-${curPageNo}-${columnNo}`]"
-                >
-                  <div class="page-column-body" v-if="column.elements.length">
-                    <topic-element-edit
-                      class="page-column-element"
-                      :data-h="element.h"
-                      v-for="element in column.elements"
-                      :key="element.id"
-                      :data="element"
-                    ></topic-element-edit>
-                  </div>
-                  <div class="page-column-body" v-else>
-                    <div
-                      class="page-column-forbid-area"
-                      v-if="cardConfig.showForbidArea"
-                    >
-                      <p>该区域严禁作答</p>
-                    </div>
-                  </div>
-                </div>
-              </div>
-            </div>
-          </div>
-          <!-- outer edit area -->
-          <div class="page-main-outer">
-            <page-number
-              type="rect"
-              :total="pages.length"
-              :current="curPageNo + 1"
-            ></page-number>
-            <page-number
-              type="text"
-              :total="pages.length"
-              :current="curPageNo + 1"
-            ></page-number>
-          </div>
-        </div>
-      </div>
-    </div>
-
-    <!-- all topics -->
-    <div class="topic-list">
-      <div :class="['page-box', `page-box-${cardConfig.pageSize}`]">
-        <div class="page-main-inner">
-          <div
-            :class="['page-main', `page-main-${cardConfig.columnNumber}`]"
-            :style="{ margin: `0 -${cardConfig.columnGap / 2}px` }"
-          >
-            <div
-              class="page-column"
-              :style="{ padding: `0 ${cardConfig.columnGap / 2}px` }"
-            >
-              <div class="page-column-main" id="topic-column">
-                <div class="page-column-body">
-                  <!-- card-head-sample -->
-                  <card-head-sample
-                    :data="cardHeadSampleData"
-                    id="simple-card-head"
-                    v-if="topics.length && cardHeadSampleData"
-                  ></card-head-sample>
-                  <!-- topic element -->
-                  <topic-element-preview
-                    class="page-column-element"
-                    v-for="element in topics"
-                    :key="element.id"
-                    :data="element"
-                  ></topic-element-preview>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-
-    <!-- element-prop-edit -->
-    <element-prop-edit ref="ElementPropEdit"></element-prop-edit>
-    <!-- right-click-menu -->
-    <right-click-menu @inset-topic="insetNewTopic"></right-click-menu>
-    <!-- paper-params -->
-    <paper-params
-      :pages="pages"
-      :paper-params="paperParams"
-      @confirm="paperParamsModified"
-      ref="PaperParams"
-    ></paper-params>
-    <!-- topic select dialog -->
-    <topic-select-dialog
-      ref="TopicSelectDialog"
-      :topics="topicList"
-      @confirm="addNewTopic"
-    ></topic-select-dialog>
-  </div>
-</template>
-
-<script>
-import { mapState, mapMutations, mapActions } from "vuex";
-import {
-  getElementModel,
-  getCardHeadModel,
-  ELEMENT_LIST,
-  TOPIC_LIST
-} from "../elementModel";
-import { CARD_VERSION } from "../enumerate";
-// import CardConfigPropEdit from "../components/CardConfigPropEdit";
-import TopicElementEdit from "../components/TopicElementEdit";
-import TopicElementPreview from "../components/TopicElementPreview";
-import PagePropEdit from "../components/PagePropEdit";
-import ElementPropEdit from "../components/ElementPropEdit";
-import RightClickMenu from "../components/RightClickMenu";
-import PageNumber from "../components/PageNumber";
-import PaperParams from "../components/PaperParams";
-import CardHeadSample from "../elements/card-head/CardHead";
-import TopicSelectDialog from "../components/TopicSelectDialog";
-
-export default {
-  name: "card-design",
-  props: {
-    content: {
-      type: Object,
-      default() {
-        return {
-          pages: [],
-          cardConfig: {},
-          paperParams: {}
-        };
-      }
-    },
-    showSaveBtn: {
-      type: Boolean,
-      default: true
-    }
-  },
-  components: {
-    // CardConfigPropEdit,
-    TopicElementEdit,
-    TopicElementPreview,
-    PagePropEdit,
-    ElementPropEdit,
-    RightClickMenu,
-    CardHeadSample,
-    PageNumber,
-    PaperParams,
-    TopicSelectDialog
-  },
-  data() {
-    return {
-      ELEMENT_LIST,
-      TOPIC_LIST,
-      topicList: [],
-      steps: ["添加标题", "基本设置", "试题配置", "预览生成"],
-      columnWidth: 0,
-      isSubmit: false,
-      canSave: false
-    };
-  },
-  computed: {
-    ...mapState("card", [
-      "cardConfig",
-      "topics",
-      "pages",
-      "paperParams",
-      "curElement",
-      "curPage",
-      "curPageNo"
-    ]),
-    cardHeadSampleData() {
-      if (!this.cardConfig["pageSize"]) return;
-      const data = getCardHeadModel(this.cardConfig);
-      data.isSimple = true;
-      return data;
-    }
-  },
-  mounted() {
-    this.initCard();
-  },
-  methods: {
-    ...mapMutations("card", [
-      "addPage",
-      "setCurPage",
-      "setCurElement",
-      "setCardConfig",
-      "setOpenElementEditDialog",
-      "setCurDragElement",
-      "setPages",
-      "setPaperParams",
-      "setInsetTarget",
-      "initState"
-    ]),
-    ...mapActions("card", [
-      "resetTopicSeries",
-      "removePage",
-      "addElement",
-      "modifyCardHead",
-      "modifyElement",
-      "rebuildPages",
-      "initTopicsFromPages"
-    ]),
-    async initCard() {
-      const { cardConfig, pages, paperParams } = this.content;
-      this.setCardConfig(cardConfig);
-      this.setPaperParams(paperParams);
-
-      if (pages && pages.length) {
-        this.setPages(pages);
-        this.initTopicsFromPages();
-        this.resetTopicSeries();
-        this.setCurPage(0);
-      } else {
-        this.initPageData();
-      }
-      this.addWatch();
-    },
-    initPageData() {
-      this.modifyCardHead({
-        ...getCardHeadModel(this.cardConfig)
-      });
-      this.$nextTick(() => {
-        this.rebuildPages();
-        this.setCurPage(0);
-      });
-    },
-    addNewTopic(item) {
-      let element = getElementModel(item.type);
-      element.w = document.getElementById("topic-column").offsetWidth;
-
-      this.setCurElement(element);
-      this.$refs.ElementPropEdit.open();
-      // to elementPropEdit/ElementPropEdit open topic edit dialog
-    },
-    insetNewTopic({ id, type }) {
-      console.log(id, type);
-      this.setInsetTarget({ id, type });
-      if (type === "FILL_QUESTION") {
-        this.topicList = this.TOPIC_LIST;
-      } else {
-        this.topicList = this.TOPIC_LIST.filter(
-          item => item.type !== "FILL_QUESTION"
-        );
-      }
-      this.$refs.TopicSelectDialog.open();
-    },
-    // 元件编辑
-    dragstart(element) {
-      this.setCurDragElement(getElementModel(element.type));
-    },
-    addWatch() {
-      this.$watch("cardConfig", val => {
-        const element = getCardHeadModel(val);
-        this.modifyCardHead(element);
-        this.$nextTick(() => {
-          this.rebuildPages();
-        });
-      });
-    },
-    swithPage(pindex) {
-      if (this.curPageNo === pindex) return;
-      this.setCurPage(pindex);
-      this.setCurElement({});
-    },
-    // paper-params
-    modifyParams() {
-      this.$refs.PaperParams.open();
-    },
-    paperParamsModified(paperParams) {
-      this.setPaperParams(paperParams);
-    },
-    // save
-    getCardData(htmlContent = "", model = "") {
-      const data = {
-        title: this.cardConfig.cardTitle,
-        content: model,
-        htmlContent
-      };
-      return data;
-    },
-    checkElementCovered() {
-      let elements = [];
-      this.pages.forEach(page => {
-        page.columns.forEach(column => {
-          column.elements.forEach(element => {
-            if (element.isCovered) {
-              elements.push(element.id);
-            }
-          });
-        });
-      });
-      return elements.length;
-    },
-    checkCardValid() {
-      if (!this.cardConfig.cardTitle) {
-        this.$message.error("题卡标题不能为空!");
-        this.setCurPageNo(0);
-        setTimeout(() => {
-          document.getElementById("cardTitleInput").focus();
-        });
-        return false;
-      }
-      // if (!this.cardConfig.cardDesc) {
-      //   this.$message.error("题卡描述信息不能为空!");
-      //   this.setCurPage(0);
-      //   setTimeout(() => {
-      //     document.getElementById("cardDescInput").focus();
-      //   });
-      //   return false;
-      // }
-      if (this.checkElementCovered()) {
-        this.$message.error("题卡中存在被遮挡的元件,请注意调整!");
-        return false;
-      }
-
-      return true;
-    },
-    getCardJson() {
-      // 防止页面未渲染完成,各试题高度未及时更新,保存数据有误的问题
-      return new Promise(resolve => {
-        setTimeout(() => {
-          const data = JSON.stringify(
-            {
-              version: CARD_VERSION,
-              cardType: "STANDARD",
-              cardConfig: this.cardConfig,
-              paperParams: this.paperParams,
-              pages: this.pages
-            },
-            (k, v) => (k.startsWith("_") ? undefined : v)
-          );
-          resolve(data);
-        }, 100);
-      });
-    },
-    async toPreview() {
-      if (this.isSubmit) return;
-      this.isSubmit = true;
-      const model = await this.getCardJson();
-      const datas = this.getCardData("", model);
-      this.$emit("on-preview", datas);
-    },
-    async toSave() {
-      if (!this.checkCardValid()) return;
-
-      if (this.isSubmit) return;
-      this.isSubmit = true;
-      const model = await this.getCardJson();
-      const datas = this.getCardData("", model);
-      this.$emit("on-save", datas);
-    },
-    toSubmit() {
-      if (this.isSubmit) return;
-      if (!this.checkCardValid()) return;
-
-      this.$emit("on-submit", {
-        cardConfig: this.cardConfig,
-        pages: this.pages,
-        paperParams: this.paperParams
-      });
-    },
-    toExit() {
-      this.$emit("on-exit");
-    },
-    loading() {
-      this.isSubmit = true;
-    },
-    unloading() {
-      this.isSubmit = false;
-    }
-  },
-  beforeDestroy() {
-    this.initState();
-  }
-};
-</script>
+<template>
+  <div class="card-design">
+    <div class="design-header">
+      <div class="design-steps">
+        <div class="step-item" v-for="(step, index) in steps" :key="index">
+          <i>{{ index + 1 }}</i>
+          <span>{{ step }}</span>
+        </div>
+      </div>
+    </div>
+
+    <!-- actions -->
+    <div class="design-action">
+      <div class="design-logo">
+        <h1>
+          <i class="el-icon-d-arrow-left" @click="toExit" title="退出"></i>
+          答题卡制作
+        </h1>
+      </div>
+
+      <div class="action-part">
+        <div class="action-part-title"><h2>基本设置</h2></div>
+        <div class="action-part-body">
+          <page-prop-edit @init-page="initPageData"></page-prop-edit>
+        </div>
+      </div>
+      <div class="action-part">
+        <div class="action-part-title"><h2>试题配置</h2></div>
+        <div class="action-part-body">
+          <div class="type-list">
+            <div
+              class="type-item"
+              v-for="(item, index) in TOPIC_LIST"
+              :key="index"
+            >
+              <el-button @click="addNewTopic(item)"
+                ><i class="el-icon-plus"></i>{{ item.name }}</el-button
+              >
+            </div>
+          </div>
+          <p class="tips-info">提示:点击创建试题</p>
+        </div>
+      </div>
+      <div class="action-part">
+        <div class="action-part-title"><h2>插入元素</h2></div>
+        <div class="action-part-body">
+          <div class="type-list">
+            <div
+              class="type-item"
+              v-for="(item, index) in ELEMENT_LIST"
+              :key="index"
+              draggable="true"
+              @dragstart="dragstart(item)"
+            >
+              <el-button><i class="el-icon-plus"></i>{{ item.name }}</el-button>
+            </div>
+            <p class="tips-info">提示:拖动插入元素</p>
+          </div>
+          <!-- Develop btns -->
+          <!-- <card-config-prop-edit></card-config-prop-edit> -->
+        </div>
+        <!-- <br /><br /> -->
+        <!-- <el-button @click="initCard">新建页面</el-button> -->
+      </div>
+      <!-- <div class="action-part">
+          <div class="action-part-title"><h2>阅卷参数</h2></div>
+          <div class="action-part-body">
+            <el-button type="primary" @click="modifyParams"
+              >上传阅卷参数<span class="color-danger"
+                >({{ paperParams["pageSumScore"] || 0 }}分)</span
+              ></el-button
+            >
+          </div>
+        </div> -->
+    </div>
+
+    <div class="design-main">
+      <!-- menus -->
+      <div class="design-control">
+        <div class="control-left tab-btns">
+          <el-button
+            v-for="(page, pageNo) in pages"
+            :key="pageNo"
+            :type="curPageNo === pageNo ? 'primary' : 'default'"
+            @click="swithPage(pageNo)"
+            >第{{ pageNo + 1 }}页</el-button
+          >
+        </div>
+        <div class="control-right">
+          <el-button
+            type="success"
+            :loading="isSubmit"
+            :disabled="!pages.length"
+            @click="toPreview"
+            >预览</el-button
+          >
+          <!-- <el-button
+            v-if="showSaveBtn"
+            type="primary"
+            :loading="isSubmit"
+            :disabled="canSave || !pages.length"
+            @click="toSave"
+            >暂存</el-button
+          > -->
+          <el-button type="primary" :loading="isSubmit" @click="toSubmit"
+            >提交</el-button
+          >
+        </div>
+      </div>
+
+      <!-- edit body -->
+      <div class="design-body">
+        <!-- 注意:后台要替换内容,改类名时,要注意 -->
+        <div
+          :class="[
+            'page-box',
+            `page-box-${cardConfig.pageSize}`,
+            `page-box-${curPageNo % 2}`,
+            { 'page-box-less': pages.length <= 2 },
+          ]"
+          v-if="curPage.locators"
+        >
+          <!-- locator -->
+          <div class="page-locator page-locator-top">
+            <div
+              v-for="elem in curPage.locators.top"
+              :key="elem.id"
+              :id="elem.id"
+              class="page-locator-item"
+            ></div>
+          </div>
+          <div class="page-locator page-locator-bottom">
+            <div
+              v-for="elem in curPage.locators.bottom"
+              :key="elem.id"
+              :id="elem.id"
+              class="page-locator-item"
+            ></div>
+          </div>
+          <!-- inner edit area -->
+          <div class="page-main-inner">
+            <div
+              :class="['page-main', `page-main-${curPage.columns.length}`]"
+              :style="{ margin: `0 -${curPage.columnGap / 2}px` }"
+            >
+              <div
+                class="page-column"
+                v-for="(column, columnNo) in curPage.columns"
+                :key="columnNo"
+                :style="{ padding: `0 ${curPage.columnGap / 2}px` }"
+              >
+                <div
+                  class="page-column-main"
+                  :id="[`column-${curPageNo}-${columnNo}`]"
+                >
+                  <div class="page-column-body" v-if="column.elements.length">
+                    <topic-element-edit
+                      class="page-column-element"
+                      :data-h="element.h"
+                      v-for="element in column.elements"
+                      :key="element.id"
+                      :data="element"
+                    ></topic-element-edit>
+                  </div>
+                  <div class="page-column-body" v-else>
+                    <div
+                      class="page-column-forbid-area"
+                      v-if="cardConfig.showForbidArea"
+                    >
+                      <p>该区域严禁作答</p>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+          <!-- outer edit area -->
+          <div class="page-main-outer">
+            <page-number
+              type="rect"
+              :total="pages.length"
+              :current="curPageNo + 1"
+            ></page-number>
+            <page-number
+              type="text"
+              :total="pages.length"
+              :current="curPageNo + 1"
+            ></page-number>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- all topics -->
+    <div class="topic-list">
+      <div :class="['page-box', `page-box-${cardConfig.pageSize}`]">
+        <div class="page-main-inner">
+          <div
+            :class="['page-main', `page-main-${cardConfig.columnNumber}`]"
+            :style="{ margin: `0 -${cardConfig.columnGap / 2}px` }"
+          >
+            <div
+              class="page-column"
+              :style="{ padding: `0 ${cardConfig.columnGap / 2}px` }"
+            >
+              <div class="page-column-main" id="topic-column">
+                <div class="page-column-body">
+                  <!-- card-head-sample -->
+                  <card-head-sample
+                    :data="cardHeadSampleData"
+                    id="simple-card-head"
+                    v-if="topics.length && cardHeadSampleData"
+                  ></card-head-sample>
+                  <!-- topic element -->
+                  <topic-element-preview
+                    class="page-column-element"
+                    v-for="element in topics"
+                    :key="element.id"
+                    :data="element"
+                  ></topic-element-preview>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- element-prop-edit -->
+    <element-prop-edit ref="ElementPropEdit"></element-prop-edit>
+    <!-- right-click-menu -->
+    <right-click-menu @inset-topic="insetNewTopic"></right-click-menu>
+    <!-- paper-params -->
+    <paper-params
+      :pages="pages"
+      :paper-params="paperParams"
+      @confirm="paperParamsModified"
+      ref="PaperParams"
+    ></paper-params>
+    <!-- topic select dialog -->
+    <topic-select-dialog
+      ref="TopicSelectDialog"
+      :topics="topicList"
+      @confirm="addNewTopic"
+    ></topic-select-dialog>
+  </div>
+</template>
+
+<script>
+import { mapState, mapMutations, mapActions } from "vuex";
+import {
+  getElementModel,
+  getCardHeadModel,
+  ELEMENT_LIST,
+  TOPIC_LIST,
+} from "../elementModel";
+import { CARD_VERSION } from "../enumerate";
+// import CardConfigPropEdit from "../components/CardConfigPropEdit";
+import TopicElementEdit from "../components/TopicElementEdit";
+import TopicElementPreview from "../components/TopicElementPreview";
+import PagePropEdit from "../components/PagePropEdit";
+import ElementPropEdit from "../components/ElementPropEdit";
+import RightClickMenu from "../components/RightClickMenu";
+import PageNumber from "../components/PageNumber";
+import PaperParams from "../components/PaperParams";
+import CardHeadSample from "../elements/card-head/CardHead";
+import TopicSelectDialog from "../components/TopicSelectDialog";
+
+export default {
+  name: "card-design",
+  props: {
+    content: {
+      type: Object,
+      default() {
+        return {
+          pages: [],
+          cardConfig: {},
+          paperParams: {},
+        };
+      },
+    },
+    showSaveBtn: {
+      type: Boolean,
+      default: true,
+    },
+  },
+  components: {
+    // CardConfigPropEdit,
+    TopicElementEdit,
+    TopicElementPreview,
+    PagePropEdit,
+    ElementPropEdit,
+    RightClickMenu,
+    CardHeadSample,
+    PageNumber,
+    PaperParams,
+    TopicSelectDialog,
+  },
+  data() {
+    return {
+      ELEMENT_LIST,
+      TOPIC_LIST,
+      topicList: [],
+      steps: ["添加标题", "基本设置", "试题配置", "预览生成"],
+      columnWidth: 0,
+      isSubmit: false,
+      canSave: false,
+    };
+  },
+  computed: {
+    ...mapState("card", [
+      "cardConfig",
+      "topics",
+      "pages",
+      "paperParams",
+      "curElement",
+      "curPage",
+      "curPageNo",
+    ]),
+    cardHeadSampleData() {
+      if (!this.cardConfig["pageSize"]) return;
+      const data = getCardHeadModel(this.cardConfig);
+      data.isSimple = true;
+      return data;
+    },
+  },
+  mounted() {
+    this.initCard();
+  },
+  methods: {
+    ...mapMutations("card", [
+      "addPage",
+      "setCurPage",
+      "setCurElement",
+      "setCardConfig",
+      "setOpenElementEditDialog",
+      "setCurDragElement",
+      "setPages",
+      "setPaperParams",
+      "setInsetTarget",
+      "initState",
+    ]),
+    ...mapActions("card", [
+      "resetTopicSeries",
+      "removePage",
+      "addElement",
+      "modifyCardHead",
+      "modifyElement",
+      "rebuildPages",
+      "initTopicsFromPages",
+    ]),
+    async initCard() {
+      const { cardConfig, pages, paperParams } = this.content;
+      this.setCardConfig(cardConfig);
+      this.setPaperParams(paperParams);
+
+      if (pages && pages.length) {
+        this.setPages(pages);
+        this.initTopicsFromPages();
+        this.resetTopicSeries();
+        this.setCurPage(0);
+      } else {
+        this.initPageData();
+      }
+      this.addWatch();
+    },
+    initPageData() {
+      this.modifyCardHead({
+        ...getCardHeadModel(this.cardConfig),
+      });
+      this.$nextTick(() => {
+        this.rebuildPages();
+        this.setCurPage(0);
+      });
+    },
+    addNewTopic(item) {
+      let element = getElementModel(item.type);
+      element.w = document.getElementById("topic-column").offsetWidth;
+
+      this.setCurElement(element);
+      this.$refs.ElementPropEdit.open();
+      // to elementPropEdit/ElementPropEdit open topic edit dialog
+    },
+    insetNewTopic({ id, type }) {
+      console.log(id, type);
+      this.setInsetTarget({ id, type });
+      if (type === "FILL_QUESTION") {
+        this.topicList = this.TOPIC_LIST;
+      } else {
+        this.topicList = this.TOPIC_LIST.filter(
+          (item) => item.type !== "FILL_QUESTION"
+        );
+      }
+      this.$refs.TopicSelectDialog.open();
+    },
+    // 元件编辑
+    dragstart(element) {
+      this.setCurDragElement(getElementModel(element.type));
+    },
+    addWatch() {
+      this.$watch("cardConfig", (val) => {
+        const element = getCardHeadModel(val);
+        this.modifyCardHead(element);
+        this.$nextTick(() => {
+          this.rebuildPages();
+        });
+      });
+    },
+    swithPage(pindex) {
+      if (this.curPageNo === pindex) return;
+      this.setCurPage(pindex);
+      this.setCurElement({});
+    },
+    // paper-params
+    modifyParams() {
+      this.$refs.PaperParams.open();
+    },
+    paperParamsModified(paperParams) {
+      this.setPaperParams(paperParams);
+    },
+    // save
+    getCardData(htmlContent = "", model = "") {
+      const data = {
+        title: this.cardConfig.cardTitle,
+        content: model,
+        htmlContent,
+      };
+      return data;
+    },
+    checkElementCovered() {
+      let elements = [];
+      this.pages.forEach((page) => {
+        page.columns.forEach((column) => {
+          column.elements.forEach((element) => {
+            if (element.isCovered) {
+              elements.push(element.id);
+            }
+          });
+        });
+      });
+      return elements.length;
+    },
+    checkCardValid() {
+      if (!this.cardConfig.cardTitle) {
+        this.$message.error("题卡标题不能为空!");
+        this.setCurPageNo(0);
+        setTimeout(() => {
+          document.getElementById("cardTitleInput").focus();
+        });
+        return false;
+      }
+      // if (!this.cardConfig.cardDesc) {
+      //   this.$message.error("题卡描述信息不能为空!");
+      //   this.setCurPage(0);
+      //   setTimeout(() => {
+      //     document.getElementById("cardDescInput").focus();
+      //   });
+      //   return false;
+      // }
+      if (this.checkElementCovered()) {
+        this.$message.error("题卡中存在被遮挡的元件,请注意调整!");
+        return false;
+      }
+
+      return true;
+    },
+    getCardJson() {
+      // 防止页面未渲染完成,各试题高度未及时更新,保存数据有误的问题
+      return new Promise((resolve) => {
+        setTimeout(() => {
+          const data = JSON.stringify(
+            {
+              version: CARD_VERSION,
+              cardType: "STANDARD",
+              cardConfig: this.cardConfig,
+              paperParams: this.paperParams,
+              pages: this.pages,
+            },
+            (k, v) => (k.startsWith("_") ? undefined : v)
+          );
+          resolve(data);
+        }, 100);
+      });
+    },
+    async toPreview() {
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      const model = await this.getCardJson();
+      const datas = this.getCardData("", model);
+      this.$emit("on-preview", datas);
+    },
+    async toSave() {
+      if (!this.checkCardValid()) return;
+
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      const model = await this.getCardJson();
+      const datas = this.getCardData("", model);
+      this.$emit("on-save", datas);
+    },
+    toSubmit() {
+      if (this.isSubmit) return;
+      if (!this.checkCardValid()) return;
+
+      this.$emit("on-submit", {
+        cardConfig: this.cardConfig,
+        pages: this.pages,
+        paperParams: this.paperParams,
+      });
+    },
+    toExit() {
+      this.$emit("on-exit");
+    },
+    loading() {
+      this.isSubmit = true;
+    },
+    unloading() {
+      this.isSubmit = false;
+    },
+  },
+  beforeDestroy() {
+    this.initState();
+  },
+};
+</script>

+ 114 - 114
card/components/CardView.vue

@@ -1,114 +1,114 @@
-<template>
-  <div class="card-view">
-    <template v-for="(page, pageNo) in pages">
-      <div
-        :class="[
-          'page-box',
-          `page-box-${cardConfig.pageSize}`,
-          `page-box-${pageNo % 2}`,
-          { 'page-box-less': pages.length <= 2 }
-        ]"
-        :key="pageNo"
-      >
-        <!-- locator -->
-        <div class="page-locator page-locator-top">
-          <div
-            v-for="elem in page.locators.top"
-            :key="elem.id"
-            :id="elem.id"
-            class="page-locator-item"
-          ></div>
-        </div>
-        <div class="page-locator page-locator-bottom">
-          <div
-            v-for="elem in page.locators.bottom"
-            :key="elem.id"
-            :id="elem.id"
-            class="page-locator-item"
-          ></div>
-        </div>
-        <!-- inner edit area -->
-        <div class="page-main-inner">
-          <div
-            :class="['page-main', `page-main-${page.columns.length}`]"
-            :style="{ margin: `0 -${page.columnGap / 2}px` }"
-          >
-            <div
-              class="page-column"
-              v-for="(column, columnNo) in page.columns"
-              :key="columnNo"
-              :style="{ padding: `0 ${page.columnGap / 2}px` }"
-            >
-              <div
-                class="page-column-main"
-                :id="[`column-${pageNo}-${columnNo}`]"
-              >
-                <div class="page-column-body" v-if="column.elements.length">
-                  <topic-element-preview
-                    class="page-column-element"
-                    v-for="element in column.elements"
-                    :key="element.id"
-                    :data="element"
-                  ></topic-element-preview>
-                </div>
-                <div class="page-column-body" v-else>
-                  <div
-                    class="page-column-forbid-area"
-                    v-if="cardConfig.showForbidArea"
-                  >
-                    <p>该区域严禁作答</p>
-                  </div>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-        <!-- outer edit area -->
-        <div class="page-main-outer">
-          <page-number
-            type="rect"
-            :total="pages.length"
-            :current="pageNo + 1"
-          ></page-number>
-          <page-number
-            type="text"
-            :total="pages.length"
-            :current="pageNo + 1"
-          ></page-number>
-        </div>
-      </div>
-    </template>
-  </div>
-</template>
-
-<script>
-import TopicElementPreview from "./TopicElementPreview";
-import PageNumber from "./PageNumber";
-import previewTemp from "../previewTemp";
-import exchangeMixins from "../mixins/exchange";
-
-export default {
-  name: "card-view",
-  components: { TopicElementPreview, PageNumber },
-  mixins: [exchangeMixins],
-  props: {
-    pages: {
-      type: Array,
-      default() {
-        return [];
-      }
-    },
-    cardConfig: {
-      type: Object,
-      default() {
-        return {};
-      }
-    }
-  },
-  methods: {
-    getPreviewTemp(htmlContent) {
-      return previewTemp(htmlContent);
-    }
-  }
-};
-</script>
+<template>
+  <div class="card-view">
+    <template v-for="(page, pageNo) in pages">
+      <div
+        :class="[
+          'page-box',
+          `page-box-${cardConfig.pageSize}`,
+          `page-box-${pageNo % 2}`,
+          { 'page-box-less': pages.length <= 2 },
+        ]"
+        :key="pageNo"
+      >
+        <!-- locator -->
+        <div class="page-locator page-locator-top">
+          <div
+            v-for="elem in page.locators.top"
+            :key="elem.id"
+            :id="elem.id"
+            class="page-locator-item"
+          ></div>
+        </div>
+        <div class="page-locator page-locator-bottom">
+          <div
+            v-for="elem in page.locators.bottom"
+            :key="elem.id"
+            :id="elem.id"
+            class="page-locator-item"
+          ></div>
+        </div>
+        <!-- inner edit area -->
+        <div class="page-main-inner">
+          <div
+            :class="['page-main', `page-main-${page.columns.length}`]"
+            :style="{ margin: `0 -${page.columnGap / 2}px` }"
+          >
+            <div
+              class="page-column"
+              v-for="(column, columnNo) in page.columns"
+              :key="columnNo"
+              :style="{ padding: `0 ${page.columnGap / 2}px` }"
+            >
+              <div
+                class="page-column-main"
+                :id="[`column-${pageNo}-${columnNo}`]"
+              >
+                <div class="page-column-body" v-if="column.elements.length">
+                  <topic-element-preview
+                    class="page-column-element"
+                    v-for="element in column.elements"
+                    :key="element.id"
+                    :data="element"
+                  ></topic-element-preview>
+                </div>
+                <div class="page-column-body" v-else>
+                  <div
+                    class="page-column-forbid-area"
+                    v-if="cardConfig.showForbidArea"
+                  >
+                    <p>该区域严禁作答</p>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+        <!-- outer edit area -->
+        <div class="page-main-outer">
+          <page-number
+            type="rect"
+            :total="pages.length"
+            :current="pageNo + 1"
+          ></page-number>
+          <page-number
+            type="text"
+            :total="pages.length"
+            :current="pageNo + 1"
+          ></page-number>
+        </div>
+      </div>
+    </template>
+  </div>
+</template>
+
+<script>
+import TopicElementPreview from "./TopicElementPreview";
+import PageNumber from "./PageNumber";
+import previewTemp from "../previewTemp";
+import exchangeMixins from "../mixins/exchange";
+
+export default {
+  name: "card-view",
+  components: { TopicElementPreview, PageNumber },
+  mixins: [exchangeMixins],
+  props: {
+    pages: {
+      type: Array,
+      default() {
+        return [];
+      },
+    },
+    cardConfig: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+  },
+  methods: {
+    getPreviewTemp(htmlContent) {
+      return previewTemp(htmlContent);
+    },
+  },
+};
+</script>

+ 9 - 9
card/components/ElementPropEdit.vue

@@ -52,7 +52,7 @@ export default {
     EditImage,
     EditLine,
     EditLines,
-    EditGrids
+    EditGrids,
   },
   data() {
     return { loading: false };
@@ -69,7 +69,7 @@ export default {
       let type = this.curElement.type.toLowerCase().replace("_", "-");
       if (type.indexOf("line-") === 0) type = "line";
       return `edit-${type}`;
-    }
+    },
   },
   methods: {
     ...mapMutations("card", ["setOpenElementEditDialog"]),
@@ -77,7 +77,7 @@ export default {
       "addElement",
       "modifyElement",
       "modifyElementChild",
-      "rebuildPages"
+      "rebuildPages",
     ]),
     cancel() {
       this.setOpenElementEditDialog(false);
@@ -97,7 +97,7 @@ export default {
       if (element.type === "COMPOSITION") return true;
 
       const relateTopics = this.topics.filter(
-        item =>
+        (item) =>
           item.topicNo === element.topicNo &&
           item.parent &&
           item.parent.id !== element.id
@@ -106,14 +106,14 @@ export default {
 
       let er = [
         element.startNumber,
-        element.startNumber + element.questionsCount - 1
+        element.startNumber + element.questionsCount - 1,
       ];
 
-      const unvalid = relateTopics.some(item => {
+      const unvalid = relateTopics.some((item) => {
         const topic = item.type === "EXPLAIN" ? item.parent : item;
         const tr = [
           topic.startNumber,
-          topic.startNumber + topic.questionsCount - 1
+          topic.startNumber + topic.questionsCount - 1,
         ];
         return (
           (er[0] <= tr[0] && er[1] >= tr[0]) ||
@@ -145,7 +145,7 @@ export default {
       this.$nextTick(() => {
         this.rebuildPages();
       });
-    }
-  }
+    },
+  },
 };
 </script>

+ 6 - 6
card/components/PageNumber.vue

@@ -22,21 +22,21 @@ export default {
       default: "text",
       validator(val) {
         return ["text", "rect"].indexOf(val) !== -1;
-      }
+      },
     },
     total: {
       type: Number,
-      default: 1
+      default: 1,
     },
     current: {
       type: Number,
-      default: 1
-    }
+      default: 1,
+    },
   },
   computed: {
     classes() {
       return ["page-number", `page-number-${this.type}`];
-    }
-  }
+    },
+  },
 };
 </script>

+ 207 - 207
card/components/PagePropEdit.vue

@@ -1,207 +1,207 @@
-<template>
-  <div class="page-prop-edit">
-    <el-form ref="form" :model="form" label-width="70px">
-      <el-form-item label="纸张规格">
-        <el-select
-          v-model="form.pageSize"
-          placeholder="请选择"
-          :disabled="pageSizeOptions.length < 2"
-          @change="modifyPageSize"
-        >
-          <el-option
-            v-for="item in pageSizeOptions"
-            :key="item"
-            :label="item"
-            :value="item"
-          >
-          </el-option>
-        </el-select>
-      </el-form-item>
-      <el-form-item label="栏位布局">
-        <el-button
-          v-for="(item, index) in columnOptions"
-          :key="index"
-          class="column-btn"
-          :title="item.title"
-          :disabled="item.disabled"
-          @click="modifyColumnNum(item)"
-        >
-          <i
-            :class="[
-              'icon',
-              form.columnNumber == item.value
-                ? `icon-column-${item.label}-act`
-                : `icon-column-${item.label}`
-            ]"
-          ></i>
-        </el-button>
-      </el-form-item>
-      <!-- <el-form-item label-width="0px">
-        <el-checkbox v-model="form.aOrB" disabled>启用A/B卷</el-checkbox>
-      </el-form-item> -->
-      <el-form-item label="禁答区域">
-        <el-checkbox
-          v-model="form.showForbidArea"
-          @change="showForbidAreaChange"
-          >启用</el-checkbox
-        >
-      </el-form-item>
-      <el-form-item label="大题顺序">
-        <ul class="topicno-list" v-if="topicNoSeries.length">
-          <li v-for="item in topicNoSeries" :key="item.id">
-            {{ item.topicNo }}
-          </li>
-        </ul>
-        <el-button type="text" class="btn-primary" @click="toViewStruct"
-          >查看题卡结构<i class="el-icon-arrow-right"></i
-        ></el-button>
-      </el-form-item>
-    </el-form>
-
-    <!-- PageStructDialog -->
-    <page-struct-dialog ref="PageStructDialog"></page-struct-dialog>
-  </div>
-</template>
-
-<script>
-import { mapState, mapMutations, mapActions } from "vuex";
-import { objAssign } from "../plugins/utils";
-import PageStructDialog from "./PageStructDialog.vue";
-
-const COLUMN_OPTIONS = [
-  {
-    value: 1,
-    title: "一栏",
-    label: "one",
-    sizeValid: ["A4"],
-    disabled: false
-  },
-  {
-    value: 2,
-    title: "二栏",
-    label: "two",
-    sizeValid: ["A3", "A4"],
-    disabled: false
-  },
-  {
-    value: 3,
-    title: "三栏",
-    label: "three",
-    sizeValid: ["A3"],
-    disabled: false
-  },
-  {
-    value: 4,
-    title: "四栏",
-    label: "four",
-    sizeValid: ["A3"],
-    disabled: false
-  }
-];
-
-export default {
-  name: "page-prop-edit",
-  components: { PageStructDialog },
-  data() {
-    return {
-      columnOptions: [],
-      pageSizeOptions: ["A3"],
-      // pageSizeOptions: ["A3", "A4"],
-      form: {
-        pageSize: "A3",
-        columnNumber: 2,
-        columnGap: 4,
-        aOrB: false,
-        showForbidArea: false
-      },
-      prePageSize: "A3"
-    };
-  },
-  computed: {
-    ...mapState("card", ["curPageNo", "pages", "cardConfig", "topicNoSeries"]),
-    curPage() {
-      return this.pages[this.curPageNo];
-    }
-    // aOrBDisabled() {
-    //   return this.cardConfig.hasOwnProperty("aOrBSystem");
-    // }
-  },
-  watch: {
-    cardConfig: {
-      immediate: true,
-      handler(val) {
-        this.form = objAssign(this.form, val);
-        this.prePageSize = this.form.pageSize;
-        this.columnOptions = COLUMN_OPTIONS.filter(item =>
-          item.sizeValid.includes(this.form.pageSize)
-        );
-        if (this.form.pageSize === "A3") {
-          this.columnOptions[2].disabled = val.examNumberStyle === "fill";
-        }
-      }
-    }
-  },
-  methods: {
-    ...mapMutations("card", [
-      "setPages",
-      "setTopics",
-      "setCurElement",
-      "setCardConfig",
-      "setTopicSeries"
-    ]),
-    ...mapActions("card", ["rebuildPages", "resetElementProp"]),
-    modifyColumnNum(item) {
-      this.$confirm(
-        "此操作会导致当前题卡编辑的所有元素清空, 是否继续?",
-        "提示",
-        {
-          type: "warning"
-        }
-      )
-        .then(() => {
-          this.columnNumChange(item.value);
-        })
-        .catch(() => {});
-    },
-    columnNumChange(val) {
-      this.form.columnNumber = val;
-      this.setCardConfig(this.form);
-      this.setPages([]);
-      this.setTopics([]);
-      this.setTopicSeries([]);
-      this.$emit("init-page");
-    },
-    showForbidAreaChange() {
-      this.setCardConfig(this.form);
-    },
-    configChange() {
-      this.setCardConfig(this.form);
-      this.$nextTick(() => {
-        this.rebuildPages();
-        this.setCurElement({});
-        this.$nextTick(() => {
-          this.resetElementProp(true);
-        });
-      });
-    },
-    modifyPageSize() {
-      this.$confirm("此操作将会重置当前页面所有元素信息, 是否继续?", "提示", {
-        type: "warning"
-      })
-        .then(() => {
-          this.columnOptions = COLUMN_OPTIONS.filter(item =>
-            item.sizeValid.includes(this.form.pageSize)
-          );
-          this.form.columnNumber = this.columnOptions[0].value;
-          this.configChange();
-        })
-        .catch(() => {
-          this.form.pageSize = this.prePageSize;
-        });
-    },
-    toViewStruct() {
-      this.$refs.PageStructDialog.open();
-    }
-  }
-};
-</script>
+<template>
+  <div class="page-prop-edit">
+    <el-form ref="form" :model="form" label-width="70px">
+      <el-form-item label="纸张规格">
+        <el-select
+          v-model="form.pageSize"
+          placeholder="请选择"
+          :disabled="pageSizeOptions.length < 2"
+          @change="modifyPageSize"
+        >
+          <el-option
+            v-for="item in pageSizeOptions"
+            :key="item"
+            :label="item"
+            :value="item"
+          >
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="栏位布局">
+        <el-button
+          v-for="(item, index) in columnOptions"
+          :key="index"
+          class="column-btn"
+          :title="item.title"
+          :disabled="item.disabled"
+          @click="modifyColumnNum(item)"
+        >
+          <i
+            :class="[
+              'icon',
+              form.columnNumber == item.value
+                ? `icon-column-${item.label}-act`
+                : `icon-column-${item.label}`,
+            ]"
+          ></i>
+        </el-button>
+      </el-form-item>
+      <!-- <el-form-item label-width="0px">
+        <el-checkbox v-model="form.aOrB" disabled>启用A/B卷</el-checkbox>
+      </el-form-item> -->
+      <el-form-item label="禁答区域">
+        <el-checkbox
+          v-model="form.showForbidArea"
+          @change="showForbidAreaChange"
+          >启用</el-checkbox
+        >
+      </el-form-item>
+      <el-form-item label="大题顺序">
+        <ul class="topicno-list" v-if="topicNoSeries.length">
+          <li v-for="item in topicNoSeries" :key="item.id">
+            {{ item.topicNo }}
+          </li>
+        </ul>
+        <el-button type="text" class="btn-primary" @click="toViewStruct"
+          >查看题卡结构<i class="el-icon-arrow-right"></i
+        ></el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- PageStructDialog -->
+    <page-struct-dialog ref="PageStructDialog"></page-struct-dialog>
+  </div>
+</template>
+
+<script>
+import { mapState, mapMutations, mapActions } from "vuex";
+import { objAssign } from "../plugins/utils";
+import PageStructDialog from "./PageStructDialog.vue";
+
+const COLUMN_OPTIONS = [
+  {
+    value: 1,
+    title: "一栏",
+    label: "one",
+    sizeValid: ["A4"],
+    disabled: false,
+  },
+  {
+    value: 2,
+    title: "二栏",
+    label: "two",
+    sizeValid: ["A3", "A4"],
+    disabled: false,
+  },
+  {
+    value: 3,
+    title: "三栏",
+    label: "three",
+    sizeValid: ["A3"],
+    disabled: false,
+  },
+  {
+    value: 4,
+    title: "四栏",
+    label: "four",
+    sizeValid: ["A3"],
+    disabled: false,
+  },
+];
+
+export default {
+  name: "page-prop-edit",
+  components: { PageStructDialog },
+  data() {
+    return {
+      columnOptions: [],
+      pageSizeOptions: ["A3"],
+      // pageSizeOptions: ["A3", "A4"],
+      form: {
+        pageSize: "A3",
+        columnNumber: 2,
+        columnGap: 4,
+        aOrB: false,
+        showForbidArea: false,
+      },
+      prePageSize: "A3",
+    };
+  },
+  computed: {
+    ...mapState("card", ["curPageNo", "pages", "cardConfig", "topicNoSeries"]),
+    curPage() {
+      return this.pages[this.curPageNo];
+    },
+    // aOrBDisabled() {
+    //   return this.cardConfig.hasOwnProperty("aOrBSystem");
+    // }
+  },
+  watch: {
+    cardConfig: {
+      immediate: true,
+      handler(val) {
+        this.form = objAssign(this.form, val);
+        this.prePageSize = this.form.pageSize;
+        this.columnOptions = COLUMN_OPTIONS.filter((item) =>
+          item.sizeValid.includes(this.form.pageSize)
+        );
+        if (this.form.pageSize === "A3") {
+          this.columnOptions[2].disabled = val.examNumberStyle === "fill";
+        }
+      },
+    },
+  },
+  methods: {
+    ...mapMutations("card", [
+      "setPages",
+      "setTopics",
+      "setCurElement",
+      "setCardConfig",
+      "setTopicSeries",
+    ]),
+    ...mapActions("card", ["rebuildPages", "resetElementProp"]),
+    modifyColumnNum(item) {
+      this.$confirm(
+        "此操作会导致当前题卡编辑的所有元素清空, 是否继续?",
+        "提示",
+        {
+          type: "warning",
+        }
+      )
+        .then(() => {
+          this.columnNumChange(item.value);
+        })
+        .catch(() => {});
+    },
+    columnNumChange(val) {
+      this.form.columnNumber = val;
+      this.setCardConfig(this.form);
+      this.setPages([]);
+      this.setTopics([]);
+      this.setTopicSeries([]);
+      this.$emit("init-page");
+    },
+    showForbidAreaChange() {
+      this.setCardConfig(this.form);
+    },
+    configChange() {
+      this.setCardConfig(this.form);
+      this.$nextTick(() => {
+        this.rebuildPages();
+        this.setCurElement({});
+        this.$nextTick(() => {
+          this.resetElementProp(true);
+        });
+      });
+    },
+    modifyPageSize() {
+      this.$confirm("此操作将会重置当前页面所有元素信息, 是否继续?", "提示", {
+        type: "warning",
+      })
+        .then(() => {
+          this.columnOptions = COLUMN_OPTIONS.filter((item) =>
+            item.sizeValid.includes(this.form.pageSize)
+          );
+          this.form.columnNumber = this.columnOptions[0].value;
+          this.configChange();
+        })
+        .catch(() => {
+          this.form.pageSize = this.prePageSize;
+        });
+    },
+    toViewStruct() {
+      this.$refs.PageStructDialog.open();
+    },
+  },
+};
+</script>

+ 6 - 6
card/components/PageStructDialog.vue

@@ -34,17 +34,17 @@ export default {
   data() {
     return {
       modalIsShow: false,
-      structData: []
+      structData: [],
     };
   },
   computed: {
-    ...mapState("card", ["topics"])
+    ...mapState("card", ["topics"]),
   },
   methods: {
     visibleChange() {
       let structData = [];
       let curTopicId = 0;
-      this.topics.forEach(topic => {
+      this.topics.forEach((topic) => {
         if (!topic.parent) return;
 
         if (curTopicId !== topic.parent.id) {
@@ -58,7 +58,7 @@ export default {
           let data = {
             topicNo: topic.parent.topicNo,
             topicName: topic.parent.topicName,
-            questionsCount
+            questionsCount,
           };
           structData.push(data);
         }
@@ -71,7 +71,7 @@ export default {
     },
     open() {
       this.modalIsShow = true;
-    }
-  }
+    },
+  },
 };
 </script>

+ 33 - 36
card/components/PaperParams.vue

@@ -29,7 +29,7 @@
         >
       </div>
       <div class="params-body">
-        <div style="text-align:right;">
+        <div style="text-align: right">
           <upload-button
             btn-icon="el-icon-upload"
             btn-content="选择上传主观题标答文件(doc/docx)"
@@ -38,7 +38,7 @@
             :format="['doc', 'docx']"
             @valid-error="validError"
             @upload-success="uploadSuccess"
-            style="margin: 0;"
+            style="margin: 0"
             v-if="topicType"
           >
           </upload-button>
@@ -111,7 +111,7 @@
         </div>
       </div>
     </div>
-    <div slot="footer" style="text-align: right;">
+    <div slot="footer" style="text-align: right">
       <el-button type="primary" @click="submit">确认</el-button>
       <el-button type="danger" @click="cancel" plain>取消</el-button>
     </div>
@@ -130,14 +130,14 @@ export default {
       type: Array,
       default() {
         return [];
-      }
+      },
     },
     paperParams: {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     return {
@@ -153,10 +153,10 @@ export default {
         id: "",
         topicNo: "",
         topicName: "",
-        type: ""
+        type: "",
       },
       // import
-      uploadUrl: "/api/print/basic/sys/saveAttachment"
+      uploadUrl: "/api/print/basic/sys/saveAttachment",
     };
   },
   methods: {
@@ -165,14 +165,14 @@ export default {
       this.curTopicList = topicType ? this.subjectives : this.objectives;
     },
     listIncludeItem(list, item) {
-      const index = list.findIndex(elem => elem.id === item.id);
+      const index = list.findIndex((elem) => elem.id === item.id);
       return index !== -1;
     },
     dialogOpen() {
       if (!isEmptyObject(this.paperParams)) {
         this.getCacheScore([
           ...this.paperParams.objectives,
-          ...this.paperParams.subjectives
+          ...this.paperParams.subjectives,
         ]);
         this.subjectiveAttachmentId = this.paperParams.subjectiveAttachmentId;
       }
@@ -181,9 +181,9 @@ export default {
       let subjectiveList = [];
       let objectives = [];
       let subjectives = [];
-      this.pages.forEach(page => {
-        page.columns.forEach(column => {
-          column.elements.forEach(element => {
+      this.pages.forEach((page) => {
+        page.columns.forEach((column) => {
+          column.elements.forEach((element) => {
             if (
               element.sign &&
               element.type !== "TOPIC_HEAD" &&
@@ -196,7 +196,7 @@ export default {
         });
       });
       // 客观题
-      objectiveList.forEach(item => {
+      objectiveList.forEach((item) => {
         const topic = item.parent || item;
         if (this.listIncludeItem(objectives, topic)) return;
         let data = {
@@ -205,21 +205,21 @@ export default {
           name: this.getObjectiveTopicName(topic),
           choiceList: this.getChoiceList(topic),
           questions: this.getQuestions(topic),
-          ...objAssign(this.initTopic, topic)
+          ...objAssign(this.initTopic, topic),
         };
         data.sumScore = this.getTopicSumScore(data);
         objectives.push(data);
       });
 
       // 主观题
-      subjectiveList.forEach(item => {
+      subjectiveList.forEach((item) => {
         const topic = item.parent || item;
         if (this.listIncludeItem(subjectives, topic)) return;
         let data = {
           sumScore: 0,
           commonQuestionScore: 1,
           name: this.getSubjectiveTopicName(topic),
-          ...objAssign(this.initTopic, topic)
+          ...objAssign(this.initTopic, topic),
         };
         if (topic.type === "COMPOSITION") {
           data.sumScore = this.cacheScores[topic.topicNo] || 1;
@@ -242,7 +242,7 @@ export default {
         let group = [];
         let question = {
           questionNo: j,
-          score: this.cacheScores[`${topic.topicNo}-${j}`] || 1
+          score: this.cacheScores[`${topic.topicNo}-${j}`] || 1,
         };
         if (topic.type === "FILL_QUESTION")
           question.answers = topic.isMultiply ? [] : "";
@@ -254,7 +254,7 @@ export default {
             score:
               this.cacheScores[`${topic.topicNo}-${numPerColumn + j}`] || 1,
             answers:
-              topic.type === "FILL_QUESTION" && topic.isMultiply ? [] : ""
+              topic.type === "FILL_QUESTION" && topic.isMultiply ? [] : "",
           };
         } else {
           group[1] = { questionNo: "" };
@@ -278,7 +278,7 @@ export default {
       const names = {
         EXPLAIN: "解答题",
         COMPOSITION: "作文题",
-        FILL_LINE: "填空题"
+        FILL_LINE: "填空题",
       };
       return names[data.type];
     },
@@ -286,14 +286,11 @@ export default {
       const options = data.isBoolean
         ? data.booleanType
         : "abcdefghijklmnopqrstuv";
-      return options
-        .toUpperCase()
-        .slice(0, data.optionCount)
-        .split("");
+      return options.toUpperCase().slice(0, data.optionCount).split("");
     },
     commonQuestionScoreChange(topic) {
-      topic.questions.map(group => {
-        group.map(question => {
+      topic.questions.map((group) => {
+        group.map((question) => {
           question.score = topic.commonQuestionScore;
         });
       });
@@ -304,25 +301,25 @@ export default {
       this.getPageSumScore();
     },
     getTopicSumScore(topic) {
-      const scoreList = topic.questions.map(group => {
-        return calcSum(group.map(question => question.score || 0));
+      const scoreList = topic.questions.map((group) => {
+        return calcSum(group.map((question) => question.score || 0));
       });
       return calcSum(scoreList);
     },
     getPageSumScore() {
       this.pageSumScore =
-        calcSum(this.objectives.map(item => item.sumScore)) +
-        calcSum(this.subjectives.map(item => item.sumScore));
+        calcSum(this.objectives.map((item) => item.sumScore)) +
+        calcSum(this.subjectives.map((item) => item.sumScore));
     },
     getCacheScore(topics) {
       topics = topics || [...this.objectives, ...this.subjectives];
       let cacheScores = {};
-      topics.map(topic => {
+      topics.map((topic) => {
         if (topic.type === "COMPOSITION") {
           cacheScores[`${topic.topicNo}`] = topic.sumScore;
         } else {
-          topic.questions.map(group => {
-            group.map(question => {
+          topic.questions.map((group) => {
+            group.map((question) => {
               cacheScores[`${topic.topicNo}-${question.questionNo}`] =
                 question.score;
             });
@@ -352,10 +349,10 @@ export default {
         pageSumScore: this.pageSumScore,
         objectives: this.objectives,
         subjectives: this.subjectives,
-        subjectiveAttachmentId: this.subjectiveAttachmentId
+        subjectiveAttachmentId: this.subjectiveAttachmentId,
       });
       this.modalIsShow = false;
-    }
-  }
+    },
+  },
 };
 </script>

+ 18 - 20
card/components/RightClickMenu.vue

@@ -70,8 +70,8 @@ export default {
       curCopyElement: null,
       styles: {
         position: "fixed",
-        zIndex: 3000
-      }
+        zIndex: 3000,
+      },
     };
   },
   computed: {
@@ -97,7 +97,7 @@ export default {
       if (this.IS_CONTAINER_ELEMENT) return false;
 
       const curTopicPos = this.topicSeries.findIndex(
-        item => item.id === this.curElement.parent.id
+        (item) => item.id === this.curElement.parent.id
       );
 
       return (
@@ -110,7 +110,7 @@ export default {
       if (this.IS_CONTAINER_ELEMENT) return false;
 
       const curTopicPos = this.topicSeries.findIndex(
-        item => item.id === this.curElement.parent.id
+        (item) => item.id === this.curElement.parent.id
       );
 
       return (
@@ -118,7 +118,7 @@ export default {
         this.topicSeries[curTopicPos + 1].sign ===
           this.topicSeries[curTopicPos].sign
       );
-    }
+    },
   },
   mounted() {
     this.init();
@@ -133,11 +133,11 @@ export default {
       "rebuildPages",
       "copyExplainChildren",
       "deleteExplainChildren",
-      "topicMoveUp"
+      "topicMoveUp",
     ]),
     init() {
       // 注册自定义右键事件菜单
-      document.oncontextmenu = function() {
+      document.oncontextmenu = function () {
         return false;
       };
       document.addEventListener("mouseup", this.docMouseUp);
@@ -166,7 +166,7 @@ export default {
       ) {
         if (curElement.container) {
           const pos = this.topics.findIndex(
-            item => item.id === curElement.container.id
+            (item) => item.id === curElement.container.id
           );
           curElement = this.topics[pos];
         }
@@ -180,10 +180,8 @@ export default {
 
       this.$nextTick(() => {
         const { x: clickLeft, y: clickTop } = e;
-        const {
-          offsetWidth: menuWidth,
-          offsetHeight: menuHeight
-        } = this.$refs.RightMenuBody;
+        const { offsetWidth: menuWidth, offsetHeight: menuHeight } =
+          this.$refs.RightMenuBody;
 
         const { innerWidth: wWidth, innerHeight: wHeight } = window;
 
@@ -198,7 +196,7 @@ export default {
 
         this.styles = Object.assign({}, this.styles, {
           top: menuTop + "px",
-          left: menuLeft + "px"
+          left: menuLeft + "px",
         });
       });
     },
@@ -229,7 +227,7 @@ export default {
     toDelete() {
       this.close();
       this.$confirm("确定要删除当前元素吗?", "提示", {
-        type: "warning"
+        type: "warning",
       })
         .then(() => {
           this.removeSelectElement();
@@ -267,13 +265,13 @@ export default {
       const pasteElement =
         this.curCopyElement.container.id === id
           ? Object.assign({}, this.curCopyElement, {
-              y: this.curCopyElement.y + 20
+              y: this.curCopyElement.y + 20,
             })
           : this.curCopyElement;
 
       this.pasteExplainElementChild({
         curElement: this.curElement,
-        pasteElement
+        pasteElement,
       });
       this.toRebuildPages();
     },
@@ -285,7 +283,7 @@ export default {
     toMoveDownTopic() {
       this.close();
       const curTopicPos = this.topicSeries.findIndex(
-        item => item.id === this.curElement.parent.id
+        (item) => item.id === this.curElement.parent.id
       );
       this.topicMoveUp(this.topicSeries[curTopicPos + 1].id);
       this.toRebuildPages();
@@ -294,18 +292,18 @@ export default {
       this.close();
       this.$emit("inset-topic", {
         id: this.curElement.parent.id,
-        type: this.curElement.type
+        type: this.curElement.type,
       });
     },
     toRebuildPages() {
       this.$nextTick(() => {
         this.rebuildPages();
       });
-    }
+    },
   },
   beforeDestroy() {
     document.oncontextmenu = null;
     document.removeEventListener("mouseup", this.docMouseUp);
-  }
+  },
 };
 </script>

+ 10 - 10
card/components/TopicElementEdit.vue

@@ -58,12 +58,12 @@ export default {
     EditExplain,
     EditComposition,
     ElementResize,
-    TopicNumber
+    TopicNumber,
   },
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {
@@ -72,8 +72,8 @@ export default {
         y: 0,
         w: 0,
         h: 0,
-        init: false
-      }
+        init: false,
+      },
     };
   },
   computed: {
@@ -93,10 +93,10 @@ export default {
           ? `element-item-type-last`
           : "element-item-type-pre",
         {
-          "element-item-error": this.data.isCovered
-        }
+          "element-item-error": this.data.isCovered,
+        },
       ];
-    }
+    },
   },
   created() {
     this.init();
@@ -119,7 +119,7 @@ export default {
       this.$nextTick(() => {
         this.rebuildPages();
       });
-    }
-  }
+    },
+  },
 };
 </script>

+ 9 - 7
card/components/TopicElementPreview.vue

@@ -27,12 +27,12 @@ export default {
     PreviewFillQuestion,
     PreviewFillLine,
     PreviewExplain,
-    PreviewComposition
+    PreviewComposition,
   },
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {};
@@ -50,7 +50,9 @@ export default {
         "element-item",
         "element-item-width",
         `element-item-${this.elementName}`,
-        this.data["isLast"] ? `element-item-type-last` : "element-item-type-pre"
+        this.data["isLast"]
+          ? `element-item-type-last`
+          : "element-item-type-pre",
       ];
     },
     styles() {
@@ -58,10 +60,10 @@ export default {
         left: this.data.x + "px",
         top: this.data.y + "px",
         width: this.data.w + "px",
-        height: this.data.h + "px"
+        height: this.data.h + "px",
       };
-    }
+    },
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 5 - 5
card/components/TopicSelectDialog.vue

@@ -35,13 +35,13 @@ export default {
       type: Array,
       default() {
         return [];
-      }
-    }
+      },
+    },
   },
   data() {
     return {
       modalIsShow: false,
-      curTopic: {}
+      curTopic: {},
     };
   },
   methods: {
@@ -60,7 +60,7 @@ export default {
     submit() {
       this.$emit("confirm", this.curTopic);
       this.cancel();
-    }
-  }
+    },
+  },
 };
 </script>

+ 21 - 24
card/components/UploadButton.vue

@@ -10,7 +10,7 @@
     :on-success="handleSuccess"
     :http-request="upload"
     :show-file-list="false"
-    style="display:inline-block;margin: 0 18px;"
+    style="display: inline-block; margin: 0 18px"
     ref="UploadComp"
   >
     <el-button :type="btnType" :icon="btnIcon" :loading="loading">{{
@@ -27,64 +27,61 @@ export default {
   name: "upload-button",
   props: {
     btnIcon: {
-      type: String
+      type: String,
     },
     btnType: {
       type: String,
-      default: "default"
+      default: "default",
     },
     btnContent: {
-      type: String
+      type: String,
     },
     format: {
       type: Array,
       default() {
         return ["jpg", "jpeg", "png"];
-      }
+      },
     },
     uploadUrl: {
       type: String,
-      required: true
+      required: true,
     },
     uploadData: {
       type: Object,
       default() {
         return {};
-      }
+      },
     },
     maxSize: {
       type: Number,
-      default: 20 * 1024 * 1024
+      default: 20 * 1024 * 1024,
     },
     addFilenameParam: {
       type: String,
-      default: "filename"
-    }
+      default: "filename",
+    },
   },
   data() {
     return {
       headers: {
         token: "",
-        md5: ""
+        md5: "",
       },
       res: {},
       loading: false,
-      uploadDataDict: {}
+      uploadDataDict: {},
     };
   },
   methods: {
     checkFileFormat(fileType) {
-      const _file_format = fileType
-        .split(".")
-        .pop()
-        .toLocaleLowerCase();
+      const _file_format = fileType.split(".").pop().toLocaleLowerCase();
       return this.format.length
-        ? this.format.some(item => item.toLocaleLowerCase() === _file_format)
+        ? this.format.some((item) => item.toLocaleLowerCase() === _file_format)
         : true;
     },
     async handleBeforeUpload(file) {
       this.uploadDataDict = {
-        ...this.uploadData
+        ...this.uploadData,
       };
       this.uploadDataDict[this.addFilenameParam] = file.name;
 
@@ -111,7 +108,7 @@ export default {
       this.loading = false;
       this.res = {
         success: false,
-        message: error.message
+        message: error.message,
       };
       this.$emit("upload-error", error);
     },
@@ -120,7 +117,7 @@ export default {
       if (response.code === "200") {
         this.res = {
           success: true,
-          message: "导入成功!"
+          message: "导入成功!",
         };
         this.$emit("upload-success", response);
       } else {
@@ -131,7 +128,7 @@ export default {
       const content = "只支持文件格式为" + this.format.join("/");
       this.res = {
         success: false,
-        message: content
+        message: content,
       };
       this.$emit("upload-error", this.res);
     },
@@ -140,10 +137,10 @@ export default {
         "文件大小不能超过" + Math.floor(this.maxSize / (1024 * 1024)) + "M";
       this.res = {
         success: false,
-        message: content
+        message: content,
       };
       this.$emit("upload-error", this.res);
-    }
-  }
+    },
+  },
 };
 </script>

+ 7 - 7
card/components/common/ColorSelect.vue

@@ -40,13 +40,13 @@ export default {
     predefine: Array,
     showEmpty: {
       type: Boolean,
-      default: false
-    }
+      default: false,
+    },
   },
   data() {
     return {
       optionList: [],
-      selected: ""
+      selected: "",
     };
   },
   watch: {
@@ -54,8 +54,8 @@ export default {
       immediate: true,
       handler(val) {
         this.selected = val;
-      }
-    }
+      },
+    },
   },
   created() {
     this.optionList =
@@ -68,7 +68,7 @@ export default {
       this.selected = option;
       this.$emit("input", this.selected);
       this.$emit("change", this.selected);
-    }
-  }
+    },
+  },
 };
 </script>

+ 9 - 9
card/components/common/DirectionSelect.vue

@@ -19,24 +19,24 @@
 const PREDEFINE_OPTIONS = [
   {
     value: "horizontal",
-    label: "水平"
+    label: "水平",
   },
   {
     value: "vertical",
-    label: "垂直"
-  }
+    label: "垂直",
+  },
 ];
 
 export default {
   name: "direction-select",
   props: {
     value: String,
-    predefine: Array
+    predefine: Array,
   },
   data() {
     return {
       optionList: [],
-      selected: ""
+      selected: "",
     };
   },
   watch: {
@@ -44,8 +44,8 @@ export default {
       immediate: true,
       handler(val) {
         this.selected = val;
-      }
-    }
+      },
+    },
   },
   created() {
     this.optionList =
@@ -57,7 +57,7 @@ export default {
     select() {
       this.$emit("input", this.selected);
       this.$emit("change", this.selected);
-    }
-  }
+    },
+  },
 };
 </script>

+ 39 - 39
card/components/common/ElementResize.vue

@@ -5,7 +5,7 @@
     v-move-ele.prevent.stop="{
       moveStart,
       moveElement,
-      moveStop: moveElementOver
+      moveStop: moveElementOver,
     }"
   >
     <slot></slot>
@@ -16,7 +16,7 @@
         :class="control.classes"
         v-move-ele.prevent.stop="{
           moveElement: control.movePoint,
-          moveStop: control.movePointOver
+          moveStop: control.movePointOver,
         }"
       ></div>
       <div class="control-line control-line-left"></div>
@@ -36,63 +36,63 @@ export default {
   props: {
     value: {
       type: Object,
-      required: true
+      required: true,
     },
     active: {
       type: Array,
       default() {
         return ["r", "rb", "b", "lb", "l", "lt", "t", "rt"];
-      }
+      },
     },
     move: {
       type: Boolean,
-      default: true
+      default: true,
     },
     minWidth: {
       type: Number,
       default: 30,
       validator(val) {
         return val >= 0;
-      }
+      },
     },
     maxWidth: {
       type: Number,
       default: 0,
       validator(val) {
         return val >= 0;
-      }
+      },
     },
     minHeight: {
       type: Number,
       default: 30,
       validator(val) {
         return val >= 0;
-      }
+      },
     },
     maxHeight: {
       type: Number,
       default: 0,
       validator(val) {
         return val >= 0;
-      }
+      },
     },
     fitParent: {
       type: Array,
       default() {
         return ["w", "h"];
-      }
+      },
     },
     isCompact: {
       type: Boolean,
-      default: false
+      default: false,
     },
     transformFit: {
-      type: Function
+      type: Function,
     },
     elementPk: {
       type: String,
-      default: ""
-    }
+      default: "",
+    },
   },
   data() {
     return {
@@ -100,14 +100,14 @@ export default {
         x: 0,
         y: 0,
         w: 0,
-        h: 0
+        h: 0,
       },
       offsetTopOrigin: 0,
       sizePos: {
         x: 0,
         y: 0,
         w: 0,
-        h: 0
+        h: 0,
       },
       lastSizePos: {},
       initOver: false,
@@ -115,8 +115,8 @@ export default {
       positionType: "static",
       parentNodeSize: {
         w: 0,
-        h: 0
-      }
+        h: 0,
+      },
     };
   },
   computed: {
@@ -128,7 +128,7 @@ export default {
             width: this.sizePos.w + "px",
             height: this.sizePos.h + "px",
             zIndex: this.sizePos.zindex,
-            position: this.positionType
+            position: this.positionType,
           }
         : {};
     },
@@ -138,8 +138,8 @@ export default {
         {
           "element-resize-move": this.move,
           "element-resize-init": this.initOver,
-          "element-resize-compact": this.isCompact
-        }
+          "element-resize-compact": this.isCompact,
+        },
       ];
     },
     fitParentTypeWidth() {
@@ -147,7 +147,7 @@ export default {
     },
     fitParentTypeHeight() {
       return this.fitParent.includes("h");
-    }
+    },
   },
   created() {
     this.initControlPoints();
@@ -161,19 +161,19 @@ export default {
         l: "Left",
         r: "Right",
         t: "Top",
-        b: "Bottom"
+        b: "Bottom",
       };
-      this.controlPoints = this.active.map(type => {
+      this.controlPoints = this.active.map((type) => {
         const posFullName = type
           .split("")
-          .map(item => {
+          .map((item) => {
             return posName[item];
           })
           .join("");
         return {
           classes: ["control-point", `control-point-${type}`],
           movePoint: this[`move${posFullName}Point`],
-          movePointOver: this.moveOver
+          movePointOver: this.moveOver,
         };
       });
     },
@@ -210,7 +210,7 @@ export default {
       // 不同的定位方式,计算方式有差异
       this.parentNodeSize = {
         w: this.$el.offsetParent.offsetWidth,
-        h: this.$el.offsetParent.offsetHeight
+        h: this.$el.offsetParent.offsetHeight,
       };
 
       if (this.fitParentTypeWidth) {
@@ -262,23 +262,23 @@ export default {
     getLeftSize(left) {
       return {
         w: -left + this.sizePosOrigin.w,
-        x: left + this.sizePosOrigin.x
+        x: left + this.sizePosOrigin.x,
       };
     },
     getRightSize(left) {
       return {
-        w: left + this.sizePosOrigin.w
+        w: left + this.sizePosOrigin.w,
       };
     },
     getTopSize(top) {
       return {
         h: -top + this.sizePosOrigin.h,
-        y: top + this.sizePosOrigin.y
+        y: top + this.sizePosOrigin.y,
       };
     },
     getBottomSize(top) {
       return {
-        h: top + this.sizePosOrigin.h
+        h: top + this.sizePosOrigin.h,
       };
     },
     moveLeftPoint({ left }) {
@@ -305,7 +305,7 @@ export default {
       const sp = {
         ...this.sizePos,
         ...this.getLeftSize(left),
-        ...this.getTopSize(top)
+        ...this.getTopSize(top),
       };
       this.sizePos = { ...this.fetchValidSizePos(sp, "left-top") };
       this.emitChange();
@@ -314,7 +314,7 @@ export default {
       const sp = {
         ...this.sizePos,
         ...this.getRightSize(left),
-        ...this.getTopSize(top)
+        ...this.getTopSize(top),
       };
       this.sizePos = { ...this.fetchValidSizePos(sp, "right-top") };
       this.emitChange();
@@ -323,7 +323,7 @@ export default {
       const sp = {
         ...this.sizePos,
         ...this.getLeftSize(left),
-        ...this.getBottomSize(top)
+        ...this.getBottomSize(top),
       };
       this.sizePos = { ...this.fetchValidSizePos(sp, "left-bottom") };
       this.emitChange();
@@ -332,7 +332,7 @@ export default {
       const sp = {
         ...this.sizePos,
         ...this.getRightSize(left),
-        ...this.getBottomSize(top)
+        ...this.getBottomSize(top),
       };
       this.sizePos = { ...this.fetchValidSizePos(sp, "right-bottom") };
       this.emitChange();
@@ -355,8 +355,8 @@ export default {
         ...this.sizePos,
         ...{
           x: left + this.sizePosOrigin.x,
-          y: top + this.sizePosOrigin.y
-        }
+          y: top + this.sizePosOrigin.y,
+        },
       };
       this.sizePos = { ...this.fetchValidSizePos(sp, "move") };
       this.emitChange();
@@ -368,8 +368,8 @@ export default {
     emitChange() {
       this.$emit("input", this.sizePos);
       this.$emit("change", this.sizePos);
-    }
-  }
+    },
+  },
 };
 </script>
 

+ 6 - 6
card/components/common/FontFamilySelect.vue

@@ -23,12 +23,12 @@ export default {
   name: "font-family-select",
   props: {
     value: String,
-    predefine: Array
+    predefine: Array,
   },
   data() {
     return {
       optionList: [],
-      selected: ""
+      selected: "",
     };
   },
   watch: {
@@ -36,8 +36,8 @@ export default {
       immediate: true,
       handler(val) {
         this.selected = val;
-      }
-    }
+      },
+    },
   },
   created() {
     this.optionList =
@@ -49,7 +49,7 @@ export default {
     select() {
       this.$emit("input", this.selected);
       this.$emit("change", this.selected);
-    }
-  }
+    },
+  },
 };
 </script>

+ 7 - 7
card/components/common/LineStyleSelect.vue

@@ -40,13 +40,13 @@ export default {
     predefine: Array,
     showEmpty: {
       type: Boolean,
-      default: false
-    }
+      default: false,
+    },
   },
   data() {
     return {
       optionList: [],
-      selected: ""
+      selected: "",
     };
   },
   watch: {
@@ -54,8 +54,8 @@ export default {
       immediate: true,
       handler(val) {
         this.selected = val;
-      }
-    }
+      },
+    },
   },
   created() {
     this.optionList =
@@ -68,7 +68,7 @@ export default {
       this.selected = option;
       this.$emit("input", this.selected);
       this.$emit("change", this.selected);
-    }
-  }
+    },
+  },
 };
 </script>

+ 6 - 6
card/components/common/LineWidthSelect.vue

@@ -38,12 +38,12 @@ export default {
   name: "line-width-select",
   props: {
     value: String,
-    predefine: Array
+    predefine: Array,
   },
   data() {
     return {
       optionList: [],
-      selected: ""
+      selected: "",
     };
   },
   watch: {
@@ -51,8 +51,8 @@ export default {
       immediate: true,
       handler(val) {
         this.selected = val;
-      }
-    }
+      },
+    },
   },
   created() {
     this.optionList =
@@ -65,7 +65,7 @@ export default {
       this.selected = option;
       this.$emit("input", this.selected);
       this.$emit("change", this.selected);
-    }
-  }
+    },
+  },
 };
 </script>

+ 6 - 6
card/components/common/PopoverButton.vue

@@ -27,23 +27,23 @@ export default {
   props: {
     confirmText: {
       type: String,
-      default: "你确定要删除当前记录吗?"
+      default: "你确定要删除当前记录吗?",
     },
     btnName: {
       type: String,
-      default: "删除"
-    }
+      default: "删除",
+    },
   },
   data() {
     return {
-      visible: false
+      visible: false,
     };
   },
   methods: {
     confirm() {
       this.visible = false;
       this.$emit("confirm");
-    }
-  }
+    },
+  },
 };
 </script>

+ 6 - 6
card/components/common/RotationSelect.vue

@@ -22,12 +22,12 @@ export default {
   name: "rotation-select",
   props: {
     value: Number,
-    predefine: Array
+    predefine: Array,
   },
   data() {
     return {
       optionList: [],
-      selected: ""
+      selected: "",
     };
   },
   watch: {
@@ -35,8 +35,8 @@ export default {
       immediate: true,
       handler(val) {
         this.selected = val;
-      }
-    }
+      },
+    },
   },
   created() {
     this.optionList =
@@ -48,7 +48,7 @@ export default {
     select() {
       this.$emit("input", this.selected);
       this.$emit("change", this.selected);
-    }
-  }
+    },
+  },
 };
 </script>

+ 5 - 5
card/components/common/ShortcutKeySpin.vue

@@ -11,8 +11,8 @@ export default {
   props: {
     data: {
       type: String,
-      default: ""
-    }
+      default: "",
+    },
   },
   computed: {
     ARROW_CONT() {
@@ -20,14 +20,14 @@ export default {
         ArrowUp: "el-icon-top",
         ArrowDown: "el-icon-bottom",
         ArrowLeft: "el-icon-back",
-        ArrowRight: "el-icon-right"
+        ArrowRight: "el-icon-right",
       };
       return arrowIcon[this.data];
-    }
+    },
   },
   data() {
     return {};
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 12 - 12
card/components/common/SizeSelect.vue

@@ -20,36 +20,36 @@
 const PREDEFINE_OPTIONS = [
   {
     value: "14px",
-    label: "小(5号)"
+    label: "小(5号)",
   },
   {
     value: "18.7px",
-    label: "中(4号)"
+    label: "中(4号)",
   },
   {
     value: "21.3px",
-    label: "大(3号)"
+    label: "大(3号)",
   },
   {
     value: "29.3px",
-    label: "特大(2号)"
+    label: "特大(2号)",
   },
   {
     value: "34.7px",
-    label: "超大(1号)"
-  }
+    label: "超大(1号)",
+  },
 ];
 
 export default {
   name: "size-select",
   props: {
     value: String,
-    predefine: Array
+    predefine: Array,
   },
   data() {
     return {
       optionList: [],
-      selected: ""
+      selected: "",
     };
   },
   watch: {
@@ -57,8 +57,8 @@ export default {
       immediate: true,
       handler(val) {
         this.selected = val;
-      }
-    }
+      },
+    },
   },
   created() {
     this.optionList =
@@ -70,7 +70,7 @@ export default {
     select() {
       this.$emit("input", this.selected);
       this.$emit("change", this.selected);
-    }
-  }
+    },
+  },
 };
 </script>

+ 3 - 3
card/components/common/TopicNumber.vue

@@ -9,12 +9,12 @@ export default {
   name: "topic-number",
   props: {
     data: {
-      type: [Number, String]
-    }
+      type: [Number, String],
+    },
   },
   data() {
     return {};
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 4 - 4
card/directives/move-ele.js

@@ -2,7 +2,7 @@ module.exports = {
   inserted(el, { value, modifiers }) {
     let [_x, _y] = [0, 0];
     // 只允许鼠标左键触发
-    let moveHandle = function(e) {
+    let moveHandle = function (e) {
       if (e.button !== 0) return;
       if (modifiers.prevent) {
         e.preventDefault();
@@ -17,7 +17,7 @@ module.exports = {
       value.moveElement({ left, top });
     };
 
-    let upHandle = function(e) {
+    let upHandle = function (e) {
       if (e.button !== 0) return;
       if (modifiers.prevent) {
         e.preventDefault();
@@ -30,7 +30,7 @@ module.exports = {
       document.removeEventListener("mouseup", upHandle);
     };
 
-    el.addEventListener("mousedown", function(e) {
+    el.addEventListener("mousedown", function (e) {
       if (e.button !== 0) return;
       if (modifiers.prevent) {
         e.preventDefault();
@@ -45,5 +45,5 @@ module.exports = {
       document.addEventListener("mousemove", moveHandle);
       document.addEventListener("mouseup", upHandle);
     });
-  }
+  },
 };

+ 187 - 187
card/elementModel.js

@@ -1,187 +1,187 @@
-/* eslint-disable no-unused-vars */
-import { deepCopy, getNumList } from "./plugins/utils";
-import { getModel as getCardHeadModel } from "./elements/card-head/model";
-import { getModel as getTopicHeadModel } from "./elements/topic-head/model";
-// element
-import { getModel as createLines } from "./elements/lines/model";
-import { getModel as createLine } from "./elements/line/model";
-import { getModel as createText } from "./elements/text/model";
-import { getModel as createImage } from "./elements/image/model";
-import { getModel as createGrids } from "./elements/grids/model";
-import {
-  getModel as createComposition,
-  getFullModel as getCompositionElements
-} from "./elements/composition/model";
-import {
-  getModel as createFillQuestion,
-  getFullModel as getFillQuesitonElements
-} from "./elements/fill-question/model";
-import {
-  getModel as createFillLine,
-  getFullModel as getFillLineElements
-} from "./elements/fill-line/model";
-import {
-  getModel as createExplain,
-  getFullModel as getExplainElements
-} from "./elements/explain/model";
-
-// page relate ------------------- >
-// 页面
-const PAGE = {
-  type: "PAGE",
-  pageSize: "A3",
-  columnNumber: 2,
-  columnGap: 20,
-  locators: [],
-  globals: [],
-  columns: []
-};
-// 可编辑栏
-const COLUMN = {
-  type: "COLUMN",
-  x: "",
-  y: "",
-  w: "",
-  h: "",
-  isFull: false, // 是否已经填满元素
-  elements: []
-};
-// 定位点
-const LOCATOR = {
-  type: "LOCATOR",
-  x: "",
-  y: "",
-  w: "",
-  h: ""
-};
-
-// available infos
-const EDITABLE_ELEMENT = [
-  "LINE_HORIZONTAL",
-  "LINE_VERTICAL",
-  "LINES",
-  "TEXT",
-  "IMAGE",
-  "GRIDS"
-];
-
-const EDITABLE_TOPIC = ["FILL_QUESTION", "FILL_LINE", "EXPLAIN", "COMPOSITION"];
-
-const ELEMENT_INFOS = {
-  LINES: {
-    name: "多横线",
-    getModel: createLines
-  },
-  LINE_HORIZONTAL: {
-    name: "横线",
-    getModel: () => createLine("HORIZONTAL")
-  },
-  LINE_VERTICAL: {
-    name: "竖线",
-    getModel: () => createLine("VERTICAL")
-  },
-  TEXT: {
-    name: "文本",
-    getModel: createText
-  },
-  IMAGE: {
-    name: "图片",
-    getModel: createImage
-  },
-  GRIDS: {
-    name: "网格",
-    getModel: createGrids
-  },
-  FILL_QUESTION: {
-    name: "选择题",
-    getModel: createFillQuestion
-  },
-  FILL_LINE: {
-    name: "填空题",
-    getModel: createFillLine
-  },
-  EXPLAIN: {
-    name: "解答题",
-    getModel: createExplain
-  },
-  COMPOSITION: {
-    name: "作文题",
-    getModel: createComposition
-  }
-};
-
-const ELEMENT_LIST = EDITABLE_ELEMENT.map(type => {
-  return {
-    ...ELEMENT_INFOS[type],
-    type
-  };
-});
-
-const TOPIC_LIST = EDITABLE_TOPIC.map(type => {
-  return {
-    ...ELEMENT_INFOS[type],
-    type
-  };
-});
-
-// 获取元件默认数据结构
-const getElementModel = type => {
-  return ELEMENT_INFOS[type].getModel();
-};
-
-const getElementName = type => {
-  return ELEMENT_INFOS[type].name;
-};
-
-const getLocators = pageNo => {
-  return {
-    top: [
-      {
-        id: `locator-${pageNo}-00`,
-        ...LOCATOR
-      },
-      {
-        id: `locator-${pageNo}-01`,
-        ...LOCATOR
-      }
-    ],
-    bottom: [
-      {
-        id: `locator-${pageNo}-10`,
-        ...LOCATOR
-      }
-    ]
-  };
-};
-
-// 创建新页面
-const getNewPage = (pageNo, { pageSize, columnNumber }) => {
-  let npage = deepCopy(PAGE);
-  npage.pageSize = pageSize;
-  npage.columnNumber = columnNumber;
-  if (
-    (pageSize === "A3" && columnNumber === 4) ||
-    (pageSize === "A4" && columnNumber === 2)
-  ) {
-    npage.columnGap = 10;
-  }
-  npage.locators = getLocators(pageNo);
-  npage.columns = getNumList(columnNumber).map((item, index) => {
-    return deepCopy(COLUMN);
-  });
-  return npage;
-};
-
-export {
-  getElementModel,
-  getElementName,
-  getNewPage,
-  getCardHeadModel,
-  getTopicHeadModel,
-  getFillQuesitonElements,
-  getFillLineElements,
-  getExplainElements,
-  getCompositionElements,
-  ELEMENT_LIST,
-  TOPIC_LIST
-};
+/* eslint-disable no-unused-vars */
+import { deepCopy, getNumList } from "./plugins/utils";
+import { getModel as getCardHeadModel } from "./elements/card-head/model";
+import { getModel as getTopicHeadModel } from "./elements/topic-head/model";
+// element
+import { getModel as createLines } from "./elements/lines/model";
+import { getModel as createLine } from "./elements/line/model";
+import { getModel as createText } from "./elements/text/model";
+import { getModel as createImage } from "./elements/image/model";
+import { getModel as createGrids } from "./elements/grids/model";
+import {
+  getModel as createComposition,
+  getFullModel as getCompositionElements,
+} from "./elements/composition/model";
+import {
+  getModel as createFillQuestion,
+  getFullModel as getFillQuesitonElements,
+} from "./elements/fill-question/model";
+import {
+  getModel as createFillLine,
+  getFullModel as getFillLineElements,
+} from "./elements/fill-line/model";
+import {
+  getModel as createExplain,
+  getFullModel as getExplainElements,
+} from "./elements/explain/model";
+
+// page relate ------------------- >
+// 页面
+const PAGE = {
+  type: "PAGE",
+  pageSize: "A3",
+  columnNumber: 2,
+  columnGap: 20,
+  locators: [],
+  globals: [],
+  columns: [],
+};
+// 可编辑栏
+const COLUMN = {
+  type: "COLUMN",
+  x: "",
+  y: "",
+  w: "",
+  h: "",
+  isFull: false, // 是否已经填满元素
+  elements: [],
+};
+// 定位点
+const LOCATOR = {
+  type: "LOCATOR",
+  x: "",
+  y: "",
+  w: "",
+  h: "",
+};
+
+// available infos
+const EDITABLE_ELEMENT = [
+  "LINE_HORIZONTAL",
+  "LINE_VERTICAL",
+  "LINES",
+  "TEXT",
+  "IMAGE",
+  "GRIDS",
+];
+
+const EDITABLE_TOPIC = ["FILL_QUESTION", "FILL_LINE", "EXPLAIN", "COMPOSITION"];
+
+const ELEMENT_INFOS = {
+  LINES: {
+    name: "多横线",
+    getModel: createLines,
+  },
+  LINE_HORIZONTAL: {
+    name: "横线",
+    getModel: () => createLine("HORIZONTAL"),
+  },
+  LINE_VERTICAL: {
+    name: "竖线",
+    getModel: () => createLine("VERTICAL"),
+  },
+  TEXT: {
+    name: "文本",
+    getModel: createText,
+  },
+  IMAGE: {
+    name: "图片",
+    getModel: createImage,
+  },
+  GRIDS: {
+    name: "网格",
+    getModel: createGrids,
+  },
+  FILL_QUESTION: {
+    name: "选择题",
+    getModel: createFillQuestion,
+  },
+  FILL_LINE: {
+    name: "填空题",
+    getModel: createFillLine,
+  },
+  EXPLAIN: {
+    name: "解答题",
+    getModel: createExplain,
+  },
+  COMPOSITION: {
+    name: "作文题",
+    getModel: createComposition,
+  },
+};
+
+const ELEMENT_LIST = EDITABLE_ELEMENT.map((type) => {
+  return {
+    ...ELEMENT_INFOS[type],
+    type,
+  };
+});
+
+const TOPIC_LIST = EDITABLE_TOPIC.map((type) => {
+  return {
+    ...ELEMENT_INFOS[type],
+    type,
+  };
+});
+
+// 获取元件默认数据结构
+const getElementModel = (type) => {
+  return ELEMENT_INFOS[type].getModel();
+};
+
+const getElementName = (type) => {
+  return ELEMENT_INFOS[type].name;
+};
+
+const getLocators = (pageNo) => {
+  return {
+    top: [
+      {
+        id: `locator-${pageNo}-00`,
+        ...LOCATOR,
+      },
+      {
+        id: `locator-${pageNo}-01`,
+        ...LOCATOR,
+      },
+    ],
+    bottom: [
+      {
+        id: `locator-${pageNo}-10`,
+        ...LOCATOR,
+      },
+    ],
+  };
+};
+
+// 创建新页面
+const getNewPage = (pageNo, { pageSize, columnNumber }) => {
+  let npage = deepCopy(PAGE);
+  npage.pageSize = pageSize;
+  npage.columnNumber = columnNumber;
+  if (
+    (pageSize === "A3" && columnNumber === 4) ||
+    (pageSize === "A4" && columnNumber === 2)
+  ) {
+    npage.columnGap = 10;
+  }
+  npage.locators = getLocators(pageNo);
+  npage.columns = getNumList(columnNumber).map((item, index) => {
+    return deepCopy(COLUMN);
+  });
+  return npage;
+};
+
+export {
+  getElementModel,
+  getElementName,
+  getNewPage,
+  getCardHeadModel,
+  getTopicHeadModel,
+  getFillQuesitonElements,
+  getFillLineElements,
+  getExplainElements,
+  getCompositionElements,
+  ELEMENT_LIST,
+  TOPIC_LIST,
+};

+ 13 - 13
card/elements/barcode/EditBarcode.vue

@@ -66,7 +66,7 @@ const initModalForm = {
   color: "#ffffff",
   bgColor: "#ffffff",
   style: "solid",
-  field: ""
+  field: "",
 };
 
 export default {
@@ -77,8 +77,8 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     return {
@@ -90,14 +90,14 @@ export default {
           {
             required: true,
             message: "请选择变量",
-            trigger: "change"
-          }
-        ]
-      }
+            trigger: "change",
+          },
+        ],
+      },
     };
   },
   computed: {
-    ...mapState("free", ["cardConfig"])
+    ...mapState("free", ["cardConfig"]),
   },
   mounted() {
     this.initData(this.instance);
@@ -106,8 +106,8 @@ export default {
     initData(val) {
       this.fieldList = [
         ...this.cardConfig.requiredFields,
-        ...this.cardConfig.extendFields
-      ].filter(item => item.enable);
+        ...this.cardConfig.extendFields,
+      ].filter((item) => item.enable);
       this.modalForm = objAssign(initModalForm, val);
       this.modalForm.field = val.fields[0] && val.fields[0].code;
     },
@@ -117,11 +117,11 @@ export default {
 
       const data = { ...this.modalForm };
       data.fields = this.fieldList.filter(
-        item => item.code === this.modalForm.field
+        (item) => item.code === this.modalForm.field
       );
       const model = objAssign(this.instance, data);
       this.$emit("modified", model);
-    }
-  }
+    },
+  },
 };
 </script>

+ 5 - 5
card/elements/barcode/ElemBarcode.vue

@@ -14,8 +14,8 @@ export default {
   name: "elem-barcode",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   computed: {
     styles() {
@@ -24,7 +24,7 @@ export default {
         borderStyle: this.data.style,
         borderWidth: this.data.bold,
         borderColor: this.data.color,
-        transform: `rotate(${this.data.rotation}deg)`
+        transform: `rotate(${this.data.rotation}deg)`,
       };
     },
     imageSrc() {
@@ -32,11 +32,11 @@ export default {
       const content = this.data.content;
 
       return content && content.indexOf("base64") !== -1 ? content : "";
-    }
+    },
   },
   data() {
     return {};
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 2 - 2
card/elements/barcode/model.js

@@ -13,14 +13,14 @@ const MODEL = {
   bgColor: "#ffffff",
   style: "solid",
   fields: [],
-  content: ""
+  content: "",
 };
 
 const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...deepCopy(MODEL)
+    ...deepCopy(MODEL),
   };
 };
 

+ 11 - 11
card/elements/card-head/CardHead.vue

@@ -113,23 +113,23 @@ export default {
     HeadStdinfo,
     HeadNotice,
     HeadDynamic,
-    CardHeadBodyAutoResize
+    CardHeadBodyAutoResize,
   },
   props: {
     data: {
-      type: Object
+      type: Object,
     },
     preview: {
       type: Boolean,
-      default: false
-    }
+      default: false,
+    },
   },
   data() {
     return {
       cardTitle: this.data.cardTitle,
       cardDesc: this.data.cardDesc,
       cardDescLineOne: "",
-      cardDescLineTwo: ""
+      cardDescLineTwo: "",
     };
   },
   created() {
@@ -147,8 +147,8 @@ export default {
           "card-head-narrow": this.narrowCard,
           "card-head-handle": this.data.examNumberStyle === "FILL",
           "card-head-normal":
-            this.data.examNumberStyle !== "FILL" && !this.narrowCard
-        }
+            this.data.examNumberStyle !== "FILL" && !this.narrowCard,
+        },
       ];
     },
     narrowCard() {
@@ -171,16 +171,16 @@ export default {
     disabledEditCardName() {
       // 客服制卡不可修改标题
       return this.cardConfig["makeMethod"] === "CUST";
-    }
+    },
   },
   methods: {
     ...mapMutations("card", ["setCardConfig"]),
     nameChange() {
       this.setCardConfig({
         cardTitle: this.cardTitle,
-        cardDesc: [this.cardDescLineOne, this.cardDescLineTwo].join("\n")
+        cardDesc: [this.cardDescLineOne, this.cardDescLineTwo].join("\n"),
       });
-    }
-  }
+    },
+  },
 };
 </script>

+ 8 - 8
card/elements/card-head/CardHeadBodyAutoResize.vue

@@ -44,20 +44,20 @@ export default {
         stdinfo: 40,
         notice: 40,
         stdno: 40,
-        dynamic: 40
+        dynamic: 40,
       },
       heights: {
         stdinfo: 40,
         notice: 40,
         stdno: 40,
-        dynamic: 40
-      }
+        dynamic: 40,
+      },
     };
   },
   computed: {
     classes() {
       return ["card-head-body-auto-resize", "col-item-auto-height"];
-    }
+    },
   },
   mounted() {
     this.initStyles();
@@ -65,13 +65,13 @@ export default {
   methods: {
     initStyles() {
       const containers = ["stdinfo", "notice", "stdno", "dynamic"];
-      containers.forEach(container => {
+      containers.forEach((container) => {
         const dom =
           this.$refs[`${container}Container`] &&
           this.$refs[`${container}Container`].firstChild;
         this.orgHeights[container] = dom ? dom.offsetHeight : 0;
       });
-      Object.keys(this.orgHeights).map(key => {
+      Object.keys(this.orgHeights).map((key) => {
         this.heights[key] = this.orgHeights[key] + 2;
       });
       this.resizeRect();
@@ -99,7 +99,7 @@ export default {
           this.heights.notice = splitHeight + this.orgHeights.notice + 2;
         }
       }
-    }
-  }
+    },
+  },
 };
 </script>

+ 2 - 2
card/elements/card-head/CardHeadSample.vue

@@ -40,9 +40,9 @@ export default {
       const data = getCardHeadModel(this.cardConfig);
       data.isSimple = true;
       return data;
-    }
+    },
   },
   mounted() {},
-  methods: {}
+  methods: {},
 };
 </script>

+ 7 - 7
card/elements/card-head/cardHeadSpin/HeadDynamic.vue

@@ -54,7 +54,7 @@
       :class="[
         'head-dynamic-part',
         'head-dynamic-aorb',
-        `head-dynamic-aorb-${data.paperType.toLowerCase()}`
+        `head-dynamic-aorb-${data.paperType.toLowerCase()}`,
       ]"
       id="head-dynamic-aorb"
       v-if="data.aOrB"
@@ -100,8 +100,8 @@ export default {
   name: "head-dynamic",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {
@@ -109,7 +109,7 @@ export default {
         this.data["fieldInfos"] && this.data["fieldInfos"]["paperType"],
       aorbBarcodeName:
         (this.data["fieldInfos"] && this.data["fieldInfos"]["paperTypeName"]) ||
-        "A"
+        "A",
     };
   },
   computed: {
@@ -121,7 +121,7 @@ export default {
       if (this.data.examAbsent || this.data.discipline) partNum++;
 
       return ["head-dynamic", "card-head-body-spin", `head-dynamic-${partNum}`];
-    }
+    },
   },
   mounted() {
     this.initStyles();
@@ -147,7 +147,7 @@ export default {
         this.$el.children[childrenCount - 1].style.height =
           lastChildHeight + "px";
       }
-    }
-  }
+    },
+  },
 };
 </script>

+ 6 - 6
card/elements/card-head/cardHeadSpin/HeadNotice.vue

@@ -13,8 +13,8 @@ export default {
   name: "head-notice",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {};
@@ -25,14 +25,14 @@ export default {
         "head-notice",
         "card-head-body-spin",
         {
-          "head-notice-exam-number-fill": this.data.examNumberStyle === "fill"
-        }
+          "head-notice-exam-number-fill": this.data.examNumberStyle === "fill",
+        },
       ];
     },
     notices() {
       return this.data.attention.split("\n") || [];
-    }
+    },
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 10 - 10
card/elements/card-head/cardHeadSpin/HeadStdinfo.vue

@@ -13,8 +13,8 @@ export default {
   name: "head-stdinfo",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {
@@ -27,8 +27,8 @@ export default {
         5: 72,
         6: 86,
         7: 100,
-        8: 114
-      }
+        8: 114,
+      },
     };
   },
   created() {
@@ -38,15 +38,15 @@ export default {
     init() {
       this.fields = [
         ...this.data.requiredFields,
-        ...this.data.extendFields
-      ].filter(item => item.enable);
-      const nameNums = this.fields.map(item => item.name.length);
+        ...this.data.extendFields,
+      ].filter((item) => item.enable);
+      const nameNums = this.fields.map((item) => item.name.length);
       const maxNameLen = Math.max.apply(null, nameNums);
       const num = maxNameLen < 3 ? 3 : maxNameLen > 8 ? 8 : maxNameLen;
       this.paramStyle = {
-        width: this.lenWidths[num] + "px"
+        width: this.lenWidths[num] + "px",
       };
-    }
-  }
+    },
+  },
 };
 </script>

+ 6 - 6
card/elements/card-head/cardHeadSpin/HeadStdno.vue

@@ -43,8 +43,8 @@ export default {
   name: "head-stdno",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {
@@ -52,7 +52,7 @@ export default {
       examNumberBarcodeSrc:
         this.data["fieldInfos"] && this.data["fieldInfos"]["examNumber"],
       examNumberBarcodeName:
-        this.data["fieldInfos"] && this.data["fieldInfos"]["examNumberStr"]
+        this.data["fieldInfos"] && this.data["fieldInfos"]["examNumberStr"],
     };
   },
   computed: {
@@ -61,10 +61,10 @@ export default {
     },
     columnStyles() {
       return {
-        width: (100 / this.fillNumber).toFixed(2) + "%"
+        width: (100 / this.fillNumber).toFixed(2) + "%",
       };
-    }
+    },
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 2 - 2
card/elements/card-head/model.js

@@ -19,10 +19,10 @@ const MODEL = {
   subjectiveAttention: [],
   columnNumber: 2,
   isSimple: false, // 是否是简化形式
-  sign: "head"
+  sign: "head",
 };
 
-const getModel = cardConfig => {
+const getModel = (cardConfig) => {
   const model = Object.assign({}, deepCopy(MODEL), cardConfig);
   model.id = getElementId();
   model.key = randomCode();

+ 11 - 11
card/elements/composition/EditComposition.vue

@@ -35,7 +35,7 @@
 const initModalForm = {
   id: "",
   topicNo: null,
-  topicName: ""
+  topicName: "",
 };
 
 export default {
@@ -45,8 +45,8 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     return {
@@ -56,17 +56,17 @@ export default {
           {
             required: true,
             message: "请输入大题序号",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         topicName: [
           {
             required: true,
             message: "请输入题目名称",
-            trigger: "change"
-          }
-        ]
-      }
+            trigger: "change",
+          },
+        ],
+      },
     };
   },
   mounted() {
@@ -82,7 +82,7 @@ export default {
       if (!valid) return;
       this.modalForm.topicName = this.modalForm.topicName.trim();
       this.$emit("modified", this.modalForm);
-    }
-  }
+    },
+  },
 };
 </script>

+ 4 - 4
card/elements/composition/ElemComposition.vue

@@ -23,8 +23,8 @@ export default {
   components: { ElemCompositionElement },
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {};
@@ -39,7 +39,7 @@ export default {
         height = this.data.h - this.$refs.ElemTitle.clientHeight;
       }
       this.$refs.ElemBody.style.height = height + "px";
-    }
-  }
+    },
+  },
 };
 </script>

+ 12 - 12
card/elements/composition/ElemCompositionEdit.vue

@@ -48,23 +48,23 @@ export default {
   mixins: [guideLinesMixins],
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {
-      bodyStyle: {}
+      bodyStyle: {},
     };
   },
   computed: {
-    ...mapState("card", ["curDragElement"])
+    ...mapState("card", ["curDragElement"]),
   },
   watch: {
     "data.parent": {
       handler() {
         this.modifyBodyStyle();
-      }
-    }
+      },
+    },
   },
   mounted() {
     this.modifyBodyStyle();
@@ -79,7 +79,7 @@ export default {
           height = this.data.h - this.$refs.ElemTitle.clientHeight;
         }
         this.bodyStyle = {
-          height: height + "px"
+          height: height + "px",
         };
       });
     },
@@ -95,8 +95,8 @@ export default {
         y: y + offsetTop,
         container: {
           id: this.data.id,
-          type: this.data.type
-        }
+          type: this.data.type,
+        },
       };
       if (["LINES", "GRIDS"].includes(curElement.type)) {
         curElement.w = this.data.parent.w;
@@ -117,7 +117,7 @@ export default {
       }
       return {
         offsetLeft,
-        offsetTop
+        offsetTop,
       };
     },
     elementResizeOver(element) {
@@ -129,7 +129,7 @@ export default {
     },
     rebuildGuides(element, actionType) {
       return this.rebuild(this.data.elements, element, actionType);
-    }
-  }
+    },
+  },
 };
 </script>

+ 7 - 7
card/elements/composition/ElemCompositionElement.vue

@@ -20,12 +20,12 @@ export default {
     ElemImage,
     ElemLine,
     ElemLines,
-    ElemGrids
+    ElemGrids,
   },
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {};
@@ -41,7 +41,7 @@ export default {
     classes() {
       return [
         "composition-element-body",
-        `composition-element-${this.elementName}`
+        `composition-element-${this.elementName}`,
       ];
     },
     styles() {
@@ -49,9 +49,9 @@ export default {
         left: this.data.x + "px",
         top: this.data.y + "px",
         width: this.data.w + "px",
-        height: this.data.h + "px"
+        height: this.data.h + "px",
       };
-    }
-  }
+    },
+  },
 };
 </script>

+ 12 - 12
card/elements/composition/ElemCompositionElementEdit.vue

@@ -41,18 +41,18 @@ export default {
     ElemLine,
     ElemLines,
     ElemGrids,
-    ElementResize
+    ElementResize,
   },
   props: {
     data: {
-      type: Object
+      type: Object,
     },
     transformFit: {
       type: Function,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     return {
@@ -60,7 +60,7 @@ export default {
         x: 0,
         y: 0,
         w: 0,
-        h: 0
+        h: 0,
       },
       styles: {},
       actives: {
@@ -69,8 +69,8 @@ export default {
         LINES: [],
         GRIDS: [],
         LINE_HORIZONTAL: ["l", "r"],
-        LINE_VERTICAL: ["t", "b"]
-      }
+        LINE_VERTICAL: ["t", "b"],
+      },
     };
   },
   computed: {
@@ -85,12 +85,12 @@ export default {
     classes() {
       return [
         "composition-element-body",
-        `composition-element-${this.elementName}`
+        `composition-element-${this.elementName}`,
       ];
     },
     active() {
       return this.actives[this.data.type];
-    }
+    },
   },
   created() {
     this.init();
@@ -103,7 +103,7 @@ export default {
         left: this.data.x + "px",
         top: this.data.y + "px",
         width: this.data.w + "px",
-        height: this.data.h + "px"
+        height: this.data.h + "px",
       };
     },
     resizeOver() {
@@ -111,7 +111,7 @@ export default {
     },
     activeCurElement() {
       this.setCurElement(this.data);
-    }
-  }
+    },
+  },
 };
 </script>

+ 6 - 6
card/elements/composition/model.js

@@ -5,7 +5,7 @@ const COMPOSITION_PROP = {
   type: "COMPOSITION",
   sign: "subjective",
   topicNo: null,
-  topicName: ""
+  topicName: "",
 };
 
 const MODEL = {
@@ -30,24 +30,24 @@ const MODEL = {
   // 新建作文题,默认插入5线的多横线
   elements: [],
   // 作文题整体信息,COMPOSITION_PROP
-  parent: {}
+  parent: {},
 };
 
 const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...COMPOSITION_PROP
+    ...COMPOSITION_PROP,
   };
 };
 
-const getFullModel = compositionProp => {
+const getFullModel = (compositionProp) => {
   const parent = { ...compositionProp };
 
   let model = {
     id: getElementId(),
     key: randomCode(),
-    ...deepCopy(MODEL)
+    ...deepCopy(MODEL),
   };
   model.w = parent.w;
   model.parent = parent;
@@ -59,7 +59,7 @@ const getFullModel = compositionProp => {
   linesModel.w = parent.w;
   linesModel.container = {
     id: model.id,
-    type: model.type
+    type: model.type,
   };
   model.h = linesModel.h + 50;
   model.elements.push(linesModel);

+ 16 - 16
card/elements/explain/EditExplain.vue

@@ -29,7 +29,7 @@
       </el-form-item>
       <el-form-item prop="startEnd" label="起止题号:">
         <el-input-number
-          style="width:40px;"
+          style="width: 40px"
           v-model="modalForm.startNumber"
           :min="0"
           :max="999"
@@ -39,7 +39,7 @@
         ></el-input-number>
         <span class="el-input-split"></span>
         <el-input-number
-          style="width:40px;"
+          style="width: 40px"
           v-model="modalForm.endNumber"
           :min="0"
           :max="999"
@@ -59,7 +59,7 @@ const initModalForm = {
   topicName: "",
   startNumber: 1,
   endNumber: 4,
-  questionsCount: 4
+  questionsCount: 4,
 };
 
 export default {
@@ -69,8 +69,8 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     const numberRangeValidater = (rule, value, callback) => {
@@ -90,29 +90,29 @@ export default {
           {
             required: true,
             message: "请输入大题序号",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         topicName: [
           {
             required: true,
             message: "请输入题目名称",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         endNumber: [
           {
             required: true,
             message: "请输入起止题号",
-            trigger: "change"
+            trigger: "change",
           },
           {
             type: "number",
             validator: numberRangeValidater,
-            trigger: "change"
-          }
-        ]
-      }
+            trigger: "change",
+          },
+        ],
+      },
     };
   },
   mounted() {
@@ -133,7 +133,7 @@ export default {
         this.modalForm.endNumber - this.modalForm.startNumber + 1;
       this.modalForm.topicName = this.modalForm.topicName.trim();
       this.$emit("modified", this.modalForm);
-    }
-  }
+    },
+  },
 };
 </script>

+ 4 - 4
card/elements/explain/ElemExplain.vue

@@ -30,8 +30,8 @@ export default {
   components: { ElemExplainElement },
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {};
@@ -46,7 +46,7 @@ export default {
         height = this.data.h - this.$refs.ElemTitle.clientHeight;
       }
       this.$refs.ElemBody.style.height = height + "px";
-    }
-  }
+    },
+  },
 };
 </script>

+ 12 - 12
card/elements/explain/ElemExplainEdit.vue

@@ -55,23 +55,23 @@ export default {
   mixins: [guideLinesMixins],
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {
-      bodyStyle: {}
+      bodyStyle: {},
     };
   },
   computed: {
-    ...mapState("card", ["curDragElement"])
+    ...mapState("card", ["curDragElement"]),
   },
   watch: {
     "data.parent": {
       handler() {
         this.modifyBodyStyle();
-      }
-    }
+      },
+    },
   },
   mounted() {
     this.modifyBodyStyle();
@@ -86,7 +86,7 @@ export default {
           height = this.data.h - this.$refs.ElemTitle.clientHeight;
         }
         this.bodyStyle = {
-          height: height + "px"
+          height: height + "px",
         };
       });
     },
@@ -102,8 +102,8 @@ export default {
         y: y + offsetTop,
         container: {
           id: this.data.id,
-          type: this.data.type
-        }
+          type: this.data.type,
+        },
       };
       this.elementResizeOver(curElement);
       this.setCurDragElement({});
@@ -120,7 +120,7 @@ export default {
       }
       return {
         offsetLeft,
-        offsetTop
+        offsetTop,
       };
     },
     elementResizeOver(element) {
@@ -132,7 +132,7 @@ export default {
     },
     rebuildGuides(element, actionType) {
       return this.rebuild(this.data.elements, element, actionType);
-    }
-  }
+    },
+  },
 };
 </script>

+ 6 - 6
card/elements/explain/ElemExplainElement.vue

@@ -20,12 +20,12 @@ export default {
     ElemImage,
     ElemLine,
     ElemLines,
-    ElemGrids
+    ElemGrids,
   },
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {};
@@ -46,10 +46,10 @@ export default {
         left: this.data.x + "px",
         top: this.data.y + "px",
         width: this.data.w + "px",
-        height: this.data.h + "px"
+        height: this.data.h + "px",
       };
-    }
+    },
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 11 - 11
card/elements/explain/ElemExplainElementEdit.vue

@@ -41,18 +41,18 @@ export default {
     ElemLine,
     ElemLines,
     ElemGrids,
-    ElementResize
+    ElementResize,
   },
   props: {
     data: {
-      type: Object
+      type: Object,
     },
     transformFit: {
       type: Function,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     return {
@@ -60,7 +60,7 @@ export default {
         x: 0,
         y: 0,
         w: 0,
-        h: 0
+        h: 0,
       },
       styles: {},
       actives: {
@@ -69,8 +69,8 @@ export default {
         LINES: ["r", "rb", "b", "lb", "l", "lt", "t", "rt"],
         GRIDS: ["r", "rb", "b", "lb", "l", "lt", "t", "rt"],
         LINE_HORIZONTAL: ["l", "r"],
-        LINE_VERTICAL: ["t", "b"]
-      }
+        LINE_VERTICAL: ["t", "b"],
+      },
     };
   },
   computed: {
@@ -87,7 +87,7 @@ export default {
     },
     active() {
       return this.actives[this.data.type];
-    }
+    },
   },
   created() {
     this.init();
@@ -100,7 +100,7 @@ export default {
         left: this.data.x + "px",
         top: this.data.y + "px",
         width: this.data.w + "px",
-        height: this.data.h + "px"
+        height: this.data.h + "px",
       };
     },
     resizeOver() {
@@ -108,7 +108,7 @@ export default {
     },
     activeCurElement() {
       this.setCurElement(this.data);
-    }
-  }
+    },
+  },
 };
 </script>

+ 5 - 5
card/elements/explain/model.js

@@ -6,7 +6,7 @@ const EXPLAIN_PROP = {
   topicNo: null,
   topicName: "",
   startNumber: 1,
-  questionsCount: 1
+  questionsCount: 1,
 };
 // 解答题-小题
 const MODEL = {
@@ -30,7 +30,7 @@ const MODEL = {
   // 每一个解答题小题都可以包含其他基础元件,这些基础元件都用绝对定位
   elements: [],
   // 解答题整体信息,EXPLAIN_PROP
-  parent: {}
+  parent: {},
 };
 // tip属性存在时的条件:parent:大题的小题,container:题目内的子元素
 
@@ -38,11 +38,11 @@ const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...EXPLAIN_PROP
+    ...EXPLAIN_PROP,
   };
 };
 
-const getFullModel = explainProp => {
+const getFullModel = (explainProp) => {
   const parent = { ...explainProp };
 
   let elements = [];
@@ -54,7 +54,7 @@ const getFullModel = explainProp => {
       w: parent.w,
       topicNo: parent.topicNo,
       serialNumber: i + explainProp.startNumber,
-      parent
+      parent,
     });
 
     elements[i] = child;

+ 21 - 21
card/elements/fill-field/EditFillField.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="edit-fill-field ">
+  <div class="edit-fill-field">
     <el-form
       ref="modalFormComp"
       :model="modalForm"
@@ -9,7 +9,7 @@
     >
       <el-form-item prop="fieldCountPerLine" label="每行变量数:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model="modalForm.fieldCountPerLine"
           :min="1"
           :max="10"
@@ -21,7 +21,7 @@
       </el-form-item>
       <el-form-item prop="lineSpacing" label="空位上下间距:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model.number="modalForm.lineSpacing"
           :min="20"
           :max="100"
@@ -65,7 +65,7 @@ const initModalForm = {
   fieldCountPerLine: 1,
   lineSpacing: 30,
   nameIsJustify: false,
-  fields: []
+  fields: [],
 };
 
 export default {
@@ -75,11 +75,11 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   computed: {
-    ...mapState("free", ["cardConfig"])
+    ...mapState("free", ["cardConfig"]),
   },
   data() {
     return {
@@ -90,26 +90,26 @@ export default {
           {
             required: true,
             message: "请选择变量",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         lineSpacing: [
           {
             required: true,
             type: "number",
             message: "请输入空位上下间距",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         fieldCountPerLine: [
           {
             required: true,
             type: "number",
             message: "请输入每行变量数",
-            trigger: "change"
-          }
-        ]
-      }
+            trigger: "change",
+          },
+        ],
+      },
     };
   },
   mounted() {
@@ -119,24 +119,24 @@ export default {
     initData(val) {
       this.fieldList = [
         ...this.cardConfig.requiredFields,
-        ...this.cardConfig.extendFields
-      ].filter(item => item.enable);
+        ...this.cardConfig.extendFields,
+      ].filter((item) => item.enable);
 
       this.modalForm = deepCopy(val);
-      this.modalForm.fields = val.fields.map(item => item.code);
+      this.modalForm.fields = val.fields.map((item) => item.code);
     },
     async submit() {
       const valid = await this.$refs.modalFormComp.validate().catch(() => {});
       if (!valid) return;
 
       const data = deepCopy(this.modalForm);
-      data.fields = this.fieldList.filter(item =>
+      data.fields = this.fieldList.filter((item) =>
         this.modalForm.fields.includes(item.code)
       );
       const model = objAssign(this.instance, data);
 
       this.$emit("modified", model);
-    }
-  }
+    },
+  },
 };
 </script>

+ 13 - 13
card/elements/fill-field/ElemFillField.vue

@@ -27,8 +27,8 @@ export default {
   name: "elem-fill-field",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {
@@ -41,44 +41,44 @@ export default {
         5: 72,
         6: 86,
         7: 100,
-        8: 114
-      }
+        8: 114,
+      },
     };
   },
   computed: {
     itemStyles() {
       return {
-        width: 100 / this.data.fieldCountPerLine + "%"
+        width: 100 / this.data.fieldCountPerLine + "%",
       };
     },
     lineStyles() {
       return {
         height: this.data.lineSpacing + "px",
-        paddingTop: this.data.lineSpacing - 26 + "px"
+        paddingTop: this.data.lineSpacing - 26 + "px",
       };
-    }
+    },
   },
   methods: {
     init() {
       if (this.data.nameIsJustify) {
-        const nameNums = this.data.fields.map(item => item.name.length);
+        const nameNums = this.data.fields.map((item) => item.name.length);
         const maxNameLen = Math.max.apply(null, nameNums);
         const num = maxNameLen < 3 ? 3 : maxNameLen > 8 ? 8 : maxNameLen;
         this.paramStyle = {
-          width: this.lenWidths[num] + "px"
+          width: this.lenWidths[num] + "px",
         };
       } else {
         this.paramStyle = {};
       }
-    }
+    },
   },
   watch: {
     data: {
       immediate: true,
       handler() {
         this.init();
-      }
-    }
-  }
+      },
+    },
+  },
 };
 </script>

+ 2 - 2
card/elements/fill-field/model.js

@@ -11,14 +11,14 @@ const MODEL = {
   lineSpacing: 30,
   nameIsJustify: false,
   fields: [],
-  fieldInfos: {}
+  fieldInfos: {},
 };
 
 const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...deepCopy(MODEL)
+    ...deepCopy(MODEL),
   };
 };
 

+ 29 - 29
card/elements/fill-line/EditFillLine.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="edit-fill-line ">
+  <div class="edit-fill-line">
     <el-form
       ref="modalFormComp"
       :model="modalForm"
@@ -29,7 +29,7 @@
       </el-form-item>
       <el-form-item prop="endNumber" label="起止题号:">
         <el-input-number
-          style="width:40px;"
+          style="width: 40px"
           v-model="modalForm.startNumber"
           :min="0"
           :max="999"
@@ -40,7 +40,7 @@
         ></el-input-number>
         <span class="el-input-split"></span>
         <el-input-number
-          style="width:40px;"
+          style="width: 40px"
           v-model="modalForm.endNumber"
           :min="0"
           :max="999"
@@ -52,7 +52,7 @@
       </el-form-item>
       <el-form-item prop="lineSpacing" label="空位上下间距:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model.number="modalForm.lineSpacing"
           :min="20"
           :max="100"
@@ -63,7 +63,7 @@
       </el-form-item>
       <el-form-item prop="questionNumberPerLine" label="每行空数:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model="modalForm.questionNumberPerLine"
           :min="1"
           :max="10"
@@ -75,7 +75,7 @@
       </el-form-item>
       <el-form-item label="题号前缀:">
         <el-input
-          style="width:125px;"
+          style="width: 125px"
           v-model.trim="modalForm.numberPre"
           :maxlength="6"
           clearable
@@ -107,7 +107,7 @@
         label="每题空数:"
       >
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model="modalForm.lineNumberPerQuestion"
           :min="1"
           :max="15"
@@ -134,7 +134,7 @@
                 :step="1"
                 step-strictly
                 :controls="false"
-                style="width:125px;"
+                style="width: 125px"
               ></el-input-number>
             </td>
           </tr>
@@ -160,7 +160,7 @@ const initModalForm = {
   questionDirection: "horizontal",
   questionLineType: "norm",
   questionLineNums: [],
-  numberPre: ""
+  numberPre: "",
 };
 
 export default {
@@ -170,8 +170,8 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     const numberRangeValidater = (rule, value, callback) => {
@@ -194,53 +194,53 @@ export default {
           {
             required: true,
             message: "请输入大题序号",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         topicName: [
           {
             required: true,
             message: "请输入题目名称",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         endNumber: [
           {
             required: true,
             message: "请输入起止题号",
-            trigger: "change"
+            trigger: "change",
           },
           {
             type: "number",
             validator: numberRangeValidater,
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         lineSpacing: [
           {
             required: true,
             type: "number",
             message: "请输入空位上下间距",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         questionNumberPerLine: [
           {
             required: true,
             type: "number",
             message: "请输入每行空数",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         lineNumberPerQuestion: [
           {
             required: true,
             type: "number",
             message: "请输入每题空数",
-            trigger: "change"
-          }
-        ]
-      }
+            trigger: "change",
+          },
+        ],
+      },
     };
   },
   mounted() {
@@ -272,7 +272,7 @@ export default {
         ) {
           questionLineNumOptions.push({
             no: i,
-            count: this.modalForm.lineNumberPerQuestion
+            count: this.modalForm.lineNumberPerQuestion,
           });
         }
         this.questionLineNumOptions = questionLineNumOptions;
@@ -289,7 +289,7 @@ export default {
       this.modalForm.questionLineNums = this.questionLineNumOptions;
       this.modalForm.topicName = this.modalForm.topicName.trim();
       this.$emit("modified", this.modalForm);
-    }
-  }
+    },
+  },
 };
 </script>

+ 8 - 8
card/elements/fill-line/ElemFillLine.vue

@@ -56,32 +56,32 @@ export default {
   name: "elem-fill-line",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {
-      questions: []
+      questions: [],
     };
   },
   computed: {
     lineStyles() {
       return {
-        height: this.data.lineSpacing + "px"
+        height: this.data.lineSpacing + "px",
       };
     },
     lineNoStyles() {
       return {
-        top: this.data.lineSpacing - 4 + "px"
+        top: this.data.lineSpacing - 4 + "px",
       };
     },
     groupStyles() {
       return {
-        width: 100 / this.data.questionNumberPerLine + "%"
+        width: 100 / this.data.questionNumberPerLine + "%",
       };
-    }
+    },
   },
   mounted() {},
-  methods: {}
+  methods: {},
 };
 </script>

+ 7 - 7
card/elements/fill-line/model.js

@@ -19,18 +19,18 @@ const MODEL = {
   questionLineType: "norm",
   questionLineNums: [],
   numberPre: "",
-  isCovered: false
+  isCovered: false,
 };
 
 const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...MODEL
+    ...MODEL,
   };
 };
 
-const getFullModel = model => {
+const getFullModel = (model) => {
   const parent = { ...model };
   const numPerLine = model.questionNumberPerLine;
   let elements = [];
@@ -45,7 +45,7 @@ const getFullModel = model => {
     ) {
       questionLineNums.push({
         no: j,
-        count: model.lineNumberPerQuestion
+        count: model.lineNumberPerQuestion,
       });
     }
   }
@@ -59,7 +59,7 @@ const getFullModel = model => {
       );
       const maxLineNumberPerQuestion = Math.max.apply(
         null,
-        childQuestionLineNums.map(item => item.count)
+        childQuestionLineNums.map((item) => item.count)
       );
       const questionHeight = model.lineSpacing * maxLineNumberPerQuestion;
       let child = Object.assign({}, parent, {
@@ -71,7 +71,7 @@ const getFullModel = model => {
           i === total - 1 ? model.questionsCount - numPerLine * i : numPerLine,
         parent: parent,
         isLast: i === total - 1,
-        questionLineNums: childQuestionLineNums
+        questionLineNums: childQuestionLineNums,
       });
       child.minHeight = child.h;
 
@@ -91,7 +91,7 @@ const getFullModel = model => {
         questionsCount: 1,
         parent: parent,
         isLast: i === model.questionsCount - 1,
-        questionLineNums: [childQuestionLineNums]
+        questionLineNums: [childQuestionLineNums],
       });
       child.minHeight = child.h;
 

+ 9 - 9
card/elements/fill-number/EditFillNumber.vue

@@ -34,7 +34,7 @@ import { objAssign } from "../../plugins/utils";
 const initModalForm = {
   id: "",
   name: "",
-  numberCount: 13
+  numberCount: 13,
 };
 
 export default {
@@ -44,8 +44,8 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     const numberValidater = (rule, value, callback) => {
@@ -63,10 +63,10 @@ export default {
           {
             required: true,
             validator: numberValidater,
-            trigger: "change"
-          }
-        ]
-      }
+            trigger: "change",
+          },
+        ],
+      },
     };
   },
   mounted() {
@@ -81,7 +81,7 @@ export default {
       if (!valid) return;
 
       this.$emit("modified", objAssign(this.instance, this.modalForm));
-    }
-  }
+    },
+  },
 };
 </script>

+ 5 - 5
card/elements/fill-number/ElemFillNumber.vue

@@ -31,19 +31,19 @@ export default {
   name: "elem-fill-number",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   computed: {
     columnStyles() {
       return {
-        width: (100 / this.data.numberCount).toFixed(2) + "%"
+        width: (100 / this.data.numberCount).toFixed(2) + "%",
       };
-    }
+    },
   },
   data() {
     return {};
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 2 - 2
card/elements/fill-number/model.js

@@ -9,14 +9,14 @@ const MODEL = {
   sign: "",
   name: "准考证号",
   numberCount: 9,
-  content: ""
+  content: "",
 };
 
 const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...deepCopy(MODEL)
+    ...deepCopy(MODEL),
   };
 };
 

+ 20 - 20
card/elements/fill-pane/EditFillPane.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="edit-fill-pane ">
+  <div class="edit-fill-pane">
     <el-form
       ref="modalFormComp"
       :model="modalForm"
@@ -9,7 +9,7 @@
     >
       <el-form-item prop="paneCount" label="方格数量:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model.number="modalForm.paneCount"
           :min="1"
           :max="100"
@@ -20,7 +20,7 @@
       </el-form-item>
       <el-form-item prop="paneGap" label="方格间距:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model="modalForm.paneGap"
           :min="1"
           :max="100"
@@ -31,7 +31,7 @@
       </el-form-item>
       <el-form-item prop="paneWidth" label="方格宽度:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model="modalForm.paneWidth"
           :min="1"
           :max="100"
@@ -42,7 +42,7 @@
       </el-form-item>
       <el-form-item prop="paneHeight" label="方格高度:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model="modalForm.paneHeight"
           :min="1"
           :max="100"
@@ -68,7 +68,7 @@ const initModalForm = {
   paneCount: 9,
   paneWidth: 30,
   paneHeight: 30,
-  borderStyle: "solid"
+  borderStyle: "solid",
 };
 
 export default {
@@ -79,8 +79,8 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     return {
@@ -91,34 +91,34 @@ export default {
             required: true,
             type: "number",
             message: "请输入方格间距",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         paneCount: [
           {
             required: true,
             type: "number",
             message: "请输入方格数量",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         paneWidth: [
           {
             required: true,
             type: "number",
             message: "请输入方格宽度",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         paneHeight: [
           {
             required: true,
             type: "number",
             message: "请输入方格高度",
-            trigger: "change"
-          }
-        ]
-      }
+            trigger: "change",
+          },
+        ],
+      },
     };
   },
   mounted() {
@@ -133,7 +133,7 @@ export default {
       if (!valid) return;
 
       this.$emit("modified", this.modalForm);
-    }
-  }
+    },
+  },
 };
 </script>

+ 7 - 7
card/elements/fill-pane/ElemFillPane.vue

@@ -16,8 +16,8 @@ export default {
   name: "elem-fill-pane",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {};
@@ -27,20 +27,20 @@ export default {
       return {
         borderStyle: this.data.borderStyle,
         width: this.data.paneWidth + "px",
-        height: this.data.paneHeight + "px"
+        height: this.data.paneHeight + "px",
       };
     },
     paneStyles() {
       return {
-        padding: this.data.paneGap / 2 + "px"
+        padding: this.data.paneGap / 2 + "px",
       };
     },
     elemStyle() {
       return {
-        padding: this.data.paneGap / 2 + "px"
+        padding: this.data.paneGap / 2 + "px",
       };
-    }
+    },
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 2 - 2
card/elements/fill-pane/model.js

@@ -11,14 +11,14 @@ const MODEL = {
   paneCount: 9,
   paneWidth: 30,
   paneHeight: 30,
-  borderStyle: "solid"
+  borderStyle: "solid",
 };
 
 const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...deepCopy(MODEL)
+    ...deepCopy(MODEL),
   };
 };
 

+ 28 - 28
card/elements/fill-question/EditFillQuestion.vue

@@ -36,7 +36,7 @@
       </el-form-item>
       <el-form-item prop="endNumber" label="起止题号:">
         <el-input-number
-          style="width:40px;"
+          style="width: 40px"
           v-model="modalForm.startNumber"
           :min="0"
           :max="999"
@@ -46,7 +46,7 @@
         ></el-input-number>
         <span class="el-input-split"></span>
         <el-input-number
-          style="width:40px;"
+          style="width: 40px"
           v-model="modalForm.endNumber"
           :min="modalForm.startNumber"
           :max="999"
@@ -57,7 +57,7 @@
       </el-form-item>
       <el-form-item prop="optionCount" label="选项个数:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model="modalForm.optionCount"
           :min="2"
           :max="22"
@@ -80,7 +80,7 @@
       <el-form-item v-if="modalForm.isBoolean" label="是否配置:">
         <el-select
           v-model="modalForm.booleanType"
-          style="width:125px;"
+          style="width: 125px"
           placeholder="请选择"
           @change="booleanTypeChange"
         >
@@ -99,14 +99,14 @@
           v-model.trim="booleanTypes.yes"
           :maxlength="1"
           placeholder="是"
-          style="margin-right: 20px;width:60px;"
+          style="margin-right: 20px; width: 60px"
         ></el-input>
         <span>否:</span>
         <el-input
           v-model.trim="booleanTypes.no"
           :maxlength="1"
           placeholder="否"
-          style="margin-right: 20px;width:60px;"
+          style="margin-right: 20px; width: 60px"
         ></el-input>
       </el-form-item>
     </el-form>
@@ -127,7 +127,7 @@ const initModalForm = {
   questionDirection: "horizontal",
   isBoolean: false,
   booleanType: BOOLEAN_TYPE[0],
-  isMultiply: false
+  isMultiply: false,
 };
 
 export default {
@@ -137,8 +137,8 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     const topicTypeValidater = (rule, value, callback) => {
@@ -183,58 +183,58 @@ export default {
       topicType: null,
       booleanTypes: {
         yes: "",
-        no: ""
+        no: "",
       },
       rules: {
         topicType: [
           {
             required: true,
             validator: topicTypeValidater,
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         topicNo: [
           {
             required: true,
             message: "请输入大题序号",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         topicName: [
           {
             required: true,
             message: "请输入题目名称",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         endNumber: [
           {
             required: true,
             message: "请输入起止题号",
-            trigger: "change"
+            trigger: "change",
           },
           {
             type: "number",
             validator: numberRangeValidater,
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         optionCount: [
           {
             required: true,
             type: "number",
             message: "请输入选项个数",
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         booleanType: [
           {
             required: true,
             validator: booleanTypeValidater,
-            trigger: "change"
-          }
-        ]
-      }
+            trigger: "change",
+          },
+        ],
+      },
     };
   },
   mounted() {
@@ -284,11 +284,11 @@ export default {
         this.modalForm.endNumber - this.modalForm.startNumber + 1;
       this.modalForm.booleanType = [
         this.booleanTypes.yes,
-        this.booleanTypes.no
+        this.booleanTypes.no,
       ].join();
       this.modalForm.topicName = this.modalForm.topicName.trim();
       this.$emit("modified", this.modalForm);
-    }
-  }
+    },
+  },
 };
 </script>

+ 11 - 11
card/elements/fill-question/ElemFillQuestion.vue

@@ -35,8 +35,8 @@ export default {
   name: "elem-fill-question",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   computed: {
     isFirstSpin() {
@@ -54,13 +54,13 @@ export default {
             !this.data.isMultiply && !this.data.isBoolean,
           "elem-fill-question-multiply": this.data.isMultiply,
           "elem-fill-question-boolean": this.data.isBoolean,
-          "elem-fill-question-first": this.isFirstSpin
-        }
+          "elem-fill-question-first": this.isFirstSpin,
+        },
       ];
     },
     groupGapStyles() {
       return {
-        marginRight: this.data.groupGap + "px"
+        marginRight: this.data.groupGap + "px",
       };
     },
     // questionGapStyles() {
@@ -75,11 +75,11 @@ export default {
           : { marginRight: this.data.optionGap + "px" };
       // styles.fontSize = this.data.fontSize;
       return styles;
-    }
+    },
   },
   data() {
     return {
-      questions: []
+      questions: [],
     };
   },
   methods: {
@@ -125,15 +125,15 @@ export default {
       return this.data.optionDirection === "vertical"
         ? { marginRight: size + "px" }
         : { marginBottom: size + "px" };
-    }
+    },
   },
   watch: {
     data: {
       immediate: true,
       handler(val) {
         this.parseQuestion(val);
-      }
-    }
-  }
+      },
+    },
+  },
 };
 </script>

+ 6 - 6
card/elements/fill-question/model.js

@@ -25,14 +25,14 @@ const MODEL = {
   booleanType: BOOLEAN_TYPE[0],
   isMultiply: false, // 是否是多选题
   isCovered: false,
-  fontSize: "14px"
+  fontSize: "14px",
 };
 
 const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...MODEL
+    ...MODEL,
   };
 };
 
@@ -44,12 +44,12 @@ const getFullModel = (model, { pageSize, columnNumber }) => {
     A3: {
       2: [0, 0, 6, 5, 4, 3, 3, 2, 2, 2, 2, 1, 1],
       3: [0, 0, 4, 3, 2, 2, 2, 1],
-      4: [0, 0, 3, 2, 2, 1]
+      4: [0, 0, 3, 2, 2, 1],
     },
     A4: {
       1: [0, 0, 6, 5, 4, 3, 3, 2, 2, 2, 2, 1, 1],
-      2: [0, 0, 3, 2, 2, 1]
-    }
+      2: [0, 0, 3, 2, 2, 1],
+    },
   };
   // 以一行4题,每题5选项为标准展示效果
   // const numberPerChildren = {
@@ -74,7 +74,7 @@ const getFullModel = (model, { pageSize, columnNumber }) => {
       questionsCount:
         i === total - 1 ? model.questionsCount - numPerLine * i : numPerLine,
       parent,
-      isLast: i === total - 1
+      isLast: i === total - 1,
     });
     const optionCount =
       model.questionDirection === "vertical"

+ 17 - 17
card/elements/fill-table/EditFillTable.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="edit-fill-table ">
+  <div class="edit-fill-table">
     <el-form
       ref="modalFormComp"
       :model="modalForm"
@@ -14,7 +14,7 @@
           </el-col>
           <el-col :span="6">
             <el-input-number
-              style="width:60px;"
+              style="width: 60px"
               v-model="modalForm.rowCount"
               :min="2"
               :max="16"
@@ -28,7 +28,7 @@
           </el-col>
           <el-col :span="6">
             <el-input-number
-              style="width:60px;"
+              style="width: 60px"
               v-model="modalForm.colCount"
               :min="2"
               :max="16"
@@ -46,7 +46,7 @@
           </el-col>
           <el-col :span="6">
             <el-input-number
-              style="width:60px;"
+              style="width: 60px"
               v-model="modalForm.paddingTop"
               :min="2"
               :max="16"
@@ -60,7 +60,7 @@
           </el-col>
           <el-col :span="6">
             <el-input-number
-              style="width:60px;"
+              style="width: 60px"
               v-model="modalForm.paddingLeft"
               :min="2"
               :max="16"
@@ -79,7 +79,7 @@
       </el-form-item>
       <el-form-item prop="lineHeight" label="行高:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model="modalForm.lineHeight"
           :min="20"
           :max="100"
@@ -118,7 +118,7 @@ const initModalForm = {
   fontSize: "14px",
   lineHeight: 30,
   lineStyle: "solid",
-  content: {}
+  content: {},
 };
 
 export default {
@@ -129,8 +129,8 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     const tdCountValidater = (rule, value, callback) => {
@@ -153,17 +153,17 @@ export default {
           {
             required: true,
             validator: tdCountValidater,
-            trigger: "change"
-          }
+            trigger: "change",
+          },
         ],
         padding: [
           {
             required: true,
             validator: paddingValidater,
-            trigger: "change"
-          }
-        ]
-      }
+            trigger: "change",
+          },
+        ],
+      },
     };
   },
   mounted() {
@@ -192,8 +192,8 @@ export default {
       model.padding = [data.paddingTop, data.paddingLeft];
 
       this.$emit("modified", model);
-    }
-  }
+    },
+  },
 };
 </script>
 

+ 6 - 6
card/elements/fill-table/ElemFillTable.vue

@@ -15,8 +15,8 @@ export default {
   name: "elem-fill-table",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {};
@@ -24,14 +24,14 @@ export default {
   computed: {
     tdStyles() {
       return {
-        padding: this.data.padding.map(item => `${item}px`).join(" "),
+        padding: this.data.padding.map((item) => `${item}px`).join(" "),
         border: `1px ${this.data.lineStyle} #000`,
         fontSize: this.data.fontSize,
-        height: this.data.lineHeight + "px"
+        height: this.data.lineHeight + "px",
       };
-    }
+    },
   },
   mounted() {},
-  methods: {}
+  methods: {},
 };
 </script>

+ 2 - 2
card/elements/fill-table/model.js

@@ -13,14 +13,14 @@ const MODEL = {
   lineStyle: "solid",
   fontSize: "14px",
   lineHeight: 30,
-  content: {}
+  content: {},
 };
 
 const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...deepCopy(MODEL)
+    ...deepCopy(MODEL),
   };
 };
 

+ 10 - 10
card/elements/grids/EditGrids.vue

@@ -8,7 +8,7 @@
     >
       <el-form-item prop="columnCount" label="单行网格数:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model.number="modalForm.columnCount"
           :min="2"
           :max="100"
@@ -19,7 +19,7 @@
       </el-form-item>
       <el-form-item prop="rowCount" label="网格行数:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model.number="modalForm.rowCount"
           :min="1"
           :max="100"
@@ -30,7 +30,7 @@
       </el-form-item>
       <el-form-item prop="rowSpace" label="网格行间距:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model.number="modalForm.rowSpace"
           :min="0"
           :max="100"
@@ -41,7 +41,7 @@
       </el-form-item>
       <el-form-item label="网格宽度:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model.number="modalForm.columnSize"
           :min="0"
           :max="100"
@@ -71,7 +71,7 @@ const initModalForm = {
   rowCount: 3,
   rowSpace: 0,
   halving: true,
-  style: "solid"
+  style: "solid",
 };
 
 export default {
@@ -82,12 +82,12 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     return {
-      modalForm: { ...initModalForm }
+      modalForm: { ...initModalForm },
     };
   },
   mounted() {
@@ -99,7 +99,7 @@ export default {
     },
     submit() {
       this.$emit("modified", this.modalForm);
-    }
-  }
+    },
+  },
 };
 </script>

+ 7 - 7
card/elements/grids/ElemGrids.vue

@@ -8,7 +8,7 @@
             :key="cindex"
             :style="styles"
           >
-            <div v-if="data.halving" style="paddingBottom: 100%;"></div>
+            <div v-if="data.halving" style="paddingbottom: 100%"></div>
           </td>
         </tr>
         <tr :key="`space-${rindex}`" v-if="data.rowSpace">
@@ -24,8 +24,8 @@ export default {
   name: "elem-grids",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {};
@@ -36,7 +36,7 @@ export default {
     },
     styles() {
       let data = {
-        borderStyle: this.data.style
+        borderStyle: this.data.style,
       };
       if (!this.data.halving) {
         data.width = this.data.columnSize + "px";
@@ -54,10 +54,10 @@ export default {
     rowSpaceStyle() {
       return {
         height: this.data.rowSpace + "px",
-        borderStyle: this.data.style
+        borderStyle: this.data.style,
       };
-    }
+    },
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 2 - 2
card/elements/grids/model.js

@@ -12,14 +12,14 @@ const MODEL = {
   rowCount: 3,
   rowSpace: 0,
   halving: true,
-  style: "solid"
+  style: "solid",
 };
 
 const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...MODEL
+    ...MODEL,
   };
 };
 

+ 12 - 12
card/elements/image/EditImage.vue

@@ -17,13 +17,13 @@
         <input
           ref="fileInput"
           type="file"
-          style="display:none;"
+          style="display: none"
           @change="imageChange"
           accept=".jpeg,.jpg,.png"
         />
       </el-form-item>
-      <div style="text-align: center;">
-        <img style="width: 150px;" :src="imageSrc" alt="图片" v-if="imageSrc" />
+      <div style="text-align: center">
+        <img style="width: 150px" :src="imageSrc" alt="图片" v-if="imageSrc" />
       </div>
     </el-form>
   </div>
@@ -37,7 +37,7 @@ const initModalForm = {
   id: "",
   borderColor: "",
   borderStyle: "",
-  content: []
+  content: [],
 };
 
 export default {
@@ -48,13 +48,13 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     return {
       imageSrc: "",
-      modalForm: { ...initModalForm }
+      modalForm: { ...initModalForm },
     };
   },
   mounted() {
@@ -78,12 +78,12 @@ export default {
       }
       const reader = new FileReader();
       reader.readAsDataURL(file);
-      reader.onload = e => {
+      reader.onload = (e) => {
         this.modalForm.content = [
           {
             type: "text",
-            content: e.target.result
-          }
+            content: e.target.result,
+          },
         ];
         this.imageSrc = e.target.result;
         this.$refs.fileInput.value = null;
@@ -91,7 +91,7 @@ export default {
     },
     submit() {
       this.$emit("modified", this.modalForm);
-    }
-  }
+    },
+  },
 };
 </script>

+ 5 - 5
card/elements/image/ElemImage.vue

@@ -10,14 +10,14 @@ export default {
   name: "elem-image",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   computed: {
     styles() {
       return {
         borderStyle: this.data.borderStyle,
-        borderColor: this.data.borderColor
+        borderColor: this.data.borderColor,
       };
     },
     imageSrc() {
@@ -27,11 +27,11 @@ export default {
         this.data.content[0].content;
 
       return content && content.indexOf("base64") !== -1 ? content : "";
-    }
+    },
   },
   data() {
     return {};
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 2 - 2
card/elements/image/model.js

@@ -9,14 +9,14 @@ const MODEL = {
   sign: "",
   borderColor: "",
   borderStyle: "",
-  content: []
+  content: [],
 };
 
 const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...MODEL
+    ...MODEL,
   };
 };
 

+ 6 - 6
card/elements/line/EditLine.vue

@@ -28,7 +28,7 @@ const initModalForm = {
   id: "",
   bold: "1px",
   color: "#000000",
-  style: "solid"
+  style: "solid",
 };
 
 export default {
@@ -39,12 +39,12 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     return {
-      modalForm: { ...initModalForm }
+      modalForm: { ...initModalForm },
     };
   },
   mounted() {
@@ -56,7 +56,7 @@ export default {
     },
     submit() {
       this.$emit("modified", this.modalForm);
-    }
-  }
+    },
+  },
 };
 </script>

+ 7 - 7
card/elements/line/ElemLine.vue

@@ -9,8 +9,8 @@ export default {
   name: "elem-line-horizontal",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   computed: {
     classes() {
@@ -18,7 +18,7 @@ export default {
         "elem-line",
         this.data.type === "LINE_HORIZONTAL"
           ? "elem-line-horizontal"
-          : "elem-line-vertical"
+          : "elem-line-vertical",
       ];
     },
     styles() {
@@ -26,18 +26,18 @@ export default {
         ? {
             borderBottomStyle: this.data.style,
             borderBottomWidth: this.data.bold,
-            borderBottomColor: this.data.color
+            borderBottomColor: this.data.color,
           }
         : {
             borderLeftStyle: this.data.style,
             borderLeftWidth: this.data.bold,
-            borderLeftColor: this.data.color
+            borderLeftColor: this.data.color,
           };
-    }
+    },
   },
   data() {
     return {};
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 4 - 4
card/elements/line/model.js

@@ -9,7 +9,7 @@ const LINE_HORIZONTAL = {
   sign: "",
   bold: "1px",
   color: "#000000",
-  style: "solid"
+  style: "solid",
 };
 // 竖线
 const LINE_VERTICAL = {
@@ -21,15 +21,15 @@ const LINE_VERTICAL = {
   sign: "",
   bold: "1px",
   color: "#000000",
-  style: "solid"
+  style: "solid",
 };
 
-const getModel = type => {
+const getModel = (type) => {
   const model = type === "HORIZONTAL" ? LINE_HORIZONTAL : LINE_VERTICAL;
   return {
     id: getElementId(),
     key: randomCode(),
-    ...model
+    ...model,
   };
 };
 

+ 9 - 9
card/elements/lines/EditLines.vue

@@ -8,7 +8,7 @@
     >
       <el-form-item prop="lineCount" label="线条数量:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model.number="modalForm.lineCount"
           :min="2"
           :max="100"
@@ -19,7 +19,7 @@
       </el-form-item>
       <el-form-item prop="lineSpacing" label="线条间距:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model.number="modalForm.lineSpacing"
           :min="2"
           :max="100"
@@ -30,7 +30,7 @@
       </el-form-item>
       <el-form-item label="左右边距:">
         <el-input-number
-          style="width:125px;"
+          style="width: 125px"
           v-model.number="modalForm.margin"
           :min="0"
           :max="100"
@@ -64,7 +64,7 @@ const initModalForm = {
   margin: 0,
   bold: "1px",
   color: "#000000",
-  style: "solid"
+  style: "solid",
 };
 
 export default {
@@ -75,12 +75,12 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     return {
-      modalForm: { ...initModalForm }
+      modalForm: { ...initModalForm },
     };
   },
   mounted() {
@@ -92,7 +92,7 @@ export default {
     },
     submit() {
       this.$emit("modified", this.modalForm);
-    }
-  }
+    },
+  },
 };
 </script>

+ 5 - 5
card/elements/lines/ElemLines.vue

@@ -16,8 +16,8 @@ export default {
   name: "elem-line-horizontal",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   computed: {
     classes() {
@@ -29,13 +29,13 @@ export default {
         borderBottomWidth: this.data.bold,
         borderBottomColor: this.data.color,
         paddingTop: this.data.lineSpacing + "px",
-        margin: this.data.margin ? `0 ${this.data.margin}px` : "0"
+        margin: this.data.margin ? `0 ${this.data.margin}px` : "0",
       };
-    }
+    },
   },
   data() {
     return {};
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 2 - 2
card/elements/lines/model.js

@@ -12,14 +12,14 @@ const MODEL = {
   margin: 0, // 左右边距
   bold: "1px",
   color: "#000000",
-  style: "solid"
+  style: "solid",
 };
 
 const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...MODEL
+    ...MODEL,
   };
 };
 

+ 21 - 21
card/elements/page/EditPage.vue

@@ -31,7 +31,7 @@
               'icon',
               form.columnNumber == item.value
                 ? `icon-column-${item.label}-act`
-                : `icon-column-${item.label}`
+                : `icon-column-${item.label}`,
             ]"
           ></i>
         </el-button>
@@ -57,26 +57,26 @@ const COLUMN_OPTIONS = [
     value: 1,
     title: "一栏",
     label: "one",
-    sizeValid: ["A3", "A4"]
+    sizeValid: ["A3", "A4"],
   },
   {
     value: 2,
     title: "二栏",
     label: "two",
-    sizeValid: ["A3", "A4"]
+    sizeValid: ["A3", "A4"],
   },
   {
     value: 3,
     title: "三栏",
     label: "three",
-    sizeValid: ["A3"]
+    sizeValid: ["A3"],
   },
   {
     value: 4,
     title: "四栏",
     label: "four",
-    sizeValid: ["A3"]
-  }
+    sizeValid: ["A3"],
+  },
 ];
 
 export default {
@@ -84,16 +84,16 @@ export default {
   props: {
     editPageSize: {
       type: Boolean,
-      default: false
+      default: false,
     },
     editColumnNumber: {
       type: Boolean,
-      default: true
+      default: true,
     },
     editForbidArea: {
       type: Boolean,
-      default: false
-    }
+      default: false,
+    },
   },
   data() {
     return {
@@ -102,13 +102,13 @@ export default {
       form: {
         pageSize: "A3",
         columnNumber: 2,
-        showForbidArea: false
+        showForbidArea: false,
       },
-      prePageSize: "A3"
+      prePageSize: "A3",
     };
   },
   computed: {
-    ...mapState("free", ["curPage"])
+    ...mapState("free", ["curPage"]),
   },
   watch: {
     curPage: {
@@ -116,17 +116,17 @@ export default {
       handler(val) {
         this.form = objAssign(this.form, val);
         this.prePageSize = this.form.pageSize;
-        this.columnOptions = COLUMN_OPTIONS.filter(item =>
+        this.columnOptions = COLUMN_OPTIONS.filter((item) =>
           item.sizeValid.includes(this.form.pageSize)
         );
-      }
-    }
+      },
+    },
   },
   methods: {
     ...mapActions("free", ["modifyPage"]),
     modifyColumnNum(item) {
       this.$confirm("此操作将会重置当前页面所有元素信息, 是否继续?", "提示", {
-        type: "warning"
+        type: "warning",
       })
         .then(() => {
           this.form.columnNumber = item.value;
@@ -139,10 +139,10 @@ export default {
     },
     modifyPageSize() {
       this.$confirm("此操作将会重置当前页面所有元素信息, 是否继续?", "提示", {
-        type: "warning"
+        type: "warning",
       })
         .then(() => {
-          this.columnOptions = COLUMN_OPTIONS.filter(item =>
+          this.columnOptions = COLUMN_OPTIONS.filter((item) =>
             item.sizeValid.includes(this.form.pageSize)
           );
           this.form.columnNumber = this.columnOptions[0].value;
@@ -160,7 +160,7 @@ export default {
       } else {
         this.modifyPage(Object.assign({}, this.curPage, this.form));
       }
-    }
-  }
+    },
+  },
 };
 </script>

+ 78 - 78
card/elements/page/model.js

@@ -1,78 +1,78 @@
-import {
-  getElementId,
-  randomCode,
-  deepCopy,
-  getNumList,
-  objAssign
-} from "../../plugins/utils";
-
-const MODEL = {
-  type: "PAGE",
-  columnGap: 20,
-  locators: [],
-  globals: [],
-  columns: [],
-  pageSize: "A3",
-  columnNumber: 2,
-  showForbidArea: false
-};
-// 可编辑栏
-const COLUMN = {
-  type: "COLUMN",
-  x: "",
-  y: "",
-  w: "",
-  h: "",
-  elements: []
-};
-// 定位点
-const LOCATOR = {
-  type: "LOCATOR",
-  x: "",
-  y: "",
-  w: "",
-  h: ""
-};
-
-const getLocators = () => {
-  const id = getElementId();
-  return {
-    top: [
-      {
-        id: `locator-${id}-00`,
-        ...LOCATOR
-      },
-      {
-        id: `locator-${id}-01`,
-        ...LOCATOR
-      }
-    ],
-    bottom: [
-      {
-        id: `locator-${id}-10`,
-        ...LOCATOR
-      }
-    ]
-  };
-};
-
-const getModel = (datas = {}) => {
-  let npage = deepCopy(MODEL);
-  npage = objAssign(npage, datas);
-  npage.id = getElementId();
-  const { pageSize, columnNumber } = npage;
-  if (
-    (pageSize === "A3" && columnNumber === 4) ||
-    (pageSize === "A4" && columnNumber === 2)
-  ) {
-    npage.columnGap = 10;
-  }
-
-  npage.locators = getLocators();
-  npage.columns = getNumList(columnNumber).map(() => {
-    return { id: `column-${randomCode()}`, ...deepCopy(COLUMN) };
-  });
-  return npage;
-};
-
-export { MODEL, getModel };
+import {
+  getElementId,
+  randomCode,
+  deepCopy,
+  getNumList,
+  objAssign,
+} from "../../plugins/utils";
+
+const MODEL = {
+  type: "PAGE",
+  columnGap: 20,
+  locators: [],
+  globals: [],
+  columns: [],
+  pageSize: "A3",
+  columnNumber: 2,
+  showForbidArea: false,
+};
+// 可编辑栏
+const COLUMN = {
+  type: "COLUMN",
+  x: "",
+  y: "",
+  w: "",
+  h: "",
+  elements: [],
+};
+// 定位点
+const LOCATOR = {
+  type: "LOCATOR",
+  x: "",
+  y: "",
+  w: "",
+  h: "",
+};
+
+const getLocators = () => {
+  const id = getElementId();
+  return {
+    top: [
+      {
+        id: `locator-${id}-00`,
+        ...LOCATOR,
+      },
+      {
+        id: `locator-${id}-01`,
+        ...LOCATOR,
+      },
+    ],
+    bottom: [
+      {
+        id: `locator-${id}-10`,
+        ...LOCATOR,
+      },
+    ],
+  };
+};
+
+const getModel = (datas = {}) => {
+  let npage = deepCopy(MODEL);
+  npage = objAssign(npage, datas);
+  npage.id = getElementId();
+  const { pageSize, columnNumber } = npage;
+  if (
+    (pageSize === "A3" && columnNumber === 4) ||
+    (pageSize === "A4" && columnNumber === 2)
+  ) {
+    npage.columnGap = 10;
+  }
+
+  npage.locators = getLocators();
+  npage.columns = getNumList(columnNumber).map(() => {
+    return { id: `column-${randomCode()}`, ...deepCopy(COLUMN) };
+  });
+  return npage;
+};
+
+export { MODEL, getModel };

+ 6 - 6
card/elements/pane/EditPane.vue

@@ -36,7 +36,7 @@ const initModalForm = {
   bold: "1px",
   color: "#000000",
   bgColor: "#ffffff",
-  style: "solid"
+  style: "solid",
 };
 
 export default {
@@ -47,13 +47,13 @@ export default {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     return {
       modalForm: { ...initModalForm },
-      predefineColors: ["#000000", "#666666", "#999999", "#ffffff"]
+      predefineColors: ["#000000", "#666666", "#999999", "#ffffff"],
     };
   },
   mounted() {
@@ -65,7 +65,7 @@ export default {
     },
     submit() {
       this.$emit("modified", this.modalForm);
-    }
-  }
+    },
+  },
 };
 </script>

+ 5 - 5
card/elements/pane/ElemPane.vue

@@ -7,8 +7,8 @@ export default {
   name: "elem-pane",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   computed: {
     styles() {
@@ -16,13 +16,13 @@ export default {
         backgroundColor: this.data.bgColor,
         borderStyle: this.data.style,
         borderWidth: this.data.bold,
-        borderColor: this.data.color
+        borderColor: this.data.color,
       };
-    }
+    },
   },
   data() {
     return {};
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 2 - 2
card/elements/pane/model.js

@@ -10,14 +10,14 @@ const MODEL = {
   bold: "1px",
   color: "#000000",
   bgColor: "#ffffff",
-  style: "solid"
+  style: "solid",
 };
 
 const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...deepCopy(MODEL)
+    ...deepCopy(MODEL),
   };
 };
 

+ 15 - 15
card/elements/text/EditText.vue

@@ -10,13 +10,13 @@
       <el-form-item label="字号:">
         <size-select
           v-model="modalForm.fontSize"
-          style="width:100%;"
+          style="width: 100%"
         ></size-select>
       </el-form-item>
       <el-form-item label="字体:">
         <font-family-select
           v-model="modalForm.fontFamily"
-          style="width:100%;"
+          style="width: 100%"
         ></font-family-select>
       </el-form-item>
       <el-form-item label="颜色:">
@@ -55,7 +55,7 @@ const initModalForm = {
   fontWeight: 400,
   rotation: 0,
   content: [],
-  contentStr: ""
+  contentStr: "",
 };
 
 export default {
@@ -63,15 +63,15 @@ export default {
   components: {
     SizeSelect,
     ColorSelect,
-    FontFamilySelect
+    FontFamilySelect,
   },
   props: {
     instance: {
       type: Object,
       default() {
         return {};
-      }
-    }
+      },
+    },
   },
   data() {
     return {
@@ -82,10 +82,10 @@ export default {
           {
             required: true,
             message: "请输入文本内容",
-            trigger: "change"
-          }
-        ]
-      }
+            trigger: "change",
+          },
+        ],
+      },
     };
   },
   mounted() {
@@ -94,7 +94,7 @@ export default {
   methods: {
     initData(val) {
       const contentStr = val.content
-        .map(item => {
+        .map((item) => {
           return item.type === "text"
             ? item.content
             : "${" + item.content + "}";
@@ -117,13 +117,13 @@ export default {
         if (text)
           contents.push({
             type: "text",
-            content: text
+            content: text,
           });
 
         if (variates && variates[index])
           contents.push({
             type: "variate",
-            content: variates[index].replace("${", "").replace("}", "")
+            content: variates[index].replace("${", "").replace("}", ""),
           });
       });
       this.modalForm.content = contents;
@@ -132,7 +132,7 @@ export default {
       const valid = await this.$refs.modalFormComp.validate().catch(() => {});
       if (!valid) return;
       this.$emit("modified", this.modalForm);
-    }
-  }
+    },
+  },
 };
 </script>

+ 5 - 5
card/elements/text/ElemText.vue

@@ -16,8 +16,8 @@ export default {
   name: "elem-text",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   computed: {
     styles() {
@@ -25,13 +25,13 @@ export default {
         fontWeight: this.data.fontWeight,
         fontFamily: this.data.fontFamily,
         fontSize: this.data.fontSize,
-        color: this.data.color
+        color: this.data.color,
       };
-    }
+    },
   },
   data() {
     return {};
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 4 - 4
card/elements/text/model.js

@@ -14,16 +14,16 @@ const MODEL = {
   content: [
     {
       type: "text",
-      content: "样例内容"
-    }
-  ]
+      content: "样例内容",
+    },
+  ],
 };
 
 const getModel = () => {
   return {
     id: getElementId(),
     key: randomCode(),
-    ...deepCopy(MODEL)
+    ...deepCopy(MODEL),
   };
 };
 

+ 5 - 5
card/elements/topic-head/TopicHead.vue

@@ -12,8 +12,8 @@ export default {
   name: "topic-head",
   props: {
     data: {
-      type: Object
-    }
+      type: Object,
+    },
   },
   data() {
     return {};
@@ -22,10 +22,10 @@ export default {
     classes() {
       return [
         "elem-topic-head",
-        { "elem-topic-head-pad": !this.data.isColumnFirst }
+        { "elem-topic-head-pad": !this.data.isColumnFirst },
       ];
-    }
+    },
   },
-  methods: {}
+  methods: {},
 };
 </script>

+ 1 - 1
card/elements/topic-head/model.js

@@ -9,7 +9,7 @@ const MODEL = {
   content: "",
   typeName: "",
   isColumnFirst: false,
-  sign: "objective" // objective:客观题,subjective:主观题
+  sign: "objective", // objective:客观题,subjective:主观题
 };
 
 const getModel = (content, type, isColumnFirst) => {

+ 23 - 23
card/enumerate.js

@@ -3,11 +3,11 @@ export const CARD_VERSION = "2.0.0";
 export const EXAM_NUMBER_STYLE = {
   PRINT: "印刷条码",
   PASTE: "粘贴条码",
-  FILL: "考号填涂"
+  FILL: "考号填涂",
 };
 
 export const PAPER_TYPE = {
-  PRINT: "印刷"
+  PRINT: "印刷",
   // FILL: "填涂"
 };
 
@@ -15,84 +15,84 @@ export const BOOLEAN_TYPE = ["√,×", "是,否", "对,错"];
 
 export const DIRECTION_TYPE = {
   horizontal: "横向",
-  vertical: "纵向"
+  vertical: "纵向",
 };
 
 export const SHORTCUT_KEYS = [
   {
     name: "向上轻微移动",
-    keys: ["ArrowUp"]
+    keys: ["ArrowUp"],
   },
   {
     name: "向下轻微移动",
-    keys: ["ArrowDown"]
+    keys: ["ArrowDown"],
   },
   {
     name: "向左轻微移动",
-    keys: ["ArrowLeft"]
+    keys: ["ArrowLeft"],
   },
   {
     name: "向右轻微移动",
-    keys: ["ArrowRight"]
+    keys: ["ArrowRight"],
   },
   {
     name: "向上大幅移动",
-    keys: ["Shift", "ArrowUp"]
+    keys: ["Shift", "ArrowUp"],
   },
   {
     name: "向下大幅移动",
-    keys: ["Shift", "ArrowDown"]
+    keys: ["Shift", "ArrowDown"],
   },
   {
     name: "向左大幅移动",
-    keys: ["Shift", "ArrowLeft"]
+    keys: ["Shift", "ArrowLeft"],
   },
   {
     name: "向右大幅移动",
-    keys: ["Shift", "ArrowRight"]
+    keys: ["Shift", "ArrowRight"],
   },
   {
     name: "向上移动一层",
-    keys: ["Ctrl", "ArrowUp"]
+    keys: ["Ctrl", "ArrowUp"],
   },
   {
     name: "向下移动一层",
-    keys: ["Ctrl", "ArrowDown"]
+    keys: ["Ctrl", "ArrowDown"],
   },
   {
     name: "复制选中元素",
-    keys: ["Ctrl", "C"]
+    keys: ["Ctrl", "C"],
   },
   {
     name: "粘贴元素",
-    keys: ["Ctrl", "V"]
+    keys: ["Ctrl", "V"],
   },
   {
     name: "编辑选中元素",
-    keys: ["Ctrl", "E"]
+    keys: ["Ctrl", "E"],
   },
   {
     name: "删除选中元素",
-    keys: ["Delete"]
+    keys: ["Delete"],
   },
   {
     name: "新建页面",
-    keys: ["Ctrl", "Alt", "N"]
+    keys: ["Ctrl", "Alt", "N"],
   },
   {
     name: "删除当前页面",
-    keys: ["Ctrl", "Alt", "D"]
+    keys: ["Ctrl", "Alt", "D"],
   },
   {
     name: "预览题卡",
-    keys: ["Ctrl", "P"]
+    keys: ["Ctrl", "P"],
   },
   {
     name: "保存题卡",
-    keys: ["Ctrl", "S"]
+    keys: ["Ctrl", "S"],
   },
   {
     name: "提交题卡",
-    keys: ["Ctrl", "Shift", "S"]
-  }
+    keys: ["Ctrl", "Shift", "S"],
+  },
 ];

+ 1 - 1
card/main.js

@@ -16,5 +16,5 @@ Vue.use(ElementUI);
 new Vue({
   router,
   store,
-  render: h => h(App)
+  render: (h) => h(App),
 }).$mount("#app");

+ 390 - 388
card/mixins/exchange.js

@@ -1,388 +1,390 @@
-import { CARD_VERSION } from "../enumerate";
-import { deepCopy } from "../plugins/utils";
-
-const initIndex = {
-  question: 1,
-  absent: 1,
-  breach: 1,
-  paperType: 1,
-  examNumber: 1,
-  selective: 1,
-  pageNumber: 1
-};
-
-/**
- * 格式文档:https://doc.qmth.com.cn/pages/viewpage.action?pageId=19661052
- */
-export default {
-  data() {
-    return {
-      fillAreaIndex: {
-        ...initIndex
-      },
-      VALID_ELEMENTS_FOR_EXTERNAL: [
-        "LOCATOR",
-        "BARCODE",
-        "CARD_HEAD",
-        "FILL_QUESTION",
-        "FILL_LINE",
-        "EXPLAIN",
-        "COMPOSITION"
-      ]
-    };
-  },
-  methods: {
-    getFillAreaIndex(type) {
-      return this.fillAreaIndex[type]++;
-    },
-    getElementHumpName(cont) {
-      return cont
-        .split("_")
-        .map(item => item[0] + item.substr(1).toLowerCase())
-        .join("");
-    },
-    getPreviewElementById(id) {
-      return document.getElementById(`preview-${id}`);
-    },
-    parsePageExchange(pages) {
-      const npages = deepCopy(pages);
-      // 单页题卡不显示页码涂块
-      const pageNumberInfo =
-        pages.length <= 2 ? null : this.getPageNumberInfo();
-      npages.forEach((page, pindex) => {
-        let exchange = {
-          card_type: 2,
-          page_size: page.pageSize,
-          page_image: "",
-          locator: this.getLocatorInfo(page.locators),
-          fill_locator: [],
-          check_area: {
-            black_line: [],
-            white_line: []
-          },
-          barcode: [],
-          qrcode: [],
-          ocr_area: [],
-          info_area: [],
-          fill_area: [],
-          answer_area: [],
-          extension: {
-            barcode: [],
-            fill_area: [],
-            ocr_area: [],
-            qrcode: []
-          }
-        };
-        const elements = [
-          page.globals,
-          ...page.columns.map(column => column.elements)
-        ];
-
-        elements.forEach(elemGroup => {
-          elemGroup.forEach(element => {
-            if (this.VALID_ELEMENTS_FOR_EXTERNAL.includes(element.type)) {
-              const funcName = this.getElementHumpName(element.type);
-              // console.log(funcName);
-              const info = this[`get${funcName}Info`](element);
-              Object.entries(info).forEach(([key, vals]) => {
-                exchange[key] = exchange[key].concat(vals);
-              });
-            }
-          });
-        });
-
-        if (!(pindex % 2) && pageNumberInfo) {
-          let pnoInfo = deepCopy(pageNumberInfo);
-          pnoInfo[0].index = this.getFillAreaIndex("pageNumber");
-          exchange.fill_area = exchange.fill_area.concat(pnoInfo);
-        }
-
-        page.exchange = exchange;
-      });
-
-      this.fillAreaIndex = { ...initIndex };
-
-      return npages;
-    },
-    getPageNumberInfo() {
-      const dom = document.querySelector(".page-box-0");
-      let options = [];
-      dom
-        .querySelector(".page-number-rect-list")
-        .childNodes.forEach((item, index) => {
-          options[index] = this.getOffsetInfo(item);
-        });
-      // console.log(options);
-      return [
-        {
-          field: "pageNumber",
-          index: 1,
-          single: true,
-          horizontal: true,
-          items: [
-            {
-              main_number: null,
-              sub_number: null,
-              options,
-              recog_info: []
-            }
-          ]
-        }
-      ];
-    },
-    getLocatorInfo(locators) {
-      const tops = locators.top.map(locator => {
-        return this.getOffsetInfo(document.getElementById(locator.id));
-      });
-      const bottoms = locators.bottom.map(locator => {
-        return this.getOffsetInfo(document.getElementById(locator.id));
-      });
-
-      return {
-        top: tops,
-        bottom: bottoms
-      };
-    },
-    getCardHeadInfo(element) {
-      const dom = this.getPreviewElementById(element.id);
-      const headArea = this.getOffsetInfo(dom);
-      let fill_area = [];
-      let barcode = [];
-      // 学生考号
-      if (element.examNumberStyle === "FILL") {
-        // fill_area
-        let listInfos = [];
-        dom
-          .querySelectorAll(".stdno-fill-list")
-          .forEach((questionItem, questionIndex) => {
-            let options = [];
-            questionItem.childNodes.forEach((optionItem, optionIndex) => {
-              options[optionIndex] = this.getOffsetInfo(optionItem);
-            });
-            listInfos[questionIndex] = {
-              main_number: null,
-              sub_number: null,
-              options,
-              recog_info: []
-            };
-          });
-
-        fill_area.push({
-          field: "examNumber",
-          index: this.getFillAreaIndex("examNumber"),
-          single: true,
-          horizontal: false,
-          items: listInfos
-        });
-      } else {
-        // barcode
-        const stdnoDom =
-          element.columnNumber <= 2
-            ? dom.querySelector(".head-stdno").parentNode
-            : dom.querySelector(".head-stdno");
-        barcode.push({
-          field: "examNumber",
-          area: this.getOffsetInfo(stdnoDom)
-        });
-      }
-      // 缺考涂填
-      if (element.examAbsent && !element.isSimple) {
-        fill_area.push({
-          field: "absent",
-          index: this.getFillAreaIndex("absent"),
-          single: true,
-          horizontal: true,
-          items: [
-            {
-              main_number: null,
-              sub_number: null,
-              options: [
-                this.getOffsetInfo(document.getElementById("dynamic-miss-area"))
-              ],
-              recog_info: []
-            }
-          ]
-        });
-      }
-      // 违纪标记
-      if (element.discipline && !element.isSimple) {
-        fill_area.push({
-          field: "breach",
-          index: this.getFillAreaIndex("breach"),
-          single: true,
-          horizontal: true,
-          items: [
-            {
-              main_number: null,
-              sub_number: null,
-              options: [
-                this.getOffsetInfo(
-                  document.getElementById("dynamic-breach-area")
-                )
-              ],
-              recog_info: []
-            }
-          ]
-        });
-      }
-      // A/B卷类型
-      if (element.aOrB && !element.isSimple) {
-        if (element.paperType === "PRINT") {
-          // barcode
-          barcode.push({
-            field: "paperType",
-            area: this.getOffsetInfo(
-              document.getElementById("dynamic-aorb-barcode")
-            )
-          });
-        } else {
-          // fill_area
-          let options = [];
-          document
-            .getElementById("head-dynamic-aorb")
-            .querySelectorAll(".head-dynamic-rect")
-            .forEach((optionItem, optionIndex) => {
-              options[optionIndex] = this.getOffsetInfo(optionItem);
-            });
-          fill_area.push({
-            field: "paperType",
-            index: this.getFillAreaIndex("paperType"),
-            single: true,
-            horizontal: true,
-            items: [
-              {
-                main_number: null,
-                sub_number: null,
-                options,
-                recog_info: []
-              }
-            ]
-          });
-        }
-      }
-
-      return {
-        info_area: [headArea],
-        fill_area,
-        barcode
-      };
-    },
-    getFillQuestionInfo(element) {
-      const dom = this.getPreviewElementById(element.id);
-      const single = !element.isMultiply;
-      const horizontal = element.optionDirection === "horizontal";
-
-      let fillAreas = [];
-      dom.querySelectorAll(".group-item").forEach(groupItem => {
-        let listInfos = [];
-
-        groupItem
-          .querySelectorAll(".question-item")
-          .forEach((questionItem, questionIndex) => {
-            let options = [];
-            questionItem.childNodes.forEach((optionItem, optionIndex) => {
-              if (optionIndex)
-                options[optionIndex - 1] = this.getOffsetInfo(optionItem);
-            });
-            listInfos[questionIndex] = {
-              main_number: element.topicNo,
-              sub_number: questionItem.firstChild.textContent * 1,
-              options,
-              recog_info: []
-            };
-          });
-        fillAreas.push({
-          field: "question",
-          index: this.getFillAreaIndex("question"),
-          single,
-          horizontal,
-          items: listInfos
-        });
-      });
-
-      return {
-        fill_area: fillAreas
-      };
-    },
-    getFillLineInfo(element) {
-      const dom = this.getPreviewElementById(element.id);
-      let sub_numbers = [];
-      for (
-        let i = element.startNumber,
-          len = element.startNumber + element.questionsCount;
-        i < len;
-        i++
-      ) {
-        sub_numbers.push(i);
-      }
-
-      return {
-        answer_area: [
-          {
-            main_number: element.topicNo,
-            sub_number: sub_numbers.join(),
-            area: this.getOffsetInfo(dom)
-          }
-        ]
-      };
-    },
-    getExplainInfo(element) {
-      const dom = this.getPreviewElementById(element.id);
-
-      return {
-        answer_area: [
-          {
-            main_number: element.topicNo,
-            sub_number: element.serialNumber,
-            area: this.getOffsetInfo(dom)
-          }
-        ]
-      };
-    },
-    getCompositionInfo(element) {
-      const dom = this.getPreviewElementById(element.id);
-
-      return {
-        answer_area: [
-          {
-            main_number: element.topicNo,
-            sub_number: null,
-            area: this.getOffsetInfo(dom)
-          }
-        ]
-      };
-    },
-    getOffsetInfo(dom) {
-      let { offsetTop, offsetLeft } = dom;
-      let parentNode = dom.offsetParent;
-      while (parentNode.className.indexOf("page-box") === -1) {
-        offsetTop += parentNode.offsetTop;
-        offsetLeft += parentNode.offsetLeft;
-        parentNode = parentNode.offsetParent;
-      }
-      const pw = parentNode.offsetWidth;
-      const ph = parentNode.offsetHeight;
-
-      const infos = [
-        offsetLeft / pw,
-        offsetTop / ph,
-        dom.offsetWidth / pw,
-        dom.offsetHeight / ph
-      ];
-
-      return infos.map(num => num.toFixed(10) * 1);
-    },
-    getPageModel({ cardConfig, paperParams, pages }) {
-      let npages = this.parsePageExchange(pages);
-      return JSON.stringify(
-        {
-          version: CARD_VERSION,
-          cardConfig,
-          paperParams,
-          pages: npages
-        },
-        (k, v) => (k.startsWith("_") ? undefined : v)
-      );
-    }
-  }
-};
+import { CARD_VERSION } from "../enumerate";
+import { deepCopy } from "../plugins/utils";
+
+const initIndex = {
+  question: 1,
+  absent: 1,
+  breach: 1,
+  paperType: 1,
+  examNumber: 1,
+  selective: 1,
+  pageNumber: 1,
+};
+
+/**
+ * 格式文档:https://doc.qmth.com.cn/pages/viewpage.action?pageId=19661052
+ */
+export default {
+  data() {
+    return {
+      fillAreaIndex: {
+        ...initIndex,
+      },
+      VALID_ELEMENTS_FOR_EXTERNAL: [
+        "LOCATOR",
+        "BARCODE",
+        "CARD_HEAD",
+        "FILL_QUESTION",
+        "FILL_LINE",
+        "EXPLAIN",
+        "COMPOSITION",
+      ],
+    };
+  },
+  methods: {
+    getFillAreaIndex(type) {
+      return this.fillAreaIndex[type]++;
+    },
+    getElementHumpName(cont) {
+      return cont
+        .split("_")
+        .map((item) => item[0] + item.substr(1).toLowerCase())
+        .join("");
+    },
+    getPreviewElementById(id) {
+      return document.getElementById(`preview-${id}`);
+    },
+    parsePageExchange(pages) {
+      const npages = deepCopy(pages);
+      // 单页题卡不显示页码涂块
+      const pageNumberInfo =
+        pages.length <= 2 ? null : this.getPageNumberInfo();
+      npages.forEach((page, pindex) => {
+        let exchange = {
+          card_type: 2,
+          page_size: page.pageSize,
+          page_image: "",
+          locator: this.getLocatorInfo(page.locators),
+          fill_locator: [],
+          check_area: {
+            black_line: [],
+            white_line: [],
+          },
+          barcode: [],
+          qrcode: [],
+          ocr_area: [],
+          info_area: [],
+          fill_area: [],
+          answer_area: [],
+          extension: {
+            barcode: [],
+            fill_area: [],
+            ocr_area: [],
+            qrcode: [],
+          },
+        };
+        const elements = [
+          page.globals,
+          ...page.columns.map((column) => column.elements),
+        ];
+
+        elements.forEach((elemGroup) => {
+          elemGroup.forEach((element) => {
+            if (this.VALID_ELEMENTS_FOR_EXTERNAL.includes(element.type)) {
+              const funcName = this.getElementHumpName(element.type);
+              // console.log(funcName);
+              const info = this[`get${funcName}Info`](element);
+              Object.entries(info).forEach(([key, vals]) => {
+                exchange[key] = exchange[key].concat(vals);
+              });
+            }
+          });
+        });
+
+        if (!(pindex % 2) && pageNumberInfo) {
+          let pnoInfo = deepCopy(pageNumberInfo);
+          pnoInfo[0].index = this.getFillAreaIndex("pageNumber");
+          exchange.fill_area = exchange.fill_area.concat(pnoInfo);
+        }
+
+        page.exchange = exchange;
+      });
+
+      this.fillAreaIndex = { ...initIndex };
+
+      return npages;
+    },
+    getPageNumberInfo() {
+      const dom = document.querySelector(".page-box-0");
+      let options = [];
+      dom
+        .querySelector(".page-number-rect-list")
+        .childNodes.forEach((item, index) => {
+          options[index] = this.getOffsetInfo(item);
+        });
+      // console.log(options);
+      return [
+        {
+          field: "pageNumber",
+          index: 1,
+          single: true,
+          horizontal: true,
+          items: [
+            {
+              main_number: null,
+              sub_number: null,
+              options,
+              recog_info: [],
+            },
+          ],
+        },
+      ];
+    },
+    getLocatorInfo(locators) {
+      const tops = locators.top.map((locator) => {
+        return this.getOffsetInfo(document.getElementById(locator.id));
+      });
+      const bottoms = locators.bottom.map((locator) => {
+        return this.getOffsetInfo(document.getElementById(locator.id));
+      });
+
+      return {
+        top: tops,
+        bottom: bottoms,
+      };
+    },
+    getCardHeadInfo(element) {
+      const dom = this.getPreviewElementById(element.id);
+      const headArea = this.getOffsetInfo(dom);
+      let fill_area = [];
+      let barcode = [];
+      // 学生考号
+      if (element.examNumberStyle === "FILL") {
+        // fill_area
+        let listInfos = [];
+        dom
+          .querySelectorAll(".stdno-fill-list")
+          .forEach((questionItem, questionIndex) => {
+            let options = [];
+            questionItem.childNodes.forEach((optionItem, optionIndex) => {
+              options[optionIndex] = this.getOffsetInfo(optionItem);
+            });
+            listInfos[questionIndex] = {
+              main_number: null,
+              sub_number: null,
+              options,
+              recog_info: [],
+            };
+          });
+
+        fill_area.push({
+          field: "examNumber",
+          index: this.getFillAreaIndex("examNumber"),
+          single: true,
+          horizontal: false,
+          items: listInfos,
+        });
+      } else {
+        // barcode
+        const stdnoDom =
+          element.columnNumber <= 2
+            ? dom.querySelector(".head-stdno").parentNode
+            : dom.querySelector(".head-stdno");
+        barcode.push({
+          field: "examNumber",
+          area: this.getOffsetInfo(stdnoDom),
+        });
+      }
+      // 缺考涂填
+      if (element.examAbsent && !element.isSimple) {
+        fill_area.push({
+          field: "absent",
+          index: this.getFillAreaIndex("absent"),
+          single: true,
+          horizontal: true,
+          items: [
+            {
+              main_number: null,
+              sub_number: null,
+              options: [
+                this.getOffsetInfo(
+                  document.getElementById("dynamic-miss-area")
+                ),
+              ],
+              recog_info: [],
+            },
+          ],
+        });
+      }
+      // 违纪标记
+      if (element.discipline && !element.isSimple) {
+        fill_area.push({
+          field: "breach",
+          index: this.getFillAreaIndex("breach"),
+          single: true,
+          horizontal: true,
+          items: [
+            {
+              main_number: null,
+              sub_number: null,
+              options: [
+                this.getOffsetInfo(
+                  document.getElementById("dynamic-breach-area")
+                ),
+              ],
+              recog_info: [],
+            },
+          ],
+        });
+      }
+      // A/B卷类型
+      if (element.aOrB && !element.isSimple) {
+        if (element.paperType === "PRINT") {
+          // barcode
+          barcode.push({
+            field: "paperType",
+            area: this.getOffsetInfo(
+              document.getElementById("dynamic-aorb-barcode")
+            ),
+          });
+        } else {
+          // fill_area
+          let options = [];
+          document
+            .getElementById("head-dynamic-aorb")
+            .querySelectorAll(".head-dynamic-rect")
+            .forEach((optionItem, optionIndex) => {
+              options[optionIndex] = this.getOffsetInfo(optionItem);
+            });
+          fill_area.push({
+            field: "paperType",
+            index: this.getFillAreaIndex("paperType"),
+            single: true,
+            horizontal: true,
+            items: [
+              {
+                main_number: null,
+                sub_number: null,
+                options,
+                recog_info: [],
+              },
+            ],
+          });
+        }
+      }
+
+      return {
+        info_area: [headArea],
+        fill_area,
+        barcode,
+      };
+    },
+    getFillQuestionInfo(element) {
+      const dom = this.getPreviewElementById(element.id);
+      const single = !element.isMultiply;
+      const horizontal = element.optionDirection === "horizontal";
+
+      let fillAreas = [];
+      dom.querySelectorAll(".group-item").forEach((groupItem) => {
+        let listInfos = [];
+
+        groupItem
+          .querySelectorAll(".question-item")
+          .forEach((questionItem, questionIndex) => {
+            let options = [];
+            questionItem.childNodes.forEach((optionItem, optionIndex) => {
+              if (optionIndex)
+                options[optionIndex - 1] = this.getOffsetInfo(optionItem);
+            });
+            listInfos[questionIndex] = {
+              main_number: element.topicNo,
+              sub_number: questionItem.firstChild.textContent * 1,
+              options,
+              recog_info: [],
+            };
+          });
+        fillAreas.push({
+          field: "question",
+          index: this.getFillAreaIndex("question"),
+          single,
+          horizontal,
+          items: listInfos,
+        });
+      });
+
+      return {
+        fill_area: fillAreas,
+      };
+    },
+    getFillLineInfo(element) {
+      const dom = this.getPreviewElementById(element.id);
+      let sub_numbers = [];
+      for (
+        let i = element.startNumber,
+          len = element.startNumber + element.questionsCount;
+        i < len;
+        i++
+      ) {
+        sub_numbers.push(i);
+      }
+
+      return {
+        answer_area: [
+          {
+            main_number: element.topicNo,
+            sub_number: sub_numbers.join(),
+            area: this.getOffsetInfo(dom),
+          },
+        ],
+      };
+    },
+    getExplainInfo(element) {
+      const dom = this.getPreviewElementById(element.id);
+
+      return {
+        answer_area: [
+          {
+            main_number: element.topicNo,
+            sub_number: element.serialNumber,
+            area: this.getOffsetInfo(dom),
+          },
+        ],
+      };
+    },
+    getCompositionInfo(element) {
+      const dom = this.getPreviewElementById(element.id);
+
+      return {
+        answer_area: [
+          {
+            main_number: element.topicNo,
+            sub_number: null,
+            area: this.getOffsetInfo(dom),
+          },
+        ],
+      };
+    },
+    getOffsetInfo(dom) {
+      let { offsetTop, offsetLeft } = dom;
+      let parentNode = dom.offsetParent;
+      while (parentNode.className.indexOf("page-box") === -1) {
+        offsetTop += parentNode.offsetTop;
+        offsetLeft += parentNode.offsetLeft;
+        parentNode = parentNode.offsetParent;
+      }
+      const pw = parentNode.offsetWidth;
+      const ph = parentNode.offsetHeight;
+
+      const infos = [
+        offsetLeft / pw,
+        offsetTop / ph,
+        dom.offsetWidth / pw,
+        dom.offsetHeight / ph,
+      ];
+
+      return infos.map((num) => num.toFixed(10) * 1);
+    },
+    getPageModel({ cardConfig, paperParams, pages }) {
+      let npages = this.parsePageExchange(pages);
+      return JSON.stringify(
+        {
+          version: CARD_VERSION,
+          cardConfig,
+          paperParams,
+          pages: npages,
+        },
+        (k, v) => (k.startsWith("_") ? undefined : v)
+      );
+    },
+  },
+};

Some files were not shown because too many files changed in this diff