Bladeren bron

自动组卷

zhangjie 2 jaren geleden
bovenliggende
commit
04475e89cb

+ 83 - 0
src/components/selection/DetailNameSelect.vue

@@ -0,0 +1,83 @@
+<template>
+  <el-select
+    v-model="selected"
+    :clearable="clearable"
+    :disabled="disabled"
+    :placeholder="placeholder"
+    @change="select"
+  >
+    <el-option
+      v-for="item in optionList"
+      :key="item"
+      :label="item"
+      :value="item"
+    ></el-option>
+  </el-select>
+</template>
+
+<script>
+import { questionDetailNameQueryApi } from "../../modules/question/api";
+
+export default {
+  name: "DetailNameSelect",
+  props: {
+    value: {
+      type: String,
+      default: "",
+    },
+    filterData: {
+      type: Object,
+      default() {
+        return {
+          courseId: "",
+          questionType: "",
+        };
+      },
+    },
+    disabled: { type: Boolean, default: false },
+    placeholder: { type: String, default: "请选择来源大题" },
+    clearable: { type: Boolean, default: true },
+  },
+  data() {
+    return {
+      selected: "",
+      optionList: [],
+    };
+  },
+  watch: {
+    value: {
+      immediate: true,
+      handler(val) {
+        this.selected = val;
+      },
+    },
+    filterData: {
+      deep: true,
+      immediate: true,
+      handler(val, oldval) {
+        if (JSON.stringify(val) === JSON.stringify(oldval)) return;
+        this.search();
+      },
+    },
+  },
+  methods: {
+    async search() {
+      if (!this.filterData.courseId || !this.filterData.questionType) {
+        this.optionList = [];
+        this.selected = "";
+        this.select();
+        return;
+      }
+
+      this.loading = true;
+      const res = await questionDetailNameQueryApi(this.filterData);
+      this.optionList = res.data || [];
+      this.loading = false;
+    },
+    select() {
+      this.$emit("input", this.selected);
+      this.$emit("change", this.selected);
+    },
+  },
+};
+</script>

+ 9 - 5
src/modules/paper/api.js

@@ -15,13 +15,17 @@ export const courseQueryApi = (name, enable) => {
 export const buildPaperApi = (datas, mode) => {
   return $httpWithMsg.post(`${QUESTION_API}/gen/paper/${mode}`, datas);
 };
-// export const questionGroupStructListApi = (datas) => {
-//   return $httpWithMsg.post(`${QUESTION_API}/paper/build`, datas);
-// };
-import folderPropStruct from "./datas/folderPropStruct.json";
 export const questionGroupStructListApi = (datas) => {
-  return Promise.resolve({ data: folderPropStruct, filter: datas });
+  return $httpWithMsg.post(
+    `${QUESTION_API}/gen/paper/auto/distribute`,
+    {},
+    { params: datas }
+  );
 };
+// import folderPropStruct from "./datas/folderPropStruct.json";
+// export const questionGroupStructListApi = (datas) => {
+//   return Promise.resolve({ data: folderPropStruct, filter: datas });
+// };
 
 // edit paper
 export const paperDetailInfoApi = (paperId) => {

+ 47 - 23
src/modules/paper/components/BuildPaperAuto.vue

@@ -56,7 +56,13 @@
           </tr>
         </table>
         <question-group-struct
-          :filter-data="{ courseId, questionType: detail.questionType }"
+          :ref="`QuestionStruct${detail.id}`"
+          :filter-data="{
+            courseId,
+            questionType: detail.questionType,
+            detailName: detail.sourceDetailName,
+          }"
+          @count-change="(val) => structCountChange(val, detail)"
         ></question-group-struct>
       </el-collapse-item>
     </el-collapse>
@@ -85,27 +91,7 @@ export default {
   },
   data() {
     return {
-      details: [
-        {
-          id: "32qk2guo99mg24no",
-          name: "单项选择题",
-          description: {
-            sections: [
-              {
-                blocks: [
-                  {
-                    type: "text",
-                    value: "请选择唯一选项",
-                    param: null,
-                  },
-                ],
-              },
-            ],
-          },
-          questionType: "SINGLE_ANSWER_QUESTION",
-          scorePerQuestion: 1,
-        },
-      ],
+      details: [],
       curDetail: {},
       activeNames: [],
     };
@@ -113,7 +99,7 @@ export default {
   methods: {
     toSelectStruct() {},
     addDetail() {
-      this.curDetail = {};
+      this.curDetail = { courseId: this.courseId };
       this.$refs.ModifyDetailStruct.open();
     },
     editDetail(curDetail) {
@@ -141,6 +127,44 @@ export default {
         );
       }
     },
+    structCountChange(val, detail) {
+      const index = this.details.findIndex((item) => item.id === detail.id);
+      if (index === -1) return;
+      this.details[index].questionCount = val;
+    },
+    getData() {
+      let detailInfo = this.details.map((item) => {
+        const structData =
+          this.$refs[`QuestionStruct${item.id}`][0].getDataList();
+        return {
+          questionType: item.questionType,
+          description: item.description,
+          detailName: item.detailName,
+          sourceDetailName: item.sourceDetailName,
+          courseId: item.courseId,
+          score: structData.questionCount * item.scorePerQuestion,
+          ...structData,
+        };
+      });
+
+      return { detailInfo };
+    },
+    validate() {
+      if (!this.details.length) {
+        this.$message.error("请设置大题!");
+        return Promise.reject();
+      }
+
+      let hasNoQuestionDetail = this.details.some(
+        (detail) => !detail.questionCount
+      );
+      if (hasNoQuestionDetail) {
+        this.$message.error("有大题未设置小题!");
+        return Promise.reject();
+      }
+
+      return Promise.resolve(true);
+    },
   },
 };
 </script>

+ 2 - 1
src/modules/paper/components/BuildPaperManual.vue

@@ -80,6 +80,7 @@
     <modify-detail-struct
       ref="ModifyDetailStruct"
       :detail="curDetail"
+      only-name
       @modified="detailModified"
     ></modify-detail-struct>
     <!-- SelectQuestionDialog -->
@@ -143,7 +144,7 @@ export default {
       return !!qtype;
     },
     addDetail() {
-      this.curDetail = {};
+      this.curDetail = { courseId: this.courseId };
       this.$refs.ModifyDetailStruct.open();
     },
     editDetail(curDetail) {

+ 22 - 4
src/modules/paper/components/ModifyDetailStruct.vue

@@ -14,9 +14,9 @@
       :rules="rules"
       label-width="90px"
     >
-      <el-form-item label="大题名称" prop="name">
+      <el-form-item label="大题名称" prop="detailName">
         <el-input
-          v-model="modalForm.name"
+          v-model="modalForm.detailName"
           class="dialog-input-width"
           placeholder="请输入题型名称"
         ></el-input>
@@ -33,6 +33,15 @@
           v-model="modalForm.questionType"
         ></question-type-select>
       </el-form-item>
+      <el-form-item v-if="!onlyName" label="来源大题" prop="sourceDetailName">
+        <detail-name-select
+          v-model="modalForm.sourceDetailName"
+          :filter-data="{
+            questionType: modalForm.questionType,
+            courseId: modalForm.courseId,
+          }"
+        ></detail-name-select>
+      </el-form-item>
       <el-form-item v-if="!onlyName" label="每题分值" prop="scorePerQuestion">
         <el-input-number
           v-model="modalForm.scorePerQuestion"
@@ -58,9 +67,11 @@ import { randomCode } from "@/plugins/utils";
 
 const initModalForm = {
   id: null,
-  name: "",
+  detailName: "",
+  courseId: "",
   description: "",
   questionType: null,
+  sourceDetailName: null,
   scorePerQuestion: 1,
 };
 export default {
@@ -82,7 +93,7 @@ export default {
       modalIsShow: false,
       modalForm: { ...initModalForm },
       rules: {
-        name: [
+        detailName: [
           {
             required: true,
             message: "请输入大题名称",
@@ -96,6 +107,13 @@ export default {
             trigger: "change",
           },
         ],
+        sourceDetailName: [
+          {
+            required: true,
+            message: "请选择来源大题",
+            trigger: "change",
+          },
+        ],
         scorePerQuestion: [
           {
             required: true,

+ 94 - 11
src/modules/paper/components/QuestionGroupStruct.vue

@@ -15,6 +15,7 @@
         v-model="curCoursePropertyId"
         class="margin-left-10"
         size="small"
+        @change="buildDataList"
       >
         <el-option
           v-for="item in propertyInfo"
@@ -54,7 +55,13 @@
                 v-if="scope.row.isClassify"
                 class="icon icon-files-act margin-right-5"
               ></i>
-              <span class="inline-middle">{{ scope.row.name }}</span>
+
+              <span
+                v-if="scope.row.isClassify && scope.row.id === 0"
+                class="inline-middle"
+                >根目录</span
+              >
+              <span v-else class="inline-middle">{{ scope.row.name }}</span>
             </template>
           </el-table-column>
           <el-table-column
@@ -72,6 +79,7 @@
                 :controls="false"
                 :precision="0"
                 step-strictly
+                @change="selectCountChange"
               ></el-input-number>
               <span class="inline-middle">/ {{ scope.row.questionCount }}</span>
             </template>
@@ -99,6 +107,7 @@
                 :controls="false"
                 :precision="0"
                 step-strictly
+                @change="selectCountChange"
               ></el-input-number>
               <span class="inline-middle"
                 >/
@@ -115,9 +124,9 @@
 </template>
 
 <script>
-import folderTree from "../datas/folderTree.json";
 import { questionGroupStructListApi } from "../api";
-import { deepCopy } from "@/plugins/utils";
+import { classifyTreeApi } from "../../question/api";
+import { calcSum, deepCopy } from "@/plugins/utils";
 
 export default {
   name: "QuestionGroupStruct",
@@ -139,8 +148,14 @@ export default {
       useProperty: false,
       checkedSet: [],
       selectedFolderIds: [],
-      classifyTree: folderTree,
-      // classifyTree: [],
+      classifyTree: [
+        {
+          id: 0,
+          parent: null,
+          name: "根目录",
+          children: [],
+        },
+      ],
       treeProps: {
         label: "name",
       },
@@ -168,9 +183,10 @@ export default {
     },
   },
   watch: {
-    "filterData.questionType": {
+    filterData: {
+      deep: true,
       handler(val, oldval) {
-        if (val !== oldval) {
+        if (JSON.stringify(val) !== JSON.stringify(oldval)) {
           this.resetDataList();
         }
       },
@@ -178,6 +194,7 @@ export default {
   },
   mounted() {
     this.resetDataList();
+    this.getClassifyTree();
   },
   methods: {
     setChange() {
@@ -188,6 +205,10 @@ export default {
       this.selectedFolderIds = this.$refs.folderTree.getCheckedKeys();
       this.resetDataList();
     },
+    async getClassifyTree() {
+      const res = await classifyTreeApi();
+      this.classifyTree[0].children = res.data || [];
+    },
     async resetDataList() {
       await this.getOriginList();
 
@@ -220,10 +241,13 @@ export default {
       let coursePropertyIds = [],
         propertyInfo = [];
       this.originList.forEach((item) => {
-        if (!item.propertyDistributeInfo || !item.propertyDistributeInfo.length)
+        if (
+          !item.coursePropertyDistributeInfo ||
+          !item.coursePropertyDistributeInfo.length
+        )
           return;
 
-        item.propertyDistributeInfo.forEach((prop) => {
+        item.coursePropertyDistributeInfo.forEach((prop) => {
           if (coursePropertyIds.includes(prop.coursePropertyId)) return;
           coursePropertyIds.push(prop.coursePropertyId);
           propertyInfo.push({
@@ -331,12 +355,13 @@ export default {
 
       if (this.USE_ONLY_DIFFICULT) {
         this.tableData = this.dataList[0].difficultDistributeInfo;
-        this.tableData.map((item) => {
+        this.tableData = this.tableData.map((item) => {
           let nitem = { ...item };
           nitem.id = item.difficultLevel;
           nitem.name = item.difficultLevel;
           return nitem;
         });
+        this.selectCountChange();
         return;
       }
       if (this.useClassify && !this.useProperty) {
@@ -345,11 +370,62 @@ export default {
           nitem.propertyDistributeInfo = null;
           return nitem;
         });
+        this.selectCountChange();
+        return;
       }
       if (!this.useClassify && this.useProperty) {
         this.tableData = this.dataList[0].propertyDistributeInfo;
+        this.selectCountChange();
         return;
       }
+
+      this.selectCountChange();
+    },
+    getTotalQuestionCount() {
+      let questionCount = 0;
+
+      if (this.USE_ONLY_DIFFICULT) {
+        questionCount = calcSum(
+          this.tableData.map((item) => item.selectCount || 0)
+        );
+        return questionCount;
+      }
+
+      let _this = this;
+      function getCount(data) {
+        let count = 0;
+        if (_this.useDifficult) {
+          if (data.difficultDistributeInfo) {
+            count = calcSum(
+              data.difficultDistributeInfo.map((item) => item.selectCount || 0)
+            );
+          }
+        } else {
+          count = data.selectCount || 0;
+        }
+
+        return count;
+      }
+
+      this.tableData.forEach((item) => {
+        questionCount += getCount(item);
+
+        if (this.useProperty && item.propertyDistributeInfo) {
+          item.propertyDistributeInfo.forEach((pItem) => {
+            questionCount += getCount(pItem);
+            if (pItem.propertyDistributeInfo) {
+              pItem.propertyDistributeInfo.forEach((spItem) => {
+                questionCount += getCount(spItem);
+              });
+            }
+          });
+        }
+      });
+
+      return questionCount;
+    },
+    selectCountChange() {
+      this.$emit("count-change", this.getTotalQuestionCount());
     },
     getDataList() {
       let dataList = deepCopy(this.dataList);
@@ -384,7 +460,14 @@ export default {
         return item;
       });
 
-      return dataList;
+      return {
+        questionDistributeInfo: dataList,
+        questionCount: this.getTotalQuestionCount(),
+        useClassify: this.useClassify,
+        useDifficult: this.useDifficult,
+        useProperty: this.useProperty,
+        curCoursePropertyId: this.curCoursePropertyId,
+      };
     },
   },
 };

+ 1 - 1
src/modules/paper/views/BuildPaper.vue

@@ -176,7 +176,7 @@ export default {
           },
         ],
       },
-      genModelType: "manual",
+      genModelType: "auto",
       modelTypes: [
         {
           code: "simple",

+ 7 - 0
src/modules/question/api.js

@@ -27,6 +27,13 @@ export const propertySecondQueryApi = (firstPropertyId) => {
 export const propertyTreeQueryApi = (coursePropertyId) => {
   return $httpWithMsg.get(`${QUESTION_API}/property/all/${coursePropertyId}`);
 };
+export const questionDetailNameQueryApi = ({ courseId, questionType }) => {
+  return $httpWithMsg.post(
+    `${QUESTION_API}/question/find_detail_name`,
+    {},
+    { params: { courseId, questionType } }
+  );
+};
 
 // question-manage
 export function questionPageListApi(data) {

+ 19 - 4
src/modules/question/components/QuestionInfoEdit.vue

@@ -123,9 +123,17 @@ export default {
   methods: {
     initData() {
       let modalForm = this.$objAssign(initModalForm, this.question);
-      modalForm.quesProperties.forEach((item) => {
-        item.key = `${item.courseProperty.id}_${item.firstProperty.id}_${item.secondProperty.id}`;
-      });
+      if (modalForm.quesProperties && modalForm.quesProperties.length) {
+        modalForm.quesProperties.forEach((item) => {
+          let ids = [item.courseProperty.id, item.firstProperty.id];
+          if (item.secondProperty && item.secondProperty.id) {
+            ids.push(item.secondProperty.id);
+          }
+          item.key = ids.join("_");
+        });
+      } else {
+        modalForm.quesProperties = [];
+      }
       this.modalForm = modalForm;
     },
     coursePropertyChange(val) {
@@ -145,8 +153,15 @@ export default {
     },
     addProperty() {
       if (!this.propSelected) return;
+      let ids = [
+        this.properties.coursePropertyId,
+        this.properties.firstPropertyId,
+      ];
+      if (this.properties.secondPropertyId) {
+        ids.push(this.properties.secondPropertyId);
+      }
       const newProperty = {
-        key: `${this.properties.coursePropertyId}_${this.properties.firstPropertyId}_${this.properties.secondPropertyId}`,
+        key: ids.join("_"),
         ...this.selection,
       };
       const propertyExist = this.modalForm.quesProperties.find(

+ 2 - 0
src/plugins/globalVuePlugins.js

@@ -6,6 +6,7 @@ import CourseSelect from "../components/selection/CourseSelect";
 import QuestionTypeSelect from "../components/selection/QuestionTypeSelect";
 import PropertySelect from "../components/selection/PropertySelect";
 import PropertySubSelect from "../components/selection/PropertySubSelect";
+import DetailNameSelect from "../components/selection/DetailNameSelect";
 // mixins
 import commonMixins from "../mixins/common";
 
@@ -20,6 +21,7 @@ export default {
     Vue.component("QuestionTypeSelect", QuestionTypeSelect);
     Vue.component("PropertySelect", PropertySelect);
     Vue.component("PropertySubSelect", PropertySubSelect);
+    Vue.component("DetailNameSelect", DetailNameSelect);
     //全局 mixins
     Vue.mixin(commonMixins);
   },