Pārlūkot izejas kodu

自动生成题卡

zhangjie 3 gadi atpakaļ
vecāks
revīzija
b94317379a

+ 4 - 4
src/modules/card/assets/styles/card-design.scss

@@ -103,12 +103,12 @@
 
     .element-item-topic-number {
       position: absolute;
-      left: -22px;
+      left: -16px;
       top: 0;
-      width: 20px;
-      height: 20px;
+      width: 14px;
+      height: 14px;
       z-index: 99;
-      line-height: 20px;
+      line-height: 14px;
       font-size: 12px;
       text-align: center;
       background-color: $--color-primary;

+ 1 - 1
src/modules/card/assets/styles/card-preview.scss

@@ -165,7 +165,6 @@
     position: absolute;
   }
   .element-item-gutter {
-    position: absolute;
     height: 100% !important;
   }
   .element-item-fill-field {
@@ -852,6 +851,7 @@
 
   .elem-body {
     padding: 18px 0 18px 16px;
+    font-size: 0px;
   }
 
   .group-item {

+ 260 - 0
src/modules/card/autoBuildCard.js

@@ -0,0 +1,260 @@
+import { numberToChinese } from "./plugins/utils";
+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";
+
+const STRUCT_TYPES = {
+  SINGLE_CHOICE: 1,
+  MULTIPLE_CHOICE: 2,
+  BOOLEAN_CHOICE: 3,
+  FILL_BLANK: 4,
+  TEXT: 5,
+  NESTED: 6,
+  LISTENING: 7,
+  MATCHES: 8,
+};
+
+const COMMON_QUESTION_TYPES = [
+  STRUCT_TYPES.SINGLE_CHOICE,
+  STRUCT_TYPES.MULTIPLE_CHOICE,
+  STRUCT_TYPES.BOOLEAN_CHOICE,
+  STRUCT_TYPES.FILL_BLANK,
+  STRUCT_TYPES.TEXT,
+];
+// TODO:  LISTENING: 7,MATCHES: 8,
+
+const structTypeToCardElementType = {
+  [STRUCT_TYPES.SINGLE_CHOICE]: "FILL_QUESTION",
+  [STRUCT_TYPES.MULTIPLE_CHOICE]: "FILL_QUESTION",
+  [STRUCT_TYPES.BOOLEAN_CHOICE]: "FILL_QUESTION",
+  [STRUCT_TYPES.FILL_BLANK]: "FILL_LINE",
+  [STRUCT_TYPES.TEXT]: "EXPLAIN",
+};
+
+const elementModel = {
+  FILL_QUESTION: (presetData) => {
+    const model = createFillQuestion(presetData);
+    return getFillQuesitonElements(model, { pageSize: "A3", columnNumber: 2 });
+  },
+  FILL_LINE: (presetData) => {
+    const model = createFillLine(presetData);
+    return getFillLineElements(model, presetData.questions);
+  },
+  EXPLAIN: (presetData) => {
+    const model = createExplain(presetData);
+    return getExplainElements(model);
+  },
+};
+
+function parseCommonPaperStruct(paperJson) {
+  let structList = [];
+  paperJson.details.forEach((detail) => {
+    const commonQuestions = detail.questions.filter((q) =>
+      COMMON_QUESTION_TYPES.includes(q.structType)
+    );
+    const commonStructList = getCommonQuestionStructList(
+      detail,
+      commonQuestions,
+      true,
+      0
+    );
+    structList.push(...commonStructList);
+
+    const nestedQuestions = detail.questions.filter(
+      (q) => !COMMON_QUESTION_TYPES.includes(q.structType)
+    );
+    const nestedStructList = getNestedQuestionStructList(
+      detail,
+      nestedQuestions
+    );
+    structList.push(...nestedStructList);
+  });
+
+  structList.sort((a, b) => a.sortNo - b.sortNo);
+  console.log(structList);
+  return structList;
+}
+
+function getCommonQuestionStructList(
+  detail,
+  questions,
+  isCommon,
+  nestedQNo = 0
+) {
+  let structList = [];
+  let structs = {};
+  const qTypeNum = isCommon ? 1 : 2;
+  questions.forEach((question) => {
+    if (!structs[question.structType]) structs[question.structType] = [];
+    structs[question.structType].push(question);
+  });
+  Object.keys(structs).forEach((structType) => {
+    const stype = structType * 1;
+    const questions = parseCommonTypeQuestions(stype, structs[structType]);
+
+    structList.push({
+      detailName: detail.name,
+      detailNo: detail.number,
+      structType: stype,
+      isCommon,
+      nestedQNo,
+      sortNo: stype * 10000 + detail.number * 1000 + qTypeNum * 100 + nestedQNo,
+      questions,
+    });
+  });
+  return structList;
+}
+
+function getNestedQuestionStructList(detail, questions) {
+  let structList = [];
+  questions.forEach((question) => {
+    const qStructList = getCommonQuestionStructList(
+      detail,
+      question.subQuestions,
+      false,
+      question.number
+    );
+    structList.push(...qStructList);
+  });
+  return structList;
+}
+
+function parseCommonTypeQuestions(stype, dataList) {
+  const choiceQs = [
+    STRUCT_TYPES.SINGLE_CHOICE,
+    STRUCT_TYPES.MULTIPLE_CHOICE,
+    STRUCT_TYPES.BOOLEAN_CHOICE,
+  ];
+  let questions = [];
+  if (choiceQs.includes(stype)) {
+    questions = dataList.map((item) => {
+      return {
+        questionNo: item.number,
+        optionCount:
+          stype === STRUCT_TYPES.BOOLEAN_CHOICE ? 2 : item.options.length,
+      };
+    });
+  } else if (stype === STRUCT_TYPES.FILL_BLANK) {
+    questions = dataList.map((item) => {
+      return {
+        questionNo: item.number,
+        fillCount: getFillBackClozeCount(item.body),
+      };
+    });
+  } else {
+    questions = dataList.map((item) => item.number);
+  }
+  return questions;
+}
+
+function getFillBackClozeCount(questionBody) {
+  let num = 0;
+  questionBody.sections.forEach((section) => {
+    section.blocks.forEach((block) => {
+      if (block.type === "cloze") num++;
+    });
+  });
+  return num;
+}
+
+function buildCardElements(structList) {
+  let cardElements = [];
+  structList.forEach((struct) => {
+    const detailChineseNumber = numberToChinese(struct.detailNo);
+    let topicName = struct.isCommon
+      ? `${detailChineseNumber}、${struct.detailName}`
+      : `${detailChineseNumber}(${struct.nestedQNo})`;
+    const modelType = structTypeToCardElementType[struct.structType];
+
+    if (!struct.isCommon && struct.structType === STRUCT_TYPES.TEXT) {
+      struct.questions.forEach((qno) => {
+        const tname = `${topicName}、${qno}`;
+
+        const elements = elementModel[modelType]({
+          questions: [""],
+          topicName: tname,
+        });
+        cardElements.push(...elements);
+      });
+      return;
+    }
+
+    let presetData = {
+      questions: struct.questions,
+      topicName,
+    };
+    if (struct.structType === STRUCT_TYPES.MULTIPLE_CHOICE)
+      presetData.isMultiply = true;
+    if (struct.structType === STRUCT_TYPES.BOOLEAN_CHOICE)
+      presetData.isBoolean = true;
+
+    const elements = elementModel[modelType](presetData);
+    cardElements.push(...elements);
+  });
+
+  return cardElements;
+}
+
+export function buildPaperCard(paperJson) {
+  const structList = parseCommonPaperStruct(paperJson);
+  const cardElements = buildCardElements(structList);
+  console.log(cardElements);
+  return cardElements;
+}
+
+// const paperStruct = {
+//   paperName: "",
+//   structList: [
+//     {
+//       detailName: "",
+//       detailNo: 1,
+//       structType: 1,
+//       questions: [
+//         { questionNo: "1", optionCount: 4 },
+//         { questionNo: "2", optionCount: 4 },
+//       ],
+//     },
+//     {
+//       detailName: "",
+//       detailNo: 1,
+//       structType: 2,
+//       questions: [
+//         { questionNo: "3", optionCount: 4 },
+//         { questionNo: "4", optionCount: 4 },
+//       ],
+//     },
+//     {
+//       detailName: "",
+//       detailNo: 1,
+//       structType: 3,
+//       questions: [
+//         { questionNo: "5", optionCount: 2 },
+//         { questionNo: "6", optionCount: 2 },
+//       ],
+//     },
+//     {
+//       detailName: "",
+//       detailNo: 1,
+//       structType: 4,
+//       questions: [
+//         { questionNo: "7", fillCount: 1 },
+//         { questionNo: "8", fillCount: 2 },
+//       ],
+//     },
+//     {
+//       detailName: "",
+//       detailNo: 1,
+//       structType: 5,
+//       questions: ["11", "12"],
+//     },
+//   ],
+// };

+ 5 - 1
src/modules/card/components/CardDesign.vue

@@ -241,6 +241,8 @@ import RightClickMenu from "../components/RightClickMenu";
 import PageNumber from "../components/PageNumber";
 import TopicSelectDialog from "../components/TopicSelectDialog";
 import { getPageInitElements } from "../pageModel";
+import initPaperJson from "../paperJsonTemp.json";
+import { buildPaperCard } from "../autoBuildCard";
 
 export default {
   name: "CardDesign",
@@ -339,7 +341,9 @@ export default {
       this.addWatch();
     },
     initPageData() {
-      this.setTopics(this.pageDefaultElems.elements || []);
+      const elements = buildPaperCard(initPaperJson);
+      this.setTopics([...this.pageDefaultElems.elements, ...elements]);
+      // this.setTopics(this.pageDefaultElems.elements || []);
       this.$nextTick(() => {
         this.rebuildPages();
         this.setCurPage(0);

+ 4 - 53
src/modules/card/components/RightClickMenu.vue

@@ -12,23 +12,16 @@
           <i class="el-icon-edit-outline"></i>
           {{ IS_CONTAINER_ELEMENT ? "编辑元素" : "编辑大题" }}
         </li>
-        <li class="li-danger" @click="toDelete">
-          <i class="el-icon-delete"></i>
-          {{ IS_CONTAINER_ELEMENT ? "删除元素" : "删除大题" }}
-        </li>
         <li
-          v-if="IS_CONTAINER_ELEMENT && (IS_EXPLAIN || IS_COMPOSITION)"
+          v-if="IS_CONTAINER_ELEMENT && IS_EXPLAIN"
           @click="toCopyExplainElement"
         >
           <i class="el-icon-copy-document"></i> 复制元素
         </li>
-        <li
-          v-if="(IS_EXPLAIN || IS_COMPOSITION) && curCopyElement"
-          @click="toPasteExplainElement"
-        >
+        <li v-if="IS_EXPLAIN && curCopyElement" @click="toPasteExplainElement">
           <i class="el-icon-document-copy"></i> 粘贴元素
         </li>
-        <template v-if="IS_EXPLAIN || IS_COMPOSITION">
+        <template v-if="IS_EXPLAIN">
           <li @click="toCopyChildren">
             <i class="el-icon-circle-plus-outline"></i> 新增答题区
           </li>
@@ -40,15 +33,6 @@
             <i class="el-icon-delete"></i> 删除答题区
           </li>
         </template>
-        <li v-if="CAN_MOVE_UP" @click="toMoveUpTopic">
-          <i class="el-icon-upload2"></i> 上移大题
-        </li>
-        <li v-if="CAN_MOVE_DOWN" @click="toMoveDownTopic">
-          <i class="el-icon-download"></i> 下移大题
-        </li>
-        <li v-if="!IS_CONTAINER_ELEMENT" @click="toInsetTopic">
-          <i class="el-icon-add-location"></i> 插入大题
-        </li>
       </ul>
     </div>
   </div>
@@ -75,7 +59,7 @@ export default {
     };
   },
   computed: {
-    ...mapState("card", ["curElement", "topics", "topicSeries"]),
+    ...mapState("card", ["curElement", "topics"]),
     IS_CONTAINER_ELEMENT() {
       return !!this.curElement.container;
     },
@@ -86,39 +70,6 @@ export default {
           this.curElement.container.type === "EXPLAIN")
       );
     },
-    IS_COMPOSITION() {
-      return (
-        this.curElement.type === "COMPOSITION" ||
-        (this.curElement.container &&
-          this.curElement.container.type === "COMPOSITION")
-      );
-    },
-    CAN_MOVE_UP() {
-      if (this.IS_CONTAINER_ELEMENT) return false;
-
-      const curTopicPos = this.topicSeries.findIndex(
-        (item) => item.id === this.curElement.parent.id
-      );
-
-      return (
-        curTopicPos &&
-        this.topicSeries[curTopicPos - 1].sign ===
-          this.topicSeries[curTopicPos].sign
-      );
-    },
-    CAN_MOVE_DOWN() {
-      if (this.IS_CONTAINER_ELEMENT) return false;
-
-      const curTopicPos = this.topicSeries.findIndex(
-        (item) => item.id === this.curElement.parent.id
-      );
-
-      return (
-        curTopicPos !== this.topicSeries.length - 1 &&
-        this.topicSeries[curTopicPos + 1].sign ===
-          this.topicSeries[curTopicPos].sign
-      );
-    },
   },
   mounted() {
     this.init();

+ 1 - 4
src/modules/card/elements/explain/ElemExplain.vue

@@ -4,10 +4,7 @@
       {{ data.parent.topicName }}
     </div>
     <div ref="ElemBody" class="elem-body">
-      <div
-        v-if="data.parent.questions.length > 1 && !data.isExtend"
-        class="elem-explain-no"
-      >
+      <div v-if="data.questionNo && !data.isExtend" class="elem-explain-no">
         {{ data.questionNo }}、
       </div>
       <!-- 解答题子元件区域 -->

+ 1 - 4
src/modules/card/elements/explain/ElemExplainEdit.vue

@@ -4,10 +4,7 @@
       {{ data.parent.topicName }}
     </div>
     <div class="elem-body" :style="bodyStyle">
-      <div
-        v-if="data.parent.questions.length > 1 && !data.isExtend"
-        class="elem-explain-no"
-      >
+      <div v-if="data.questionNo && !data.isExtend" class="elem-explain-no">
         {{ data.questionNo }}、
       </div>
       <!-- 解答题子元件编辑区域 -->

+ 15 - 8
src/modules/card/elements/fill-line/ElemFillLine.vue

@@ -1,19 +1,26 @@
 <template>
   <div class="elem-fill-line">
-    <div v-if="isFirst" class="elem-title">
+    <div v-if="data.isFirst" class="elem-title">
       {{ data.topicName }}
     </div>
     <div class="elem-body">
-      <ul class="elem-fill-quesiton" :style="groupStyles">
-        <li class="elem-fill-no">
+      <ul
+        v-for="line in data.fillCount"
+        :key="line"
+        class="elem-fill-quesiton"
+        :style="groupStyles"
+      >
+        <li v-if="line === 1" class="elem-fill-no">
           <span :style="lineNoStyles">{{ data.questionNo }}.</span>
         </li>
         <li
-          v-for="line in data.fillCount"
-          :key="line"
-          class="elem-fill-line"
-          :style="lineStyles"
-        ></li>
+          v-if="line !== data.fillCount"
+          class="elem-fill-comma"
+          :style="lineNoStyles"
+        >
+          ,
+        </li>
+        <li class="elem-fill-line" :style="lineStyles"></li>
       </ul>
     </div>
   </div>

+ 1 - 1
src/modules/card/elements/fill-question/ElemFillQuestion.vue

@@ -1,6 +1,6 @@
 <template>
   <div :class="classes">
-    <div v-if="isFirstSpin" class="elem-title">
+    <div v-if="data.isFirst" class="elem-title">
       {{ data.parent.topicName }}
     </div>
     <div class="elem-body">

+ 1019 - 0
src/modules/card/paperJsonTemp.json

@@ -0,0 +1,1019 @@
+{
+  "code": "m7rn0g68ifd5k1v8",
+  "name": "题卡测试试卷",
+  "courseCode": "kc1",
+  "courseName": "课程1",
+  "totalScore": 21,
+  "answerMode": 1,
+  "hasAudio": false,
+  "detailCount": 3,
+  "details": [
+    {
+      "number": 1,
+      "name": "单选、多选和填空",
+      "description": "",
+      "totalScore": 7,
+      "questionCount": 7,
+      "questions": [
+        {
+          "id": "d86de3e0-1b59-481d-ae80-762a8fd3ebed",
+          "number": 1,
+          "score": 1,
+          "structType": 1,
+          "objective": true,
+          "options": [
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "", "param": null },
+                      { "type": "text", "value": "和", "param": null },
+                      {
+                        "type": "image",
+                        "value": "./1652665540422.png",
+                        "param": { "width": "124px", "height": "38px" }
+                      },
+                      { "type": "text", "value": "", "param": null },
+                      { "type": "text", "value": "", "param": null },
+                      { "type": "text", "value": "", "param": null },
+                      { "type": "text", "value": "", "param": null }
+                    ]
+                  },
+                  {
+                    "blocks": [{ "type": "text", "value": "", "param": null }]
+                  },
+                  { "blocks": [{ "type": "text", "value": "", "param": null }] }
+                ]
+              },
+              "number": 1
+            },
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": " ", "param": null },
+                      {
+                        "type": "image",
+                        "value": "./1652665471769.png",
+                        "param": { "width": "90px", "height": "36px" }
+                      },
+                      { "type": "text", "value": "和", "param": null },
+                      {
+                        "type": "image",
+                        "value": "./1652665471783.png",
+                        "param": { "width": "112px", "height": "42px" }
+                      },
+                      { "type": "text", "value": "", "param": null },
+                      { "type": "text", "value": "", "param": null }
+                    ]
+                  },
+                  { "blocks": [{ "type": "text", "value": "", "param": null }] }
+                ]
+              },
+              "number": 2
+            },
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "444", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 3
+            }
+          ],
+          "body": {
+            "sections": [
+              {
+                "blocks": [
+                  { "type": "text", "value": "1. 函数", "param": null },
+                  {
+                    "type": "image",
+                    "value": "./1652325380032.png",
+                    "param": { "width": "126px", "height": "62px" }
+                  },
+                  {
+                    "type": "text",
+                    "value": "的连续区间是 (   )",
+                    "param": null
+                  },
+                  { "type": "text", "value": "", "param": null },
+                  { "type": "text", "value": "", "param": null },
+                  { "type": "text", "value": "", "param": null },
+                  { "type": "text", "value": "", "param": null }
+                ]
+              },
+              {
+                "blocks": [
+                  { "type": "text", "value": "A. ", "param": null },
+                  {
+                    "type": "image",
+                    "value": "./1652665136713.png",
+                    "param": { "width": "104px", "height": "33px" }
+                  },
+                  { "type": "text", "value": "和", "param": null },
+                  {
+                    "type": "image",
+                    "value": "./1652665136722.png",
+                    "param": { "width": "111px", "height": "34px" }
+                  },
+                  { "type": "text", "value": " ", "param": null },
+                  { "type": "text", "value": "", "param": null },
+                  { "type": "text", "value": "", "param": null }
+                ]
+              },
+              { "blocks": [{ "type": "text", "value": "", "param": null }] }
+            ]
+          },
+          "param": {},
+          "comments": ""
+        },
+        {
+          "id": "9376dc2c-5592-4ada-a484-da2f74cc22f7",
+          "number": 2,
+          "score": 1,
+          "structType": 1,
+          "objective": true,
+          "options": [
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [{ "type": "text", "value": "11", "param": null }]
+                  }
+                ]
+              },
+              "number": 1
+            },
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "112", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 2
+            },
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "333", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 3
+            }
+          ],
+          "body": {
+            "sections": [
+              {
+                "blocks": [
+                  { "type": "text", "value": "测试输入00", "param": null },
+                  {
+                    "type": "image",
+                    "value": "./1653036609654.png",
+                    "param": { "width": 395, "height": 553 }
+                  },
+                  { "type": "text", "value": "", "param": null },
+                  { "type": "text", "value": "", "param": null },
+                  { "type": "text", "value": "", "param": null }
+                ]
+              }
+            ]
+          },
+          "param": {},
+          "comments": ""
+        },
+        {
+          "id": "e879f55a-d122-498c-982b-5887d7c60cf7",
+          "number": 3,
+          "score": 1,
+          "structType": 1,
+          "objective": true,
+          "options": [
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "111", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 1
+            },
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "222", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 2
+            },
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "333", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 3
+            }
+          ],
+          "body": {
+            "sections": [
+              {
+                "blocks": [
+                  { "type": "text", "value": "测试输入0001", "param": null }
+                ]
+              }
+            ]
+          },
+          "param": {},
+          "comments": ""
+        },
+        {
+          "id": "9f791be3-b32c-4387-8957-231d5c179226",
+          "number": 4,
+          "score": 1,
+          "structType": 4,
+          "objective": false,
+          "options": [],
+          "body": {
+            "sections": [
+              {
+                "blocks": [
+                  { "type": "cloze", "value": 1, "param": null },
+                  {
+                    "type": "text",
+                    "value": "123",
+                    "param": {
+                      "italic": false,
+                      "bold": true,
+                      "underline": false
+                    }
+                  },
+                  {
+                    "type": "text",
+                    "value": "123",
+                    "param": {
+                      "italic": false,
+                      "bold": true,
+                      "underline": false
+                    }
+                  },
+                  { "type": "text", "value": "", "param": null }
+                ]
+              },
+              {
+                "blocks": [
+                  { "type": "cloze", "value": 2, "param": null },
+                  { "type": "text", "value": "1", "param": null },
+                  {
+                    "type": "text",
+                    "value": "231",
+                    "param": {
+                      "italic": false,
+                      "bold": false,
+                      "underline": true
+                    }
+                  },
+                  { "type": "text", "value": "23", "param": null },
+                  { "type": "cloze", "value": 3, "param": null },
+                  { "type": "text", "value": "", "param": null }
+                ]
+              },
+              {
+                "blocks": [
+                  { "type": "text", "value": "1", "param": null },
+                  {
+                    "type": "text",
+                    "value": "23",
+                    "param": {
+                      "italic": true,
+                      "bold": false,
+                      "underline": false
+                    }
+                  },
+                  { "type": "text", "value": "1", "param": null }
+                ]
+              },
+              { "blocks": [{ "type": "text", "value": "332", "param": null }] },
+              { "blocks": [{ "type": "text", "value": "", "param": null }] },
+              { "blocks": [{ "type": "text", "value": "", "param": null }] }
+            ]
+          },
+          "param": {},
+          "comments": ""
+        },
+        {
+          "id": "1330bc9d-fe1e-4185-8db8-8e0c51d5a391",
+          "number": 5,
+          "score": 1,
+          "structType": 4,
+          "objective": false,
+          "options": [],
+          "body": {
+            "sections": [
+              {
+                "blocks": [
+                  { "type": "cloze", "value": 1, "param": null },
+                  { "type": "cloze", "value": 2, "param": null },
+                  { "type": "cloze", "value": 3, "param": null },
+                  { "type": "cloze", "value": 4, "param": null },
+                  { "type": "cloze", "value": 5, "param": null },
+                  { "type": "cloze", "value": 6, "param": null },
+                  { "type": "cloze", "value": 7, "param": null },
+                  { "type": "cloze", "value": 8, "param": null },
+                  { "type": "cloze", "value": 9, "param": null },
+                  { "type": "cloze", "value": 10, "param": null },
+                  { "type": "cloze", "value": 11, "param": null },
+                  { "type": "cloze", "value": 12, "param": null },
+                  { "type": "cloze", "value": 13, "param": null },
+                  { "type": "cloze", "value": 14, "param": null },
+                  { "type": "cloze", "value": 15, "param": null },
+                  { "type": "cloze", "value": 16, "param": null },
+                  { "type": "cloze", "value": 17, "param": null },
+                  { "type": "cloze", "value": 18, "param": null },
+                  { "type": "cloze", "value": 19, "param": null },
+                  { "type": "cloze", "value": 20, "param": null },
+                  { "type": "cloze", "value": 21, "param": null },
+                  { "type": "cloze", "value": 22, "param": null },
+                  { "type": "cloze", "value": 23, "param": null },
+                  { "type": "cloze", "value": 24, "param": null },
+                  { "type": "cloze", "value": 25, "param": null },
+                  { "type": "cloze", "value": 26, "param": null },
+                  { "type": "cloze", "value": 27, "param": null },
+                  { "type": "cloze", "value": 28, "param": null },
+                  { "type": "cloze", "value": 29, "param": null },
+                  { "type": "text", "value": "3", "param": null }
+                ]
+              }
+            ]
+          },
+          "param": {},
+          "comments": ""
+        },
+        {
+          "id": "fc38bbbb-7d0e-4d13-ba65-fa6855f4ba4e",
+          "number": 6,
+          "score": 1,
+          "structType": 2,
+          "objective": true,
+          "options": [
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "1111", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 1
+            },
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "2222", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 2
+            },
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "3333", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 3
+            },
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "4444", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 4
+            },
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "5555", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 5
+            }
+          ],
+          "body": {
+            "sections": [
+              {
+                "blocks": [
+                  { "type": "text", "value": "多选题00251", "param": null }
+                ]
+              }
+            ]
+          },
+          "param": {},
+          "comments": ""
+        },
+        {
+          "id": "bf7d4e57-2196-4f35-a169-e746eebd1cf3",
+          "number": 7,
+          "score": 1,
+          "structType": 2,
+          "objective": true,
+          "options": [
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "1111", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 1
+            },
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "222", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 2
+            },
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "333", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 3
+            },
+            {
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "444", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "number": 4
+            }
+          ],
+          "body": {
+            "sections": [
+              {
+                "blocks": [{ "type": "text", "value": "多选题", "param": null }]
+              }
+            ]
+          },
+          "param": {},
+          "comments": ""
+        }
+      ]
+    },
+    {
+      "number": 2,
+      "name": "判断、填空和简答",
+      "description": "",
+      "totalScore": 5,
+      "questionCount": 5,
+      "questions": [
+        {
+          "id": "14e9212b-7315-4a05-b27c-26c0f7343346",
+          "number": 1,
+          "score": 1,
+          "structType": 4,
+          "objective": false,
+          "options": [],
+          "body": {
+            "sections": [
+              {
+                "blocks": [
+                  { "type": "text", "value": "沙发上放假", "param": null },
+                  { "type": "cloze", "value": 1, "param": null },
+                  { "type": "text", "value": "啦考师范", "param": null },
+                  { "type": "cloze", "value": 2, "param": null },
+                  { "type": "text", "value": "大法可垃圾是咖", "param": null },
+                  { "type": "cloze", "value": 3, "param": null },
+                  { "type": "text", "value": "啡机阿拉斯加", "param": null },
+                  { "type": "cloze", "value": 4, "param": null },
+                  { "type": "text", "value": "发卡机发家史", "param": null }
+                ]
+              }
+            ]
+          },
+          "param": {},
+          "comments": ""
+        },
+        {
+          "id": "a9545179-2977-44f1-8fac-a09e4c50faf4",
+          "number": 2,
+          "score": 1,
+          "structType": 4,
+          "objective": false,
+          "options": [],
+          "body": {
+            "sections": [
+              {
+                "blocks": [
+                  {
+                    "type": "text",
+                    "value": "爱上的看法了看实际",
+                    "param": null
+                  },
+                  { "type": "cloze", "value": 1, "param": null },
+                  {
+                    "type": "text",
+                    "value": ",大卡司快递费就阿卡",
+                    "param": null
+                  },
+                  { "type": "cloze", "value": 2, "param": null },
+                  { "type": "text", "value": ",", "param": null },
+                  {
+                    "type": "text",
+                    "value": "老师拉数据库里发动机阿喀琉斯进度分开啦放假啦",
+                    "param": null
+                  }
+                ]
+              }
+            ]
+          },
+          "param": {},
+          "comments": ""
+        },
+        {
+          "id": "3856a81e-2a6e-4d15-ba55-532b70213fff",
+          "number": 3,
+          "score": 1,
+          "structType": 4,
+          "objective": false,
+          "options": [],
+          "body": {
+            "sections": [
+              {
+                "blocks": [
+                  { "type": "text", "value": "12312", "param": null },
+                  { "type": "cloze", "value": 1, "param": null },
+                  { "type": "text", "value": ",12123阿道夫", "param": null },
+                  { "type": "cloze", "value": 2, "param": null },
+                  {
+                    "type": "text",
+                    "value": ",阿凡达大发了上开发看,",
+                    "param": null
+                  },
+                  { "type": "cloze", "value": 3, "param": null },
+                  { "type": "text", "value": "发生的范范", "param": null }
+                ]
+              }
+            ]
+          },
+          "param": {},
+          "comments": ""
+        },
+        {
+          "id": "aae5c95d-8ea5-4e8c-a3ec-1b0109ace3b4",
+          "number": 4,
+          "score": 1,
+          "structType": 3,
+          "objective": true,
+          "options": [],
+          "body": {
+            "sections": [
+              {
+                "blocks": [
+                  { "type": "text", "value": "3123123123123", "param": null }
+                ]
+              }
+            ]
+          },
+          "param": {},
+          "comments": ""
+        },
+        {
+          "id": "a8da5218-a52c-4b79-b14c-035752511b6b",
+          "number": 5,
+          "score": 1,
+          "structType": 5,
+          "objective": false,
+          "options": [],
+          "body": {
+            "sections": [
+              {
+                "blocks": [
+                  { "type": "text", "value": "3123123123333", "param": null }
+                ]
+              }
+            ]
+          },
+          "param": {},
+          "comments": ""
+        }
+      ]
+    },
+    {
+      "number": 3,
+      "name": "套题",
+      "description": "",
+      "totalScore": 9,
+      "questionCount": 2,
+      "questions": [
+        {
+          "id": "ae97b042-5071-4a3b-b342-a2ed1300c6df",
+          "number": 1,
+          "score": 5,
+          "structType": 6,
+          "objective": false,
+          "options": [],
+          "body": {
+            "sections": [
+              {
+                "blocks": [
+                  {
+                    "type": "text",
+                    "value": "In Britain people usually have a doctor near their home or in their town. This is the local doctor. You have to register with a doctor before you can make an appointment.\r\nYou usually have to fill in a form and the doctor examines you. Families often all \r\nregister with the same doctor."
+                  }
+                ]
+              }
+            ]
+          },
+          "param": {},
+          "subQuestions": [
+            {
+              "id": "1-0",
+              "number": 1,
+              "score": 1,
+              "structType": 1,
+              "objective": true,
+              "options": [
+                {
+                  "number": 1,
+                  "body": {
+                    "sections": [
+                      { "blocks": [{ "type": "text", "value": "Right" }] }
+                    ]
+                  }
+                },
+                {
+                  "number": 2,
+                  "body": {
+                    "sections": [
+                      { "blocks": [{ "type": "text", "value": "Wrong" }] }
+                    ]
+                  }
+                },
+                {
+                  "number": 3,
+                  "body": {
+                    "sections": [
+                      { "blocks": [{ "type": "text", "value": "Don’t say" }] }
+                    ]
+                  }
+                }
+              ],
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      {
+                        "type": "text",
+                        "value": "British people usually go a long way to see a doctor.(  )"
+                      }
+                    ]
+                  }
+                ]
+              },
+              "control": { "maxAnswerTime": 1 },
+              "comments": ""
+            },
+            {
+              "id": "1-1",
+              "number": 2,
+              "score": 1,
+              "structType": 2,
+              "objective": true,
+              "options": [
+                {
+                  "number": 1,
+                  "body": {
+                    "sections": [
+                      { "blocks": [{ "type": "text", "value": "Right" }] }
+                    ]
+                  }
+                },
+                {
+                  "number": 2,
+                  "body": {
+                    "sections": [
+                      { "blocks": [{ "type": "text", "value": "Wrong" }] }
+                    ]
+                  }
+                },
+                {
+                  "number": 3,
+                  "body": {
+                    "sections": [
+                      { "blocks": [{ "type": "text", "value": "Don’t say" }] }
+                    ]
+                  }
+                }
+              ],
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      {
+                        "type": "text",
+                        "value": "Some rich British families don't register with the same doctor."
+                      }
+                    ]
+                  }
+                ]
+              },
+              "control": { "maxAnswerTime": 1 },
+              "comments": ""
+            },
+            {
+              "id": "1-2",
+              "number": 3,
+              "score": 1,
+              "structType": 4,
+              "objective": false,
+              "options": [],
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "认识开始于感觉”,这是 (" },
+                      { "type": "cloze", "value": 1 },
+                      { "type": "text", "value": ") 观点,但(" },
+                      { "type": "cloze", "value": 2 },
+                      { "type": "text", "value": ")和唯心主义都能接受" }
+                    ]
+                  }
+                ]
+              },
+              "control": { "maxAnswerTime": 1 },
+              "comments": ""
+            },
+            {
+              "id": "1-3",
+              "number": 4,
+              "score": 1,
+              "structType": 5,
+              "objective": false,
+              "options": [],
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      {
+                        "type": "text",
+                        "value": "问答题12121222",
+                        "param": null
+                      }
+                    ]
+                  }
+                ]
+              },
+              "control": null,
+              "comments": ""
+            },
+            {
+              "id": "1-4",
+              "number": 5,
+              "score": 1,
+              "structType": 3,
+              "objective": true,
+              "options": [],
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "112312", "param": null }
+                    ]
+                  }
+                ]
+              },
+              "control": null,
+              "comments": ""
+            }
+          ],
+          "comments": ""
+        },
+        {
+          "id": "21b495c3-e61f-430c-b28b-3ce3cabae11b",
+          "number": 2,
+          "score": 4,
+          "structType": 6,
+          "objective": false,
+          "options": [],
+          "body": {
+            "sections": [
+              {
+                "blocks": [
+                  {
+                    "type": "text",
+                    "value": "In Britain people usually have a doctor near their home or in their town. This is the local doctor. You have to register with a doctor before you can make an appointment.\r\nYou usually have to fill in a form and the doctor examines you. Families often all \r\nregister with the same doctor."
+                  }
+                ]
+              }
+            ]
+          },
+          "param": {},
+          "subQuestions": [
+            {
+              "id": "2-0",
+              "number": 1,
+              "score": 1,
+              "structType": 1,
+              "objective": true,
+              "options": [
+                {
+                  "number": 1,
+                  "body": {
+                    "sections": [
+                      { "blocks": [{ "type": "text", "value": "Right" }] }
+                    ]
+                  }
+                },
+                {
+                  "number": 2,
+                  "body": {
+                    "sections": [
+                      { "blocks": [{ "type": "text", "value": "Wrong" }] }
+                    ]
+                  }
+                },
+                {
+                  "number": 3,
+                  "body": {
+                    "sections": [
+                      { "blocks": [{ "type": "text", "value": "Don’t say" }] }
+                    ]
+                  }
+                }
+              ],
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      {
+                        "type": "text",
+                        "value": "British people usually go a long way to see a doctor.(  )"
+                      }
+                    ]
+                  }
+                ]
+              },
+              "control": { "maxAnswerTime": 1 },
+              "comments": ""
+            },
+            {
+              "id": "2-1",
+              "number": 2,
+              "score": 1,
+              "structType": 2,
+              "objective": true,
+              "options": [
+                {
+                  "number": 1,
+                  "body": {
+                    "sections": [
+                      { "blocks": [{ "type": "text", "value": "Right" }] }
+                    ]
+                  }
+                },
+                {
+                  "number": 2,
+                  "body": {
+                    "sections": [
+                      { "blocks": [{ "type": "text", "value": "Wrong" }] }
+                    ]
+                  }
+                },
+                {
+                  "number": 3,
+                  "body": {
+                    "sections": [
+                      { "blocks": [{ "type": "text", "value": "Don’t say" }] }
+                    ]
+                  }
+                }
+              ],
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      {
+                        "type": "text",
+                        "value": "Some rich British families don't register with the same doctor."
+                      }
+                    ]
+                  }
+                ]
+              },
+              "control": { "maxAnswerTime": 1 },
+              "comments": ""
+            },
+            {
+              "id": "2-2",
+              "number": 3,
+              "score": 1,
+              "structType": 4,
+              "objective": false,
+              "options": [],
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      { "type": "text", "value": "认识开始于感觉”,这是 (" },
+                      { "type": "cloze", "value": 1 },
+                      { "type": "text", "value": ") 观点,但(" },
+                      { "type": "cloze", "value": 2 },
+                      { "type": "text", "value": ")和唯心主义都能接受" }
+                    ]
+                  }
+                ]
+              },
+              "control": { "maxAnswerTime": 1 },
+              "comments": ""
+            },
+            {
+              "id": "2-3",
+              "number": 4,
+              "score": 1,
+              "structType": 5,
+              "objective": false,
+              "options": [],
+              "body": {
+                "sections": [
+                  {
+                    "blocks": [
+                      {
+                        "type": "text",
+                        "value": "Some rich British families don't register with the same doctor?\r\n____________________________________________________________"
+                      }
+                    ]
+                  }
+                ]
+              },
+              "control": { "maxAnswerTime": 255 },
+              "comments": ""
+            }
+          ],
+          "comments": ""
+        }
+      ]
+    }
+  ]
+}

+ 25 - 0
src/modules/card/plugins/utils.js

@@ -132,6 +132,30 @@ function numberIsOdd(num) {
   return !!(num % 2);
 }
 
+/**
+ * 百以下数字转中文汉字
+ * @param {Number} num 大于0的100以下数字,其他数值直接转字符串
+ *
+ * @returns {String}
+ */
+function numberToChinese(num) {
+  if (num >= 100 || num <= 0) return num + "";
+  const cnNums = "一二三四五六七八九十".split("");
+  if (num <= 10) return cnNums[num - 1];
+
+  return (num + "")
+    .split("")
+    .map((item) => item * 1)
+    .map((item, index) => {
+      if (index) {
+        return !item ? "" : cnNums[item - 1];
+      } else {
+        return item === 1 ? "" : cnNums[item - 1];
+      }
+    })
+    .join("十");
+}
+
 export {
   objTypeOf,
   deepCopy,
@@ -145,4 +169,5 @@ export {
   isEmptyObject,
   getElementId,
   numberIsOdd,
+  numberToChinese,
 };