소스 검색

题卡新卡格式更新

zhangjie 2 년 전
부모
커밋
f0da75cfed

+ 16 - 32
card/assets/styles/card-preview.scss

@@ -313,47 +313,31 @@
 }
 
 // locator
-.page-locators {
+.page-locator {
   position: absolute;
-  top: 60px;
   left: 80px;
   right: 80px;
-  bottom: 86px;
+  height: 16px;
   z-index: 8;
-}
-.page-locator-group {
-  position: absolute;
-  top: 0;
-  bottom: 0;
-  width: 24px;
-  &:first-child {
-    left: 0;
-  }
-  &:nth-of-type(2) {
-    left: 50%;
-    margin-left: -12px;
+
+  &-top {
+    top: 40px;
   }
-  &:last-child {
-    left: auto;
-    right: 96px;
+  &-bottom {
+    bottom: 40px;
   }
-  li {
+
+  &-item {
     position: absolute;
     width: 24px;
     border-bottom: 16px solid #000;
-    z-index: 99;
-    &:first-child {
-      top: -20px;
-    }
-    &:last-child {
-      bottom: -46px;
+    top: 0;
+
+    &:nth-of-type(1) {
+      left: 0;
     }
-  }
-}
-.page-box-1 {
-  .page-locator-group {
-    &:first-child {
-      left: -30px;
+    &:nth-of-type(2) {
+      right: 96px;
     }
   }
 }
@@ -362,7 +346,7 @@
   position: absolute;
   bottom: 40px;
   &-rect {
-    left: 152px;
+    left: 252px;
   }
   &-rect-list {
     font-size: 0;

+ 12 - 27
card/assets/styles/card-temp.css

@@ -249,45 +249,30 @@
   .element-item-card-head.element-item-type-pre::before {
   border-bottom: 0;
 }
-.page-locators {
+.page-locator {
   position: absolute;
-  top: 60px;
   left: 80px;
   right: 80px;
-  bottom: 86px;
+  height: 16px;
   z-index: 8;
 }
-.page-locator-group {
-  position: absolute;
-  top: 0;
-  bottom: 0;
-  width: 24px;
-}
-.page-locator-group:first-child {
-  left: 0;
-}
-.page-locator-group:nth-of-type(2) {
-  left: 50%;
-  margin-left: -12px;
+.page-locator-top {
+  top: 40px;
 }
-.page-locator-group:last-child {
-  left: auto;
-  right: 96px;
+.page-locator-bottom {
+  bottom: 40px;
 }
-.page-locator-group li {
+.page-locator-item {
   position: absolute;
   width: 24px;
   border-bottom: 16px solid #000;
-  z-index: 99;
-}
-.page-locator-group li:first-child {
-  top: -20px;
+  top: 0;
 }
-.page-locator-group li:last-child {
-  bottom: -46px;
+.page-locator-item:nth-of-type(1) {
+  left: 0;
 }
-.page-box-1 .page-locator-group:first-child {
-  left: -30px;
+.page-locator-item:nth-of-type(2) {
+  right: 96px;
 }
 .page-number {
   position: absolute;

+ 16 - 17
card/components/CardDesign.vue

@@ -119,23 +119,22 @@
           ]"
           v-if="curPage.locators"
         >
-          <div
-            :class="[
-              'page-locators',
-              `page-locators-${curPage.locators.length}`
-            ]"
-          >
-            <ul
-              class="page-locator-group"
-              v-for="(locator, iind) in curPage.locators"
-              :key="iind"
-            >
-              <li
-                v-for="(elem, eindex) in locator"
-                :key="eindex"
-                :id="elem.id"
-              ></li>
-            </ul>
+          <!-- 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">

+ 16 - 14
card/components/CardView.vue

@@ -10,20 +10,22 @@
         ]"
         :key="pageNo"
       >
-        <div
-          :class="['page-locators', `page-locators-${page.locators.length}`]"
-        >
-          <ul
-            class="page-locator-group"
-            v-for="(locator, iind) in page.locators"
-            :key="iind"
-          >
-            <li
-              v-for="(elem, eindex) in locator"
-              :key="eindex"
-              :id="elem.id"
-            ></li>
-          </ul>
+        <!-- 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">

+ 187 - 174
card/elementModel.js

@@ -1,174 +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",
-  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 getNewPage = (pageNo, { pageSize, columnNumber }) => {
-  let npage = deepCopy(PAGE);
-  if (
-    (pageSize === "A3" && columnNumber === 4) ||
-    (pageSize === "A4" && columnNumber === 2)
-  ) {
-    npage.columnGap = 10;
-  }
-  const num = pageSize === "A3" ? 3 : 2;
-  npage.locators = getNumList(num).map((item, index) => {
-    return [
-      {
-        ...LOCATOR,
-        id: `locator-${pageNo}-${index}0`
-      },
-      {
-        ...LOCATOR,
-        id: `locator-${pageNo}-${index}1`
-      }
-    ];
-  });
-  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
+};

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

@@ -1,69 +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 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;
-  }
-
-  const num = pageSize === "A3" ? 3 : 2;
-  npage.locators = getNumList(num).map((item, index) => {
-    const id = getElementId();
-    return [
-      {
-        ...LOCATOR,
-        id: `locator-${id}-${index}0`
-      },
-      {
-        ...LOCATOR,
-        id: `locator-${id}-${index}1`
-      }
-    ];
-  });
-  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 };

+ 44 - 21
card/mixins/exchange.js

@@ -10,6 +10,9 @@ const initIndex = {
   pageNumber: 1
 };
 
+/**
+ * 格式文档:https://doc.qmth.com.cn/pages/viewpage.action?pageId=19661052
+ */
 export default {
   data() {
     return {
@@ -47,11 +50,27 @@ export default {
         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: []
+          answer_area: [],
+          extension: {
+            barcode: [],
+            fill_area: [],
+            ocr_area: [],
+            qrcode: []
+          }
         };
         const elements = [
           page.globals,
@@ -62,7 +81,7 @@ export default {
           elemGroup.forEach(element => {
             if (this.VALID_ELEMENTS_FOR_EXTERNAL.includes(element.type)) {
               const funcName = this.getElementHumpName(element.type);
-              console.log(funcName);
+              // console.log(funcName);
               const info = this[`get${funcName}Info`](element);
               Object.entries(info).forEach(([key, vals]) => {
                 exchange[key] = exchange[key].concat(vals);
@@ -103,22 +122,25 @@ export default {
             {
               main_number: null,
               sub_number: null,
-              options
+              options,
+              recog_info: []
             }
           ]
         }
       ];
     },
     getLocatorInfo(locators) {
-      return locators.map(locatorGroup => {
-        const locatorInfos = locatorGroup.map(locator => {
-          return this.getOffsetInfo(document.getElementById(locator.id));
-        });
-        return {
-          top: locatorInfos[0],
-          bottom: locatorInfos[1]
-        };
+      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);
@@ -139,7 +161,8 @@ export default {
             listInfos[questionIndex] = {
               main_number: null,
               sub_number: null,
-              options
+              options,
+              recog_info: []
             };
           });
 
@@ -174,7 +197,8 @@ export default {
               sub_number: null,
               options: [
                 this.getOffsetInfo(document.getElementById("dynamic-miss-area"))
-              ]
+              ],
+              recog_info: []
             }
           ]
         });
@@ -207,7 +231,8 @@ export default {
               {
                 main_number: null,
                 sub_number: null,
-                options
+                options,
+                recog_info: []
               }
             ]
           });
@@ -240,7 +265,8 @@ export default {
             listInfos[questionIndex] = {
               main_number: element.topicNo,
               sub_number: questionItem.firstChild.textContent * 1,
-              options
+              options,
+              recog_info: []
             };
           });
         fillAreas.push({
@@ -272,7 +298,7 @@ export default {
         answer_area: [
           {
             main_number: element.topicNo,
-            sub_numbers,
+            sub_number: sub_numbers.join(),
             area: this.getOffsetInfo(dom)
           }
         ]
@@ -285,7 +311,7 @@ export default {
         answer_area: [
           {
             main_number: element.topicNo,
-            sub_numbers: [element.serialNumber],
+            sub_number: element.serialNumber,
             area: this.getOffsetInfo(dom)
           }
         ]
@@ -298,7 +324,7 @@ export default {
         answer_area: [
           {
             main_number: element.topicNo,
-            sub_numbers: [],
+            sub_number: null,
             area: this.getOffsetInfo(dom)
           }
         ]
@@ -326,9 +352,6 @@ export default {
     },
     getPageModel({ cardConfig, paperParams, pages }) {
       let npages = this.parsePageExchange(pages);
-      npages.forEach(page => {
-        page.exchange.page_size = cardConfig.pageSize;
-      });
       return JSON.stringify(
         {
           version: CARD_VERSION,

+ 311 - 299
card/modules/free/cardFormatTransform.js

@@ -1,299 +1,311 @@
-import { CARD_VERSION } from "../../enumerate";
-import { deepCopy } from "../../plugins/utils";
-
-const initIndex = {
-  question: 1,
-  absent: 1,
-  paperType: 1,
-  examNumber: 1,
-  selective: 1,
-  pageNumber: 1
-};
-let fillAreaIndex = { ...initIndex };
-
-const VALID_ELEMENTS_FOR_EXTERNAL = [
-  "LOCATOR",
-  "BARCODE",
-  "FILL_QUESTION",
-  "FILL_LINE",
-  "FILL_NUMBER",
-  "FILL_FIELD",
-  "FILL_TABLE",
-  "LINES",
-  "GRIDS"
-];
-
-function initFillAreaIndex() {
-  fillAreaIndex = { ...initIndex };
-}
-
-function getFillAreaIndex(type) {
-  return fillAreaIndex[type]++;
-}
-
-function getPreviewElementById(id) {
-  return document.getElementById(`preview-${id}`);
-}
-
-function 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);
-}
-
-// locator: [],
-// barcode: [],
-// info_area: [],
-// fill_area: [],
-// answer_area: []
-
-const elementInfoFunc = {
-  LOCATOR: locators => {
-    const result = locators.map(locatorGroup => {
-      const locatorInfos = locatorGroup.map(locator => {
-        return getOffsetInfo(document.getElementById(locator.id));
-      });
-      return {
-        top: locatorInfos[0],
-        bottom: locatorInfos[1]
-      };
-    });
-    return {
-      locator: result
-    };
-  },
-  BARCODE: element => {
-    return {
-      barcode: [
-        {
-          field: element.field,
-          area: getOffsetInfo(getPreviewElementById(element.id))
-        }
-      ]
-    };
-  },
-  FILL_QUESTION: element => {
-    const dom = 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] = getOffsetInfo(optionItem);
-          });
-          listInfos[questionIndex] = {
-            main_number: element.topicNo,
-            sub_number: questionItem.firstChild.textContent * 1,
-            options
-          };
-        });
-      fillAreas.push({
-        field: "question",
-        index: getFillAreaIndex("question"),
-        single,
-        horizontal,
-        items: listInfos
-      });
-    });
-
-    return {
-      fill_area: fillAreas
-    };
-  },
-  FILL_LINE: element => {
-    const dom = 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_numbers,
-          area: getOffsetInfo(dom)
-        }
-      ]
-    };
-  },
-  FILL_NUMBER: element => {
-    let listInfos = [];
-    const dom = getPreviewElementById(element.id);
-
-    dom
-      .querySelectorAll(".fill-number-list")
-      .forEach((questionItem, questionIndex) => {
-        let options = [];
-        questionItem.childNodes.forEach((optionItem, optionIndex) => {
-          options[optionIndex] = getOffsetInfo(optionItem);
-        });
-        listInfos[questionIndex] = {
-          main_number: null,
-          sub_number: null,
-          options
-        };
-      });
-
-    return {
-      fill_area: [
-        {
-          field: "examNumber",
-          index: getFillAreaIndex("examNumber"),
-          single: true,
-          horizontal: false,
-          items: listInfos
-        }
-      ]
-    };
-  },
-  FILL_FIELD: element => {
-    const dom = getPreviewElementById(element.id);
-
-    return {
-      info_area: [getOffsetInfo(dom)]
-    };
-  },
-  FILL_TABLE: element => {
-    const dom = getPreviewElementById(element.id);
-
-    return {
-      info_area: [getOffsetInfo(dom)]
-    };
-  },
-  LINES: element => {
-    const dom = getPreviewElementById(element.id);
-
-    return {
-      answer_area: [
-        {
-          main_number: null,
-          sub_numbers: null,
-          area: getOffsetInfo(dom)
-        }
-      ]
-    };
-  },
-  GRIDS: element => {
-    const dom = getPreviewElementById(element.id);
-
-    return {
-      answer_area: [
-        {
-          main_number: null,
-          sub_numbers: null,
-          area: getOffsetInfo(dom)
-        }
-      ]
-    };
-  }
-};
-
-function getPageNumberInfo() {
-  const dom = document.querySelector(".page-box-0");
-  let options = [];
-  dom
-    .querySelector(".page-number-rect-list")
-    .childNodes.forEach((item, index) => {
-      options[index] = getOffsetInfo(item);
-    });
-  return [
-    {
-      field: "pageNumber",
-      index: 1,
-      single: true,
-      horizontal: true,
-      items: [
-        {
-          main_number: null,
-          sub_number: null,
-          options
-        }
-      ]
-    }
-  ];
-}
-
-function parsePageExchange(pages) {
-  initFillAreaIndex();
-
-  const npages = deepCopy(pages);
-  const pageNumberInfo = getPageNumberInfo();
-  npages.forEach((page, pindex) => {
-    let exchange = {
-      locator: elementInfoFunc.LOCATOR(page.locators),
-      barcode: [],
-      info_area: [],
-      fill_area: [],
-      answer_area: []
-    };
-    const elements = [
-      page.globals,
-      ...page.columns.map(column => column.elements)
-    ];
-
-    elements.forEach(elemGroup => {
-      elemGroup.forEach(element => {
-        if (!VALID_ELEMENTS_FOR_EXTERNAL.includes(element.type)) return;
-        const info = elementInfoFunc[element.type](element);
-        Object.entries(info).forEach(([key, vals]) => {
-          exchange[key] = exchange[key].concat(vals);
-        });
-      });
-    });
-
-    if (!(pindex % 2)) {
-      let pnoInfo = deepCopy(pageNumberInfo);
-      pnoInfo[0].index = getFillAreaIndex("pageNumber");
-      exchange.fill_area = exchange.fill_area.concat(pnoInfo);
-    }
-
-    page.exchange = exchange;
-  });
-
-  return npages;
-}
-
-export function getPageModel({ cardConfig, paperParams, pages }) {
-  let npages = parsePageExchange(pages);
-  npages.forEach(page => {
-    page.exchange.page_size = cardConfig.pageSize;
-  });
-  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,
+  paperType: 1,
+  examNumber: 1,
+  selective: 1,
+  pageNumber: 1
+};
+let fillAreaIndex = { ...initIndex };
+
+const VALID_ELEMENTS_FOR_EXTERNAL = [
+  "LOCATOR",
+  "BARCODE",
+  "FILL_QUESTION",
+  "FILL_LINE",
+  "FILL_NUMBER",
+  "FILL_FIELD",
+  "FILL_TABLE",
+  "LINES",
+  "GRIDS"
+];
+
+function initFillAreaIndex() {
+  fillAreaIndex = { ...initIndex };
+}
+
+function getFillAreaIndex(type) {
+  return fillAreaIndex[type]++;
+}
+
+function getPreviewElementById(id) {
+  return document.getElementById(`preview-${id}`);
+}
+
+function 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);
+}
+
+// locator: [],
+// barcode: [],
+// info_area: [],
+// fill_area: [],
+// answer_area: []
+
+const elementInfoFunc = {
+  LOCATOR: locators => {
+    const tops = locators.top.map(locator => {
+      return getOffsetInfo(document.getElementById(locator.id));
+    });
+    const bottoms = locators.bottom.map(locator => {
+      return getOffsetInfo(document.getElementById(locator.id));
+    });
+
+    return { top: tops, bottom: bottoms };
+  },
+  BARCODE: element => {
+    return {
+      barcode: [
+        {
+          field: element.field,
+          area: getOffsetInfo(getPreviewElementById(element.id))
+        }
+      ]
+    };
+  },
+  FILL_QUESTION: element => {
+    const dom = 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] = getOffsetInfo(optionItem);
+          });
+          listInfos[questionIndex] = {
+            main_number: element.topicNo,
+            sub_number: questionItem.firstChild.textContent * 1,
+            options,
+            recog_info: []
+          };
+        });
+      fillAreas.push({
+        field: "question",
+        index: getFillAreaIndex("question"),
+        single,
+        horizontal,
+        items: listInfos
+      });
+    });
+
+    return {
+      fill_area: fillAreas
+    };
+  },
+  FILL_LINE: element => {
+    const dom = 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: getOffsetInfo(dom)
+        }
+      ]
+    };
+  },
+  FILL_NUMBER: element => {
+    let listInfos = [];
+    const dom = getPreviewElementById(element.id);
+
+    dom
+      .querySelectorAll(".fill-number-list")
+      .forEach((questionItem, questionIndex) => {
+        let options = [];
+        questionItem.childNodes.forEach((optionItem, optionIndex) => {
+          options[optionIndex] = getOffsetInfo(optionItem);
+        });
+        listInfos[questionIndex] = {
+          main_number: null,
+          sub_number: null,
+          options,
+          recog_info: []
+        };
+      });
+
+    return {
+      fill_area: [
+        {
+          field: "examNumber",
+          index: getFillAreaIndex("examNumber"),
+          single: true,
+          horizontal: false,
+          items: listInfos
+        }
+      ]
+    };
+  },
+  FILL_FIELD: element => {
+    const dom = getPreviewElementById(element.id);
+
+    return {
+      info_area: [getOffsetInfo(dom)]
+    };
+  },
+  FILL_TABLE: element => {
+    const dom = getPreviewElementById(element.id);
+
+    return {
+      info_area: [getOffsetInfo(dom)]
+    };
+  },
+  LINES: element => {
+    const dom = getPreviewElementById(element.id);
+
+    return {
+      answer_area: [
+        {
+          main_number: null,
+          sub_number: null,
+          area: getOffsetInfo(dom)
+        }
+      ]
+    };
+  },
+  GRIDS: element => {
+    const dom = getPreviewElementById(element.id);
+
+    return {
+      answer_area: [
+        {
+          main_number: null,
+          sub_number: null,
+          area: getOffsetInfo(dom)
+        }
+      ]
+    };
+  }
+};
+
+function getPageNumberInfo() {
+  const dom = document.querySelector(".page-box-0");
+  let options = [];
+  dom
+    .querySelector(".page-number-rect-list")
+    .childNodes.forEach((item, index) => {
+      options[index] = getOffsetInfo(item);
+    });
+  return [
+    {
+      field: "pageNumber",
+      index: 1,
+      single: true,
+      horizontal: true,
+      items: [
+        {
+          main_number: null,
+          sub_number: null,
+          options,
+          recog_info: []
+        }
+      ]
+    }
+  ];
+}
+
+function parsePageExchange(pages) {
+  initFillAreaIndex();
+
+  const npages = deepCopy(pages);
+  const pageNumberInfo = pages.length > 2 ? getPageNumberInfo() : null;
+  npages.forEach((page, pindex) => {
+    let exchange = {
+      card_type: 2,
+      page_size: page.pageSize,
+      page_image: "",
+      locator: elementInfoFunc.LOCATOR(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 (!VALID_ELEMENTS_FOR_EXTERNAL.includes(element.type)) return;
+        const info = elementInfoFunc[element.type](element);
+        Object.entries(info).forEach(([key, vals]) => {
+          exchange[key] = exchange[key].concat(vals);
+        });
+      });
+    });
+
+    if (!(pindex % 2) && pageNumberInfo) {
+      let pnoInfo = deepCopy(pageNumberInfo);
+      pnoInfo[0].index = getFillAreaIndex("pageNumber");
+      exchange.fill_area = exchange.fill_area.concat(pnoInfo);
+    }
+
+    page.exchange = exchange;
+  });
+
+  return npages;
+}
+
+export function getPageModel({ cardConfig, paperParams, pages }) {
+  let npages = parsePageExchange(pages);
+  return JSON.stringify(
+    {
+      version: CARD_VERSION,
+      cardConfig,
+      paperParams,
+      pages: npages
+    },
+    (k, v) => (k.startsWith("_") ? undefined : v)
+  );
+}

+ 16 - 17
card/modules/free/components/CardFreeDesign.vue

@@ -126,23 +126,22 @@
           ]"
           v-if="curPage.id"
         >
-          <div
-            :class="[
-              'page-locators',
-              `page-locators-${curPage.locators.length}`
-            ]"
-          >
-            <ul
-              class="page-locator-group"
-              v-for="(locator, iind) in curPage.locators"
-              :key="iind"
-            >
-              <li
-                v-for="(elem, eindex) in locator"
-                :key="eindex"
-                :id="elem.id"
-              ></li>
-            </ul>
+          <!-- 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">

+ 16 - 14
card/modules/free/components/CardFreeView.vue

@@ -10,20 +10,22 @@
         ]"
         :key="pageNo"
       >
-        <div
-          :class="['page-locators', `page-locators-${page.locators.length}`]"
-        >
-          <ul
-            class="page-locator-group"
-            v-for="(locator, iind) in page.locators"
-            :key="iind"
-          >
-            <li
-              v-for="(elem, eindex) in locator"
-              :key="eindex"
-              :id="elem.id"
-            ></li>
-          </ul>
+        <!-- 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">

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
card/previewTemp.js


+ 1933 - 0
card/samples/commonCardSample.json

@@ -0,0 +1,1933 @@
+{
+  "version": "2.0.0",
+  "cardConfig": {
+    "id": "281718408712552448",
+    "createId": "233604222107521024",
+    "createTime": 1658107702715,
+    "updateId": null,
+    "updateTime": 1658107702715,
+    "schoolId": "2",
+    "orgId": "167590127315451904",
+    "name": "m题卡规则",
+    "examNumberStyle": "PRINT",
+    "paperType": "PRINT",
+    "examAbsent": true,
+    "writeSign": true,
+    "discipline": true,
+    "requiredFields": [
+      { "code": "ticketNumber", "name": "考号", "enable": true },
+      { "code": "siteNumber", "name": "座位号", "enable": true },
+      { "code": "studentName", "name": "姓名", "enable": true },
+      { "code": "courseName", "name": "课程名称", "enable": true }
+    ],
+    "extendFields": [
+      { "code": "studentCode", "name": "学号", "enable": false },
+      { "code": "courseCode", "name": "课程代码", "enable": false },
+      { "code": "paperNumber", "name": "试卷编号", "enable": true },
+      { "code": "campusName", "name": "校区", "enable": false },
+      { "code": "examPlace", "name": "考点", "enable": false },
+      { "code": "examRoom", "name": "考场", "enable": true },
+      { "code": "examDate", "name": "考试日期", "enable": true },
+      { "code": "examTime", "name": "考试时间", "enable": false }
+    ],
+    "titleRule": "标题mmm",
+    "attention": "注意mm",
+    "objectiveAttention": "客观mm",
+    "subjectiveAttention": "主观mmm",
+    "enable": true,
+    "remark": null,
+    "orgIds": null,
+    "pageSize": "A3",
+    "columnNumber": 2,
+    "columnGap": 20,
+    "showForbidArea": true,
+    "cardDesc": "",
+    "aOrB": true,
+    "cardTitle": "2342"
+  },
+  "paperParams": {},
+  "pages": [
+    {
+      "type": "PAGE",
+      "pageSize": "A3",
+      "columnNumber": 2,
+      "columnGap": 20,
+      "locators": {
+        "top": [
+          {
+            "id": "locator-0-00",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          },
+          {
+            "id": "locator-0-01",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          }
+        ],
+        "bottom": [
+          {
+            "id": "locator-0-10",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          }
+        ]
+      },
+      "globals": [],
+      "columns": [
+        {
+          "type": "COLUMN",
+          "x": "",
+          "y": "",
+          "w": "",
+          "h": "",
+          "isFull": false,
+          "elements": [
+            {
+              "type": "CARD_HEAD",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 517,
+              "cardTitle": "2342",
+              "cardDesc": "",
+              "aOrB": true,
+              "paperType": "PRINT",
+              "examAbsent": true,
+              "writeSign": true,
+              "examNumberStyle": "PRINT",
+              "businessParams": [],
+              "attention": "注意mm",
+              "objectiveAttention": "客观mm",
+              "subjectiveAttention": "主观mmm",
+              "columnNumber": 2,
+              "isSimple": false,
+              "sign": "head",
+              "id": "element-9oum7118jr3hg5ug",
+              "createId": "233604222107521024",
+              "createTime": 1658107702715,
+              "updateId": null,
+              "updateTime": 1658107702715,
+              "schoolId": "2",
+              "orgId": "167590127315451904",
+              "name": "m题卡规则",
+              "discipline": true,
+              "requiredFields": [
+                { "code": "ticketNumber", "name": "考号", "enable": true },
+                { "code": "siteNumber", "name": "座位号", "enable": true },
+                { "code": "studentName", "name": "姓名", "enable": true },
+                { "code": "courseName", "name": "课程名称", "enable": true }
+              ],
+              "extendFields": [
+                { "code": "studentCode", "name": "学号", "enable": false },
+                { "code": "courseCode", "name": "课程代码", "enable": false },
+                { "code": "paperNumber", "name": "试卷编号", "enable": true },
+                { "code": "campusName", "name": "校区", "enable": false },
+                { "code": "examPlace", "name": "考点", "enable": false },
+                { "code": "examRoom", "name": "考场", "enable": true },
+                { "code": "examDate", "name": "考试日期", "enable": true },
+                { "code": "examTime", "name": "考试时间", "enable": false }
+              ],
+              "titleRule": "标题mmm",
+              "enable": true,
+              "remark": null,
+              "orgIds": null,
+              "pageSize": "A3",
+              "columnGap": 20,
+              "showForbidArea": true,
+              "key": "51fvfnogrehitjbo",
+              "isCovered": false
+            },
+            {
+              "type": "TOPIC_HEAD",
+              "x": 0,
+              "y": 0,
+              "w": 0,
+              "h": 70,
+              "content": "客观mm",
+              "typeName": "客观题",
+              "isColumnFirst": false,
+              "sign": "objective",
+              "id": "element-dupmnrag810bea2g",
+              "key": "g0arqmggdb846vog"
+            },
+            {
+              "id": "element-dq9jeoeo24rd6jto",
+              "key": "leaov5motlfocsig",
+              "type": "FILL_QUESTION",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 172,
+              "minHeight": 172,
+              "sign": "objective",
+              "topicName": "选择题",
+              "topicNo": 1,
+              "startNumber": 1,
+              "questionsCount": 20,
+              "optionCount": 4,
+              "questionCountPerGroup": 5,
+              "groupPerLine": 4,
+              "optionDirection": "horizontal",
+              "questionDirection": "vertical",
+              "questionGap": 8,
+              "groupGap": 30,
+              "optionGap": 12,
+              "isBoolean": false,
+              "booleanType": "√,×",
+              "isMultiply": false,
+              "isCovered": false,
+              "fontSize": "14px",
+              "endNumber": 40,
+              "parent": {
+                "id": "element-jt8gd7i86kqhlikg",
+                "key": "60i1iq48reoc7g6o",
+                "type": "FILL_QUESTION",
+                "x": 0,
+                "y": 0,
+                "w": 703,
+                "h": 138,
+                "minHeight": 138,
+                "sign": "objective",
+                "topicName": "选择题",
+                "topicNo": null,
+                "startNumber": 1,
+                "questionsCount": 40,
+                "optionCount": 4,
+                "questionCountPerGroup": 5,
+                "groupPerLine": 4,
+                "optionDirection": "horizontal",
+                "questionDirection": "vertical",
+                "questionGap": 8,
+                "groupGap": 30,
+                "optionGap": 12,
+                "isBoolean": false,
+                "booleanType": "√,×",
+                "isMultiply": false,
+                "isCovered": false,
+                "fontSize": "14px",
+                "endNumber": 40
+              },
+              "isLast": false,
+              "elementSerialNo": 0
+            },
+            {
+              "id": "element-s3njv9cghf8v7sod",
+              "key": "3rmi05091nh7q5e8",
+              "type": "FILL_QUESTION",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 138,
+              "minHeight": 138,
+              "sign": "objective",
+              "topicName": "选择题",
+              "topicNo": 1,
+              "startNumber": 21,
+              "questionsCount": 20,
+              "optionCount": 4,
+              "questionCountPerGroup": 5,
+              "groupPerLine": 4,
+              "optionDirection": "horizontal",
+              "questionDirection": "vertical",
+              "questionGap": 8,
+              "groupGap": 30,
+              "optionGap": 12,
+              "isBoolean": false,
+              "booleanType": "√,×",
+              "isMultiply": false,
+              "isCovered": false,
+              "fontSize": "14px",
+              "endNumber": 40,
+              "parent": {
+                "id": "element-jt8gd7i86kqhlikg",
+                "key": "60i1iq48reoc7g6o",
+                "type": "FILL_QUESTION",
+                "x": 0,
+                "y": 0,
+                "w": 703,
+                "h": 138,
+                "minHeight": 138,
+                "sign": "objective",
+                "topicName": "选择题",
+                "topicNo": null,
+                "startNumber": 1,
+                "questionsCount": 40,
+                "optionCount": 4,
+                "questionCountPerGroup": 5,
+                "groupPerLine": 4,
+                "optionDirection": "horizontal",
+                "questionDirection": "vertical",
+                "questionGap": 8,
+                "groupGap": 30,
+                "optionGap": 12,
+                "isBoolean": false,
+                "booleanType": "√,×",
+                "isMultiply": false,
+                "isCovered": false,
+                "fontSize": "14px",
+                "endNumber": 40
+              },
+              "isLast": true,
+              "elementSerialNo": 1
+            }
+          ]
+        },
+        {
+          "type": "COLUMN",
+          "x": "",
+          "y": "",
+          "w": "",
+          "h": "",
+          "isFull": false,
+          "elements": [
+            {
+              "type": "TOPIC_HEAD",
+              "x": 0,
+              "y": 0,
+              "w": 0,
+              "h": 60,
+              "content": "主观mmm",
+              "typeName": "主观题",
+              "isColumnFirst": true,
+              "sign": "subjective",
+              "id": "element-g31p7jeag7q4qm58",
+              "key": "k11n898gjj2tq8ig"
+            },
+            {
+              "id": "element-v2v1tvv28fmu2hag",
+              "key": "d394s39gsatnvg1o",
+              "type": "FILL_LINE",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 74,
+              "minHeight": 74,
+              "sign": "subjective",
+              "topicName": "填空题",
+              "topicNo": 2,
+              "startNumber": 1,
+              "questionsCount": 4,
+              "questionNumberPerLine": 4,
+              "lineNumberPerQuestion": 1,
+              "lineSpacing": 40,
+              "questionDirection": "vertical",
+              "questionLineType": "norm",
+              "questionLineNums": [
+                { "no": 1, "count": 1 },
+                { "no": 2, "count": 1 },
+                { "no": 3, "count": 1 },
+                { "no": 4, "count": 1 }
+              ],
+              "numberPre": "",
+              "isCovered": false,
+              "endNumber": 20,
+              "parent": {
+                "id": "element-38m4krr8p3d1tk98",
+                "key": "5q9j3q5gota52gnl",
+                "type": "FILL_LINE",
+                "x": 0,
+                "y": 0,
+                "w": 703,
+                "h": 40,
+                "minHeight": 40,
+                "sign": "subjective",
+                "topicName": "填空题",
+                "topicNo": null,
+                "startNumber": 1,
+                "questionsCount": 20,
+                "questionNumberPerLine": 4,
+                "lineNumberPerQuestion": 1,
+                "lineSpacing": 40,
+                "questionDirection": "vertical",
+                "questionLineType": "norm",
+                "questionLineNums": [],
+                "numberPre": "",
+                "isCovered": false,
+                "endNumber": 20
+              },
+              "isLast": false,
+              "elementSerialNo": 2
+            },
+            {
+              "id": "element-takp5km832lg4q2g",
+              "key": "c1k4mvuov8hl7c2m",
+              "type": "FILL_LINE",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 40,
+              "minHeight": 40,
+              "sign": "subjective",
+              "topicName": "填空题",
+              "topicNo": 2,
+              "startNumber": 5,
+              "questionsCount": 4,
+              "questionNumberPerLine": 4,
+              "lineNumberPerQuestion": 1,
+              "lineSpacing": 40,
+              "questionDirection": "vertical",
+              "questionLineType": "norm",
+              "questionLineNums": [
+                { "no": 5, "count": 1 },
+                { "no": 6, "count": 1 },
+                { "no": 7, "count": 1 },
+                { "no": 8, "count": 1 }
+              ],
+              "numberPre": "",
+              "isCovered": false,
+              "endNumber": 20,
+              "parent": {
+                "id": "element-38m4krr8p3d1tk98",
+                "key": "5q9j3q5gota52gnl",
+                "type": "FILL_LINE",
+                "x": 0,
+                "y": 0,
+                "w": 703,
+                "h": 40,
+                "minHeight": 40,
+                "sign": "subjective",
+                "topicName": "填空题",
+                "topicNo": null,
+                "startNumber": 1,
+                "questionsCount": 20,
+                "questionNumberPerLine": 4,
+                "lineNumberPerQuestion": 1,
+                "lineSpacing": 40,
+                "questionDirection": "vertical",
+                "questionLineType": "norm",
+                "questionLineNums": [],
+                "numberPre": "",
+                "isCovered": false,
+                "endNumber": 20
+              },
+              "isLast": false,
+              "elementSerialNo": 3
+            },
+            {
+              "id": "element-366n3s0m4ja373pk",
+              "key": "671g2c28vbtelf38",
+              "type": "FILL_LINE",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 40,
+              "minHeight": 40,
+              "sign": "subjective",
+              "topicName": "填空题",
+              "topicNo": 2,
+              "startNumber": 9,
+              "questionsCount": 4,
+              "questionNumberPerLine": 4,
+              "lineNumberPerQuestion": 1,
+              "lineSpacing": 40,
+              "questionDirection": "vertical",
+              "questionLineType": "norm",
+              "questionLineNums": [
+                { "no": 9, "count": 1 },
+                { "no": 10, "count": 1 },
+                { "no": 11, "count": 1 },
+                { "no": 12, "count": 1 }
+              ],
+              "numberPre": "",
+              "isCovered": false,
+              "endNumber": 20,
+              "parent": {
+                "id": "element-38m4krr8p3d1tk98",
+                "key": "5q9j3q5gota52gnl",
+                "type": "FILL_LINE",
+                "x": 0,
+                "y": 0,
+                "w": 703,
+                "h": 40,
+                "minHeight": 40,
+                "sign": "subjective",
+                "topicName": "填空题",
+                "topicNo": null,
+                "startNumber": 1,
+                "questionsCount": 20,
+                "questionNumberPerLine": 4,
+                "lineNumberPerQuestion": 1,
+                "lineSpacing": 40,
+                "questionDirection": "vertical",
+                "questionLineType": "norm",
+                "questionLineNums": [],
+                "numberPre": "",
+                "isCovered": false,
+                "endNumber": 20
+              },
+              "isLast": false,
+              "elementSerialNo": 4
+            },
+            {
+              "id": "element-qsol4fig5apngsjg",
+              "key": "iniun1ec9m56rtqo",
+              "type": "FILL_LINE",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 40,
+              "minHeight": 40,
+              "sign": "subjective",
+              "topicName": "填空题",
+              "topicNo": 2,
+              "startNumber": 13,
+              "questionsCount": 4,
+              "questionNumberPerLine": 4,
+              "lineNumberPerQuestion": 1,
+              "lineSpacing": 40,
+              "questionDirection": "vertical",
+              "questionLineType": "norm",
+              "questionLineNums": [
+                { "no": 13, "count": 1 },
+                { "no": 14, "count": 1 },
+                { "no": 15, "count": 1 },
+                { "no": 16, "count": 1 }
+              ],
+              "numberPre": "",
+              "isCovered": false,
+              "endNumber": 20,
+              "parent": {
+                "id": "element-38m4krr8p3d1tk98",
+                "key": "5q9j3q5gota52gnl",
+                "type": "FILL_LINE",
+                "x": 0,
+                "y": 0,
+                "w": 703,
+                "h": 40,
+                "minHeight": 40,
+                "sign": "subjective",
+                "topicName": "填空题",
+                "topicNo": null,
+                "startNumber": 1,
+                "questionsCount": 20,
+                "questionNumberPerLine": 4,
+                "lineNumberPerQuestion": 1,
+                "lineSpacing": 40,
+                "questionDirection": "vertical",
+                "questionLineType": "norm",
+                "questionLineNums": [],
+                "numberPre": "",
+                "isCovered": false,
+                "endNumber": 20
+              },
+              "isLast": false,
+              "elementSerialNo": 5
+            },
+            {
+              "id": "element-kbgnhht81un2jl38",
+              "key": "ef1j7rroptd8n2nq",
+              "type": "FILL_LINE",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 40,
+              "minHeight": 40,
+              "sign": "subjective",
+              "topicName": "填空题",
+              "topicNo": 2,
+              "startNumber": 17,
+              "questionsCount": 4,
+              "questionNumberPerLine": 4,
+              "lineNumberPerQuestion": 1,
+              "lineSpacing": 40,
+              "questionDirection": "vertical",
+              "questionLineType": "norm",
+              "questionLineNums": [
+                { "no": 17, "count": 1 },
+                { "no": 18, "count": 1 },
+                { "no": 19, "count": 1 },
+                { "no": 20, "count": 1 }
+              ],
+              "numberPre": "",
+              "isCovered": false,
+              "endNumber": 20,
+              "parent": {
+                "id": "element-38m4krr8p3d1tk98",
+                "key": "5q9j3q5gota52gnl",
+                "type": "FILL_LINE",
+                "x": 0,
+                "y": 0,
+                "w": 703,
+                "h": 40,
+                "minHeight": 40,
+                "sign": "subjective",
+                "topicName": "填空题",
+                "topicNo": null,
+                "startNumber": 1,
+                "questionsCount": 20,
+                "questionNumberPerLine": 4,
+                "lineNumberPerQuestion": 1,
+                "lineSpacing": 40,
+                "questionDirection": "vertical",
+                "questionLineType": "norm",
+                "questionLineNums": [],
+                "numberPre": "",
+                "isCovered": false,
+                "endNumber": 20
+              },
+              "isLast": true,
+              "elementSerialNo": 6
+            },
+            {
+              "type": "EXPLAIN",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 680,
+              "minHeight": 60,
+              "sign": "subjective",
+              "topicNo": 3,
+              "isCovered": false,
+              "isLast": true,
+              "isExtend": false,
+              "showTitle": true,
+              "serialNumber": 1,
+              "elements": [],
+              "parent": {
+                "id": "element-hmkner4grlip0ob8",
+                "key": "fmr6gvd5vuesqmvb",
+                "type": "EXPLAIN",
+                "sign": "subjective",
+                "topicNo": null,
+                "topicName": "解答题",
+                "startNumber": 1,
+                "questionsCount": 8,
+                "w": 703,
+                "endNumber": 8
+              },
+              "id": "element-qoat6aaoad275h3l",
+              "key": "p7qbdalkrrt252n5",
+              "elementSerialNo": 7,
+              "init": false
+            }
+          ]
+        }
+      ],
+      "exchange": {
+        "card_type": 2,
+        "page_size": "A3",
+        "page_image": "",
+        "locator": {
+          "top": [
+            [0.0504413619, 0.0356506239, 0.0151324086, 0.0142602496],
+            [0.8738965952, 0.0356506239, 0.0151324086, 0.0142602496]
+          ],
+          "bottom": [[0.0504413619, 0.9500891266, 0.0151324086, 0.0142602496]]
+        },
+        "fill_locator": [],
+        "check_area": { "black_line": [], "white_line": [] },
+        "barcode": [
+          {
+            "field": "examNumber",
+            "area": [0.0504413619, 0.1310160428, 0.2181588903, 0.1978609626]
+          },
+          {
+            "field": "paperType",
+            "area": [0.3284993695, 0.4759358289, 0.1651954603, 0.0383244207]
+          }
+        ],
+        "qrcode": [],
+        "ocr_area": [],
+        "info_area": [[0.0504413619, 0.0534759358, 0.4432534678, 0.4607843137]],
+        "fill_area": [
+          {
+            "field": "absent",
+            "index": 1,
+            "single": true,
+            "horizontal": true,
+            "items": [
+              {
+                "main_number": null,
+                "sub_number": null,
+                "options": [
+                  [0.3373266078, 0.4518716578, 0.0189155107, 0.0124777184]
+                ],
+                "recog_info": []
+              }
+            ]
+          },
+          {
+            "field": "question",
+            "index": 1,
+            "single": true,
+            "horizontal": true,
+            "items": [
+              {
+                "main_number": 1,
+                "sub_number": 1,
+                "options": [
+                  [0.079445145, 0.6229946524, 0.0113493064, 0.0124777184],
+                  [0.0983606557, 0.6229946524, 0.0113493064, 0.0124777184],
+                  [0.1172761665, 0.6229946524, 0.0113493064, 0.0124777184],
+                  [0.1361916772, 0.6229946524, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 2,
+                "options": [
+                  [0.079445145, 0.6426024955, 0.0113493064, 0.0124777184],
+                  [0.0983606557, 0.6426024955, 0.0113493064, 0.0124777184],
+                  [0.1172761665, 0.6426024955, 0.0113493064, 0.0124777184],
+                  [0.1361916772, 0.6426024955, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 3,
+                "options": [
+                  [0.079445145, 0.6622103387, 0.0113493064, 0.0124777184],
+                  [0.0983606557, 0.6622103387, 0.0113493064, 0.0124777184],
+                  [0.1172761665, 0.6622103387, 0.0113493064, 0.0124777184],
+                  [0.1361916772, 0.6622103387, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 4,
+                "options": [
+                  [0.079445145, 0.6818181818, 0.0113493064, 0.0124777184],
+                  [0.0983606557, 0.6818181818, 0.0113493064, 0.0124777184],
+                  [0.1172761665, 0.6818181818, 0.0113493064, 0.0124777184],
+                  [0.1361916772, 0.6818181818, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 5,
+                "options": [
+                  [0.079445145, 0.701426025, 0.0113493064, 0.0124777184],
+                  [0.0983606557, 0.701426025, 0.0113493064, 0.0124777184],
+                  [0.1172761665, 0.701426025, 0.0113493064, 0.0124777184],
+                  [0.1361916772, 0.701426025, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              }
+            ]
+          },
+          {
+            "field": "question",
+            "index": 2,
+            "single": true,
+            "horizontal": true,
+            "items": [
+              {
+                "main_number": 1,
+                "sub_number": 6,
+                "options": [
+                  [0.185372005, 0.6229946524, 0.0113493064, 0.0124777184],
+                  [0.2042875158, 0.6229946524, 0.0113493064, 0.0124777184],
+                  [0.2232030265, 0.6229946524, 0.0113493064, 0.0124777184],
+                  [0.2421185372, 0.6229946524, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 7,
+                "options": [
+                  [0.185372005, 0.6426024955, 0.0113493064, 0.0124777184],
+                  [0.2042875158, 0.6426024955, 0.0113493064, 0.0124777184],
+                  [0.2232030265, 0.6426024955, 0.0113493064, 0.0124777184],
+                  [0.2421185372, 0.6426024955, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 8,
+                "options": [
+                  [0.185372005, 0.6622103387, 0.0113493064, 0.0124777184],
+                  [0.2042875158, 0.6622103387, 0.0113493064, 0.0124777184],
+                  [0.2232030265, 0.6622103387, 0.0113493064, 0.0124777184],
+                  [0.2421185372, 0.6622103387, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 9,
+                "options": [
+                  [0.185372005, 0.6818181818, 0.0113493064, 0.0124777184],
+                  [0.2042875158, 0.6818181818, 0.0113493064, 0.0124777184],
+                  [0.2232030265, 0.6818181818, 0.0113493064, 0.0124777184],
+                  [0.2421185372, 0.6818181818, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 10,
+                "options": [
+                  [0.185372005, 0.701426025, 0.0113493064, 0.0124777184],
+                  [0.2042875158, 0.701426025, 0.0113493064, 0.0124777184],
+                  [0.2232030265, 0.701426025, 0.0113493064, 0.0124777184],
+                  [0.2421185372, 0.701426025, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              }
+            ]
+          },
+          {
+            "field": "question",
+            "index": 3,
+            "single": true,
+            "horizontal": true,
+            "items": [
+              {
+                "main_number": 1,
+                "sub_number": 11,
+                "options": [
+                  [0.2912988651, 0.6229946524, 0.0113493064, 0.0124777184],
+                  [0.3102143758, 0.6229946524, 0.0113493064, 0.0124777184],
+                  [0.3291298865, 0.6229946524, 0.0113493064, 0.0124777184],
+                  [0.3480453972, 0.6229946524, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 12,
+                "options": [
+                  [0.2912988651, 0.6426024955, 0.0113493064, 0.0124777184],
+                  [0.3102143758, 0.6426024955, 0.0113493064, 0.0124777184],
+                  [0.3291298865, 0.6426024955, 0.0113493064, 0.0124777184],
+                  [0.3480453972, 0.6426024955, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 13,
+                "options": [
+                  [0.2912988651, 0.6622103387, 0.0113493064, 0.0124777184],
+                  [0.3102143758, 0.6622103387, 0.0113493064, 0.0124777184],
+                  [0.3291298865, 0.6622103387, 0.0113493064, 0.0124777184],
+                  [0.3480453972, 0.6622103387, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 14,
+                "options": [
+                  [0.2912988651, 0.6818181818, 0.0113493064, 0.0124777184],
+                  [0.3102143758, 0.6818181818, 0.0113493064, 0.0124777184],
+                  [0.3291298865, 0.6818181818, 0.0113493064, 0.0124777184],
+                  [0.3480453972, 0.6818181818, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 15,
+                "options": [
+                  [0.2912988651, 0.701426025, 0.0113493064, 0.0124777184],
+                  [0.3102143758, 0.701426025, 0.0113493064, 0.0124777184],
+                  [0.3291298865, 0.701426025, 0.0113493064, 0.0124777184],
+                  [0.3480453972, 0.701426025, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              }
+            ]
+          },
+          {
+            "field": "question",
+            "index": 4,
+            "single": true,
+            "horizontal": true,
+            "items": [
+              {
+                "main_number": 1,
+                "sub_number": 16,
+                "options": [
+                  [0.3972257251, 0.6229946524, 0.0113493064, 0.0124777184],
+                  [0.4161412358, 0.6229946524, 0.0113493064, 0.0124777184],
+                  [0.4350567465, 0.6229946524, 0.0113493064, 0.0124777184],
+                  [0.4539722573, 0.6229946524, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 17,
+                "options": [
+                  [0.3972257251, 0.6426024955, 0.0113493064, 0.0124777184],
+                  [0.4161412358, 0.6426024955, 0.0113493064, 0.0124777184],
+                  [0.4350567465, 0.6426024955, 0.0113493064, 0.0124777184],
+                  [0.4539722573, 0.6426024955, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 18,
+                "options": [
+                  [0.3972257251, 0.6622103387, 0.0113493064, 0.0124777184],
+                  [0.4161412358, 0.6622103387, 0.0113493064, 0.0124777184],
+                  [0.4350567465, 0.6622103387, 0.0113493064, 0.0124777184],
+                  [0.4539722573, 0.6622103387, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 19,
+                "options": [
+                  [0.3972257251, 0.6818181818, 0.0113493064, 0.0124777184],
+                  [0.4161412358, 0.6818181818, 0.0113493064, 0.0124777184],
+                  [0.4350567465, 0.6818181818, 0.0113493064, 0.0124777184],
+                  [0.4539722573, 0.6818181818, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 20,
+                "options": [
+                  [0.3972257251, 0.701426025, 0.0113493064, 0.0124777184],
+                  [0.4161412358, 0.701426025, 0.0113493064, 0.0124777184],
+                  [0.4350567465, 0.701426025, 0.0113493064, 0.0124777184],
+                  [0.4539722573, 0.701426025, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              }
+            ]
+          },
+          {
+            "field": "question",
+            "index": 5,
+            "single": true,
+            "horizontal": true,
+            "items": [
+              {
+                "main_number": 1,
+                "sub_number": 21,
+                "options": [
+                  [0.079445145, 0.7459893048, 0.0113493064, 0.0124777184],
+                  [0.0983606557, 0.7459893048, 0.0113493064, 0.0124777184],
+                  [0.1172761665, 0.7459893048, 0.0113493064, 0.0124777184],
+                  [0.1361916772, 0.7459893048, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 22,
+                "options": [
+                  [0.079445145, 0.765597148, 0.0113493064, 0.0124777184],
+                  [0.0983606557, 0.765597148, 0.0113493064, 0.0124777184],
+                  [0.1172761665, 0.765597148, 0.0113493064, 0.0124777184],
+                  [0.1361916772, 0.765597148, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 23,
+                "options": [
+                  [0.079445145, 0.7852049911, 0.0113493064, 0.0124777184],
+                  [0.0983606557, 0.7852049911, 0.0113493064, 0.0124777184],
+                  [0.1172761665, 0.7852049911, 0.0113493064, 0.0124777184],
+                  [0.1361916772, 0.7852049911, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 24,
+                "options": [
+                  [0.079445145, 0.8048128342, 0.0113493064, 0.0124777184],
+                  [0.0983606557, 0.8048128342, 0.0113493064, 0.0124777184],
+                  [0.1172761665, 0.8048128342, 0.0113493064, 0.0124777184],
+                  [0.1361916772, 0.8048128342, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 25,
+                "options": [
+                  [0.079445145, 0.8244206774, 0.0113493064, 0.0124777184],
+                  [0.0983606557, 0.8244206774, 0.0113493064, 0.0124777184],
+                  [0.1172761665, 0.8244206774, 0.0113493064, 0.0124777184],
+                  [0.1361916772, 0.8244206774, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              }
+            ]
+          },
+          {
+            "field": "question",
+            "index": 6,
+            "single": true,
+            "horizontal": true,
+            "items": [
+              {
+                "main_number": 1,
+                "sub_number": 26,
+                "options": [
+                  [0.185372005, 0.7459893048, 0.0113493064, 0.0124777184],
+                  [0.2042875158, 0.7459893048, 0.0113493064, 0.0124777184],
+                  [0.2232030265, 0.7459893048, 0.0113493064, 0.0124777184],
+                  [0.2421185372, 0.7459893048, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 27,
+                "options": [
+                  [0.185372005, 0.765597148, 0.0113493064, 0.0124777184],
+                  [0.2042875158, 0.765597148, 0.0113493064, 0.0124777184],
+                  [0.2232030265, 0.765597148, 0.0113493064, 0.0124777184],
+                  [0.2421185372, 0.765597148, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 28,
+                "options": [
+                  [0.185372005, 0.7852049911, 0.0113493064, 0.0124777184],
+                  [0.2042875158, 0.7852049911, 0.0113493064, 0.0124777184],
+                  [0.2232030265, 0.7852049911, 0.0113493064, 0.0124777184],
+                  [0.2421185372, 0.7852049911, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 29,
+                "options": [
+                  [0.185372005, 0.8048128342, 0.0113493064, 0.0124777184],
+                  [0.2042875158, 0.8048128342, 0.0113493064, 0.0124777184],
+                  [0.2232030265, 0.8048128342, 0.0113493064, 0.0124777184],
+                  [0.2421185372, 0.8048128342, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 30,
+                "options": [
+                  [0.185372005, 0.8244206774, 0.0113493064, 0.0124777184],
+                  [0.2042875158, 0.8244206774, 0.0113493064, 0.0124777184],
+                  [0.2232030265, 0.8244206774, 0.0113493064, 0.0124777184],
+                  [0.2421185372, 0.8244206774, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              }
+            ]
+          },
+          {
+            "field": "question",
+            "index": 7,
+            "single": true,
+            "horizontal": true,
+            "items": [
+              {
+                "main_number": 1,
+                "sub_number": 31,
+                "options": [
+                  [0.2912988651, 0.7459893048, 0.0113493064, 0.0124777184],
+                  [0.3102143758, 0.7459893048, 0.0113493064, 0.0124777184],
+                  [0.3291298865, 0.7459893048, 0.0113493064, 0.0124777184],
+                  [0.3480453972, 0.7459893048, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 32,
+                "options": [
+                  [0.2912988651, 0.765597148, 0.0113493064, 0.0124777184],
+                  [0.3102143758, 0.765597148, 0.0113493064, 0.0124777184],
+                  [0.3291298865, 0.765597148, 0.0113493064, 0.0124777184],
+                  [0.3480453972, 0.765597148, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 33,
+                "options": [
+                  [0.2912988651, 0.7852049911, 0.0113493064, 0.0124777184],
+                  [0.3102143758, 0.7852049911, 0.0113493064, 0.0124777184],
+                  [0.3291298865, 0.7852049911, 0.0113493064, 0.0124777184],
+                  [0.3480453972, 0.7852049911, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 34,
+                "options": [
+                  [0.2912988651, 0.8048128342, 0.0113493064, 0.0124777184],
+                  [0.3102143758, 0.8048128342, 0.0113493064, 0.0124777184],
+                  [0.3291298865, 0.8048128342, 0.0113493064, 0.0124777184],
+                  [0.3480453972, 0.8048128342, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 35,
+                "options": [
+                  [0.2912988651, 0.8244206774, 0.0113493064, 0.0124777184],
+                  [0.3102143758, 0.8244206774, 0.0113493064, 0.0124777184],
+                  [0.3291298865, 0.8244206774, 0.0113493064, 0.0124777184],
+                  [0.3480453972, 0.8244206774, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              }
+            ]
+          },
+          {
+            "field": "question",
+            "index": 8,
+            "single": true,
+            "horizontal": true,
+            "items": [
+              {
+                "main_number": 1,
+                "sub_number": 36,
+                "options": [
+                  [0.3972257251, 0.7459893048, 0.0113493064, 0.0124777184],
+                  [0.4161412358, 0.7459893048, 0.0113493064, 0.0124777184],
+                  [0.4350567465, 0.7459893048, 0.0113493064, 0.0124777184],
+                  [0.4539722573, 0.7459893048, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 37,
+                "options": [
+                  [0.3972257251, 0.765597148, 0.0113493064, 0.0124777184],
+                  [0.4161412358, 0.765597148, 0.0113493064, 0.0124777184],
+                  [0.4350567465, 0.765597148, 0.0113493064, 0.0124777184],
+                  [0.4539722573, 0.765597148, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 38,
+                "options": [
+                  [0.3972257251, 0.7852049911, 0.0113493064, 0.0124777184],
+                  [0.4161412358, 0.7852049911, 0.0113493064, 0.0124777184],
+                  [0.4350567465, 0.7852049911, 0.0113493064, 0.0124777184],
+                  [0.4539722573, 0.7852049911, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 39,
+                "options": [
+                  [0.3972257251, 0.8048128342, 0.0113493064, 0.0124777184],
+                  [0.4161412358, 0.8048128342, 0.0113493064, 0.0124777184],
+                  [0.4350567465, 0.8048128342, 0.0113493064, 0.0124777184],
+                  [0.4539722573, 0.8048128342, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": 1,
+                "sub_number": 40,
+                "options": [
+                  [0.3972257251, 0.8244206774, 0.0113493064, 0.0124777184],
+                  [0.4161412358, 0.8244206774, 0.0113493064, 0.0124777184],
+                  [0.4350567465, 0.8244206774, 0.0113493064, 0.0124777184],
+                  [0.4539722573, 0.8244206774, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              }
+            ]
+          },
+          {
+            "field": "pageNumber",
+            "index": 1,
+            "single": true,
+            "horizontal": true,
+            "items": [
+              {
+                "main_number": null,
+                "sub_number": null,
+                "options": [
+                  [0.15889029, 0.9500891266, 0.0151324086, 0.0142602496],
+                  [0.1803278689, 0.9500891266, 0.0151324086, 0.0142602496],
+                  [0.2017654477, 0.9500891266, 0.0151324086, 0.0142602496],
+                  [0.2232030265, 0.9500891266, 0.0151324086, 0.0142602496]
+                ],
+                "recog_info": []
+              }
+            ]
+          }
+        ],
+        "answer_area": [
+          {
+            "main_number": 2,
+            "sub_number": "1,2,3,4",
+            "area": [0.5063051702, 0.1069518717, 0.4432534678, 0.0659536542]
+          },
+          {
+            "main_number": 2,
+            "sub_number": "5,6,7,8",
+            "area": [0.5063051702, 0.1729055258, 0.4432534678, 0.0356506239]
+          },
+          {
+            "main_number": 2,
+            "sub_number": "9,10,11,12",
+            "area": [0.5063051702, 0.2085561497, 0.4432534678, 0.0356506239]
+          },
+          {
+            "main_number": 2,
+            "sub_number": "13,14,15,16",
+            "area": [0.5063051702, 0.2442067736, 0.4432534678, 0.0356506239]
+          },
+          {
+            "main_number": 2,
+            "sub_number": "17,18,19,20",
+            "area": [0.5063051702, 0.2798573975, 0.4432534678, 0.0356506239]
+          },
+          {
+            "main_number": 3,
+            "sub_number": 1,
+            "area": [0.5063051702, 0.3155080214, 0.4432534678, 0.6060606061]
+          }
+        ],
+        "extension": {
+          "barcode": [],
+          "fill_area": [],
+          "ocr_area": [],
+          "qrcode": []
+        }
+      }
+    },
+    {
+      "type": "PAGE",
+      "pageSize": "A3",
+      "columnNumber": 2,
+      "columnGap": 20,
+      "locators": {
+        "top": [
+          {
+            "id": "locator-1-00",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          },
+          {
+            "id": "locator-1-01",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          }
+        ],
+        "bottom": [
+          {
+            "id": "locator-1-10",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          }
+        ]
+      },
+      "globals": [],
+      "columns": [
+        {
+          "type": "COLUMN",
+          "x": "",
+          "y": "",
+          "w": "",
+          "h": "",
+          "isFull": false,
+          "elements": [
+            {
+              "type": "TOPIC_HEAD",
+              "x": 0,
+              "y": 0,
+              "w": 0,
+              "h": 60,
+              "content": "主观mmm",
+              "typeName": "主观题",
+              "isColumnFirst": true,
+              "sign": "subjective",
+              "id": "element-kbq16sd8cll1mqau",
+              "key": "tufu3msgvjll6178"
+            },
+            {
+              "type": "EXPLAIN",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 458,
+              "minHeight": 60,
+              "sign": "subjective",
+              "topicNo": 3,
+              "isCovered": false,
+              "isLast": true,
+              "isExtend": false,
+              "showTitle": false,
+              "serialNumber": 2,
+              "elements": [],
+              "parent": {
+                "id": "element-hmkner4grlip0ob8",
+                "key": "fmr6gvd5vuesqmvb",
+                "type": "EXPLAIN",
+                "sign": "subjective",
+                "topicNo": null,
+                "topicName": "解答题",
+                "startNumber": 1,
+                "questionsCount": 8,
+                "w": 703,
+                "endNumber": 8
+              },
+              "id": "element-2l7to1ocfs40eqjr",
+              "key": "pcji6gd2q7q6hlho",
+              "elementSerialNo": 8
+            },
+            {
+              "type": "EXPLAIN",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 458,
+              "minHeight": 60,
+              "sign": "subjective",
+              "topicNo": 3,
+              "isCovered": false,
+              "isLast": true,
+              "isExtend": false,
+              "showTitle": false,
+              "serialNumber": 3,
+              "elements": [],
+              "parent": {
+                "id": "element-hmkner4grlip0ob8",
+                "key": "fmr6gvd5vuesqmvb",
+                "type": "EXPLAIN",
+                "sign": "subjective",
+                "topicNo": null,
+                "topicName": "解答题",
+                "startNumber": 1,
+                "questionsCount": 8,
+                "w": 703,
+                "endNumber": 8
+              },
+              "id": "element-rg5c9i38j17jh04p",
+              "key": "18d4bi3gjmda2bn8",
+              "elementSerialNo": 9
+            }
+          ]
+        },
+        {
+          "type": "COLUMN",
+          "x": "",
+          "y": "",
+          "w": "",
+          "h": "",
+          "isFull": false,
+          "elements": [
+            {
+              "type": "TOPIC_HEAD",
+              "x": 0,
+              "y": 0,
+              "w": 0,
+              "h": 60,
+              "content": "主观mmm",
+              "typeName": "主观题",
+              "isColumnFirst": true,
+              "sign": "subjective",
+              "id": "element-uqe6f4ngd9gsrh5k",
+              "key": "k9echvstdt1fd2jg"
+            },
+            {
+              "type": "EXPLAIN",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 458,
+              "minHeight": 60,
+              "sign": "subjective",
+              "topicNo": 3,
+              "isCovered": false,
+              "isLast": true,
+              "isExtend": false,
+              "showTitle": false,
+              "serialNumber": 4,
+              "elements": [],
+              "parent": {
+                "id": "element-hmkner4grlip0ob8",
+                "key": "fmr6gvd5vuesqmvb",
+                "type": "EXPLAIN",
+                "sign": "subjective",
+                "topicNo": null,
+                "topicName": "解答题",
+                "startNumber": 1,
+                "questionsCount": 8,
+                "w": 703,
+                "endNumber": 8
+              },
+              "id": "element-c70q9uukt1rt5ur8",
+              "key": "7r06rec8vkktgle5",
+              "elementSerialNo": 10
+            },
+            {
+              "type": "EXPLAIN",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 458,
+              "minHeight": 60,
+              "sign": "subjective",
+              "topicNo": 3,
+              "isCovered": false,
+              "isLast": true,
+              "isExtend": false,
+              "showTitle": false,
+              "serialNumber": 5,
+              "elements": [],
+              "parent": {
+                "id": "element-hmkner4grlip0ob8",
+                "key": "fmr6gvd5vuesqmvb",
+                "type": "EXPLAIN",
+                "sign": "subjective",
+                "topicNo": null,
+                "topicName": "解答题",
+                "startNumber": 1,
+                "questionsCount": 8,
+                "w": 703,
+                "endNumber": 8
+              },
+              "id": "element-oc00ttroscl9i3kg",
+              "key": "5refkikgf9t4ihug",
+              "elementSerialNo": 11
+            }
+          ]
+        }
+      ],
+      "exchange": {
+        "card_type": 2,
+        "page_size": "A3",
+        "page_image": "",
+        "locator": {
+          "top": [
+            [0.0504413619, 0.0356506239, 0.0151324086, 0.0142602496],
+            [0.8738965952, 0.0356506239, 0.0151324086, 0.0142602496]
+          ],
+          "bottom": [[0.0504413619, 0.9500891266, 0.0151324086, 0.0142602496]]
+        },
+        "fill_locator": [],
+        "check_area": { "black_line": [], "white_line": [] },
+        "barcode": [],
+        "qrcode": [],
+        "ocr_area": [],
+        "info_area": [],
+        "fill_area": [],
+        "answer_area": [
+          {
+            "main_number": 3,
+            "sub_number": 2,
+            "area": [0.0504413619, 0.1069518717, 0.4432534678, 0.4081996435]
+          },
+          {
+            "main_number": 3,
+            "sub_number": 3,
+            "area": [0.0504413619, 0.5151515152, 0.4432534678, 0.4081996435]
+          },
+          {
+            "main_number": 3,
+            "sub_number": 4,
+            "area": [0.5063051702, 0.1069518717, 0.4432534678, 0.4081996435]
+          },
+          {
+            "main_number": 3,
+            "sub_number": 5,
+            "area": [0.5063051702, 0.5151515152, 0.4432534678, 0.4081996435]
+          }
+        ],
+        "extension": {
+          "barcode": [],
+          "fill_area": [],
+          "ocr_area": [],
+          "qrcode": []
+        }
+      }
+    },
+    {
+      "type": "PAGE",
+      "pageSize": "A3",
+      "columnNumber": 2,
+      "columnGap": 20,
+      "locators": {
+        "top": [
+          {
+            "id": "locator-2-00",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          },
+          {
+            "id": "locator-2-01",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          }
+        ],
+        "bottom": [
+          {
+            "id": "locator-2-10",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          }
+        ]
+      },
+      "globals": [],
+      "columns": [
+        {
+          "type": "COLUMN",
+          "x": "",
+          "y": "",
+          "w": "",
+          "h": "",
+          "isFull": false,
+          "elements": [
+            {
+              "type": "CARD_HEAD",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 309,
+              "cardTitle": "2342",
+              "cardDesc": "",
+              "aOrB": true,
+              "paperType": "PRINT",
+              "examAbsent": true,
+              "writeSign": true,
+              "examNumberStyle": "PRINT",
+              "businessParams": [],
+              "attention": "注意mm",
+              "objectiveAttention": "客观mm",
+              "subjectiveAttention": "主观mmm",
+              "columnNumber": 2,
+              "isSimple": true,
+              "sign": "head",
+              "id": "element-cc66r9b9f26uptpo",
+              "createId": "233604222107521024",
+              "createTime": 1658107702715,
+              "updateId": null,
+              "updateTime": 1658107702715,
+              "schoolId": "2",
+              "orgId": "167590127315451904",
+              "name": "m题卡规则",
+              "discipline": true,
+              "requiredFields": [
+                { "code": "ticketNumber", "name": "考号", "enable": true },
+                { "code": "siteNumber", "name": "座位号", "enable": true },
+                { "code": "studentName", "name": "姓名", "enable": true },
+                { "code": "courseName", "name": "课程名称", "enable": true }
+              ],
+              "extendFields": [
+                { "code": "studentCode", "name": "学号", "enable": false },
+                { "code": "courseCode", "name": "课程代码", "enable": false },
+                { "code": "paperNumber", "name": "试卷编号", "enable": true },
+                { "code": "campusName", "name": "校区", "enable": false },
+                { "code": "examPlace", "name": "考点", "enable": false },
+                { "code": "examRoom", "name": "考场", "enable": true },
+                { "code": "examDate", "name": "考试日期", "enable": true },
+                { "code": "examTime", "name": "考试时间", "enable": false }
+              ],
+              "titleRule": "标题mmm",
+              "enable": true,
+              "remark": null,
+              "orgIds": null,
+              "pageSize": "A3",
+              "columnGap": 20,
+              "showForbidArea": true,
+              "key": "51fvfnogrehitjbo",
+              "isCovered": false
+            },
+            {
+              "type": "TOPIC_HEAD",
+              "x": 0,
+              "y": 0,
+              "w": 0,
+              "h": 70,
+              "content": "主观mmm",
+              "typeName": "主观题",
+              "isColumnFirst": false,
+              "sign": "subjective",
+              "id": "element-491s0ilo0kffhjcl",
+              "key": "3df6mvpi3c46jnao"
+            },
+            {
+              "type": "EXPLAIN",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 458,
+              "minHeight": 60,
+              "sign": "subjective",
+              "topicNo": 3,
+              "isCovered": false,
+              "isLast": true,
+              "isExtend": false,
+              "showTitle": false,
+              "serialNumber": 6,
+              "elements": [],
+              "parent": {
+                "id": "element-hmkner4grlip0ob8",
+                "key": "fmr6gvd5vuesqmvb",
+                "type": "EXPLAIN",
+                "sign": "subjective",
+                "topicNo": null,
+                "topicName": "解答题",
+                "startNumber": 1,
+                "questionsCount": 8,
+                "w": 703,
+                "endNumber": 8
+              },
+              "id": "element-nilv7v78uuvfc3gg",
+              "key": "nph1v83oo23qddob",
+              "elementSerialNo": 12
+            }
+          ]
+        },
+        {
+          "type": "COLUMN",
+          "x": "",
+          "y": "",
+          "w": "",
+          "h": "",
+          "isFull": false,
+          "elements": [
+            {
+              "type": "TOPIC_HEAD",
+              "x": 0,
+              "y": 0,
+              "w": 0,
+              "h": 60,
+              "content": "主观mmm",
+              "typeName": "主观题",
+              "isColumnFirst": true,
+              "sign": "subjective",
+              "id": "element-1eanpnd80062gfv8",
+              "key": "dmo7hd9os49vp99h"
+            },
+            {
+              "type": "EXPLAIN",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 458,
+              "minHeight": 60,
+              "sign": "subjective",
+              "topicNo": 3,
+              "isCovered": false,
+              "isLast": true,
+              "isExtend": false,
+              "showTitle": false,
+              "serialNumber": 7,
+              "elements": [],
+              "parent": {
+                "id": "element-hmkner4grlip0ob8",
+                "key": "fmr6gvd5vuesqmvb",
+                "type": "EXPLAIN",
+                "sign": "subjective",
+                "topicNo": null,
+                "topicName": "解答题",
+                "startNumber": 1,
+                "questionsCount": 8,
+                "w": 703,
+                "endNumber": 8
+              },
+              "id": "element-mpobmln1dd1g2ico",
+              "key": "f6pn3kogmpg86u9g",
+              "elementSerialNo": 13
+            },
+            {
+              "type": "EXPLAIN",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 458,
+              "minHeight": 60,
+              "sign": "subjective",
+              "topicNo": 3,
+              "isCovered": false,
+              "isLast": true,
+              "isExtend": false,
+              "showTitle": false,
+              "serialNumber": 8,
+              "elements": [],
+              "parent": {
+                "id": "element-hmkner4grlip0ob8",
+                "key": "fmr6gvd5vuesqmvb",
+                "type": "EXPLAIN",
+                "sign": "subjective",
+                "topicNo": null,
+                "topicName": "解答题",
+                "startNumber": 1,
+                "questionsCount": 8,
+                "w": 703,
+                "endNumber": 8
+              },
+              "id": "element-oid289dodg4vkgt8",
+              "key": "es5afh5opi8mplu8",
+              "elementSerialNo": 14
+            }
+          ]
+        }
+      ],
+      "exchange": {
+        "card_type": 2,
+        "page_size": "A3",
+        "page_image": "",
+        "locator": {
+          "top": [
+            [0.0504413619, 0.0356506239, 0.0151324086, 0.0142602496],
+            [0.8738965952, 0.0356506239, 0.0151324086, 0.0142602496]
+          ],
+          "bottom": [[0.0504413619, 0.9500891266, 0.0151324086, 0.0142602496]]
+        },
+        "fill_locator": [],
+        "check_area": { "black_line": [], "white_line": [] },
+        "barcode": [
+          {
+            "field": "examNumber",
+            "area": [0.0504413619, 0.1310160428, 0.2181588903, 0.1978609626]
+          }
+        ],
+        "qrcode": [],
+        "ocr_area": [],
+        "info_area": [[0.0504413619, 0.0534759358, 0.4432534678, 0.2754010695]],
+        "fill_area": [
+          {
+            "field": "pageNumber",
+            "index": 2,
+            "single": true,
+            "horizontal": true,
+            "items": [
+              {
+                "main_number": null,
+                "sub_number": null,
+                "options": [
+                  [0.15889029, 0.9500891266, 0.0151324086, 0.0142602496],
+                  [0.1803278689, 0.9500891266, 0.0151324086, 0.0142602496],
+                  [0.2017654477, 0.9500891266, 0.0151324086, 0.0142602496],
+                  [0.2232030265, 0.9500891266, 0.0151324086, 0.0142602496]
+                ],
+                "recog_info": []
+              }
+            ]
+          }
+        ],
+        "answer_area": [
+          {
+            "main_number": 3,
+            "sub_number": 6,
+            "area": [0.0504413619, 0.3912655971, 0.4432534678, 0.4081996435]
+          },
+          {
+            "main_number": 3,
+            "sub_number": 7,
+            "area": [0.5063051702, 0.1069518717, 0.4432534678, 0.4081996435]
+          },
+          {
+            "main_number": 3,
+            "sub_number": 8,
+            "area": [0.5063051702, 0.5151515152, 0.4432534678, 0.4081996435]
+          }
+        ],
+        "extension": {
+          "barcode": [],
+          "fill_area": [],
+          "ocr_area": [],
+          "qrcode": []
+        }
+      }
+    },
+    {
+      "type": "PAGE",
+      "pageSize": "A3",
+      "columnNumber": 2,
+      "columnGap": 20,
+      "locators": {
+        "top": [
+          {
+            "id": "locator-3-00",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          },
+          {
+            "id": "locator-3-01",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          }
+        ],
+        "bottom": [
+          {
+            "id": "locator-3-10",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          }
+        ]
+      },
+      "globals": [],
+      "columns": [
+        {
+          "type": "COLUMN",
+          "x": "",
+          "y": "",
+          "w": "",
+          "h": "",
+          "isFull": false,
+          "elements": [
+            {
+              "type": "TOPIC_HEAD",
+              "x": 0,
+              "y": 0,
+              "w": 0,
+              "h": 60,
+              "content": "主观mmm",
+              "typeName": "主观题",
+              "isColumnFirst": true,
+              "sign": "subjective",
+              "id": "element-cpkk8t38a0h74fco",
+              "key": "l4pc2adgojeg35js"
+            },
+            {
+              "id": "element-2d0fqn9g0fmf0on8",
+              "key": "mpd52m18isssg9do",
+              "type": "COMPOSITION",
+              "x": 0,
+              "y": 0,
+              "w": 703,
+              "h": 915,
+              "minHeight": 60,
+              "sign": "subjective",
+              "topicNo": 4,
+              "isCovered": false,
+              "isLast": true,
+              "isExtend": false,
+              "showTitle": true,
+              "serialNumber": 0,
+              "elements": [
+                {
+                  "id": "element-0ktd0deobo7q159g",
+                  "key": "ct6ell585mftds4g",
+                  "type": "LINES",
+                  "x": 0,
+                  "y": 38,
+                  "w": 703,
+                  "h": 205,
+                  "sign": "",
+                  "lineCount": 5,
+                  "lineSpacing": 40,
+                  "margin": 0,
+                  "bold": "1px",
+                  "color": "#000000",
+                  "style": "solid",
+                  "container": {
+                    "id": "element-2d0fqn9g0fmf0on8",
+                    "type": "COMPOSITION"
+                  }
+                }
+              ],
+              "parent": {
+                "id": "element-if81tmo8afd1s5ig",
+                "key": "nnv412lgg6r4pfdk",
+                "type": "COMPOSITION",
+                "sign": "subjective",
+                "topicNo": null,
+                "topicName": "作文题",
+                "w": 703
+              },
+              "elementSerialNo": 15,
+              "init": false
+            }
+          ]
+        },
+        {
+          "type": "COLUMN",
+          "x": "",
+          "y": "",
+          "w": "",
+          "h": "",
+          "isFull": false,
+          "elements": []
+        }
+      ],
+      "exchange": {
+        "card_type": 2,
+        "page_size": "A3",
+        "page_image": "",
+        "locator": {
+          "top": [
+            [0.0504413619, 0.0356506239, 0.0151324086, 0.0142602496],
+            [0.8738965952, 0.0356506239, 0.0151324086, 0.0142602496]
+          ],
+          "bottom": [[0.0504413619, 0.9500891266, 0.0151324086, 0.0142602496]]
+        },
+        "fill_locator": [],
+        "check_area": { "black_line": [], "white_line": [] },
+        "barcode": [],
+        "qrcode": [],
+        "ocr_area": [],
+        "info_area": [],
+        "fill_area": [],
+        "answer_area": [
+          {
+            "main_number": 4,
+            "sub_number": null,
+            "area": [0.0504413619, 0.1069518717, 0.4432534678, 0.8155080214]
+          }
+        ],
+        "extension": {
+          "barcode": [],
+          "fill_area": [],
+          "ocr_area": [],
+          "qrcode": []
+        }
+      }
+    }
+  ]
+}

+ 701 - 0
card/samples/freeCardSample.json

@@ -0,0 +1,701 @@
+{
+  "version": "2.0.0",
+  "cardConfig": {
+    "pageSize": "A3",
+    "columnNumber": 2,
+    "columnGap": 20,
+    "showForbidArea": true,
+    "cardDesc": "",
+    "requiredFields": [
+      { "code": "studentCode", "name": "学号", "enable": true },
+      { "code": "ticketNumber", "name": "考号", "enable": true },
+      { "code": "siteNumber", "name": "座位号", "enable": true },
+      { "code": "studentName", "name": "姓名", "enable": true },
+      { "code": "courseCode", "name": "课程代码", "enable": true },
+      { "code": "courseName", "name": "课程名称", "enable": true },
+      { "code": "paperNumber", "name": "试卷编号", "enable": true },
+      { "code": "campusName", "name": "校区", "enable": true },
+      { "code": "examPlace", "name": "考点", "enable": true },
+      { "code": "examRoom", "name": "考场", "enable": true },
+      { "code": "examDate", "name": "考试日期", "enable": true },
+      { "code": "examTime", "name": "考试时间", "enable": true }
+    ],
+    "extendFields": [{ "name": "测试", "code": "test", "enable": false }],
+    "cardTitle": "123123"
+  },
+  "pages": [
+    {
+      "type": "PAGE",
+      "columnGap": 20,
+      "locators": {
+        "top": [
+          {
+            "id": "locator-element-88hu020g4q3tajd3-00",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          },
+          {
+            "id": "locator-element-88hu020g4q3tajd3-01",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          }
+        ],
+        "bottom": [
+          {
+            "id": "locator-element-88hu020g4q3tajd3-10",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          }
+        ]
+      },
+      "globals": [],
+      "columns": [
+        {
+          "id": "column-o7a7iifm3jjpbtj6",
+          "type": "COLUMN",
+          "x": "",
+          "y": "",
+          "w": "",
+          "h": "",
+          "elements": [
+            {
+              "id": "element-8ifsc8tg062jg3a8",
+              "key": "66n9724g3n49ae18",
+              "type": "GRIDS",
+              "x": 34,
+              "y": 766,
+              "w": 300,
+              "h": 112,
+              "sign": "",
+              "columnSize": 43,
+              "columnCount": 16,
+              "rowCount": 3,
+              "rowSpace": 0,
+              "halving": true,
+              "style": "solid",
+              "zindex": 16,
+              "desc": "网格-16×3",
+              "init": false
+            },
+            {
+              "id": "element-i6n1lcngsg7vuv5g",
+              "key": "1tg18c6o6tftgidg",
+              "type": "LINES",
+              "x": 383,
+              "y": 682,
+              "w": 187,
+              "h": 100,
+              "sign": "",
+              "lineCount": 2,
+              "lineSpacing": 40,
+              "margin": 0,
+              "bold": "1px",
+              "color": "#000000",
+              "style": "solid",
+              "zindex": 15,
+              "desc": "多横线-行数:2",
+              "init": false
+            },
+            {
+              "id": "element-culaq7sgivn2br5g",
+              "key": "6tr6stf862ajk74o",
+              "type": "FILL_PANE",
+              "x": 34,
+              "y": 692,
+              "w": 324,
+              "h": 40,
+              "sign": "",
+              "paneGap": 5,
+              "paneCount": 9,
+              "paneWidth": 30,
+              "paneHeight": 30,
+              "borderStyle": "solid",
+              "zindex": 14,
+              "desc": "方格组-9",
+              "init": false
+            },
+            {
+              "id": "element-qnsoje88tqrqlh0o",
+              "key": "rh2srk2o5lunb1t3",
+              "type": "FILL_TABLE",
+              "x": 383,
+              "y": 528,
+              "w": 176,
+              "h": 120,
+              "sign": "",
+              "colCount": 3,
+              "rowCount": 3,
+              "padding": [5, 5],
+              "lineStyle": "solid",
+              "fontSize": "14px",
+              "lineHeight": 30,
+              "content": {},
+              "zindex": 13,
+              "desc": "表格-3×3",
+              "init": false
+            },
+            {
+              "id": "element-m37vm17o71palsmt",
+              "key": "4jn2prf2t29vb4mg",
+              "type": "FILL_FIELD",
+              "x": 432,
+              "y": 379,
+              "w": 200,
+              "h": 100,
+              "sign": "",
+              "fieldCountPerLine": 1,
+              "lineSpacing": 30,
+              "nameIsJustify": false,
+              "fields": [],
+              "fieldInfos": {},
+              "zindex": 12,
+              "desc": "变量-",
+              "init": false
+            },
+            {
+              "id": "element-ckpp18hjr0t0u7o8",
+              "key": "j62prdc8tmut6vja",
+              "type": "FILL_NUMBER",
+              "x": 6,
+              "y": 368,
+              "w": 300,
+              "h": 280,
+              "sign": "",
+              "name": "准考证号",
+              "numberCount": 9,
+              "content": "",
+              "zindex": 11,
+              "desc": "号码填涂-准考证号",
+              "init": false
+            },
+            {
+              "type": "FILL_LINE",
+              "x": 146,
+              "y": 26,
+              "w": 462,
+              "h": 100,
+              "minHeight": 40,
+              "sign": "subjective",
+              "topicName": "",
+              "topicNo": null,
+              "startNumber": 1,
+              "questionsCount": 4,
+              "questionNumberPerLine": 2,
+              "lineNumberPerQuestion": 1,
+              "lineSpacing": 40,
+              "questionDirection": "vertical",
+              "questionLineType": "norm",
+              "questionLineNums": [
+                { "no": 1, "count": 1 },
+                { "no": 2, "count": 1 },
+                { "no": 3, "count": 1 },
+                { "no": 4, "count": 1 }
+              ],
+              "numberPre": "",
+              "isCovered": false,
+              "key": "1rqissjgemam50gt",
+              "id": "element-7e8njjmgdv8q1ovg",
+              "zindex": 10,
+              "desc": "填空-1~4",
+              "init": false
+            },
+            {
+              "id": "element-pt9v7m5mdqigh1t8",
+              "key": "kein0t78s927nta6",
+              "type": "FILL_QUESTION",
+              "x": 34,
+              "y": 150,
+              "w": 467,
+              "h": 138,
+              "minHeight": 138,
+              "sign": "objective",
+              "topicName": "",
+              "topicNo": null,
+              "startNumber": 1,
+              "questionsCount": 10,
+              "optionCount": 4,
+              "questionCountPerGroup": 5,
+              "groupPerLine": 4,
+              "optionDirection": "horizontal",
+              "questionDirection": "vertical",
+              "questionGap": 8,
+              "groupGap": 30,
+              "optionGap": 12,
+              "isBoolean": false,
+              "booleanType": "√,×",
+              "isMultiply": false,
+              "isCovered": false,
+              "fontSize": "14px",
+              "zindex": 9,
+              "desc": "选项填涂-1~10",
+              "init": false
+            }
+          ]
+        },
+        {
+          "id": "column-0k7bjcvgqniov4v8",
+          "type": "COLUMN",
+          "x": "",
+          "y": "",
+          "w": "",
+          "h": "",
+          "elements": [
+            {
+              "id": "element-fenb2p7ghb4i2f98",
+              "key": "83icfdlge1524lg8",
+              "type": "BARCODE",
+              "x": 18,
+              "y": 149,
+              "w": 300,
+              "h": 60,
+              "sign": "",
+              "rotation": 0,
+              "bold": "1px",
+              "color": "#ffffff",
+              "bgColor": "#ffffff",
+              "style": "solid",
+              "fields": [],
+              "content": "",
+              "zindex": 9,
+              "desc": "条形码-",
+              "init": false
+            }
+          ]
+        }
+      ],
+      "pageSize": "A3",
+      "columnNumber": 2,
+      "showForbidArea": true,
+      "id": "element-01ut2421oe94ct2d",
+      "exchange": {
+        "card_type": 2,
+        "page_size": "A3",
+        "page_image": "",
+        "locator": {
+          "top": [
+            [0.0504413619, 0.0356506239, 0.0151324086, 0.0142602496],
+            [0.8738965952, 0.0356506239, 0.0151324086, 0.0142602496]
+          ],
+          "bottom": [[0.0504413619, 0.9500891266, 0.0151324086, 0.0142602496]]
+        },
+        "fill_locator": [],
+        "check_area": { "black_line": [], "white_line": [] },
+        "barcode": [
+          { "area": [0.5176544767, 0.1862745098, 0.1891551072, 0.0534759358] }
+        ],
+        "qrcode": [],
+        "ocr_area": [],
+        "info_area": [
+          [0.2919293821, 0.5240641711, 0.1109709962, 0.1069518717],
+          [0.3228247163, 0.3912655971, 0.1261034048, 0.0891265597]
+        ],
+        "fill_area": [
+          {
+            "field": "examNumber",
+            "index": 1,
+            "single": true,
+            "horizontal": false,
+            "items": [
+              {
+                "main_number": null,
+                "sub_number": null,
+                "options": [
+                  [0.0586380832, 0.4349376114, 0.0126103405, 0.0124777184],
+                  [0.0586380832, 0.4545454545, 0.0126103405, 0.0124777184],
+                  [0.0586380832, 0.4741532977, 0.0126103405, 0.0124777184],
+                  [0.0586380832, 0.4937611408, 0.0126103405, 0.0124777184],
+                  [0.0586380832, 0.513368984, 0.0126103405, 0.0124777184],
+                  [0.0586380832, 0.5329768271, 0.0126103405, 0.0124777184],
+                  [0.0586380832, 0.5525846702, 0.0126103405, 0.0124777184],
+                  [0.0586380832, 0.5721925134, 0.0126103405, 0.0124777184],
+                  [0.0586380832, 0.5918003565, 0.0126103405, 0.0124777184],
+                  [0.0586380832, 0.6114081996, 0.0126103405, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": null,
+                "options": [
+                  [0.078814628, 0.4349376114, 0.0126103405, 0.0124777184],
+                  [0.078814628, 0.4545454545, 0.0126103405, 0.0124777184],
+                  [0.078814628, 0.4741532977, 0.0126103405, 0.0124777184],
+                  [0.078814628, 0.4937611408, 0.0126103405, 0.0124777184],
+                  [0.078814628, 0.513368984, 0.0126103405, 0.0124777184],
+                  [0.078814628, 0.5329768271, 0.0126103405, 0.0124777184],
+                  [0.078814628, 0.5525846702, 0.0126103405, 0.0124777184],
+                  [0.078814628, 0.5721925134, 0.0126103405, 0.0124777184],
+                  [0.078814628, 0.5918003565, 0.0126103405, 0.0124777184],
+                  [0.078814628, 0.6114081996, 0.0126103405, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": null,
+                "options": [
+                  [0.1002522068, 0.4349376114, 0.0126103405, 0.0124777184],
+                  [0.1002522068, 0.4545454545, 0.0126103405, 0.0124777184],
+                  [0.1002522068, 0.4741532977, 0.0126103405, 0.0124777184],
+                  [0.1002522068, 0.4937611408, 0.0126103405, 0.0124777184],
+                  [0.1002522068, 0.513368984, 0.0126103405, 0.0124777184],
+                  [0.1002522068, 0.5329768271, 0.0126103405, 0.0124777184],
+                  [0.1002522068, 0.5525846702, 0.0126103405, 0.0124777184],
+                  [0.1002522068, 0.5721925134, 0.0126103405, 0.0124777184],
+                  [0.1002522068, 0.5918003565, 0.0126103405, 0.0124777184],
+                  [0.1002522068, 0.6114081996, 0.0126103405, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": null,
+                "options": [
+                  [0.1210592686, 0.4349376114, 0.0126103405, 0.0124777184],
+                  [0.1210592686, 0.4545454545, 0.0126103405, 0.0124777184],
+                  [0.1210592686, 0.4741532977, 0.0126103405, 0.0124777184],
+                  [0.1210592686, 0.4937611408, 0.0126103405, 0.0124777184],
+                  [0.1210592686, 0.513368984, 0.0126103405, 0.0124777184],
+                  [0.1210592686, 0.5329768271, 0.0126103405, 0.0124777184],
+                  [0.1210592686, 0.5525846702, 0.0126103405, 0.0124777184],
+                  [0.1210592686, 0.5721925134, 0.0126103405, 0.0124777184],
+                  [0.1210592686, 0.5918003565, 0.0126103405, 0.0124777184],
+                  [0.1210592686, 0.6114081996, 0.0126103405, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": null,
+                "options": [
+                  [0.1418663304, 0.4349376114, 0.0126103405, 0.0124777184],
+                  [0.1418663304, 0.4545454545, 0.0126103405, 0.0124777184],
+                  [0.1418663304, 0.4741532977, 0.0126103405, 0.0124777184],
+                  [0.1418663304, 0.4937611408, 0.0126103405, 0.0124777184],
+                  [0.1418663304, 0.513368984, 0.0126103405, 0.0124777184],
+                  [0.1418663304, 0.5329768271, 0.0126103405, 0.0124777184],
+                  [0.1418663304, 0.5525846702, 0.0126103405, 0.0124777184],
+                  [0.1418663304, 0.5721925134, 0.0126103405, 0.0124777184],
+                  [0.1418663304, 0.5918003565, 0.0126103405, 0.0124777184],
+                  [0.1418663304, 0.6114081996, 0.0126103405, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": null,
+                "options": [
+                  [0.1626733922, 0.4349376114, 0.0126103405, 0.0124777184],
+                  [0.1626733922, 0.4545454545, 0.0126103405, 0.0124777184],
+                  [0.1626733922, 0.4741532977, 0.0126103405, 0.0124777184],
+                  [0.1626733922, 0.4937611408, 0.0126103405, 0.0124777184],
+                  [0.1626733922, 0.513368984, 0.0126103405, 0.0124777184],
+                  [0.1626733922, 0.5329768271, 0.0126103405, 0.0124777184],
+                  [0.1626733922, 0.5525846702, 0.0126103405, 0.0124777184],
+                  [0.1626733922, 0.5721925134, 0.0126103405, 0.0124777184],
+                  [0.1626733922, 0.5918003565, 0.0126103405, 0.0124777184],
+                  [0.1626733922, 0.6114081996, 0.0126103405, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": null,
+                "options": [
+                  [0.183480454, 0.4349376114, 0.0126103405, 0.0124777184],
+                  [0.183480454, 0.4545454545, 0.0126103405, 0.0124777184],
+                  [0.183480454, 0.4741532977, 0.0126103405, 0.0124777184],
+                  [0.183480454, 0.4937611408, 0.0126103405, 0.0124777184],
+                  [0.183480454, 0.513368984, 0.0126103405, 0.0124777184],
+                  [0.183480454, 0.5329768271, 0.0126103405, 0.0124777184],
+                  [0.183480454, 0.5525846702, 0.0126103405, 0.0124777184],
+                  [0.183480454, 0.5721925134, 0.0126103405, 0.0124777184],
+                  [0.183480454, 0.5918003565, 0.0126103405, 0.0124777184],
+                  [0.183480454, 0.6114081996, 0.0126103405, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": null,
+                "options": [
+                  [0.2042875158, 0.4349376114, 0.0126103405, 0.0124777184],
+                  [0.2042875158, 0.4545454545, 0.0126103405, 0.0124777184],
+                  [0.2042875158, 0.4741532977, 0.0126103405, 0.0124777184],
+                  [0.2042875158, 0.4937611408, 0.0126103405, 0.0124777184],
+                  [0.2042875158, 0.513368984, 0.0126103405, 0.0124777184],
+                  [0.2042875158, 0.5329768271, 0.0126103405, 0.0124777184],
+                  [0.2042875158, 0.5525846702, 0.0126103405, 0.0124777184],
+                  [0.2042875158, 0.5721925134, 0.0126103405, 0.0124777184],
+                  [0.2042875158, 0.5918003565, 0.0126103405, 0.0124777184],
+                  [0.2042875158, 0.6114081996, 0.0126103405, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": null,
+                "options": [
+                  [0.2250945776, 0.4349376114, 0.0126103405, 0.0124777184],
+                  [0.2250945776, 0.4545454545, 0.0126103405, 0.0124777184],
+                  [0.2250945776, 0.4741532977, 0.0126103405, 0.0124777184],
+                  [0.2250945776, 0.4937611408, 0.0126103405, 0.0124777184],
+                  [0.2250945776, 0.513368984, 0.0126103405, 0.0124777184],
+                  [0.2250945776, 0.5329768271, 0.0126103405, 0.0124777184],
+                  [0.2250945776, 0.5525846702, 0.0126103405, 0.0124777184],
+                  [0.2250945776, 0.5721925134, 0.0126103405, 0.0124777184],
+                  [0.2250945776, 0.5918003565, 0.0126103405, 0.0124777184],
+                  [0.2250945776, 0.6114081996, 0.0126103405, 0.0124777184]
+                ],
+                "recog_info": []
+              }
+            ]
+          },
+          {
+            "field": "question",
+            "index": 1,
+            "single": true,
+            "horizontal": true,
+            "items": [
+              {
+                "main_number": null,
+                "sub_number": 1,
+                "options": [
+                  [0.1008827238, 0.2032085561, 0.0113493064, 0.0124777184],
+                  [0.1197982346, 0.2032085561, 0.0113493064, 0.0124777184],
+                  [0.1387137453, 0.2032085561, 0.0113493064, 0.0124777184],
+                  [0.157629256, 0.2032085561, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": 2,
+                "options": [
+                  [0.1008827238, 0.2228163993, 0.0113493064, 0.0124777184],
+                  [0.1197982346, 0.2228163993, 0.0113493064, 0.0124777184],
+                  [0.1387137453, 0.2228163993, 0.0113493064, 0.0124777184],
+                  [0.157629256, 0.2228163993, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": 3,
+                "options": [
+                  [0.1008827238, 0.2424242424, 0.0113493064, 0.0124777184],
+                  [0.1197982346, 0.2424242424, 0.0113493064, 0.0124777184],
+                  [0.1387137453, 0.2424242424, 0.0113493064, 0.0124777184],
+                  [0.157629256, 0.2424242424, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": 4,
+                "options": [
+                  [0.1008827238, 0.2620320856, 0.0113493064, 0.0124777184],
+                  [0.1197982346, 0.2620320856, 0.0113493064, 0.0124777184],
+                  [0.1387137453, 0.2620320856, 0.0113493064, 0.0124777184],
+                  [0.157629256, 0.2620320856, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": 5,
+                "options": [
+                  [0.1008827238, 0.2816399287, 0.0113493064, 0.0124777184],
+                  [0.1197982346, 0.2816399287, 0.0113493064, 0.0124777184],
+                  [0.1387137453, 0.2816399287, 0.0113493064, 0.0124777184],
+                  [0.157629256, 0.2816399287, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              }
+            ]
+          },
+          {
+            "field": "question",
+            "index": 2,
+            "single": true,
+            "horizontal": true,
+            "items": [
+              {
+                "main_number": null,
+                "sub_number": 6,
+                "options": [
+                  [0.2068095839, 0.2032085561, 0.0113493064, 0.0124777184],
+                  [0.2257250946, 0.2032085561, 0.0113493064, 0.0124777184],
+                  [0.2446406053, 0.2032085561, 0.0113493064, 0.0124777184],
+                  [0.263556116, 0.2032085561, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": 7,
+                "options": [
+                  [0.2068095839, 0.2228163993, 0.0113493064, 0.0124777184],
+                  [0.2257250946, 0.2228163993, 0.0113493064, 0.0124777184],
+                  [0.2446406053, 0.2228163993, 0.0113493064, 0.0124777184],
+                  [0.263556116, 0.2228163993, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": 8,
+                "options": [
+                  [0.2068095839, 0.2424242424, 0.0113493064, 0.0124777184],
+                  [0.2257250946, 0.2424242424, 0.0113493064, 0.0124777184],
+                  [0.2446406053, 0.2424242424, 0.0113493064, 0.0124777184],
+                  [0.263556116, 0.2424242424, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": 9,
+                "options": [
+                  [0.2068095839, 0.2620320856, 0.0113493064, 0.0124777184],
+                  [0.2257250946, 0.2620320856, 0.0113493064, 0.0124777184],
+                  [0.2446406053, 0.2620320856, 0.0113493064, 0.0124777184],
+                  [0.263556116, 0.2620320856, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              },
+              {
+                "main_number": null,
+                "sub_number": 10,
+                "options": [
+                  [0.2068095839, 0.2816399287, 0.0113493064, 0.0124777184],
+                  [0.2257250946, 0.2816399287, 0.0113493064, 0.0124777184],
+                  [0.2446406053, 0.2816399287, 0.0113493064, 0.0124777184],
+                  [0.263556116, 0.2816399287, 0.0113493064, 0.0124777184]
+                ],
+                "recog_info": []
+              }
+            ]
+          }
+        ],
+        "answer_area": [
+          {
+            "main_number": null,
+            "sub_number": null,
+            "area": [0.0718789407, 0.7361853832, 0.1891551072, 0.0998217469]
+          },
+          {
+            "main_number": null,
+            "sub_number": null,
+            "area": [0.2919293821, 0.6613190731, 0.1179066835, 0.0891265597]
+          },
+          {
+            "main_number": null,
+            "sub_number": "1,2,3,4",
+            "area": [0.1424968474, 0.0766488414, 0.2912988651, 0.0891265597]
+          }
+        ],
+        "extension": {
+          "barcode": [],
+          "fill_area": [],
+          "ocr_area": [],
+          "qrcode": []
+        }
+      }
+    },
+    {
+      "type": "PAGE",
+      "columnGap": 20,
+      "locators": {
+        "top": [
+          {
+            "id": "locator-element-hii5dnl83efbuec8-00",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          },
+          {
+            "id": "locator-element-hii5dnl83efbuec8-01",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          }
+        ],
+        "bottom": [
+          {
+            "id": "locator-element-hii5dnl83efbuec8-10",
+            "type": "LOCATOR",
+            "x": "",
+            "y": "",
+            "w": "",
+            "h": ""
+          }
+        ]
+      },
+      "globals": [],
+      "columns": [
+        {
+          "id": "column-51eoaq4oo1no4p28",
+          "type": "COLUMN",
+          "x": "",
+          "y": "",
+          "w": "",
+          "h": "",
+          "elements": []
+        },
+        {
+          "id": "column-ii5n11jo601mt6bo",
+          "type": "COLUMN",
+          "x": "",
+          "y": "",
+          "w": "",
+          "h": "",
+          "elements": []
+        }
+      ],
+      "pageSize": "A3",
+      "columnNumber": 2,
+      "showForbidArea": true,
+      "id": "element-tm6gbgf87hjjaaeo",
+      "exchange": {
+        "card_type": 2,
+        "page_size": "A3",
+        "page_image": "",
+        "locator": {
+          "top": [
+            [0.0504413619, 0.0356506239, 0.0151324086, 0.0142602496],
+            [0.8738965952, 0.0356506239, 0.0151324086, 0.0142602496]
+          ],
+          "bottom": [[0.0504413619, 0.9500891266, 0.0151324086, 0.0142602496]]
+        },
+        "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": []
+        }
+      }
+    }
+  ]
+}

+ 301 - 291
src/modules/card/views/CardEdit.vue

@@ -1,291 +1,301 @@
-<template>
-  <div class="card-edit">
-    <component
-      v-if="dataReady"
-      :is="editComp"
-      ref="CardDesign"
-      :content="cardContent"
-      :show-save-btn="!IS_GENERIC"
-      @on-preview="toPreview"
-      @on-save="toSave"
-      @on-submit="toSubmit"
-      @on-exit="toExit"
-    ></component>
-
-    <!-- card-view-frame -->
-    <div class="design-preview-frame" v-if="cardPreviewUrl">
-      <iframe :src="cardPreviewUrl" frameborder="0"></iframe>
-    </div>
-  </div>
-</template>
-
-<script>
-import { cardConfigInfos, cardDetail, saveCard } from "../api";
-import CardDesign from "../../../../card/components/CardDesign";
-import CardFreeDesign from "../../../../card/modules/free/components/CardFreeDesign";
-import { examRuleDetail } from "../../base/api";
-import { getEnums } from "../../login/api";
-
-export default {
-  name: "card-edit",
-  components: {
-    CardDesign,
-    CardFreeDesign
-  },
-  props: {
-    isDialog: {
-      type: Boolean,
-      default: false
-    }
-  },
-  data() {
-    return {
-      cardId: this.$route.params.cardId || this.$ls.get("cardId"),
-      prepareTcPCard: this.$ls.get("prepareTcPCard", {}),
-      cardType: "CUSTOM",
-      cardCreateMethod: "STANDARD",
-      cardContent: {},
-      cardPreviewUrl: "",
-      canSave: false,
-      dataReady: false
-    };
-  },
-  computed: {
-    isEdit() {
-      return !!this.cardId;
-    },
-    editComp() {
-      return this.cardCreateMethod === "STANDARD"
-        ? "card-design"
-        : "card-free-design";
-    },
-    IS_GENERIC() {
-      return this.cardType === "GENERIC";
-    }
-  },
-  mounted() {
-    this.cardCreateMethod = this.prepareTcPCard.createMethod || "STANDARD";
-    this.cardId = this.cardId || this.prepareTcPCard.id;
-    this.cardType = this.prepareTcPCard.type || "CUSTOM";
-    // if (
-    //   !this.prepareTcPCard.examTaskId &&
-    //   !this.isEdit &&
-    //   this.cardType === "CUSTOM"
-    // ) {
-    //   this.$message.error("找不到命题任务,请退出题卡制作!");
-    //   return;
-    // }
-    this.initCard();
-    this.registWindowSubmit();
-  },
-  methods: {
-    async initCard() {
-      this.dataReady = false;
-      if (this.isEdit) {
-        await this.getCardTempDetail();
-      } else {
-        let cardConfig = await this.getCardConfig();
-        if (this.IS_GENERIC) {
-          cardConfig.cardTitle = this.prepareTcPCard.title;
-        }
-        this.cardContent = {
-          pages: [],
-          cardConfig,
-          paperParams: {}
-        };
-      }
-      this.dataReady = true;
-    },
-    getCardTitle(titleRule) {
-      const fieldMap = {
-        courseCode: this.prepareTcPCard.courseCode || "",
-        courseName: this.prepareTcPCard.courseName || "",
-        schoolName: this.prepareTcPCard.schoolName || ""
-      };
-      Object.entries(fieldMap).forEach(([key, val]) => {
-        titleRule = titleRule.replace("${" + key + "}", val);
-      });
-      return titleRule;
-    },
-    async getCardTempDetail() {
-      const detData = await cardDetail(this.cardId);
-      // 可能存在题卡内容没有记录的情况
-      if (detData.content) {
-        this.cardContent = JSON.parse(detData.content);
-      } else {
-        let cardConfig = await this.getCardConfig();
-        // 没有题卡内容时,直接创建新的内容
-        if (detData.makeMethod === "CUST" || detData.type === "GENERIC") {
-          cardConfig.cardTitle = detData.title;
-        }
-        this.cardContent = {
-          pages: [],
-          cardConfig,
-          paperParams: {}
-        };
-      }
-    },
-    async getCardConfig() {
-      if (this.cardCreateMethod === "STANDARD") {
-        const data = await cardConfigInfos(this.prepareTcPCard.cardRuleId);
-        if (!data) {
-          this.$message.error("找不到题卡规则!");
-          return Promise.reject();
-        }
-        let config = {
-          ...data,
-          ...{
-            pageSize: "A3",
-            columnNumber: 2,
-            columnGap: 20,
-            showForbidArea: true,
-            cardDesc: "",
-            makeMethod: this.prepareTcPCard.makeMethod
-          }
-        };
-        config.aOrB = true; // 默认开启A/B卷型
-        config.requiredFields = JSON.parse(config.requiredFields);
-        config.extendFields = JSON.parse(config.extendFields);
-        config.cardTitle = this.getCardTitle(config.titleRule);
-        return config;
-      } else {
-        let requiredFields = await getEnums("REQUIRED_FIELDS");
-        requiredFields = requiredFields.map(item => {
-          return {
-            code: item.code,
-            name: item.desc,
-            enable: true
-          };
-        });
-        const examRule = await examRuleDetail();
-        const extendFields = examRule.extendFields || "[]";
-        let config = {
-          pageSize: "A3",
-          columnNumber: 2,
-          columnGap: 20,
-          showForbidArea: true,
-          cardDesc: "",
-          requiredFields,
-          extendFields: JSON.parse(extendFields)
-        };
-        return config;
-      }
-    },
-    // 操作
-    getRequestConfig() {
-      return this.prepareTcPCard.makeMethod === "CUST"
-        ? {
-            headers: {
-              schoolId: this.prepareTcPCard.schoolId
-            }
-          }
-        : {};
-    },
-    getCardInfo(data) {
-      let cardInfo = {
-        ...data,
-        ...this.prepareTcPCard
-      };
-      if (this.cardId) cardInfo.id = this.cardId;
-      return cardInfo;
-    },
-    async toPreview(cardModel) {
-      await this.toSave(cardModel);
-
-      const { href } = this.$router.resolve({
-        name: "CardPreview",
-        params: {
-          cardId: this.cardId,
-          viewType: "view"
-        }
-      });
-      window.open(href);
-    },
-    // save
-    async toSave(datas) {
-      let cardInfo = this.getCardInfo(datas);
-      cardInfo.status = "STAGE";
-      const result = await saveCard(
-        cardInfo,
-        this.getRequestConfig()
-      ).catch(() => {});
-
-      this.$refs.CardDesign.unloading();
-      if (!result) return;
-
-      this.cardId = result;
-      this.$ls.set("cardId", this.cardId);
-      this.$message.success("保存成功!");
-    },
-    async toSubmit(cardData) {
-      const res = await this.$confirm("确定要提交当前题卡吗?", "提示", {
-        type: "warning"
-      }).catch(() => {});
-      if (res !== "confirm") return;
-
-      this.$refs.CardDesign.loading();
-      window.cardData = {
-        ...cardData,
-        createMethod: this.cardCreateMethod,
-        type: this.cardType
-      };
-      const { href } = this.$router.resolve({
-        name: "CardPreview",
-        params: {
-          cardId: 1,
-          viewType: "frame"
-        }
-      });
-      this.cardPreviewUrl = href;
-    },
-    registWindowSubmit() {
-      window.submitCardTemp = async (htmlContent, model) => {
-        this.cardPreviewUrl = "";
-        const datas = this.$refs.CardDesign.getCardData(htmlContent, model);
-        const cardInfo = this.getCardInfo(datas);
-        cardInfo.status = "SUBMIT";
-        const result = await saveCard(
-          cardInfo,
-          this.getRequestConfig()
-        ).catch(() => {});
-        this.$refs.CardDesign.unloading();
-        window.cardData = null;
-        if (result) {
-          this.cardId = result;
-          this.$ls.set("cardId", this.cardId);
-          this.canSave = false;
-          this.$message.success("提交成功!");
-          this.goback();
-        } else {
-          this.$message.error("提交失败,请重新尝试!");
-        }
-      };
-    },
-    toExit() {
-      this.$confirm(
-        "请确保当前题卡已经正常保存,确定要退出当前题卡编辑吗?",
-        "提示",
-        {
-          type: "warning"
-        }
-      )
-        .then(() => {
-          this.goback();
-        })
-        .catch(() => {});
-    },
-    goback() {
-      if (this.isDialog) {
-        this.$emit("exit", this.cardId);
-      } else {
-        this.$router.go(-1);
-      }
-    }
-  },
-  beforeDestroy() {
-    this.$ls.remove("cardId");
-    this.$ls.remove("prepareTcPCard");
-    delete window.submitCardTemp;
-  }
-};
-</script>
+<template>
+  <div class="card-edit">
+    <component
+      v-if="dataReady"
+      :is="editComp"
+      ref="CardDesign"
+      :content="cardContent"
+      :show-save-btn="!IS_GENERIC"
+      @on-preview="toPreview"
+      @on-save="toSave"
+      @on-submit="toSubmit"
+      @on-exit="toExit"
+    ></component>
+
+    <!-- card-view-frame -->
+    <div class="design-preview-frame" v-if="cardPreviewUrl">
+      <iframe :src="cardPreviewUrl" frameborder="0"></iframe>
+    </div>
+  </div>
+</template>
+
+<script>
+import { cardConfigInfos, cardDetail, saveCard } from "../api";
+import CardDesign from "../../../../card/components/CardDesign";
+import CardFreeDesign from "../../../../card/modules/free/components/CardFreeDesign";
+import { examRuleDetail } from "../../base/api";
+import { getEnums } from "../../login/api";
+
+export default {
+  name: "card-edit",
+  components: {
+    CardDesign,
+    CardFreeDesign
+  },
+  props: {
+    isDialog: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      cardId: this.$route.params.cardId || this.$ls.get("cardId"),
+      prepareTcPCard: this.$ls.get("prepareTcPCard", {}),
+      cardType: "CUSTOM",
+      cardCreateMethod: "STANDARD",
+      cardContent: {},
+      cardPreviewUrl: "",
+      canSave: false,
+      dataReady: false
+    };
+  },
+  computed: {
+    isEdit() {
+      return !!this.cardId;
+    },
+    editComp() {
+      return this.cardCreateMethod === "STANDARD"
+        ? "card-design"
+        : "card-free-design";
+    },
+    IS_GENERIC() {
+      return this.cardType === "GENERIC";
+    }
+  },
+  mounted() {
+    this.cardCreateMethod = this.prepareTcPCard.createMethod || "STANDARD";
+    this.cardId = this.cardId || this.prepareTcPCard.id;
+    this.cardType = this.prepareTcPCard.type || "CUSTOM";
+    // if (
+    //   !this.prepareTcPCard.examTaskId &&
+    //   !this.isEdit &&
+    //   this.cardType === "CUSTOM"
+    // ) {
+    //   this.$message.error("找不到命题任务,请退出题卡制作!");
+    //   return;
+    // }
+    this.initCard();
+    this.registWindowSubmit();
+  },
+  methods: {
+    async initCard() {
+      this.dataReady = false;
+      if (this.isEdit) {
+        await this.getCardTempDetail();
+      } else {
+        let cardConfig = await this.getCardConfig();
+        if (this.IS_GENERIC) {
+          cardConfig.cardTitle = this.prepareTcPCard.title;
+        }
+        this.cardContent = {
+          pages: [],
+          cardConfig,
+          paperParams: {}
+        };
+      }
+      this.dataReady = true;
+    },
+    getCardTitle(titleRule) {
+      const fieldMap = {
+        courseCode: this.prepareTcPCard.courseCode || "",
+        courseName: this.prepareTcPCard.courseName || "",
+        schoolName: this.prepareTcPCard.schoolName || ""
+      };
+      Object.entries(fieldMap).forEach(([key, val]) => {
+        titleRule = titleRule.replace("${" + key + "}", val);
+      });
+      return titleRule;
+    },
+    async getCardTempDetail() {
+      const detData = await cardDetail(this.cardId);
+      // 可能存在题卡内容没有记录的情况
+      if (detData.content) {
+        this.cardContent = JSON.parse(detData.content);
+      } else {
+        let cardConfig = await this.getCardConfig();
+        // 没有题卡内容时,直接创建新的内容
+        if (detData.makeMethod === "CUST" || detData.type === "GENERIC") {
+          cardConfig.cardTitle = detData.title;
+        }
+        this.cardContent = {
+          pages: [],
+          cardConfig,
+          paperParams: {}
+        };
+      }
+    },
+    async getCardConfig() {
+      if (this.cardCreateMethod === "STANDARD") {
+        const data = await cardConfigInfos(this.prepareTcPCard.cardRuleId);
+        if (!data) {
+          this.$message.error("找不到题卡规则!");
+          return Promise.reject();
+        }
+        let config = {
+          ...data,
+          ...{
+            pageSize: "A3",
+            columnNumber: 2,
+            columnGap: 20,
+            showForbidArea: true,
+            cardDesc: "",
+            makeMethod: this.prepareTcPCard.makeMethod
+          }
+        };
+        config.aOrB = true; // 默认开启A/B卷型
+        config.requiredFields = JSON.parse(config.requiredFields);
+        config.extendFields = JSON.parse(config.extendFields);
+        config.cardTitle = this.getCardTitle(config.titleRule);
+        return config;
+      } else {
+        let requiredFields = await getEnums("REQUIRED_FIELDS");
+        requiredFields = requiredFields.map(item => {
+          return {
+            code: item.code,
+            name: item.desc,
+            enable: true
+          };
+        });
+        const examRule = await examRuleDetail();
+        const extendFields = examRule.extendFields || "[]";
+        let config = {
+          pageSize: "A3",
+          columnNumber: 2,
+          columnGap: 20,
+          showForbidArea: true,
+          cardDesc: "",
+          requiredFields,
+          extendFields: JSON.parse(extendFields)
+        };
+        return config;
+      }
+    },
+    // 操作
+    getRequestConfig() {
+      return this.prepareTcPCard.makeMethod === "CUST"
+        ? {
+            headers: {
+              schoolId: this.prepareTcPCard.schoolId
+            }
+          }
+        : {};
+    },
+    getCardInfo(data) {
+      let cardInfo = {
+        ...data,
+        ...this.prepareTcPCard
+      };
+      if (this.cardId) cardInfo.id = this.cardId;
+      return cardInfo;
+    },
+    async toPreview(cardModel) {
+      await this.toSave(cardModel);
+
+      const { href } = this.$router.resolve({
+        name: "CardPreview",
+        params: {
+          cardId: this.cardId,
+          viewType: "view"
+        }
+      });
+      window.open(href);
+    },
+    // save
+    async toSave(datas) {
+      let cardInfo = this.getCardInfo(datas);
+      cardInfo.status = "STAGE";
+      const result = await saveCard(
+        cardInfo,
+        this.getRequestConfig()
+      ).catch(() => {});
+
+      this.$refs.CardDesign.unloading();
+      if (!result) return;
+
+      this.cardId = result;
+      this.$ls.set("cardId", this.cardId);
+      this.$message.success("保存成功!");
+    },
+    async toSubmit(cardData) {
+      const res = await this.$confirm("确定要提交当前题卡吗?", "提示", {
+        type: "warning"
+      }).catch(() => {});
+      if (res !== "confirm") return;
+
+      this.$refs.CardDesign.loading();
+      window.cardData = {
+        ...cardData,
+        createMethod: this.cardCreateMethod,
+        type: this.cardType
+      };
+      const { href } = this.$router.resolve({
+        name: "CardPreview",
+        params: {
+          cardId: 1,
+          viewType: "frame"
+        },
+        query: {
+          t: Date.now()
+        }
+      });
+      this.cardPreviewUrl = href;
+    },
+    registWindowSubmit() {
+      window.submitCardTemp = async (htmlContent, model) => {
+        if (!htmlContent || !model) {
+          this.$refs.CardDesign.unloading();
+          window.cardData = null;
+          this.cardPreviewUrl = "";
+          this.$message.error("提交失败,请重新尝试!");
+          return;
+        }
+        this.cardPreviewUrl = "";
+        const datas = this.$refs.CardDesign.getCardData(htmlContent, model);
+        const cardInfo = this.getCardInfo(datas);
+        cardInfo.status = "SUBMIT";
+        const result = await saveCard(
+          cardInfo,
+          this.getRequestConfig()
+        ).catch(() => {});
+        this.$refs.CardDesign.unloading();
+        window.cardData = null;
+        if (result) {
+          this.cardId = result;
+          this.$ls.set("cardId", this.cardId);
+          this.canSave = false;
+          this.$message.success("提交成功!");
+          this.goback();
+        } else {
+          this.$message.error("提交失败,请重新尝试!");
+        }
+      };
+    },
+    toExit() {
+      this.$confirm(
+        "请确保当前题卡已经正常保存,确定要退出当前题卡编辑吗?",
+        "提示",
+        {
+          type: "warning"
+        }
+      )
+        .then(() => {
+          this.goback();
+        })
+        .catch(() => {});
+    },
+    goback() {
+      if (this.isDialog) {
+        this.$emit("exit", this.cardId);
+      } else {
+        this.$router.go(-1);
+      }
+    }
+  },
+  beforeDestroy() {
+    this.$ls.remove("cardId");
+    this.$ls.remove("prepareTcPCard");
+    delete window.submitCardTemp;
+  }
+};
+</script>

+ 219 - 212
src/modules/card/views/CardPreview.vue

@@ -1,212 +1,219 @@
-<template>
-  <div :class="classes">
-    <div v-if="IS_HTML_TEMPLATE" class="preview-frame" id="preview-frame"></div>
-
-    <component
-      v-if="!IS_HTML_TEMPLATE && pages.length"
-      :is="editComp"
-      ref="CardView"
-      class="preview-body"
-      :pages="pages"
-      :card-config="cardConfig"
-    ></component>
-  </div>
-</template>
-
-<script>
-import CardView from "../../../../card/components/CardView";
-import CardFreeView from "../../../../card/modules/free/components/CardFreeView";
-import { cardDetail } from "../api";
-import { deepCopy } from "@/plugins/utils";
-const JsBarcode = require("jsbarcode");
-
-export default {
-  name: "card-preview",
-  components: { CardView, CardFreeView },
-  data() {
-    return {
-      isPrint: this.$route.params.viewType !== "view",
-      isFrame: this.$route.params.viewType === "frame",
-      cardId: this.$route.params.cardId,
-      cardCreateMethod: "STANDARD",
-      cardType: "CUSTOM",
-      cardConfig: {},
-      pages: [],
-      IS_HTML_TEMPLATE: false
-    };
-  },
-  computed: {
-    classes() {
-      return [
-        "card-preview",
-        {
-          "card-print": this.isPrint,
-          "card-free-preview": this.cardCreateMethod === "FREE"
-        }
-      ];
-    },
-    editComp() {
-      return this.cardCreateMethod === "FREE" ? "card-free-view" : "card-view";
-    }
-  },
-  mounted() {
-    if (this.isFrame) {
-      this.initFrame();
-    } else {
-      this.init();
-    }
-  },
-  methods: {
-    initFrame() {
-      const cardData = window.parent.cardData;
-      if (!cardData) return;
-
-      const { cardConfig, pages, createMethod, type } = deepCopy(cardData);
-      this.cardCreateMethod = createMethod;
-      this.cardType = type;
-
-      this.IS_HTML_TEMPLATE =
-        this.cardType === "GENERIC" && this.cardCreateMethod === "UPLOAD";
-      let fieldInfos = {};
-      [...cardConfig.requiredFields, ...cardConfig.extendFields]
-        .filter(item => item.enable)
-        .map(item => {
-          fieldInfos[item.code] = "${" + item.code + "}";
-        });
-
-      if (this.cardCreateMethod === "STANDARD") {
-        if (cardConfig.examNumberStyle === "PRINT") {
-          fieldInfos.examNumber = "data:image/png;base64,${examNumber}";
-          fieldInfos.examNumberStr = "${examNumberStr}";
-        }
-
-        if (cardConfig.aOrB && cardConfig.paperType === "PRINT") {
-          fieldInfos.paperType = "data:image/png;base64,${paperType}";
-          fieldInfos.paperTypeName = "${paperTypeName}";
-        }
-      }
-
-      this.cardConfig = cardConfig;
-      this.pages = this.appendFieldInfo(pages, fieldInfos);
-
-      this.$nextTick(() => {
-        const cardContentTemp = this.$refs.CardView.getPreviewTemp(
-          this.$el.outerHTML
-        );
-        const model = this.$refs.CardView.getPageModel(cardData);
-        window.parent &&
-          window.parent.submitCardTemp &&
-          window.parent.submitCardTemp(cardContentTemp, model);
-      });
-    },
-    async init() {
-      const detData = await cardDetail(this.cardId);
-      this.cardCreateMethod = detData.createMethod;
-      this.cardType = detData.type;
-
-      this.IS_HTML_TEMPLATE =
-        detData.type === "GENERIC" && detData.createMethod === "UPLOAD";
-      // 通卡展示
-      if (this.IS_HTML_TEMPLATE) {
-        this.$nextTick(() => {
-          this.initHtmlTemp(detData.htmlContent);
-        });
-        return;
-      }
-      // 常规卡展示
-      if (!detData.content) {
-        this.$message.error("很抱歉,当前题卡还没开始制作!");
-        return;
-      }
-      const { cardConfig, pages } = JSON.parse(detData.content);
-      const fieldInfos = this.fetchFieldInfos(cardConfig, {});
-
-      this.cardConfig = cardConfig;
-      this.pages = this.appendFieldInfo(pages, fieldInfos);
-    },
-    initHtmlTemp(htmlTemp) {
-      const iframeDom = document.createElement("iframe");
-      document.getElementById("preview-frame").appendChild(iframeDom);
-      const wwidth = window.innerWidth - 10;
-      const wheight = window.innerHeight - 10;
-      iframeDom.style.cssText = `width: ${wwidth}px;height: ${wheight}px;border:none;outline:none;`;
-      const iframeDoc = iframeDom.contentDocument;
-      iframeDoc.open();
-      iframeDoc.write(htmlTemp);
-      iframeDoc.close();
-    },
-    fetchFieldInfos(cardConfig, stdInfo) {
-      let fieldInfos = {};
-      const defContent = "相关信息";
-      const defNumber = "123456789";
-      [...cardConfig.requiredFields, ...cardConfig.extendFields]
-        .filter(item => item.enable)
-        .map(item => {
-          fieldInfos[item.code] = stdInfo[item.code] || defContent;
-        });
-      if (this.cardCreateMethod === "STANDARD") {
-        if (cardConfig.examNumberStyle === "PRINT") {
-          fieldInfos.examNumber = this.getBase64Barcode(
-            stdInfo["examNumber"] || defNumber
-          );
-          fieldInfos.examNumberStr = stdInfo["examNumber"] || defNumber;
-        }
-        if (cardConfig.aOrB && cardConfig.paperType === "PRINT") {
-          fieldInfos.paperType = this.getBase64Barcode(
-            stdInfo["paperType"] || defNumber
-          );
-          fieldInfos.paperTypeName = stdInfo["paperTypeName"] || "A";
-        }
-      }
-
-      return fieldInfos;
-    },
-    getBase64Barcode(str) {
-      const canvas = document.createElement("CANVAS");
-      JsBarcode(canvas, str, {
-        width: 2,
-        height: 30,
-        displayValue: false,
-        marginLeft: 20,
-        marginRight: 20,
-        marginTop: 0,
-        marginBottom: 0
-      });
-
-      return canvas.toDataURL();
-    },
-    appendFieldInfo(pages, fieldInfos) {
-      if (this.cardCreateMethod === "STANDARD") {
-        pages.forEach((page, pageNo) => {
-          if (pageNo % 2) return;
-          const cardHeadElement = page.columns[0].elements[0];
-
-          if (cardHeadElement.type === "CARD_HEAD") {
-            cardHeadElement.fieldInfos = fieldInfos;
-          }
-        });
-      } else {
-        const VALID_ELEMENTS_FOR_EXTERNAL = ["BARCODE"];
-        // PS:系统暂时没有设置变量值获取方法,变量站位填充暂时取消。
-        // const VALID_ELEMENTS_FOR_EXTERNAL = ["BARCODE", "FILL_FIELD"];
-        pages.forEach(page => {
-          page.columns.forEach(column => {
-            column.elements.forEach(element => {
-              if (!VALID_ELEMENTS_FOR_EXTERNAL.includes(element.type)) return;
-
-              if (element.type === "BARCODE") {
-                const field = element.fields[0] && element.fields[0].code;
-                element.content = `data:image/png;base64,${fieldInfos[field]}`;
-                return;
-              }
-
-              element.fieldInfos = fieldInfos;
-            });
-          });
-        });
-      }
-      return pages;
-    }
-  }
-};
-</script>
+<template>
+  <div :class="classes">
+    <div v-if="IS_HTML_TEMPLATE" class="preview-frame" id="preview-frame"></div>
+
+    <component
+      v-if="!IS_HTML_TEMPLATE && pages.length"
+      :is="editComp"
+      ref="CardView"
+      class="preview-body"
+      :pages="pages"
+      :card-config="cardConfig"
+    ></component>
+  </div>
+</template>
+
+<script>
+import CardView from "../../../../card/components/CardView";
+import CardFreeView from "../../../../card/modules/free/components/CardFreeView";
+import { cardDetail } from "../api";
+import { deepCopy } from "@/plugins/utils";
+const JsBarcode = require("jsbarcode");
+
+export default {
+  name: "card-preview",
+  components: { CardView, CardFreeView },
+  data() {
+    return {
+      isPrint: this.$route.params.viewType !== "view",
+      isFrame: this.$route.params.viewType === "frame",
+      cardId: this.$route.params.cardId,
+      cardCreateMethod: "STANDARD",
+      cardType: "CUSTOM",
+      cardConfig: {},
+      pages: [],
+      IS_HTML_TEMPLATE: false
+    };
+  },
+  computed: {
+    classes() {
+      return [
+        "card-preview",
+        {
+          "card-print": this.isPrint,
+          "card-free-preview": this.cardCreateMethod === "FREE"
+        }
+      ];
+    },
+    editComp() {
+      return this.cardCreateMethod === "FREE" ? "card-free-view" : "card-view";
+    }
+  },
+  mounted() {
+    if (this.isFrame) {
+      this.initFrame();
+    } else {
+      this.init();
+    }
+  },
+  methods: {
+    initFrame() {
+      const cardData = window.parent.cardData;
+      if (!cardData) return;
+
+      const { cardConfig, pages, createMethod, type } = deepCopy(cardData);
+      this.cardCreateMethod = createMethod;
+      this.cardType = type;
+
+      this.IS_HTML_TEMPLATE =
+        this.cardType === "GENERIC" && this.cardCreateMethod === "UPLOAD";
+      let fieldInfos = {};
+      [...cardConfig.requiredFields, ...cardConfig.extendFields]
+        .filter(item => item.enable)
+        .map(item => {
+          fieldInfos[item.code] = "${" + item.code + "}";
+        });
+
+      if (this.cardCreateMethod === "STANDARD") {
+        if (cardConfig.examNumberStyle === "PRINT") {
+          fieldInfos.examNumber = "data:image/png;base64,${examNumber}";
+          fieldInfos.examNumberStr = "${examNumberStr}";
+        }
+
+        if (cardConfig.aOrB && cardConfig.paperType === "PRINT") {
+          fieldInfos.paperType = "data:image/png;base64,${paperType}";
+          fieldInfos.paperTypeName = "${paperTypeName}";
+        }
+      }
+
+      this.cardConfig = cardConfig;
+      this.pages = this.appendFieldInfo(pages, fieldInfos);
+
+      this.$nextTick(() => {
+        const cardContentTemp = this.$refs.CardView.getPreviewTemp(
+          this.$el.outerHTML
+        );
+        try {
+          const model = this.$refs.CardView.getPageModel(cardData);
+          window.parent &&
+            window.parent.submitCardTemp &&
+            window.parent.submitCardTemp(cardContentTemp, model);
+        } catch (error) {
+          console.dir(error);
+          window.parent &&
+            window.parent.submitCardTemp &&
+            window.parent.submitCardTemp("", "");
+        }
+      });
+    },
+    async init() {
+      const detData = await cardDetail(this.cardId);
+      this.cardCreateMethod = detData.createMethod;
+      this.cardType = detData.type;
+
+      this.IS_HTML_TEMPLATE =
+        detData.type === "GENERIC" && detData.createMethod === "UPLOAD";
+      // 通卡展示
+      if (this.IS_HTML_TEMPLATE) {
+        this.$nextTick(() => {
+          this.initHtmlTemp(detData.htmlContent);
+        });
+        return;
+      }
+      // 常规卡展示
+      if (!detData.content) {
+        this.$message.error("很抱歉,当前题卡还没开始制作!");
+        return;
+      }
+      const { cardConfig, pages } = JSON.parse(detData.content);
+      const fieldInfos = this.fetchFieldInfos(cardConfig, {});
+
+      this.cardConfig = cardConfig;
+      this.pages = this.appendFieldInfo(pages, fieldInfos);
+    },
+    initHtmlTemp(htmlTemp) {
+      const iframeDom = document.createElement("iframe");
+      document.getElementById("preview-frame").appendChild(iframeDom);
+      const wwidth = window.innerWidth - 10;
+      const wheight = window.innerHeight - 10;
+      iframeDom.style.cssText = `width: ${wwidth}px;height: ${wheight}px;border:none;outline:none;`;
+      const iframeDoc = iframeDom.contentDocument;
+      iframeDoc.open();
+      iframeDoc.write(htmlTemp);
+      iframeDoc.close();
+    },
+    fetchFieldInfos(cardConfig, stdInfo) {
+      let fieldInfos = {};
+      const defContent = "相关信息";
+      const defNumber = "123456789";
+      [...cardConfig.requiredFields, ...cardConfig.extendFields]
+        .filter(item => item.enable)
+        .map(item => {
+          fieldInfos[item.code] = stdInfo[item.code] || defContent;
+        });
+      if (this.cardCreateMethod === "STANDARD") {
+        if (cardConfig.examNumberStyle === "PRINT") {
+          fieldInfos.examNumber = this.getBase64Barcode(
+            stdInfo["examNumber"] || defNumber
+          );
+          fieldInfos.examNumberStr = stdInfo["examNumber"] || defNumber;
+        }
+        if (cardConfig.aOrB && cardConfig.paperType === "PRINT") {
+          fieldInfos.paperType = this.getBase64Barcode(
+            stdInfo["paperType"] || defNumber
+          );
+          fieldInfos.paperTypeName = stdInfo["paperTypeName"] || "A";
+        }
+      }
+
+      return fieldInfos;
+    },
+    getBase64Barcode(str) {
+      const canvas = document.createElement("CANVAS");
+      JsBarcode(canvas, str, {
+        width: 2,
+        height: 30,
+        displayValue: false,
+        marginLeft: 20,
+        marginRight: 20,
+        marginTop: 0,
+        marginBottom: 0
+      });
+
+      return canvas.toDataURL();
+    },
+    appendFieldInfo(pages, fieldInfos) {
+      if (this.cardCreateMethod === "STANDARD") {
+        pages.forEach((page, pageNo) => {
+          if (pageNo % 2) return;
+          const cardHeadElement = page.columns[0].elements[0];
+
+          if (cardHeadElement.type === "CARD_HEAD") {
+            cardHeadElement.fieldInfos = fieldInfos;
+          }
+        });
+      } else {
+        const VALID_ELEMENTS_FOR_EXTERNAL = ["BARCODE"];
+        // PS:系统暂时没有设置变量值获取方法,变量站位填充暂时取消。
+        // const VALID_ELEMENTS_FOR_EXTERNAL = ["BARCODE", "FILL_FIELD"];
+        pages.forEach(page => {
+          page.columns.forEach(column => {
+            column.elements.forEach(element => {
+              if (!VALID_ELEMENTS_FOR_EXTERNAL.includes(element.type)) return;
+
+              if (element.type === "BARCODE") {
+                const field = element.fields[0] && element.fields[0].code;
+                element.content = `data:image/png;base64,${fieldInfos[field]}`;
+                return;
+              }
+
+              element.fieldInfos = fieldInfos;
+            });
+          });
+        });
+      }
+      return pages;
+    }
+  }
+};
+</script>

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.