Browse Source

评卷参数试题结构/客观题答案调整

zhangjie 2 years ago
parent
commit
6337f24965

+ 2 - 4
card/components/ElementPropEdit.vue

@@ -111,10 +111,8 @@ export default {
       const relateTopics = this.topics.filter(
         (item) =>
           item.topicNo === element.topicNo &&
-          ((element.type !== "COMPOSITION" &&
-            item.parent &&
-            item.parent.id !== element.id) ||
-            (element.type === "COMPOSITION" && item.id !== element.id))
+          item.parent &&
+          item.parent.id !== element.id
       );
       if (!relateTopics.length) return true;
 

+ 7 - 0
src/assets/styles/element-ui-costom.scss

@@ -658,3 +658,10 @@
     margin: 3px;
   }
 }
+// el-tree
+.el-tree {
+  .el-tree-node__content {
+    height: auto;
+    min-height: 26px;
+  }
+}

+ 8 - 3
src/modules/base/views/CardManage.vue

@@ -131,7 +131,9 @@
             >
             <el-button
               v-if="
-                checkPrivilege('link', 'delete') && scope.row.type !== 'CUSTOM'
+                checkPrivilege('link', 'delete') &&
+                scope.row.type !== 'CUSTOM' &&
+                scope.row.used
               "
               class="btn-danger"
               type="text"
@@ -141,7 +143,8 @@
             <el-button
               v-if="
                 checkPrivilege('link', 'edit') &&
-                scope.row.createMethod !== 'UPLOAD'
+                scope.row.createMethod !== 'UPLOAD' &&
+                scope.row.used
               "
               class="btn-primary"
               type="text"
@@ -150,7 +153,9 @@
             >
             <el-button
               v-if="
-                checkPrivilege('link', 'edit') && scope.row.type !== 'CUSTOM'
+                checkPrivilege('link', 'edit') &&
+                scope.row.type !== 'CUSTOM' &&
+                scope.row.used
               "
               class="btn-primary"
               type="text"

+ 32 - 46
src/modules/stmms/components/markParam/MarkPaperStructure.vue

@@ -29,29 +29,27 @@
       </el-table-column>
       <el-table-column prop="mainTitle" label="大题名称">
         <span slot-scope="scope" v-if="scope.row.mainFirstSub">
-          <el-input
-            v-model.trim="scope.row.mainTitle"
-            size="small"
-            :maxlength="32"
-            clearable
-            @change="mainTitleChange(scope.row)"
-          ></el-input>
+          {{ scope.row.mainTitle }}
         </span>
       </el-table-column>
-      <el-table-column prop="qType" label="类型" width="160">
+      <el-table-column prop="typeName" label="题型" width="160">
         <template slot-scope="scope" v-if="scope.row.mainFirstSub">
-          <el-radio-group
-            v-model="scope.row.qType"
-            size="mini"
-            @change="qTypeChange(scope.row)"
-          >
-            <el-radio-button
-              v-for="(val, key) in Q_TYPE"
-              :key="key"
-              :label="key"
-              >{{ val }}</el-radio-button
-            >
-          </el-radio-group>
+          {{ scope.row.typeName }}
+        </template>
+      </el-table-column>
+      <el-table-column label="每题分值" width="160">
+        <template slot-scope="scope" v-if="scope.row.mainFirstSub">
+          <el-input-number
+            v-model="scoresPerTopic[scope.row.mainId]"
+            class="width-80"
+            size="small"
+            :min="0.5"
+            :max="500"
+            :step="0.5"
+            step-strictly
+            :controls="false"
+            @change="(val) => scorePerTopicChange(val, scope.row)"
+          ></el-input-number>
         </template>
       </el-table-column>
       <el-table-column prop="mainNumber" label="大题号" width="80">
@@ -78,29 +76,6 @@
           ></el-input-number>
         </template>
       </el-table-column>
-      <el-table-column class-name="action-column" label="操作" width="200px">
-        <template slot-scope="scope">
-          <el-button
-            class="btn-primary"
-            type="text"
-            @click="toAddMain(scope.row)"
-            >新增大题</el-button
-          >
-          <el-button
-            class="btn-primary"
-            type="text"
-            @click="toAddSub(scope.row)"
-            >新增小题</el-button
-          >
-          <el-button
-            :disabled="tableData.length <= 1"
-            class="btn-danger"
-            type="text"
-            @click="toDeleteSub(scope.row)"
-            >删除</el-button
-          >
-        </template>
-      </el-table-column>
     </el-table>
     <div class="total-info">
       试卷总分:<span>{{ paperTotalScore }}</span
@@ -133,6 +108,7 @@ export default {
         objective: "客观题",
         subjective: "主观题",
       },
+      scoresPerTopic: {},
     };
   },
   computed: {
@@ -145,12 +121,16 @@ export default {
   },
   methods: {
     initData() {
+      let curMainId = null;
+      let scoresPerTopic = {};
       this.tableData = this.datas.paperStructureInfo.map((item) => {
+        if (curMainId !== item.mainId) {
+          curMainId = item.mainId;
+          scoresPerTopic[curMainId] = undefined;
+        }
         return { ...item };
       });
-      if (!this.tableData.length) {
-        this.createMain();
-      }
+      this.scoresPerTopic = scoresPerTopic;
 
       this.$emit("on-ready");
     },
@@ -265,6 +245,12 @@ export default {
         .filter((item) => item.mainId === row.mainId && !item.mainFirstSub)
         .forEach((item) => (item.qType = row.qType));
     },
+    scorePerTopicChange(val, row) {
+      if (!val) return;
+      this.tableData
+        .filter((item) => item.mainId === row.mainId)
+        .forEach((item) => (item.totalScore = val));
+    },
     checkData() {
       // if (
       //   this.tableData.some(item => item.qType === "objective") &&

+ 134 - 9
src/modules/stmms/components/markParam/ModifyMarkParams.vue

@@ -67,6 +67,7 @@ import MarkPaperMarker from "./MarkPaperMarker.vue";
 import MarkPaperStructure from "./MarkPaperStructure.vue";
 // import paramData from "./paramData";
 import { examStructureSubmit } from "../../api";
+import { cardDetail } from "../../../card/api";
 import { calcSum } from "@/plugins/utils";
 
 const STEPS_LIST = [
@@ -124,7 +125,7 @@ export default {
     },
   },
   methods: {
-    visibleChange() {
+    async visibleChange() {
       this.current = 0;
       this.loading = false;
 
@@ -143,16 +144,140 @@ export default {
         this.infos.paperStat = this.statPaperStructure(
           this.infos.paperStructureInfo
         );
-      } else {
-        this.infos = {
-          paperStructureInfo: [],
-          groupInfo: [],
-          basicPaperInfo: { ...this.instance },
-          paperStat: this.statPaperStructure([]),
-        };
+        this.dataReady = true;
+        return;
       }
 
-      this.dataReady = true;
+      const detData = await cardDetail(this.instance.cardId);
+      const cardContent = JSON.parse(detData.content);
+      this.infos = {
+        paperStructureInfo: this.parsePaperStructureFromCard(cardContent.pages),
+        groupInfo: [],
+        basicPaperInfo: { ...this.instance },
+        paperStat: this.statPaperStructure([]),
+      };
+    },
+    parsePaperStructureFromCard(pages) {
+      let structData = [];
+      let curTopicId = 0;
+      pages.forEach((page) => {
+        page.columns.forEach((column) => {
+          column.elements.forEach((topic) => {
+            if (!topic.parent) return;
+            if (curTopicId === topic.parent.id) return;
+
+            curTopicId = topic.parent.id;
+            let questionsCount = 1,
+              startNumber = 1;
+            if (topic.type === "COMPOSITION") {
+              // 相同大题号的作文题合并处理
+              const compositionData = structData.find(
+                (struct) =>
+                  struct.cardTopicType === "COMPOSITION" &&
+                  struct.mainNumber === topic.parent.topicNo * 1
+              );
+              if (compositionData) return;
+            } else {
+              questionsCount = topic.parent.questionsCount;
+              startNumber = topic.parent.startNumber || 1;
+            }
+            const typeInfo = this.getQuestionType(topic);
+            if (!typeInfo) return;
+
+            let data = {
+              mainNumber: topic.parent.topicNo * 1,
+              mainTitle: topic.parent.topicName,
+              questionsCount,
+              startNumber,
+              cardTopicType: topic.type,
+              ...typeInfo,
+            };
+            if (topic.type === "FILL_QUESTION") {
+              data.optionCount = topic.optionCount;
+            }
+            structData.push(data);
+          });
+        });
+      });
+      let structure = [];
+      let mainIds = {};
+      structData.forEach((struct) => {
+        const { startNumber, questionCount, qType, mainNumber, mainTitle } =
+          struct;
+        if (!mainIds[mainNumber]) {
+          mainIds[mainNumber] = this.$randomCode();
+        }
+        for (let i = 0; i < questionCount; i++) {
+          structure.push({
+            id: this.$randomCode(),
+            qType,
+            mainId: mainIds[mainNumber],
+            mainTitle,
+            mainNumber,
+            subNumber: startNumber + i,
+            type: struct.type,
+            typeName: struct.typeName,
+            optionCount: struct.optionCount || null,
+            totalScore: undefined,
+            mainFirstSub: false,
+            expandSub: true,
+          });
+        }
+      });
+      structure.sort(
+        (a, b) => a.mainNumber - b.mainNumber || a.subNumber - b.subNumber
+      );
+      let curMainId = null;
+      structData.forEach((item) => {
+        if (curMainId !== item.mainId) {
+          curMainId = item.mainId;
+          item.mainFirstSub = true;
+        }
+      });
+      return structure;
+    },
+    getQuestionType(topic) {
+      // const questionType = {
+      //   1: "SINGLE_ANSWER_QUESTION",
+      //   2: "MULTIPLE_ANSWER_QUESTION",
+      //   3: "BOOL_ANSWER_QUESTION",
+      //   4: "FILL_BLANK_QUESTION",
+      //   5: "TEXT_ANSWER_QUESTION",
+      // };
+      if (topic.type === "COMPOSITION" || topic.type === "EXPLAIN") {
+        return {
+          type: 5,
+          typeName: "解答题",
+          qType: "subjective",
+        };
+      }
+      if (topic.type === "FILL_LINE") {
+        return {
+          type: 4,
+          typeName: "填空题",
+          qType: "subjective",
+        };
+      }
+      if (topic.type === "FILL_QUESTION") {
+        if (topic.isBoolean)
+          return {
+            type: 3,
+            typeName: "判断题",
+            qType: "objective",
+          };
+        if (topic.isMultiply)
+          return {
+            type: 2,
+            typeName: "多选题",
+            qType: "objective",
+          };
+        return {
+          type: 1,
+          typeName: "单选题",
+          qType: "objective",
+        };
+      }
+      return;
     },
     statPaperStructure(paperStructureInfo) {
       const questionCount = paperStructureInfo.length;

+ 68 - 28
src/modules/stmms/components/markParam/ModifyObjectiveAnswer.vue

@@ -66,14 +66,21 @@
       <el-table-column prop="totalScore" label="小题满分" width="105">
       </el-table-column>
       <el-table-column label="答案" width="200px">
-        <template slot-scope="scope">
+        <div
+          slot-scope="scope"
+          :class="['el-form-item', { 'is-error': scope.row.error }]"
+        >
           <el-input
             v-model.trim="scope.row.answer"
             placeholder="请输入答案"
-            maxlength="16"
+            :maxlength="scope.row.optionCount"
             clearable
+            @change="validateAnswer(scope.row)"
           ></el-input>
-        </template>
+          <div v-if="scope.row.error" class="color-danger">
+            {{ scope.row.errMsg }}
+          </div>
+        </div>
       </el-table-column>
     </el-table>
 
@@ -99,6 +106,7 @@ export default {
       modalIsShow: false,
       isSubmit: false,
       tableData: [],
+      abc: "abcdefghijklmnopqrstuvwxyz".toUpperCase(),
     };
   },
   methods: {
@@ -127,6 +135,8 @@ export default {
         nitem.mainId = curMainId;
         nitem.expandSub = true;
         nitem.answer = item.answer || "";
+        nitem.error = false;
+        nitem.errMsg = "";
         return nitem;
       });
     },
@@ -155,35 +165,60 @@ export default {
         .filter((item) => item.mainId === row.mainId && !item.mainFirstSub)
         .forEach((item) => (item.expandSub = row.expandSub));
     },
-    checkData() {
-      let errorMessages = [];
-      this.tableData.forEach((item) => {
-        let errorMsg = "";
-        if (item.answer) {
-          if (!/^[A-Z]{1,26}$/.test(item.answer)) {
-            errorMsg += `答案只能输入英文大写字母`;
-          } else {
-            const ansSet = new Set(item.answer.split(""));
-            if (ansSet.size !== item.answer.length) {
-              errorMsg += `答案不能重复`;
-            }
-          }
-        } else {
-          errorMsg += `答案不能为空`;
+    validateAnswer(row) {
+      if (!row.answer) {
+        row.error = true;
+        row.errMsg = "不能为空";
+        return;
+      }
+
+      if (!/^[A-Z]{1,26}$/.test(row.answer)) {
+        row.error = true;
+        row.errMsg = "只能输入英文大写字母";
+        return;
+      }
+
+      const validAnswers = this.abc.substring(1, row.optionCount);
+      // 单选题 判断题
+      if (row.type === 1 || row.type === 3) {
+        if (
+          row.answer.length !== 1 ||
+          row.answer.split("").some((item) => !validAnswers.includes(item))
+        ) {
+          row.error = true;
+          row.errMsg = `只能输入${validAnswers}中的一个`;
+          return;
         }
+      }
 
-        if (errorMsg) {
-          errorMessages.push(
-            `第${item.mainNumber}大题,第${item.subNumber}小题,${errorMsg}`
-          );
+      // 多选题
+      if (row.type === 2) {
+        if (
+          row.answer.length > 1 ||
+          row.answer.split("").some((item) => !validAnswers.includes(item))
+        ) {
+          row.error = true;
+          row.errMsg = `只能输入${validAnswers}中的字符`;
+          return;
+        }
+
+        const ansSet = new Set(row.answer.split(""));
+        if (ansSet.size !== row.answer.length) {
+          row.error = true;
+          row.errMsg = "答案不能重复";
+          return;
         }
-      });
-      if (errorMessages.length) {
-        this.$message.error(errorMessages.join("。"));
-        return;
       }
 
-      return true;
+      row.error = false;
+      row.errMsg = "";
+    },
+    checkData() {
+      this.tableData.forEach((item) => {
+        this.validateAnswer(item);
+      });
+
+      return !this.tableData.some((item) => item.error);
     },
     async submit() {
       if (!this.checkData()) return;
@@ -192,7 +227,12 @@ export default {
       this.isSubmit = true;
       const datas = {
         id: this.instance.id,
-        objectiveStructure: this.tableData,
+        objectiveStructure: this.tableData.map((item) => {
+          let nitem = { ...item };
+          delete nitem.errMsg;
+          delete nitem.error;
+          return nitem;
+        }),
       };
       const data = await updateObjectiveAnswer(datas).catch(() => {});
       this.isSubmit = false;