Explorar el Código

自动生成题卡数据页面

zhangjie hace 3 años
padre
commit
ce112f0b94

+ 1 - 1
src/modules/card/api.js

@@ -77,7 +77,7 @@ export const cardDetail = () => {
 };
 
 export const saveCard = (datas) => {
-  Vue.ls.set("cardData", datas);
+  window.sessionStorage.setItem("cardData", JSON.stringify(datas));
   return Promise.resolve("11");
 };
 export const paperDetailApi = (paperId) => {

+ 4 - 4
src/modules/card/autoBuild/paperCard.js

@@ -44,7 +44,7 @@ const elementModel = {
   },
 };
 
-function parseCommonPaperStruct(paperJson) {
+function parsePaperStruct(paperJson) {
   let structList = [];
   paperJson.paperDetails.forEach((detail) => {
     const commonQuestions = detail.paperDetailUnits.filter((q) =>
@@ -91,7 +91,7 @@ function getCommonQuestionStructList(
     structs[question.questionType].push(question);
   });
   Object.keys(structs).forEach((structType) => {
-    const typeNo = COMMON_QUESTION_TYPES.indexOf(structType);
+    const typeNo = COMMON_QUESTION_TYPES.indexOf(structType) + 1;
     const questions = parseCommonTypeQuestions(structType, structs[structType]);
 
     structList.push({
@@ -170,7 +170,7 @@ export function getFillBackClozeCount(questionBodyContent) {
   return num;
 }
 
-function buildCardElements(structList) {
+export function buildCardElements(structList) {
   let cardElements = [];
   structList.forEach((struct) => {
     const detailChineseNumber = numberToChinese(struct.detailNo);
@@ -209,7 +209,7 @@ function buildCardElements(structList) {
 }
 
 export function buildPaperCard(paperJson) {
-  const structList = parseCommonPaperStruct(paperJson);
+  const structList = parsePaperStruct(paperJson);
   const cardElements = buildCardElements(structList);
   console.log(cardElements);
   return cardElements;

+ 1 - 1
src/modules/card/autoBuild/paperStruct.js

@@ -11,7 +11,7 @@ const COMMON_QUESTION_TYPES = [
 export function getPaperJsonSimpleStructInfo(paperJson) {
   let struct = [];
   paperJson.paperDetails.forEach((detail) => {
-    struct.push(`${detail.number}-${detail.name}`);
+    struct.push(`detail:${detail.number}-${detail.name}`);
     detail.paperDetailUnits.forEach((question) => {
       if (COMMON_QUESTION_TYPES.includes(question.questionType)) {
         const info = parseCommonTypeQuestion(question);

+ 175 - 0
src/modules/card/autoBuild/simplePaperCard.js

@@ -0,0 +1,175 @@
+import { buildCardElements } from "./paperCard";
+
+const COMMON_QUESTION_TYPES = [
+  "SINGLE_ANSWER_QUESTION",
+  "MULTIPLE_ANSWER_QUESTION",
+  "BOOL_ANSWER_QUESTION",
+  "FILL_BLANK_QUESTION",
+  "TEXT_ANSWER_QUESTION",
+];
+
+function parseSimpleQuestion(simpleQuestion) {
+  const [numbers, questionType, qinfo] = simpleQuestion.split(":");
+  const [detailNo, questionNo, subQno] = numbers.split("-");
+  return {
+    detailNo: detailNo * 1,
+    questionNo: questionNo * 1,
+    subQno: subQno && subQno * 1,
+    questionType,
+    qinfo: qinfo * 1,
+  };
+}
+
+function parsePaperStruct(paperSimpleStruct) {
+  console.log(paperSimpleStruct);
+  const dataList = paperSimpleStruct.split("#");
+  const details = dataList.filter((item) => item.startsWith("detail"));
+  let detailNames = {};
+  details.forEach((detail) => {
+    const [detailNos, detailName] = detail.split("-");
+    const detailNo = detailNos.replace("detail:", "") * 1;
+    detailNames[detailNo] = detailName;
+  });
+  const questions = dataList
+    .filter((item) => !item.startsWith("detail"))
+    .map((q) => parseSimpleQuestion(q));
+
+  // parse paper struct
+  let detailList = [];
+  questions.forEach((q) => {
+    const dind = q.detailNo - 1;
+    if (!detailList[dind]) {
+      detailList[dind] = {
+        detailNo: q.detailNo,
+        detailName: detailNames[q.detailNo],
+        questions: [],
+      };
+    }
+    detailList[dind].questions.push(q);
+  });
+
+  let structList = [];
+  detailList.forEach((detail) => {
+    const commonQuestions = detail.questions.filter((q) =>
+      COMMON_QUESTION_TYPES.includes(q.questionType)
+    );
+    if (commonQuestions.length) {
+      const commonStructList = getCommonQuestionStructList(
+        detail,
+        commonQuestions,
+        true,
+        0
+      );
+      structList.push(...commonStructList);
+    }
+
+    const nestedQuestions = detail.questions.filter(
+      (q) => !COMMON_QUESTION_TYPES.includes(q.questionType)
+    );
+    if (nestedQuestions.length) {
+      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.questionType]) structs[question.questionType] = [];
+    structs[question.questionType].push(question);
+  });
+  Object.keys(structs).forEach((structType) => {
+    const typeNo = COMMON_QUESTION_TYPES.indexOf(structType) + 1;
+    const questions = parseCommonTypeQuestions(structType, structs[structType]);
+
+    structList.push({
+      detailName: detail.detailName,
+      detailNo: detail.detailNo,
+      structType,
+      isCommon,
+      nestedQNo,
+      sortNo:
+        typeNo * 10000 + detail.number * 1000 + qTypeNum * 100 + nestedQNo,
+      questions,
+    });
+  });
+  return structList;
+}
+
+function getNestedQuestionStructList(detail, questions) {
+  let nestedQuestions = [];
+  questions.forEach((question) => {
+    const nestedNo = question.questionNo - 1;
+    if (!nestedQuestions[nestedNo]) {
+      nestedQuestions[nestedNo] = {
+        questionNo: question.questionNo,
+        subQuestions: [],
+      };
+    }
+    nestedQuestions[nestedNo].subQuestions.push({
+      ...question,
+      questionNo: question.subQno,
+    });
+  });
+
+  let structList = [];
+  nestedQuestions.forEach((question) => {
+    const qStructList = getCommonQuestionStructList(
+      detail,
+      question.subQuestions,
+      false,
+      question.questionNo
+    );
+    structList.push(...qStructList);
+  });
+  return structList;
+}
+
+function parseCommonTypeQuestions(structType, dataList) {
+  const choiceQs = [
+    "SINGLE_ANSWER_QUESTION",
+    "MULTIPLE_ANSWER_QUESTION",
+    "BOOL_ANSWER_QUESTION",
+  ];
+  let questions = [];
+  if (choiceQs.includes(structType)) {
+    questions = dataList.map((item) => {
+      return {
+        questionNo: item.questionNo,
+        optionCount: structType === "BOOL_ANSWER_QUESTION" ? 2 : item.qinfo,
+      };
+    });
+  } else if (structType === "FILL_BLANK_QUESTION") {
+    questions = dataList.map((item) => {
+      return {
+        questionNo: item.questionNo,
+        fillCount: item.qinfo,
+      };
+    });
+  } else {
+    questions = dataList.map((item) => item.questionNo);
+  }
+  return questions;
+}
+
+export function buildCardFromPaperSimpleStruct(paperSimpleStruct) {
+  const structList = parsePaperStruct(paperSimpleStruct);
+  const cardElements = buildCardElements(structList);
+  console.log(cardElements);
+  return cardElements;
+}

+ 2 - 1
src/modules/card/mixins/exchange.js

@@ -245,7 +245,7 @@ export default {
 
       return infos.map((num) => num.toFixed(10) * 1);
     },
-    getPageModel({ cardConfig, pages }) {
+    getPageModel({ cardConfig, pages, paperSimpleStruct }) {
       let npages = this.parsePageExchange(pages);
       npages.forEach((page) => {
         page.exchange.page_size = cardConfig.pageSize;
@@ -255,6 +255,7 @@ export default {
           version: CARD_VERSION,
           cardConfig,
           pages: npages,
+          paperSimpleStruct,
         },
         (k, v) => (k.startsWith("_") ? undefined : v)
       );

+ 6 - 0
src/modules/card/router/index.js

@@ -42,4 +42,10 @@ export const editRoutes = [
     component: () =>
       import(/* webpackChunkName: "card" */ "../views/CardPreview.vue"),
   },
+  {
+    path: "/card/build",
+    name: "CardBuild",
+    component: () =>
+      import(/* webpackChunkName: "card" */ "../views/CardBuild.vue"),
+  },
 ];

+ 148 - 0
src/modules/card/views/CardBuild.vue

@@ -0,0 +1,148 @@
+<template>
+  <div class="card-build card-preview card-print">
+    <card-view
+      v-if="pages.length"
+      ref="CardView"
+      class="preview-body"
+      :pages="pages"
+      :card-config="cardConfig"
+    ></card-view>
+    <!-- all topics -->
+    <div v-else class="topic-list">
+      <div :class="['page-box', `page-box-${cardConfig.pageSize}`]">
+        <div class="page-main-inner">
+          <div
+            :class="['page-main', `page-main-${cardConfig.columnNumber}`]"
+            :style="{ margin: `0 -${cardConfig.columnGap / 2}px` }"
+          >
+            <div
+              class="page-column"
+              :style="{ padding: `0 ${cardConfig.columnGap / 2}px` }"
+            >
+              <div id="topic-column" class="page-column-main">
+                <div class="page-column-body">
+                  <!-- topic element -->
+                  <topic-element-preview
+                    v-for="element in topics"
+                    :key="element.id"
+                    class="page-column-element"
+                    :data="element"
+                  ></topic-element-preview>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState, mapMutations, mapActions } from "vuex";
+import TopicElementPreview from "../components/TopicElementPreview";
+import CardView from "../components/CardView";
+import html2canvas from "html2canvas";
+import { getPageInitElements } from "../pageModel";
+import { buildCardFromPaperSimpleStruct } from "../autoBuild/simplePaperCard";
+import { saveCard } from "../api";
+
+// import cardData from "./data";
+
+export default {
+  name: "CardBuild",
+  components: { CardView, TopicElementPreview },
+  data() {
+    return {};
+  },
+  computed: {
+    ...mapState("card", [
+      "cardConfig",
+      "paperSimpleStruct",
+      "pageDefaultElems",
+      "topics",
+      "pages",
+    ]),
+  },
+  mounted() {
+    this.initData();
+  },
+  methods: {
+    ...mapMutations("card", [
+      "setCardConfig",
+      "setPages",
+      "setTopics",
+      "setPageDefaultElems",
+      "initState",
+      "setPaperSimpleStruct",
+    ]),
+    ...mapActions("card", ["resetTopicSeries", "rebuildPages"]),
+    initData() {
+      this.initState();
+      const cardData = window.parent.cardData;
+      if (!cardData) return;
+
+      const { cardConfig, paperSimpleStruct } = cardData;
+      this.setCardConfig(cardConfig);
+      this.setPaperSimpleStruct(paperSimpleStruct);
+      const pageDefaultElems = getPageInitElements(cardConfig);
+      this.setPageDefaultElems(pageDefaultElems);
+
+      const elements = buildCardFromPaperSimpleStruct(paperSimpleStruct);
+      this.setTopics([...this.pageDefaultElems.elements, ...elements]);
+      this.resetTopicSeries();
+
+      this.$nextTick(() => {
+        this.rebuildPages();
+
+        this.$nextTick(() => {
+          this.buildData();
+        });
+      });
+    },
+    async buildData() {
+      const cardContentTemp = this.$refs.CardView.getPreviewTemp(
+        this.$el.outerHTML
+      );
+      const model = this.$refs.CardView.getPageModel({
+        cardConfig: this.cardConfig,
+        pages: this.pages,
+        paperSimpleStruct: this.paperSimpleStruct,
+      });
+      const cardImages = await this.transformImags().catch(() => {});
+
+      const datas = {
+        title: this.cardConfig.cardTitle,
+        content: model,
+        htmlContent: cardContentTemp,
+        cardImages,
+        status: "SUBMIT",
+      };
+      console.log(datas);
+      const result = await saveCard(datas).catch(() => {});
+
+      window.parent &&
+        window.parent.emitResult &&
+        window.parent.emitResult(result, datas);
+    },
+    async transformPageToImage(pageDom) {
+      const canvasDom = await html2canvas(pageDom, {
+        allowTaint: true,
+        imageTimeout: 3000,
+      });
+
+      return canvasDom.toDataURL();
+    },
+    async transformImags() {
+      const pageDoms = this.$refs.CardView.$el.querySelectorAll(".page-box");
+      let images = [];
+      for (let i = 0; i < pageDoms.length; i++) {
+        const pageDom = pageDoms[i];
+        const imgDataUrl = await this.transformPageToImage(pageDom);
+        images[i] = imgDataUrl;
+      }
+      return images;
+    },
+  },
+};
+</script>

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

@@ -171,9 +171,7 @@ export default {
         const datas = this.getCardData(htmlContent, model);
         datas.status = "SUBMIT";
         datas.cardImages = cardImages;
-        const result = await saveCard(datas, this.getRequestConfig()).catch(
-          () => {}
-        );
+        const result = await saveCard(datas).catch(() => {});
         this.cardPreviewUrl = "";
         window.cardData = null;
         if (result) {

+ 24 - 0
src/modules/card/views/data.js

@@ -0,0 +1,24 @@
+export default {
+  pages: [],
+  cardConfig: {
+    id: "173438690998091776",
+    createId: "173437828976345088",
+    createTime: 1632291806278,
+    updateId: null,
+    updateTime: 1632291806278,
+    name: "测试题卡规则1-版头名称",
+    cardTitle: "测试题卡规则1-题卡标题",
+    attention:
+      "测试题卡规则1-注意事项\n测试题卡规则1-注意事项\n测试题卡规则1-注意事项",
+    objectiveAttention: "测试题卡规则1-客观题-注意事项",
+    subjectiveAttention: "测试题卡规则1-主观题-注意事项",
+    templateType: "GRADUATE",
+    pageSize: "A3",
+    columnNumber: 2,
+    columnGap: 20,
+    showForbidArea: true,
+    showScorePan: false,
+  },
+  paperSimpleStruct:
+    "detail:1-单项选择题#1-1:SINGLE_ANSWER_QUESTION:4#1-2:SINGLE_ANSWER_QUESTION:4#1-3:SINGLE_ANSWER_QUESTION:4#1-4:SINGLE_ANSWER_QUESTION:4#1-5:SINGLE_ANSWER_QUESTION:4#1-6:SINGLE_ANSWER_QUESTION:4#1-7:SINGLE_ANSWER_QUESTION:4#1-8:SINGLE_ANSWER_QUESTION:4#1-9:SINGLE_ANSWER_QUESTION:4#1-10:SINGLE_ANSWER_QUESTION:4#detail:2-多项选择题#2-1:MULTIPLE_ANSWER_QUESTION:4#2-2:MULTIPLE_ANSWER_QUESTION:4#2-3:MULTIPLE_ANSWER_QUESTION:4#2-4:MULTIPLE_ANSWER_QUESTION:4#2-5:MULTIPLE_ANSWER_QUESTION:5#detail:3-判断题#3-1:BOOL_ANSWER_QUESTION:#3-2:BOOL_ANSWER_QUESTION:#3-3:BOOL_ANSWER_QUESTION:#3-4:BOOL_ANSWER_QUESTION:#3-5:BOOL_ANSWER_QUESTION:#3-6:BOOL_ANSWER_QUESTION:#3-7:BOOL_ANSWER_QUESTION:#3-8:BOOL_ANSWER_QUESTION:#3-9:BOOL_ANSWER_QUESTION:#3-10:BOOL_ANSWER_QUESTION:#3-11:BOOL_ANSWER_QUESTION:#3-12:BOOL_ANSWER_QUESTION:#3-13:BOOL_ANSWER_QUESTION:#3-14:BOOL_ANSWER_QUESTION:#3-15:BOOL_ANSWER_QUESTION:#detail:4-简答题#4-1:TEXT_ANSWER_QUESTION:#4-2:TEXT_ANSWER_QUESTION:#4-3:TEXT_ANSWER_QUESTION:#4-4:TEXT_ANSWER_QUESTION:#4-5:TEXT_ANSWER_QUESTION:#detail:5-论述题#5-1:TEXT_ANSWER_QUESTION:",
+};