Sfoglia il codice sorgente

试题管理接口调试

zhangjie 2 anni fa
parent
commit
04b355ab24

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

@@ -811,47 +811,6 @@
   overflow-y: auto;
 }
 
-// folder-tree
-.folder-tree {
-  .node-icon {
-    margin-right: 8px;
-    width: 18px;
-    height: 14px;
-  }
-  .node-cont {
-    display: inline-block;
-    vertical-align: middle;
-    border-radius: 3px;
-    height: 26px;
-    line-height: 26px;
-    padding-left: 5px;
-    padding-right: 5px;
-    &.is-active {
-      background-color: mix(#fff, $--color-primary, 80%);
-    }
-  }
-
-  .el-tree-node__content {
-    color: $--color-text-primary;
-    height: auto;
-    min-height: 30px;
-    background-color: transparent !important;
-  }
-  .node-form {
-    display: inline-block;
-    vertical-align: middle;
-  }
-  .el-form-item {
-    margin-bottom: 0;
-  }
-  .el-input__inner {
-    width: 240px;
-  }
-  .el-button {
-    padding: 5px;
-    font-size: 14px;
-  }
-}
 .question-statistics-dialog {
   .el-dialog {
     .el-dialog__body {
@@ -1103,3 +1062,78 @@
     }
   }
 }
+
+// folder-question
+.folder-question-manage-dialog {
+  .el-dialog__body {
+    position: relative;
+    height: 100%;
+    overflow: hidden;
+  }
+}
+.folder-question {
+  height: 100%;
+  overflow: hidden;
+  display: flex;
+  justify-content: space-between;
+  align-items: stretch;
+
+  .folder-list {
+    width: 380px;
+    margin-right: 20px;
+    flex-grow: 0;
+    flex-shrink: 0;
+    padding: 15px;
+    background-color: #fff;
+    border-radius: 10px;
+    overflow-x: hidden;
+    overflow-y: auto;
+  }
+  .question-list {
+    flex-grow: 2;
+    padding: 15px;
+    background-color: #fff;
+    border-radius: 10px;
+    overflow-x: hidden;
+    overflow-y: auto;
+  }
+}
+// folder-tree
+.folder-tree {
+  .node-icon {
+    margin-right: 8px;
+    width: 18px;
+    height: 14px;
+  }
+  .node-cont {
+    display: inline-block;
+    vertical-align: middle;
+    border-radius: 3px;
+    height: 26px;
+    line-height: 26px;
+    padding-left: 5px;
+    padding-right: 5px;
+    &.is-active {
+      background-color: mix(#fff, $--color-primary, 80%);
+    }
+  }
+
+  .el-tree-node__content {
+    color: $--color-text-primary;
+    height: auto;
+    min-height: 30px;
+    background-color: transparent !important;
+  }
+  .node-form {
+    display: inline-block;
+    vertical-align: middle;
+  }
+  .el-form-item {
+    margin-bottom: 0;
+    margin-right: 6px;
+  }
+  .el-button {
+    padding: 5px;
+    font-size: 14px;
+  }
+}

+ 47 - 23
src/modules/question/api.js

@@ -24,15 +24,24 @@ export const propertyFirstQueryApi = (coursePropertyId) => {
 export const propertySecondQueryApi = (firstPropertyId) => {
   return $httpWithMsg.get(`${QUESTION_API}/property/second/${firstPropertyId}`);
 };
+export const propertyTreeQueryApi = (coursePropertyId) => {
+  return $httpWithMsg.get(`${QUESTION_API}/property/all/${coursePropertyId}`);
+};
 
 // question-manage
 export function questionPageListApi(data) {
   const url = `${QUESTION_API}/question/classify/find_classify_content`;
   return $httpWithMsg.post(url, {}, { params: data });
 }
-export function deleteQuestionApi(questionId) {
+export function classifyQuestionPageListApi(data) {
+  const url = `${QUESTION_API}/question/classify/find_current_classify_question_page`;
+  return $httpWithMsg.post(url, {}, { params: data });
+}
+export function deleteQuestionApi(idList) {
   return $httpWithMsg.post(
-    `${QUESTION_API}/paper/deleteQuestion/${questionId}`
+    `${QUESTION_API}/paper/delete`,
+    {},
+    { params: idList }
   );
 }
 export function moveQuestionApi(questionIdList, targetClassifyId) {
@@ -44,13 +53,17 @@ export function moveQuestionApi(questionIdList, targetClassifyId) {
     }
   );
 }
-export function copyQuestionApi(questionId) {
-  return $httpWithMsg.post(`${QUESTION_API}/paper/copyQuestion/`, {
-    params: { questionId },
-  });
+export function copyQuestionApi(questionIdList, targetClassifyId) {
+  return $httpWithMsg.post(
+    `${QUESTION_API}/question/copy`,
+    {},
+    {
+      params: { questionIdList, targetClassifyId },
+    }
+  );
 }
 export function importQuestionApi(data, headData) {
-  return $httpWithMsg.post(`${QUESTION_API}/paper/copyQuestion/`, data, {
+  return $httpWithMsg.post(`${QUESTION_API}/question/import`, data, {
     headers: headData,
   });
 }
@@ -61,22 +74,27 @@ export function updateQuestionApi(data) {
   // return Promise.resolve(data);
 }
 // statistics
-import distributionData from "./datas/distributionData.json";
+// import distributionData from "./datas/distributionData.json";
 export function questionDistributionStatisticsApi(courseId) {
-  // return $httpWithMsg.post(`${QUESTION_API}/question/statistic/distribution`, {
-  //   params: { courseId },
-  // });
-  return Promise.resolve({ data: distributionData, courseId });
+  return $httpWithMsg.post(
+    `${QUESTION_API}/question/statistic/distribution`,
+    {},
+    {
+      params: { courseId },
+    }
+  );
+  // return Promise.resolve({ data: distributionData, courseId });
 }
-import distributionPropData from "./datas/distributionPropData.json";
+// import distributionPropData from "./datas/distributionPropData.json";
 export function questionPropertyDistributionStatisticsApi(data) {
-  // return $httpWithMsg.post(
-  //   `${QUESTION_API}/question/statistic/property_distribution`,
-  //   {
-  //     params: data,
-  //   }
-  // );
-  return Promise.resolve({ data: distributionPropData, filter: data });
+  return $httpWithMsg.post(
+    `${QUESTION_API}/question/statistic/property_distribution`,
+    {},
+    {
+      params: data,
+    }
+  );
+  // return Promise.resolve({ data: distributionPropData, filter: data });
 }
 // classify-manage
 export function classifyListApi(parentId) {
@@ -95,9 +113,15 @@ export function updateClassifyApi(datas) {
   return $httpWithMsg.post(`${QUESTION_API}/question/classify/save`, datas);
 }
 export function deleteClassifyApi(questionClassifyIdList) {
-  return $httpWithMsg.post(`${QUESTION_API}/question/classify/dalete`, {
-    questionClassifyIdList,
-  });
+  return $httpWithMsg.post(
+    `${QUESTION_API}/question/classify/delete`,
+    {},
+    {
+      params: {
+        questionClassifyIdList,
+      },
+    }
+  );
 }
 export function moveClassifyApi(movedClassifyId, targetClassifyId) {
   return $httpWithMsg.post(

+ 43 - 48
src/modules/question/components/FolderQuestionManageDialog.vue

@@ -8,6 +8,7 @@
       :close-on-press-escape="false"
       append-to-body
       fullscreen
+      custom-class="folder-question-manage-dialog"
     >
       <div class="folder-question">
         <div class="folder-list">
@@ -17,7 +18,7 @@
             @selected="folderFilterSelected"
           ></question-folder>
         </div>
-        <div class="question-list part-box">
+        <div class="question-list">
           <el-form class="part-filter-form" :inline="true" :model="filter">
             <el-form-item label="课程名称">
               <course-select v-model="filter.courseId"> </course-select>
@@ -26,25 +27,11 @@
               <question-type-select v-model="filter.quesStructType">
               </question-type-select>
             </el-form-item>
-            <el-form-item label="属性">
-              <property-select
-                v-model="filter.coursePropertyId"
+            <el-form-item label="属性">
+              <property-tree-select
+                v-model="filter.propertyIdList"
                 :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>
@@ -54,13 +41,25 @@
 
           <div class="part-box-action">
             <div>
-              <el-button type="primary" plain @click="toBatchMove"
+              <el-button
+                type="primary"
+                plain
+                icon="el-icon-position"
+                @click="toBatchMove"
                 >移动</el-button
               >
-              <el-button type="danger" plain @click="toBatchCopy"
+              <el-button
+                type="primary"
+                plain
+                icon="el-icon-copy-document"
+                @click="toBatchCopy"
                 >复制</el-button
               >
-              <el-button type="danger" plain @click="toBatchDelete"
+              <el-button
+                type="danger"
+                plain
+                icon="el-icon-circle-close"
+                @click="toBatchDelete"
                 >删除</el-button
               >
             </div>
@@ -98,12 +97,11 @@
                 <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>
@@ -149,15 +147,6 @@
                           >删除</el-button
                         >
                       </el-dropdown-item>
-                      <el-dropdown-item>
-                        <el-button
-                          size="mini"
-                          type="primary"
-                          plain
-                          @click="toLinkQuestion(scope.row)"
-                          >关联属性</el-button
-                        >
-                      </el-dropdown-item>
                     </el-dropdown-menu>
                   </el-dropdown>
                 </div>
@@ -203,7 +192,7 @@
 
 <script>
 import {
-  questionPageListApi,
+  classifyQuestionPageListApi,
   deleteQuestionApi,
   moveQuestionApi,
   copyQuestionApi,
@@ -212,6 +201,7 @@ import QuestionFolder from "./QuestionFolder.vue";
 import QuestionEditDialog from "./QuestionEditDialog.vue";
 import QuestionPreviewDialog from "./QuestionPreviewDialog.vue";
 import QuestionFolderDialog from "./QuestionFolderDialog.vue";
+import PropertyTreeSelect from "../components/PropertyTreeSelect.vue";
 
 export default {
   name: "FolderQuestionManageDialog",
@@ -220,6 +210,7 @@ export default {
     QuestionEditDialog,
     QuestionPreviewDialog,
     QuestionFolderDialog,
+    PropertyTreeSelect,
   },
   data() {
     return {
@@ -228,9 +219,7 @@ export default {
         classifyId: null,
         courseId: "",
         quesStructType: "",
-        coursePropertyId: "",
-        firstPropertyId: "",
-        secondPropertyId: "",
+        propertyIdList: [],
       },
       questionList: [],
       currentPage: 1,
@@ -258,11 +247,13 @@ export default {
     async getList() {
       this.selectedQuestionIds = [];
       this.loading = true;
-      const res = await questionPageListApi({
+      let data = {
         ...this.filter,
         curPage: this.currentPage,
         pageSize: this.pageSize,
-      }).catch(() => {});
+      };
+      data.propertyIdList = data.propertyIdList.join();
+      const res = await classifyQuestionPageListApi(data).catch(() => {});
       this.loading = false;
       if (!res) return;
       this.questionList = res.data.content;
@@ -296,8 +287,14 @@ export default {
       this.$refs.QuestionFolderDialog.open();
     },
     async moveQuestion(folder) {
+      if (folder.id === this.curFolder.id) {
+        this.$message.error("内容就在当前当前文件中");
+        return;
+      }
       let res = null;
-      res = await moveQuestionApi(this.curMoveQids, folder.id).catch(() => {});
+      res = await moveQuestionApi(this.curMoveQids.join(), folder.id).catch(
+        () => {}
+      );
 
       if (!res) return;
       this.$message.success("操作成功!");
@@ -319,7 +316,7 @@ export default {
     },
     async deleteQuestion(ids) {
       this.loading = true;
-      const res = await deleteQuestionApi(ids).catch((error) => {
+      const res = await deleteQuestionApi(ids.join()).catch((error) => {
         this.$notify({
           message: error.response.data.desc,
           type: "error",
@@ -340,6 +337,7 @@ export default {
         return;
       }
       this.curMoveQids = [...this.selectedQuestionIds];
+      this.$refs.QuestionFolderDialog.open();
     },
     toBatchCopy() {
       if (!this.selectedQuestionIds.length) {
@@ -361,9 +359,6 @@ export default {
 
       this.deleteQuestion(this.selectedQuestionIds);
     },
-    toLinkQuestion(row) {
-      console.log(row);
-    },
     toAddFolder() {
       this.curFolder = { parentId: this.filter.classifyId };
       this.$refs.ModifyFolder.open();

+ 218 - 0
src/modules/question/components/PropertyTreeSelect.vue

@@ -0,0 +1,218 @@
+<template>
+  <div
+    class="property-tree-select el-select el-select--medium"
+    @click="switchOpen"
+  >
+    <div
+      :class="[
+        'el-input el-input--medium el-input--suffix',
+        { 'is-focus': isFocus },
+      ]"
+      @mouseenter="inputHovering = true"
+      @mouseleave="inputHovering = false"
+    >
+      <input
+        ref="inputRef"
+        type="text"
+        autocomplete="off"
+        :placeholder="placeholder"
+        class="el-input__inner"
+        :value="selectedPropName"
+        readonly
+      />
+      <span class="el-input__suffix">
+        <span class="el-input__suffix-inner">
+          <i
+            v-show="!showClose"
+            :class="[
+              'el-select__caret',
+              'el-input__icon',
+              'el-icon-arrow-up',
+              { 'is-reverse': visible },
+            ]"
+          ></i>
+          <i
+            v-if="showClose"
+            class="el-select__caret el-input__icon el-icon-circle-close"
+            @click="handleClearClick"
+          ></i>
+        </span>
+      </span>
+    </div>
+
+    <el-popover
+      v-model="visible"
+      popper-class="property-popover"
+      placement="bottom"
+      trigger="manual"
+    >
+      <div ref="popoverRef" slot="reference"></div>
+      <div v-clickoutside="handleClose" class="property-popover-tree">
+        <el-tree
+          ref="PropertyTree"
+          :data="proptree"
+          default-expand-all
+          show-checkbox
+          node-key="id"
+          :props="defaultProps"
+          :check-strictly="true"
+          check-on-click-node
+          :expand-on-click-node="false"
+          @check-change="checkChange"
+        >
+          <span slot-scope="{ data }" :class="['custom-tree-node']">
+            <span v-if="!data.code">{{ data.name }}</span>
+            <span v-else>[{{ data.code }}]{{ data.name }}</span>
+          </span>
+        </el-tree>
+      </div>
+    </el-popover>
+  </div>
+</template>
+
+<script>
+import { propertyTreeQueryApi, propertyNameQueryApi } from "../api";
+import Clickoutside from "element-ui/src/utils/clickoutside";
+
+export default {
+  name: "PropertyTreeSelect",
+  directives: { Clickoutside },
+  props: {
+    value: {
+      type: [Array, String],
+      default: "",
+    },
+    placeholder: { type: String, default: "请选择" },
+    multiple: {
+      type: Boolean,
+      default: false,
+    },
+    disabled: {
+      type: Boolean,
+      default: false,
+    },
+    clearable: {
+      type: Boolean,
+      default: true,
+    },
+    courseId: {
+      type: [String, Number],
+      default: "",
+    },
+  },
+  data() {
+    return {
+      selectedPropName: "",
+      selectedPropList: [],
+      selectedPropIds: [],
+      visible: false,
+      isFocus: false,
+      inputHovering: false,
+      proptree: [],
+      defaultProps: {
+        children: "propertyList",
+        disabled: "disabled",
+      },
+    };
+  },
+  computed: {
+    showClose() {
+      let hasValue = this.multiple
+        ? Array.isArray(this.value) && this.value.length > 0
+        : this.value !== undefined && this.value !== null && this.value !== "";
+      let criteria = this.clearable && this.inputHovering && hasValue;
+      return criteria;
+    },
+  },
+  watch: {
+    value(val, oldval) {
+      if (val !== oldval) this.initSelected(val);
+    },
+    courseId(val, oldval) {
+      if (val !== oldval) {
+        this.resetData();
+        this.emitChange();
+        this.getList();
+      }
+    },
+  },
+  methods: {
+    resetData() {
+      this.selectedPropName = "";
+      this.selectedPropList = [];
+      this.selectedPropIds = [];
+      this.visible = false;
+      this.isFocus = false;
+      this.inputHovering = false;
+      this.proptree = [];
+    },
+    async getList() {
+      if (!this.courseId) return;
+      const res = await propertyNameQueryApi(this.courseId);
+      let propList = res.data || [];
+      const fetchAll = propList.map((item) => propertyTreeQueryApi(item.id));
+      const datas = await Promise.all(fetchAll).catch(() => {});
+      if (!datas) return;
+
+      this.proptree = propList.map((item, index) => {
+        let nitem = { ...item, disabled: true };
+        nitem.propertyList = datas[index].data;
+        return nitem;
+      });
+      if (this.value) this.initSelected(this.value);
+    },
+    switchOpen() {
+      if (this.visible) {
+        this.handleClose();
+      } else {
+        this.handleOpen();
+      }
+    },
+    handleOpen() {
+      this.isFocus = true;
+      setTimeout(() => {
+        this.visible = true;
+      }, 100);
+    },
+    handleClose() {
+      this.visible = false;
+      this.isFocus = false;
+    },
+    initSelected(val) {
+      this.$refs.PropertyTree.setCheckedKeys(val);
+    },
+    handleClearClick(event) {
+      event.stopPropagation();
+      this.$refs.PropertyTree.setCheckedKeys([]);
+      this.selectedPropName = "";
+      this.emitChange();
+      this.handleClose();
+    },
+    checkChange() {
+      const nodes = this.$refs.PropertyTree.getCheckedNodes(true);
+      this.selectedPropName = nodes.map((item) => item.name).join(";");
+      this.emitChange();
+    },
+    emitChange() {
+      this.selectedPropIds = this.$refs.PropertyTree.getCheckedKeys();
+      this.$emit("input", this.selectedPropIds);
+      this.$emit("change", this.selectedPropIds);
+    },
+  },
+};
+</script>
+
+<style lang="scss">
+.property-popover {
+  &.el-popover {
+    width: 300px;
+    padding: 0;
+  }
+
+  &-tree {
+    max-height: 300px;
+    overflow: auto;
+    padding: 10px;
+  }
+}
+</style>

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

@@ -1,20 +1,18 @@
 <template>
   <div class="question-folder">
-    <div class="folder-action box-justify">
-      <div v-if="isEdit">
-        <el-button
-          type="primary"
-          :disabled="curNodeData.level >= MAX_FOLDER_LEVEL"
-          @click="toAddFolder"
-          >新建文件夹</el-button
-        >
-        <el-button
-          type="danger"
-          :disabled="curNodeData.level >= MAX_FOLDER_LEVEL"
-          @click="toDeleteFolder"
-          >删除文件夹</el-button
-        >
-      </div>
+    <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
+      >
+      <el-button
+        type="danger"
+        :disabled="curNodeData.level >= MAX_FOLDER_LEVEL"
+        @click="toDeleteFolder"
+        >删除文件夹</el-button
+      >
     </div>
 
     <el-tree
@@ -55,6 +53,7 @@
                 type="danger"
                 icon="el-icon-close"
                 :disabled="loading"
+                style="margin-left: 6px"
                 @click="toRemoveFolder(node, data)"
               ></el-button>
             </el-form-item>
@@ -63,7 +62,7 @@
         <span
           v-else
           :class="['node-cont', { 'is-active': curNodeData.id === data.id }]"
-          >{{ node.label }}</span
+          >{{ data.name }}</span
         >
       </span>
     </el-tree>
@@ -81,12 +80,16 @@ const initModalForm = {
 };
 
 export default {
-  name: "QuestionFolderDialog",
+  name: "QuestionFolder",
   props: {
     isEdit: {
       type: Boolean,
       default: true,
     },
+    folderId: {
+      type: [Number, String],
+      default: "",
+    },
   },
   data() {
     return {
@@ -100,7 +103,7 @@ export default {
         },
       ],
       defaultProps: {
-        label: "questionClassifyName",
+        label: "name",
       },
       curNodeData: {},
       loading: false,
@@ -164,7 +167,7 @@ export default {
             findNode(item.children, level);
         });
       };
-      findNode(this.classifyTree, 0);
+      findNode(this.classifyTree, -1);
 
       return curNode || {};
     },
@@ -180,7 +183,7 @@ export default {
       this.classifyTree = removePreNewChild(this.classifyTree);
     },
     toAddFolder() {
-      if (!this.curNodeData.id) {
+      if (!this.curNodeData.id && this.curNodeData.id !== 0) {
         this.$message.error("请先选择文件夹!");
         return;
       }
@@ -218,8 +221,11 @@ export default {
       this.loading = false;
       if (!res) return;
       this.$message.success("操作成功");
-      const newChild = this.curNodeData.find((item) => item.id === null);
+      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;

+ 1 - 0
src/modules/question/components/QuestionFolderDialog.vue

@@ -66,6 +66,7 @@ export default {
         return;
       }
       this.$emit("selected", this.curNodeData);
+      this.cancel();
     },
   },
 };

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

@@ -184,11 +184,11 @@ export default {
     },
     async getBlueData() {
       const res = await questionPropertyDistributionStatisticsApi(this.filter);
-      // console.log(res.data);
 
       this.blueDataList = res.data.map((mainGroup) => {
         let dataList = [];
         mainGroup.distributeInfo.forEach((item) => {
+          if (!item.children || !item.children.length) return;
           const rowspan = item.children.length;
           item.children.forEach((elem, index) => {
             let nelem = {

+ 22 - 57
src/modules/question/views/QuestionManage.vue

@@ -16,25 +16,11 @@
         <el-form-item label="题目内容">
           <el-input v-model="filter.content" 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.propertyIdList"
             :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>
@@ -90,11 +76,6 @@
         element-loading-text="加载中"
         :data="questionList"
       >
-        <el-table-column
-          type="selection"
-          width="50"
-          align="center"
-        ></el-table-column>
         <el-table-column label="题干">
           <template slot-scope="scope">
             <rich-text
@@ -165,15 +146,6 @@
                       >删除</el-button
                     >
                   </el-dropdown-item>
-                  <el-dropdown-item>
-                    <el-button
-                      size="mini"
-                      type="primary"
-                      plain
-                      @click="toLinkQuestion(scope.row)"
-                      >关联属性</el-button
-                    >
-                  </el-dropdown-item>
                 </el-dropdown-menu>
               </el-dropdown>
             </div>
@@ -218,7 +190,7 @@
     <!-- QuestionFolderDialog -->
     <question-folder-dialog
       ref="QuestionFolderDialog"
-      :is-edit="isEditFolder"
+      :is-edit="false"
       @selected="folderSelected"
     ></question-folder-dialog>
     <!-- QuestionImportDialog -->
@@ -238,7 +210,6 @@ import {
   questionPageListApi,
   deleteQuestionApi,
   moveQuestionApi,
-  moveClassifyApi,
   copyQuestionApi,
 } from "../api";
 import QuestionStatisticsDialog from "../components/QuestionStatisticsDialog.vue";
@@ -248,6 +219,7 @@ import QuestionImportDialog from "../components/QuestionImportDialog.vue";
 import QuestionEditDialog from "../components/QuestionEditDialog.vue";
 import QuestionPreviewDialog from "../components/QuestionPreviewDialog.vue";
 import FolderQuestionManageDialog from "../components/FolderQuestionManageDialog.vue";
+import PropertyTreeSelect from "../components/PropertyTreeSelect.vue";
 
 export default {
   name: "QuestionMamage",
@@ -259,6 +231,7 @@ export default {
     QuestionEditDialog,
     QuestionPreviewDialog,
     FolderQuestionManageDialog,
+    PropertyTreeSelect,
   },
   data() {
     return {
@@ -267,17 +240,15 @@ export default {
         courseId: "",
         quesStructType: "",
         content: "",
-        coursePropertyId: "",
-        firstPropertyId: "",
-        secondPropertyId: "",
+        propertyIdList: [],
       },
+      curFolderAction: "",
       folderList: [],
       questionList: [],
       currentPage: 1,
       pageSize: 10,
       total: 0,
       loading: false,
-      isEditFolder: true,
       curQuestion: {},
       curFolder: {},
       curCourse: {},
@@ -294,11 +265,13 @@ export default {
     },
     async getList() {
       this.loading = true;
-      const res = await questionPageListApi({
+      let data = {
         ...this.filter,
         curPage: this.currentPage,
         pageSize: this.pageSize,
-      }).catch(() => {});
+      };
+      data.propertyIdList = data.propertyIdList.join();
+      const res = await questionPageListApi(data).catch(() => {});
       this.loading = false;
       if (!res) return;
       this.questionList = res.data.questionPageResult.content;
@@ -337,40 +310,35 @@ export default {
       this.$refs.QuestionImportDialog.open();
     },
     toViewQuestion(row) {
-      console.log(row);
       this.curQuestion = row;
       this.$refs.QuestionPreviewDialog.open();
     },
     toEditQuestion(row) {
-      console.log(row);
-      // todo:编辑试题
       this.curQuestion = row;
       this.$refs.QuestionEditDialog.open();
     },
     toMoveQuestion(row) {
-      this.isEditFolder = false;
-      this.curMoveType = "question";
       this.curQuestion = row;
+      this.curFolderAction = "move";
+      this.$refs.QuestionFolderDialog.open();
+    },
+    toCopyQuestion(row) {
+      this.curQuestion = row;
+      this.curFolderAction = "copy";
       this.$refs.QuestionFolderDialog.open();
     },
     async folderSelected(folder) {
       let res = null;
-      if (this.curMoveType === "question") {
+      if (this.curFolderAction === "move") {
         res = await moveQuestionApi(this.curQuestion.id, folder.id).catch(
           () => {}
         );
       } else {
-        res = await moveClassifyApi(this.curFolder.id, folder.id).catch(
+        res = await copyQuestionApi(this.curQuestion.id, folder.id).catch(
           () => {}
         );
       }
-      if (!res) return;
-      this.$message.success("操作成功!");
-      this.getList();
-    },
-    async toCopyQuestion(row) {
-      console.log(row);
-      const res = await copyQuestionApi(row.id).catch(() => {});
+
       if (!res) return;
       this.$message.success("操作成功!");
       this.getList();
@@ -397,9 +365,6 @@ export default {
       });
       this.getList();
     },
-    toLinkQuestion(row) {
-      console.log(row);
-    },
     toRecycle() {
       this.$router.push({
         name: "QuestionRecycle",