Ver código fonte

简易和手动组卷

zhangjie 2 anos atrás
pai
commit
03dc2f915e

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

@@ -12,9 +12,8 @@ export const courseQueryApi = (name, enable) => {
 };
 
 //  build paper
-export const buildPaperApi = (datas) => {
-  // return $httpWithMsg.post(`${QUESTION_API}/paper/build`, datas);
-  return Promise.resolve(datas);
+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);
@@ -153,3 +152,10 @@ export const paperSimpleTypeDistributeApi = (courseId) => {
     { params: { courseId } }
   );
 };
+export const paperSimpleCountDistributeApi = (params) => {
+  return $httpWithMsg.post(
+    `${QUESTION_API}/gen/paper/simple/count/distribute`,
+    {},
+    { params }
+  );
+};

+ 43 - 3
src/modules/paper/components/BuildPaperManual.vue

@@ -106,7 +106,7 @@ import SelectQuestionDialog from "./SelectQuestionDialog.vue";
 import QuestionEditDialog from "../../question/components/QuestionEditDialog.vue";
 import { BASE_QUESTION_TYPES } from "@/constants/constants";
 
-import details from "../datas/details.json";
+// import details from "../datas/details.json";
 
 export default {
   name: "BuildPaperManual",
@@ -125,8 +125,8 @@ export default {
   },
   data() {
     return {
-      // details: [],
-      details,
+      details: [],
+      // details,
       curDetail: {},
       curQuestion: {},
       activeNames: [],
@@ -205,6 +205,46 @@ export default {
         if (qindex !== -1) detail.questions.splice(qindex, 1);
       });
     },
+    getData() {
+      let detailInfo = this.details.map((item) => {
+        return {
+          description: item.description,
+          detailName: item.name,
+          unitInfo: item.questions.map((q) => {
+            return {
+              questionId: q.id,
+              score: q.score,
+            };
+          }),
+        };
+      });
+
+      return { detailInfo };
+    },
+    validate() {
+      if (!this.details.length) {
+        this.$message.error("请设置大题!");
+        return Promise.reject();
+      }
+
+      let hasNoQuestionDetail = this.details.some(
+        (detail) => !detail.questions.length
+      );
+      if (hasNoQuestionDetail) {
+        this.$message.error("有大题未设置小题!");
+        return Promise.reject();
+      }
+
+      let hasNoScoreQuestion = this.details.some((detail) => {
+        return detail.questions.some((q) => !q.score);
+      });
+      if (hasNoScoreQuestion) {
+        this.$message.error("有小题未设置分数!");
+        return Promise.reject();
+      }
+
+      return Promise.resolve(true);
+    },
   },
 };
 </script>

+ 132 - 10
src/modules/paper/components/BuildPaperSimple.vue

@@ -19,7 +19,7 @@
           label="题型小类"
           prop="questionType"
           align="center"
-          min-width="240"
+          min-width="200"
         >
           <div slot-scope="scope" class="box-justify">
             <div>{{ scope.row.quesStructType | questionTypeFilter }}</div>
@@ -104,7 +104,10 @@
 </template>
 
 <script>
-import { paperSimpleTypeDistributeApi } from "../api";
+import {
+  paperSimpleTypeDistributeApi,
+  paperSimpleCountDistributeApi,
+} from "../api";
 
 export default {
   name: "BuildPaperSimple",
@@ -118,6 +121,7 @@ export default {
     return {
       baseDataList: [],
       questionTypeSources: {},
+      simpleTypeDistributeInfo: [],
     };
   },
   mounted() {
@@ -125,22 +129,30 @@ export default {
   },
   methods: {
     spanMethod({ row, columnIndex }) {
-      if (columnIndex === 0) {
+      if (!row.rowspans) return;
+      if (columnIndex > 1) return;
+
+      if (row.rowspans[columnIndex] > 0) {
         return {
-          rowspan: row.rowspan || 0,
+          rowspan: row.rowspans[columnIndex],
           colspan: 1,
         };
+      } else {
+        return {
+          rowspan: 0,
+          colspan: 0,
+        };
       }
     },
     async getBaseData() {
       const res = await paperSimpleTypeDistributeApi(this.courseId);
+      this.simpleTypeDistributeInfo = res.data;
       // console.log(res.data);
       // parse data
       let baseDataList = [];
       let questionTypeSources = {};
       res.data.forEach((mainGroup) => {
-        let qtRowspan = mainGroup.quesTypeDistributeList.length;
-        mainGroup.quesTypeDistributeList.forEach((quesItem, qindex) => {
+        mainGroup.quesTypeDistributeList.forEach((quesItem) => {
           let nitem = {
             quesMainType: mainGroup.quesMainType,
             quesStructType: quesItem.quesStructType,
@@ -149,7 +161,6 @@ export default {
             selectCount: undefined,
             questionScore: undefined,
           };
-          if (qindex === 0) nitem.rowspan = qtRowspan;
           baseDataList.push(nitem);
           questionTypeSources[quesItem.quesStructType] = {
             detailNames: [],
@@ -157,14 +168,125 @@ export default {
           };
         });
       });
-      this.baseDataList = baseDataList;
+      this.baseDataList = this.buildTableStruct(baseDataList);
       this.questionTypeSources = questionTypeSources;
     },
-    sourceInfoChange(quesStructType) {
+    async sourceInfoChange(quesStructType) {
       console.log(quesStructType);
+      const detailNames = this.questionTypeSources[quesStructType].detailNames;
+      let curQuesStructTypeSource = [];
+
+      if (detailNames.length) {
+        const res = await paperSimpleCountDistributeApi({
+          courseId: this.courseId,
+          detailNameList: detailNames.join(),
+          quesStructType,
+        });
+        curQuesStructTypeSource = res.data;
+      }
+
+      let baseDataMap = {};
+      this.baseDataList.forEach((item) => {
+        if (!item.detailName || quesStructType === item.quesStructType) return;
+        const k = item.quesStructType;
+        if (!baseDataMap[k]) baseDataMap[k] = [];
+        baseDataMap[k].push(item);
+      });
+
+      let baseDataList = [];
+      this.simpleTypeDistributeInfo.forEach((mainGroup) => {
+        mainGroup.quesTypeDistributeList.forEach((quesItem) => {
+          if (baseDataMap[quesItem.quesStructType]) {
+            baseDataList.push(...baseDataMap[quesItem.quesStructType]);
+            return;
+          }
+
+          if (
+            quesItem.quesStructType === quesStructType &&
+            curQuesStructTypeSource.length
+          ) {
+            curQuesStructTypeSource.forEach((sitem) => {
+              let nsitem = {
+                quesMainType: mainGroup.quesMainType,
+                quesStructType: quesItem.quesStructType,
+                detailName: sitem.detailName,
+                questionCount: sitem.count,
+                selectCount: undefined,
+                questionScore: undefined,
+              };
+              baseDataList.push(nsitem);
+            });
+          } else {
+            let nitem = {
+              quesMainType: mainGroup.quesMainType,
+              quesStructType: quesItem.quesStructType,
+              detailName: "",
+              questionCount: undefined,
+              selectCount: undefined,
+              questionScore: undefined,
+            };
+            baseDataList.push(nitem);
+          }
+        });
+      });
+      this.baseDataList = this.buildTableStruct(baseDataList);
+    },
+    buildTableStruct(baseDataList) {
+      let curQtype = null;
+      let curMainType = null;
+      baseDataList.forEach((item) => {
+        if (curMainType !== item.quesMainType) {
+          curMainType = item.quesMainType;
+          const rowspan = baseDataList.filter(
+            (elem) => elem.quesMainType === curMainType
+          ).length;
+          item.rowspans = [rowspan];
+        } else {
+          item.rowspans = [0];
+        }
+        if (curQtype !== item.quesStructType) {
+          curQtype = item.quesStructType;
+          const rowspan = baseDataList.filter(
+            (elem) => elem.quesStructType === curQtype
+          ).length;
+          item.rowspans.push(rowspan);
+        } else {
+          item.rowspans.push(0);
+        }
+      });
+      console.log(baseDataList);
+      return baseDataList;
     },
     getData() {
-      return this.baseDataList;
+      let questionInfo = this.baseDataList
+        .filter((item) => item.selectCount)
+        .map((item) => {
+          return {
+            count: item.selectCount,
+            score: item.questionScore,
+            questionType: item.quesStructType,
+            sourceDetailName: item.detailName,
+          };
+        });
+      return { questionInfo };
+    },
+    validate() {
+      let valid = this.baseDataList.some((item) => item.selectCount);
+      if (!valid) {
+        this.$message.error("题目数量不能为空!");
+        return Promise.reject();
+      }
+
+      let unvalid = this.baseDataList
+        .filter((item) => item.selectCount)
+        .some((item) => !item.questionScore);
+
+      if (unvalid) {
+        this.$message.error("有小题未设置分数!");
+        return Promise.reject();
+      }
+
+      return Promise.resolve(true);
     },
   },
 };

+ 50 - 67
src/modules/paper/components/SelectQuestionDialog.vue

@@ -22,34 +22,20 @@
           <div class="part-filter-form">
             <el-form class="part-filter-form" :inline="true" :model="filter">
               <el-form-item label="题型">
-                <question-type-select v-model="filter.quesStructType">
+                <question-type-select v-model="filter.questionType">
                 </question-type-select>
               </el-form-item>
               <el-form-item label="题目内容">
                 <el-input
-                  v-model="filter.content"
+                  v-model="filter.questionBody"
                   placeholder="题目内容"
                 ></el-input>
               </el-form-item>
-              <el-form-item label="属性">
-                <property-select
-                  v-model="filter.coursePropertyId"
+              <el-form-item label="属性">
+                <property-tree-select
+                  v-model="filter.questionProperty"
                   :course-id="filter.courseId"
-                ></property-select>
-              </el-form-item>
-              <el-form-item label="一级属性">
-                <property-sub-select
-                  v-model="filter.firstPropertyId"
-                  :parent-id="filter.coursePropertyId"
-                  data-type="first"
-                ></property-sub-select>
-              </el-form-item>
-              <el-form-item label="二级属性">
-                <property-sub-select
-                  v-model="filter.secondPropertyId"
-                  :parent-id="filter.firstPropertyId"
-                  data-type="second"
-                ></property-sub-select>
+                ></property-tree-select>
               </el-form-item>
 
               <el-form-item>
@@ -67,6 +53,15 @@
             label="编号"
           >
           </el-table-column>
+          <el-table-column label="题干">
+            <div slot-scope="scope" @click="toViewQuestion(scope.row)">
+              <rich-text
+                class="row-question-body"
+                title="点击查看试题"
+                :text-json="scope.row.quesBody"
+              ></rich-text>
+            </div>
+          </el-table-column>
           <el-table-column label="课程" width="120">
             <template slot-scope="scope">
               <span>{{ scope.row.course.name }}</span>
@@ -77,30 +72,20 @@
               <span>{{ scope.row.questionType | questionType }}</span>
             </template>
           </el-table-column>
-          <el-table-column label="难度" width="80"> </el-table-column>
-          <el-table-column label="使用量" width="80"> </el-table-column>
-          <el-table-column label="创建人" width="120">
-            <template slot-scope="scope">
-              <span>{{ scope.row.creator }}</span>
-            </template>
+          <el-table-column label="难度" prop="difficulty" width="80">
+          </el-table-column>
+          <el-table-column label="使用量" prop="usageAmount" width="80">
+          </el-table-column>
+          <el-table-column label="创建人" prop="creator" width="120">
           </el-table-column>
           <el-table-column label="创建时间" width="170" prop="creationTime">
           </el-table-column>
           <el-table-column label="操作" width="160" fixed="right">
             <div v-if="!scope.row.disabled" slot-scope="scope">
-              <!-- <el-button
-                size="mini"
-                type="primary"
-                plain
-                @click="toDetail(scope.row)"
-              >
-                详情
-              </el-button> -->
               <el-button
                 v-if="scope.row.selected"
                 size="mini"
                 type="danger"
-                plain
                 @click="toDelete(scope.row)"
               >
                 删除
@@ -140,7 +125,16 @@
         <el-table :data="curSelectedQuestions" border>
           <el-table-column width="60" type="index" label="编号">
           </el-table-column>
-          <el-table-column label="课程" width="120">
+          <el-table-column label="题干">
+            <div slot-scope="scope" @click="toViewQuestion(scope.row)">
+              <rich-text
+                class="row-question-body"
+                title="点击查看试题"
+                :text-json="scope.row.quesBody"
+              ></rich-text>
+            </div>
+          </el-table-column>
+          <el-table-column label="课程" width="200">
             <template slot-scope="scope">
               <span>{{ scope.row.course.name }}</span>
             </template>
@@ -150,29 +144,19 @@
               <span>{{ scope.row.questionType | questionType }}</span>
             </template>
           </el-table-column>
-          <el-table-column label="难度" width="80"> </el-table-column>
-          <el-table-column label="使用量" width="80"> </el-table-column>
-          <el-table-column label="创建人" width="120">
-            <template slot-scope="scope">
-              <span>{{ scope.row.creator }}</span>
-            </template>
+          <el-table-column label="难度" prop="difficulty" width="80">
+          </el-table-column>
+          <el-table-column label="使用量" prop="usageAmount" width="80">
+          </el-table-column>
+          <el-table-column label="创建人" prop="creator" width="120">
           </el-table-column>
           <el-table-column label="创建时间" width="170" prop="creationTime">
           </el-table-column>
           <el-table-column label="操作" width="160" fixed="right">
             <div slot-scope="scope">
-              <!-- <el-button
-                size="mini"
-                type="primary"
-                plain
-                @click="toDetail(scope.row)"
-              >
-                详情
-              </el-button> -->
               <el-button
                 size="mini"
                 type="danger"
-                plain
                 @click="toDeleteSelected(scope.row)"
               >
                 删除
@@ -193,13 +177,14 @@
 </template>
 
 <script>
-// import QuestionPreviewDialog from "./QuestionPreviewDialog";
+import QuestionPreviewDialog from "../../question/components/QuestionPreviewDialog";
+import PropertyTreeSelect from "../../question/components/PropertyTreeSelect.vue";
 import { questionPageListApi } from "../../question/api";
 import { deepCopy } from "@/plugins/utils";
 
 export default {
   name: "SelectQuestionDialog",
-  // components: {  QuestionPreviewDialog },
+  components: { QuestionPreviewDialog, PropertyTreeSelect },
   props: {
     courseId: {
       type: [String, Number],
@@ -223,11 +208,9 @@ export default {
       modalIsShow: false,
       filter: {
         courseId: "",
-        quesStructType: "",
-        content: "",
-        coursePropertyId: "",
-        firstPropertyId: "",
-        secondPropertyId: "",
+        questionType: "",
+        questionBody: "",
+        questionProperty: [],
       },
       tabType: "1",
       tableData: [],
@@ -257,15 +240,15 @@ export default {
       this.modalIsShow = true;
     },
     async getList() {
-      const res = await questionPageListApi({
+      let data = {
         ...this.filter,
-        enabled: 1,
         curPage: this.currentPage,
         pageSize: this.pageSize,
-      });
-      this.questions = res.records.map((item) => {
+      };
+      data.questionProperty = data.questionProperty.join();
+      const res = await questionPageListApi(data).catch(() => {});
+      this.questions = res.data.content.map((item) => {
         return {
-          // ...this.transformQuestionData(item),
           ...item,
           selected: this.curSelectedQuestionIds.includes(item.id),
           disabled: this.disabledQuestionIds.includes(item.id),
@@ -292,10 +275,10 @@ export default {
         });
       }
     },
-    // toDetail(row) {
-    //   this.curQuestion = { ...row };
-    //   this.$refs.QuestionPreviewDialog.open();
-    // },
+    toViewQuestion(row) {
+      this.curQuestion = row;
+      this.$refs.QuestionPreviewDialog.open();
+    },
     toSelect(row) {
       row.selected = true;
       this.curSelectedQuestions.push({ ...row });

+ 23 - 18
src/modules/paper/views/BuildPaper.vue

@@ -38,23 +38,24 @@
             placeholder="试卷名称"
           ></el-input>
         </el-form-item>
-        <el-form-item prop="genNumber" label="组卷套数">
+        <el-form-item v-if="!IS_MANUAL_MODE" prop="paperCount" label="组卷套数">
           <el-input-number
-            v-model="modalForm.genNumber"
+            v-model="modalForm.paperCount"
             :min="1"
             :max="5"
             :step="1"
             step-strictly
           ></el-input-number>
         </el-form-item>
-        <el-form-item style="border: none">
+        <el-form-item v-if="!IS_MANUAL_MODE" style="border: none">
           <el-checkbox v-model="modalForm.checkRepeat"
             >校验试卷重复率</el-checkbox
           >
         </el-form-item>
+        <el-form-item v-else></el-form-item>
       </el-form>
       <el-form>
-        <template v-if="modalForm.checkRepeat">
+        <template v-if="modalForm.checkRepeat && !IS_MANUAL_MODE">
           <el-form-item
             label="校验重复率的试卷范围:"
             label-width="180px"
@@ -93,7 +94,7 @@
             <el-input-number
               v-model="modalForm.timeLimit"
               style="width: 125px"
-              :min="0"
+              :min="1"
               :max="100"
               :step="1"
               step-strictly
@@ -104,10 +105,7 @@
           </el-form-item>
         </template>
         <el-form-item label="组卷模式" style="margin: 0">
-          <el-radio-group
-            v-model="modalForm.genModelType"
-            style="padding-left: 15px"
-          >
+          <el-radio-group v-model="genModelType" style="padding-left: 15px">
             <el-radio
               v-for="item in modelTypes"
               :key="item.code"
@@ -140,13 +138,12 @@ const initModalForm = {
   courseCode: "",
   courseName: "",
   paperName: "",
-  genNumber: 1,
-  genModelType: "simple",
+  paperCount: 1,
   checkRepeat: false,
   storage: false,
   maxLimit: 0,
   topicOnly: false,
-  timeLimit: 0,
+  timeLimit: 1,
 };
 
 export default {
@@ -171,7 +168,7 @@ export default {
             trigger: "change",
           },
         ],
-        genNumber: [
+        paperCount: [
           {
             required: true,
             message: "请输入组卷套数",
@@ -179,6 +176,7 @@ export default {
           },
         ],
       },
+      genModelType: "manual",
       modelTypes: [
         {
           code: "simple",
@@ -197,11 +195,18 @@ export default {
   },
   computed: {
     buildCompName() {
-      return `build-paper-${this.modalForm.genModelType}`;
+      return `build-paper-${this.genModelType}`;
+    },
+    IS_MANUAL_MODE() {
+      return this.genModelType === "manual";
     },
   },
   created() {
-    this.modalForm.courseId = this.$route.params.courseId;
+    let genPaperInfo = sessionStorage.getItem("gen_paper");
+    genPaperInfo = genPaperInfo ? JSON.parse(genPaperInfo) : {};
+    this.modalForm.courseCode = genPaperInfo.courseCode;
+    this.modalForm.courseName = genPaperInfo.courseName;
+    this.modalForm.courseId = genPaperInfo.courseId;
   },
   methods: {
     async confirm() {
@@ -213,12 +218,12 @@ export default {
       if (this.loading) return;
       this.loading = true;
 
-      let paperSet = this.$refs.BuildPaperDetail.getData();
+      let questionInfo = this.$refs.BuildPaperDetail.getData();
       const datas = {
         ...this.modalForm,
-        paperSet,
+        ...questionInfo,
       };
-      const res = await buildPaperApi(datas).catch(() => {});
+      const res = await buildPaperApi(datas, this.genModelType).catch(() => {});
       this.loading = false;
       if (!res) return;
 

+ 2 - 2
src/modules/question/components/QuestionBasePreview.vue

@@ -9,7 +9,7 @@
         :key="option.number"
         class="question-option"
       >
-        <rich-text :text-json="option.body"></rich-text>
+        <rich-text :text-json="option.optionBody"></rich-text>
       </div>
     </div>
     <div class="question-answer">
@@ -111,7 +111,7 @@ export default {
       if (this.question.quesOptions && this.question.quesOptions.length) {
         const quesOptions = deepCopy(this.question.quesOptions);
         quesOptions.forEach((option) => {
-          option.body.sections[0].blocks.unshift({
+          option.optionBody.sections[0].blocks.unshift({
             type: "text",
             value: String.fromCharCode(64 + option.number) + "、",
           });

+ 7 - 3
src/modules/questions/views/GenPaper.vue

@@ -649,9 +649,13 @@ export default {
           type: "warning",
         });
       } else {
-        var course = this.getCourseObj(courseId);
-        this.formSearch.courseName = course.name;
-        sessionStorage.setItem("gen_paper", JSON.stringify(this.formSearch));
+        let genPaperData = { ...this.formSearch };
+        var course = this.getCourseObj(this.formSearch.courseId);
+        if (course) {
+          genPaperData.courseName = course.name;
+          genPaperData.courseCode = course.code;
+        }
+        sessionStorage.setItem("gen_paper", JSON.stringify(genPaperData));
         sessionStorage.setItem("gen_paper_currentPage", this.currentPage);
         this.$router.push({
           name: "gen_paper_detail",