Bläddra i källkod

文件夹编辑移动修改

zhangjie 2 år sedan
förälder
incheckning
34f8d14311

+ 3 - 0
src/assets/styles/pages.scss

@@ -1112,6 +1112,9 @@
     &.is-active {
       background-color: mix(#fff, $--color-primary, 80%);
     }
+    &.is-drag-over {
+      background-color: $--color-primary;
+    }
   }
 
   .el-tree-node__content {

+ 97 - 27
src/modules/question/components/QuestionFolder.vue

@@ -1,17 +1,33 @@
 <template>
   <div class="question-folder">
     <div v-if="isEdit" class="folder-action box-justify margin-bottom-15">
-      <el-button
-        type="primary"
-        :disabled="curNodeData.level >= MAX_FOLDER_LEVEL"
-        @click="toAddFolder"
-        >新建文件夹</el-button
-      >
+      <div>
+        <el-button
+          type="primary"
+          size="small"
+          plain
+          icon="el-icon-circle-plus-outline"
+          :disabled="curNodeData.level >= MAX_FOLDER_LEVEL"
+          @click="toAddFolder"
+          >新建</el-button
+        >
+        <el-button
+          type="primary"
+          size="small"
+          icon="el-icon-edit"
+          plain
+          @click="toEditFolder"
+          >编辑</el-button
+        >
+      </div>
       <el-button
         type="danger"
+        size="small"
+        icon="el-icon-circle-close"
+        plain
         :disabled="curNodeData.level >= MAX_FOLDER_LEVEL"
         @click="toDeleteFolder"
-        >删除文件夹</el-button
+        >删除</el-button
       >
     </div>
 
@@ -25,12 +41,17 @@
       :draggable="isEdit"
       :allow-drop="allowDrop"
       :allow-drag="allowDrag"
+      @node-drag-enter="handleDragEnter"
+      @node-drag-leave="handleDragLeave"
       @node-drop="handleDrop"
       @node-click="nodeClick"
     >
       <span slot-scope="{ node, data }">
         <i class="icon icon-files-act node-icon"></i>
-        <span v-if="data.id === null" class="node-form">
+        <span
+          v-if="data.id === null || curEditClassifyId === data.id"
+          class="node-form"
+        >
           <el-form
             ref="modalFormComp"
             :model="modalForm"
@@ -51,9 +72,11 @@
                 type="primary"
                 icon="el-icon-check"
                 :disabled="loading"
-                @click="toCreateFolder"
+                @click="toModifyFolder"
               ></el-button>
+              <!-- 新增的时候可以删除临时文件 -->
               <el-button
+                v-if="!modalForm.id"
                 type="danger"
                 icon="el-icon-close"
                 :disabled="loading"
@@ -65,7 +88,13 @@
         </span>
         <span
           v-else
-          :class="['node-cont', { 'is-active': curNodeData.id === data.id }]"
+          :class="[
+            'node-cont',
+            {
+              'is-active': curNodeData.id === data.id,
+              'is-drag-over': dragOverClassifyId === data.id,
+            },
+          ]"
           >{{ data.name }}</span
         >
       </span>
@@ -74,7 +103,12 @@
 </template>
 
 <script>
-import { classifyTreeApi, updateClassifyApi, deleteClassifyApi } from "../api";
+import {
+  classifyTreeApi,
+  updateClassifyApi,
+  deleteClassifyApi,
+  moveClassifyApi,
+} from "../api";
 
 const initModalForm = {
   id: null,
@@ -111,6 +145,8 @@ export default {
       },
       curNodeData: {},
       loading: false,
+      dragOverClassifyId: null,
+      curEditClassifyId: null,
       modalForm: {
         ...initModalForm,
       },
@@ -138,6 +174,16 @@ export default {
     async getClassifyTree() {
       const res = await classifyTreeApi();
       this.classifyTree[0].children = res.data || [];
+
+      const findNode = (data, level) => {
+        level++;
+        data.forEach((item) => {
+          this.$set(item, "level", level);
+          if (item.children && item.children.length)
+            findNode(item.children, level);
+        });
+      };
+      findNode(this.classifyTree, -1);
     },
     nodeClick(data) {
       if (!data.id && data.id !== 0) {
@@ -156,22 +202,19 @@ export default {
     },
     findNodeById(id) {
       let curNode = null;
-      const findNode = (data, level) => {
+      const findNode = (data) => {
         if (curNode) return;
-        level++;
         data.forEach((item) => {
           if (curNode) return;
 
           if (item.id === id) {
             curNode = item;
-            curNode.level = level;
             return;
           }
-          if (item.children && item.children.length)
-            findNode(item.children, level);
+          if (item.children && item.children.length) findNode(item.children);
         });
       };
-      findNode(this.classifyTree, -1);
+      findNode(this.classifyTree);
 
       return curNode || {};
     },
@@ -213,7 +256,15 @@ export default {
       this.curNodeData.children.push(newChild);
       this.modalForm = { ...newChild };
     },
-    async toCreateFolder() {
+    toEditFolder() {
+      if (!this.curNodeData.id && this.curNodeData.id !== 0) {
+        this.$message.error("请先选择文件夹!");
+        return;
+      }
+      this.curEditClassifyId = this.curNodeData.id;
+      this.modalForm = { ...this.curNodeData };
+    },
+    async toModifyFolder() {
       const valid = await this.$refs.modalFormComp.validate().catch(() => {});
       if (!valid) return;
 
@@ -225,11 +276,17 @@ export default {
       this.loading = false;
       if (!res) return;
       this.$message.success("操作成功");
-      const newChild = this.curNodeData.children.find(
-        (item) => item.id === null
-      );
-      newChild.id = res.data;
-      newChild.name = this.modalForm.name;
+      this.curEditClassifyId = null;
+
+      if (this.modalForm.id) {
+        this.curNodeData.name = this.modalForm.name;
+      } else {
+        const newChild = this.curNodeData.children.find(
+          (item) => item.id === null
+        );
+        newChild.id = res.data;
+        newChild.name = this.modalForm.name;
+      }
     },
     toRemoveFolder(node, data) {
       const parent = node.parent;
@@ -256,10 +313,23 @@ export default {
       return this.curNodeData;
     },
     // drop
-    handleDrop(draggingNode, dropNode, dropType) {
-      console.log("draggingNode", draggingNode);
-      console.log("dropNode", dropNode);
-      console.log("dropType", dropType);
+    handleDragEnter(draggingNode, dropNode) {
+      this.dragOverClassifyId = dropNode.data.id;
+    },
+    handleDragLeave() {
+      this.dragOverClassifyId = null;
+    },
+    async handleDrop(draggingNode, dropNode, dropType) {
+      // console.log("draggingNode", draggingNode);
+      // console.log("dropNode", dropNode);
+      // console.log("dropType", dropType);
+      this.dragOverClassifyId = null;
+      const targetClassifyId =
+        dropType === "inner" ? dropNode.data.id : dropNode.data.parentId;
+      if (targetClassifyId === draggingNode.data.parentId) return;
+
+      await moveClassifyApi(draggingNode.data.id, targetClassifyId);
+      this.initData();
     },
     allowDrop(draggingNode, dropNode, type) {
       if (

+ 1 - 1
src/modules/question/components/QuestionInfoEdit.vue

@@ -97,7 +97,7 @@
           >
         </div>
       </el-form-item>
-      <el-form-item label="属性列表">
+      <el-form-item v-if="modalForm.quesProperties.length" label="属性列表">
         <el-tag
           v-for="content in modalForm.quesProperties"
           :key="content.key"

+ 1 - 0
src/modules/question/components/edit/FillBlankQuestion.vue

@@ -26,6 +26,7 @@
           <div class="option-body">
             <v-editor
               v-model="answer.body"
+              :enable-audio="false"
               @change="() => answerBodyChange(oindex)"
             ></v-editor>
           </div>

+ 16 - 4
src/modules/question/components/edit/NestedQuestion.vue

@@ -19,7 +19,7 @@
       <p>小题数:{{ modalForm.subQuestions.length }}</p>
     </div>
 
-    <el-collapse v-model="activeNames">
+    <el-collapse v-model="activeNames" style="margin-top: 10px">
       <el-collapse-item
         v-for="(subq, index) in modalForm.subQuestions"
         :key="subq.questionKey"
@@ -46,6 +46,7 @@
           :is="getStructTypeComp(subq.questionType)"
           ref="QuestionEditDetail"
           :question="subq"
+          :show-ques-body="!IS_CLOZE"
         ></component>
       </el-collapse-item>
     </el-collapse>
@@ -87,7 +88,7 @@
 </template>
 
 <script>
-import { isAnEmptyRichText } from "@/utils/utils";
+import { isAnEmptyRichText, checkRichTextHasAudio } from "@/utils/utils";
 import { randomCode } from "@/plugins/utils";
 import {
   getInitQuestionModel,
@@ -124,11 +125,14 @@ export default {
         quesBody: [
           {
             validator: (rule, value, callback) => {
-              if (!this.IS_CLOZE) return callback();
-
               if (!value || isAnEmptyRichText(value)) {
                 return callback(new Error(`请输入题干`));
               }
+
+              if (this.IS_LISTENING_QUESTION && !checkRichTextHasAudio(value)) {
+                return callback(new Error(`题干中需要包含音频`));
+              }
+
               callback();
             },
             trigger: "change",
@@ -202,6 +206,14 @@ export default {
       this.$refs.modalFormComp.validateField(`quesBody`, () => {});
     },
     async validate() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return Promise.reject();
+
+      if (!this.modalForm.subQuestions.length) {
+        this.$message.error("请录入小题");
+        return Promise.reject();
+      }
+
       let errorQuestionIndexs = [];
       for (let i = 0; i < this.$refs.QuestionEditDetail.length; i++) {
         const compInst = this.$refs.QuestionEditDetail[i];

+ 5 - 1
src/modules/question/components/edit/SelectQuestion.vue

@@ -6,7 +6,7 @@
       :rules="rules"
       label-width="100px"
     >
-      <el-form-item prop="quesBody" label="题干">
+      <el-form-item v-if="showQuesBody" prop="quesBody" label="题干">
         <v-editor
           v-model="modalForm.quesBody"
           @change="quesBodyChange"
@@ -120,6 +120,10 @@ export default {
         return {};
       },
     },
+    showQuesBody: {
+      type: Boolean,
+      default: true,
+    },
   },
   data() {
     return {

+ 5 - 1
src/modules/question/components/edit/TextAnswerQuestion.vue

@@ -13,7 +13,11 @@
         ></v-editor>
       </el-form-item>
       <el-form-item label="答案">
-        <v-editor v-model="quesAnswer" @change="answerChange"></v-editor>
+        <v-editor
+          v-model="quesAnswer"
+          :enable-audio="false"
+          @change="answerChange"
+        ></v-editor>
       </el-form-item>
       <el-form-item label="答案解析">
         <v-editor v-model="modalForm.comment"></v-editor>

+ 13 - 0
src/utils/utils.js

@@ -30,3 +30,16 @@ export function isAnEmptyRichText(cont) {
       .trim();
   }
 }
+
+/**
+ * 判断富文本是否包含音频
+ * @param  cont 富文本对象
+ * @returns Boolean
+ */
+export function checkRichTextHasAudio(cont) {
+  if (isAnEmptyRichText(cont)) return false;
+
+  return cont.sections.some((section) =>
+    section.blocks.some((block) => block.type === "audio")
+  );
+}