Przeglądaj źródła

feat: 试题日志

zhangjie 7 miesięcy temu
rodzic
commit
ee11ef611b

+ 41 - 1
src/assets/styles/pages.scss

@@ -1242,7 +1242,8 @@
   &.el-dialog {
     max-width: 1000px;
     width: 100%;
-    height: 100%;
+    top: 15%;
+    height: 70%;
     overflow: hidden;
     display: flex;
     flex-direction: column;
@@ -1258,6 +1259,13 @@
   .el-dialog__header {
     border-bottom: 1px solid #f0f0f0;
     padding: 15px;
+
+    h2 {
+      font-size: 16px;
+    }
+  }
+  .el-dialog__headerbtn {
+    display: none;
   }
   .el-dialog__footer {
     border-top: 1px solid #f0f0f0;
@@ -1277,6 +1285,38 @@
     }
   }
 }
+// question-edit-log-dialog
+.question-edit-log-dialog {
+  .el-dialog__footer {
+    display: none;
+  }
+
+  .log-container {
+    height: 100%;
+    overflow: hidden;
+
+    display: flex;
+    justify-content: space-between;
+    align-items: stretch;
+  }
+
+  .log-question {
+    height: 100%;
+    flex-grow: 2;
+    overflow-y: auto;
+    overflow-x: hidden;
+  }
+  .log-history {
+    height: 100%;
+    width: 330px;
+    flex-grow: 0;
+    flex-shrink: 0;
+    overflow-y: auto;
+    overflow-x: hidden;
+    padding: 15px;
+  }
+}
+
 .synthesis-paper-storage-dialog {
   width: 100vw;
   margin-top: 0 !important;

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

@@ -96,6 +96,11 @@ export const exportQuestionApi = (data) => {
   });
 };
 
+export function questionEditLogsApi(id) {
+  const url = `${QUESTION_API}/question/log/${id}`;
+  return $httpWithMsg.get(url);
+}
+
 export function updateQuestionApi(data) {
   return $httpWithMsg.post(`${QUESTION_API}/question/save`, data, {
     params: { courseId: data.courseId },

+ 222 - 0
src/modules/question/components/QuestionEditLogDialog.vue

@@ -0,0 +1,222 @@
+<template>
+  <div>
+    <el-dialog
+      custom-class="question-preview-dialog edit-paper question-edit-log-dialog"
+      :visible.sync="modalIsShow"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      append-to-body
+      @open="openHandle"
+    >
+      <div class="box-justify" slot="title">
+        <h2>修改记录</h2>
+        <div>
+          <el-button icon="el-icon-back" @click="cancel">返回</el-button>
+        </div>
+      </div>
+
+      <div class="log-container">
+        <div class="log-question">
+          <div v-if="question.id" class="edit-part" :key="question.id">
+            <div class="edit-cont">
+              <div class="edit-cont-title">
+                <rich-text :text-json="question.quesBody"></rich-text>
+              </div>
+              <div class="edit-cont-body">
+                <template v-if="question.quesOptions">
+                  <div
+                    v-for="(quesOption, optionIndex) in question.quesOptions"
+                    :key="optionIndex"
+                    class="paper-option"
+                  >
+                    <span>{{ optionIndex | optionOrderWordFilter }}. </span>
+                    <rich-text :text-json="quesOption.optionBody"></rich-text>
+                  </div>
+                </template>
+                <div
+                  v-if="!isNested(question.questionType)"
+                  class="paper-answer"
+                >
+                  <span>答案:</span>
+                  <question-answer :data="question"></question-answer>
+                </div>
+              </div>
+              <div
+                v-if="
+                  !isNested(question.questionType) && question.quesProperties
+                "
+                class="edit-cont-props"
+                style="margin-top: 10px"
+              >
+                <el-tag
+                  v-for="(content, propIndex) in question.quesProperties"
+                  :key="propIndex"
+                  type="primary"
+                  effect="dark"
+                  style="margin-right: 5px; margin-bottom: 5px"
+                >
+                  <!-- {{ content.courseProperty && content.courseProperty.name }}
+                  <span style="margin: 0 3px">/</span> -->
+                  {{ content.firstProperty && content.firstProperty.name }}
+                  <span
+                    v-if="content.secondProperty && content.secondProperty.name"
+                    style="margin: 0 3px"
+                    >/</span
+                  >
+                  {{ content.secondProperty && content.secondProperty.name }}
+                </el-tag>
+              </div>
+              <div
+                v-if="isNested(question.questionType)"
+                class="edit-paper-question-subs"
+              >
+                <div
+                  v-for="(subQuestion, subIndex) in question.subQuestions"
+                  :key="subIndex"
+                  class="edit-part"
+                >
+                  <div class="edit-cont">
+                    <div class="edit-cont-title">
+                      <span>{{ subIndex + 1 }}. </span>
+                      <rich-text :text-json="subQuestion.quesBody"></rich-text>
+                    </div>
+                    <div class="edit-cont-body">
+                      <template
+                        v-if="!isMatchingQuestion(question.questionType)"
+                      >
+                        <div
+                          v-for="(
+                            subQuesOption, subOptIndex
+                          ) in subQuestion.quesOptions"
+                          :key="subOptIndex"
+                          class="paper-option"
+                        >
+                          <span
+                            >{{ subOptIndex | optionOrderWordFilter }}.
+                          </span>
+                          <rich-text
+                            :text-json="subQuesOption.optionBody"
+                          ></rich-text>
+                        </div>
+                      </template>
+                      <div class="paper-answer">
+                        <span>答案:</span>
+                        <question-answer :data="subQuestion"></question-answer>
+                      </div>
+                    </div>
+                    <div
+                      v-if="subQuestion.quesProperties"
+                      class="edit-cont-props"
+                      style="margin-top: 10px"
+                    >
+                      <el-tag
+                        v-for="(
+                          content, propIndex
+                        ) in subQuestion.quesProperties"
+                        :key="propIndex"
+                        type="primary"
+                        effect="dark"
+                        style="margin-right: 5px; margin-bottom: 5px"
+                      >
+                        <!-- {{ content.courseProperty && content.courseProperty.name }}
+                        <span style="margin: 0 3px">/</span> -->
+                        {{
+                          content.firstProperty && content.firstProperty.name
+                        }}
+                        <span
+                          v-if="
+                            content.secondProperty &&
+                            content.secondProperty.name
+                          "
+                          style="margin: 0 3px"
+                          >/</span
+                        >
+                        {{
+                          content.secondProperty && content.secondProperty.name
+                        }}
+                      </el-tag>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="log-history">
+          <el-table
+            element-loading-text="加载中"
+            :data="logList"
+            :row-class-name="rowClassHandle"
+            @row-click="selectQuestion"
+          >
+            <el-table-column label="修改时间" width="180" prop="creationTime">
+            </el-table-column>
+            <el-table-column label="修改人" prop="creator" width="120">
+            </el-table-column>
+          </el-table>
+        </div>
+      </div>
+
+      <div slot="footer"></div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { questionEditLogsApi } from "../api";
+
+export default {
+  name: "QuestionEditLogDialog",
+  props: {
+    paperId: {
+      type: [String, Number],
+      default: "",
+    },
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      question: {},
+      logList: [],
+      curLogId: "",
+    };
+  },
+  methods: {
+    async openHandle() {
+      const res = await questionEditLogsApi(this.paperId);
+
+      this.logList = res || [];
+
+      if (this.logList.length) this.selectQuestion(this.logList[0]);
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    isNested(questionType) {
+      const nestedQuestion = [
+        "PARAGRAPH_MATCHING",
+        "BANKED_CLOZE",
+        "CLOZE",
+        "READING_COMPREHENSION",
+        "LISTENING_QUESTION",
+      ];
+
+      return nestedQuestion.includes(questionType);
+    },
+    isMatchingQuestion(questionType) {
+      const typeQuestion = ["PARAGRAPH_MATCHING", "BANKED_CLOZE"];
+      return typeQuestion.includes(questionType);
+    },
+    rowClassHandle({ row }) {
+      return row.id === this.curLogId ? "is-active" : "";
+    },
+    selectQuestion(row) {
+      this.curLogId = row.id;
+      this.question = row.question;
+    },
+  },
+};
+</script>

+ 150 - 115
src/modules/question/components/QuestionPreviewDialog.vue

@@ -1,155 +1,184 @@
 <template>
-  <el-dialog
-    custom-class="question-preview-dialog edit-paper"
-    :visible.sync="modalIsShow"
-    title="试题预览"
-    :close-on-click-modal="false"
-    :close-on-press-escape="false"
-    append-to-body
-    @open="openHandle"
-  >
-    <div class="edit-part" :key="question.id">
-      <div class="edit-cont">
-        <div class="edit-cont-title">
-          <rich-text :text-json="question.quesBody"></rich-text>
+  <div>
+    <el-dialog
+      custom-class="question-preview-dialog edit-paper"
+      :visible.sync="modalIsShow"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      append-to-body
+      @open="openHandle"
+    >
+      <div class="box-justify" slot="title">
+        <h2>试题预览</h2>
+        <div>
+          <el-button
+            v-if="showLog"
+            icon="el-icon-document"
+            type="primary"
+            @click="toViewLog"
+            >修改记录</el-button
+          >
+          <el-button icon="el-icon-back" @click="cancel">返回</el-button>
         </div>
-        <div class="edit-cont-body">
-          <template v-if="question.quesOptions">
-            <div
-              v-for="(quesOption, optionIndex) in question.quesOptions"
-              :key="optionIndex"
-              class="paper-option"
-            >
-              <span>{{ optionIndex | optionOrderWordFilter }}. </span>
-              <rich-text :text-json="quesOption.optionBody"></rich-text>
+      </div>
+      <div class="edit-part" :key="question.id">
+        <div class="edit-cont">
+          <div class="edit-cont-title">
+            <rich-text :text-json="question.quesBody"></rich-text>
+          </div>
+          <div class="edit-cont-body">
+            <template v-if="question.quesOptions">
+              <div
+                v-for="(quesOption, optionIndex) in question.quesOptions"
+                :key="optionIndex"
+                class="paper-option"
+              >
+                <span>{{ optionIndex | optionOrderWordFilter }}. </span>
+                <rich-text :text-json="quesOption.optionBody"></rich-text>
+              </div>
+            </template>
+            <div v-if="!isNested(question.questionType)" class="paper-answer">
+              <span>答案:</span>
+              <question-answer :data="question"></question-answer>
             </div>
-          </template>
-          <div v-if="!isNested(question.questionType)" class="paper-answer">
-            <span>答案:</span>
-            <question-answer :data="question"></question-answer>
           </div>
-        </div>
-        <div
-          v-if="!isNested(question.questionType) && question.quesProperties"
-          class="edit-cont-props"
-          style="margin-top: 10px"
-        >
-          <el-tag
-            v-for="(content, propIndex) in question.quesProperties"
-            :key="propIndex"
-            type="primary"
-            effect="dark"
-            style="margin-right: 5px; margin-bottom: 5px"
+          <div
+            v-if="!isNested(question.questionType) && question.quesProperties"
+            class="edit-cont-props"
+            style="margin-top: 10px"
           >
-            <!-- {{ content.courseProperty && content.courseProperty.name }}
-            <span style="margin: 0 3px">/</span> -->
-            {{ content.firstProperty && content.firstProperty.name }}
-            <span
-              v-if="content.secondProperty && content.secondProperty.name"
-              style="margin: 0 3px"
-              >/</span
+            <el-tag
+              v-for="(content, propIndex) in question.quesProperties"
+              :key="propIndex"
+              type="primary"
+              effect="dark"
+              style="margin-right: 5px; margin-bottom: 5px"
             >
-            {{ content.secondProperty && content.secondProperty.name }}
-          </el-tag>
-        </div>
-        <div
-          v-if="isNested(question.questionType)"
-          class="edit-paper-question-subs"
-        >
+              <!-- {{ content.courseProperty && content.courseProperty.name }}
+              <span style="margin: 0 3px">/</span> -->
+              {{ content.firstProperty && content.firstProperty.name }}
+              <span
+                v-if="content.secondProperty && content.secondProperty.name"
+                style="margin: 0 3px"
+                >/</span
+              >
+              {{ content.secondProperty && content.secondProperty.name }}
+            </el-tag>
+          </div>
           <div
-            v-for="(subQuestion, subIndex) in question.subQuestions"
-            :key="subIndex"
-            class="edit-part"
+            v-if="isNested(question.questionType)"
+            class="edit-paper-question-subs"
           >
-            <div class="edit-cont">
-              <div class="edit-cont-title">
-                <span>{{ subIndex + 1 }}. </span>
-                <rich-text :text-json="subQuestion.quesBody"></rich-text>
-              </div>
-              <div class="edit-cont-body">
-                <template v-if="!isMatchingQuestion(question.questionType)">
-                  <div
-                    v-for="(
-                      subQuesOption, subOptIndex
-                    ) in subQuestion.quesOptions"
-                    :key="subOptIndex"
-                    class="paper-option"
-                  >
-                    <span>{{ subOptIndex | optionOrderWordFilter }}. </span>
-                    <rich-text
-                      :text-json="subQuesOption.optionBody"
-                    ></rich-text>
+            <div
+              v-for="(subQuestion, subIndex) in question.subQuestions"
+              :key="subIndex"
+              class="edit-part"
+            >
+              <div class="edit-cont">
+                <div class="edit-cont-title">
+                  <span>{{ subIndex + 1 }}. </span>
+                  <rich-text :text-json="subQuestion.quesBody"></rich-text>
+                </div>
+                <div class="edit-cont-body">
+                  <template v-if="!isMatchingQuestion(question.questionType)">
+                    <div
+                      v-for="(
+                        subQuesOption, subOptIndex
+                      ) in subQuestion.quesOptions"
+                      :key="subOptIndex"
+                      class="paper-option"
+                    >
+                      <span>{{ subOptIndex | optionOrderWordFilter }}. </span>
+                      <rich-text
+                        :text-json="subQuesOption.optionBody"
+                      ></rich-text>
+                    </div>
+                  </template>
+                  <div class="paper-answer">
+                    <span>答案:</span>
+                    <question-answer :data="subQuestion"></question-answer>
                   </div>
-                </template>
-                <div class="paper-answer">
-                  <span>答案:</span>
-                  <question-answer :data="subQuestion"></question-answer>
                 </div>
-              </div>
-              <div
-                v-if="subQuestion.quesProperties"
-                class="edit-cont-props"
-                style="margin-top: 10px"
-              >
-                <el-tag
-                  v-for="(content, propIndex) in subQuestion.quesProperties"
-                  :key="propIndex"
-                  type="primary"
-                  effect="dark"
-                  style="margin-right: 5px; margin-bottom: 5px"
+                <div
+                  v-if="subQuestion.quesProperties"
+                  class="edit-cont-props"
+                  style="margin-top: 10px"
                 >
-                  <!-- {{ content.courseProperty && content.courseProperty.name }}
-                  <span style="margin: 0 3px">/</span> -->
-                  {{ content.firstProperty && content.firstProperty.name }}
-                  <span
-                    v-if="content.secondProperty && content.secondProperty.name"
-                    style="margin: 0 3px"
-                    >/</span
+                  <el-tag
+                    v-for="(content, propIndex) in subQuestion.quesProperties"
+                    :key="propIndex"
+                    type="primary"
+                    effect="dark"
+                    style="margin-right: 5px; margin-bottom: 5px"
                   >
-                  {{ content.secondProperty && content.secondProperty.name }}
-                </el-tag>
+                    <!-- {{ content.courseProperty && content.courseProperty.name }}
+                    <span style="margin: 0 3px">/</span> -->
+                    {{ content.firstProperty && content.firstProperty.name }}
+                    <span
+                      v-if="
+                        content.secondProperty && content.secondProperty.name
+                      "
+                      style="margin: 0 3px"
+                      >/</span
+                    >
+                    {{ content.secondProperty && content.secondProperty.name }}
+                  </el-tag>
+                </div>
               </div>
             </div>
           </div>
         </div>
       </div>
-    </div>
 
-    <div class="box-justify" slot="footer">
-      <div>
+      <div class="text-center" slot="footer">
         <template v-if="showSwitch">
-          <el-button
-            icon="el-icon-caret-left"
-            :disabled="loading"
-            @click="toPrev"
-          ></el-button>
-          <el-button
-            icon="el-icon-caret-right"
-            :disabled="loading"
-            @click="toNext"
-          ></el-button>
+          <el-button type="primary" :disabled="loading" @click="toPrev"
+            >上一题</el-button
+          >
+          <el-button type="primary" :disabled="loading" @click="toNext"
+            >下一题</el-button
+          >
         </template>
+
+        <el-button v-if="showEdit" type="primary" @click="toEdit"
+          >编辑</el-button
+        >
       </div>
-      <el-button @click="cancel">关闭</el-button>
-    </div>
-  </el-dialog>
+    </el-dialog>
+
+    <!-- QuestionEditLogDialog -->
+    <question-edit-log-dialog
+      v-if="showLog"
+      ref="QuestionEditLogDialog"
+      :paper-id="this.question.id"
+    ></question-edit-log-dialog>
+  </div>
 </template>
 
 <script>
 import QuestionAnswer from "./QuestionAnswer.vue";
+import QuestionEditLogDialog from "./QuestionEditLogDialog.vue";
 
 export default {
   name: "QuestionPreviewDialog",
-  components: { QuestionAnswer },
+  components: { QuestionAnswer, QuestionEditLogDialog },
   props: {
     data: {
       type: Object,
       default: null,
     },
+    showEdit: {
+      type: Boolean,
+      default: false,
+    },
     showSwitch: {
       type: Boolean,
       default: false,
     },
+    showLog: {
+      type: Boolean,
+      default: false,
+    },
     listInfo: {
       type: Object,
       default: null,
@@ -190,6 +219,12 @@ export default {
     open() {
       this.modalIsShow = true;
     },
+    toEdit() {
+      this.$emit("on-edit", this.question);
+    },
+    toViewLog() {
+      this.$refs.QuestionEditLogDialog.open();
+    },
     isNested(questionType) {
       const nestedQuestion = [
         "PARAGRAPH_MATCHING",

+ 3 - 0
src/modules/question/views/QuestionManage.vue

@@ -317,6 +317,9 @@
       :list-info="listInfo"
       :fetchPage="toPage"
       show-switch
+      show-edit
+      show-log
+      @on-edit="toEditQuestion"
     ></question-preview-dialog>
     <!-- QuestionStatisticsDialog -->
     <question-statistics-dialog