浏览代码

禁答区新增

zhangjie 2 年之前
父节点
当前提交
6631b9ac0f

+ 46 - 72
card/assets/styles/card-preview.scss

@@ -61,51 +61,7 @@
 
     .page-main {
       &-inner {
-        padding: 60px 80px 86px;
-      }
-
-      &-1 {
-        .page-column-forbid-area {
-          &::before {
-            width: 2000px;
-            transform: rotate(34.326deg);
-          }
-          &::after {
-            width: 2000px;
-            transform: rotate(-34.326deg);
-          }
-        }
-      }
-      &-2 {
-        .page-column-forbid-area {
-          &::before {
-            transform: rotate(54.216deg);
-          }
-          &::after {
-            transform: rotate(-54.216deg);
-          }
-        }
-      }
-
-      &-3 {
-        .page-column-forbid-area {
-          &::before {
-            transform: rotate(64.6555deg);
-          }
-          &::after {
-            transform: rotate(-64.6555deg);
-          }
-        }
-      }
-      &-4 {
-        .page-column-forbid-area {
-          &::before {
-            transform: rotate(70.3109deg);
-          }
-          &::after {
-            transform: rotate(-70.3109deg);
-          }
-        }
+        padding: 60px 80px;
       }
     }
   }
@@ -115,29 +71,7 @@
 
     .page-main {
       &-inner {
-        padding: 60px 45px 86px;
-      }
-
-      &-1 {
-        .page-column-forbid-area {
-          &::before {
-            transform: rotate(54.216deg);
-          }
-          &::after {
-            transform: rotate(-54.216deg);
-          }
-        }
-      }
-
-      &-2 {
-        .page-column-forbid-area {
-          &::before {
-            transform: rotate(70.5109deg);
-          }
-          &::after {
-            transform: rotate(-70.5109deg);
-          }
-        }
+        padding: 60px 45px;
       }
     }
   }
@@ -322,10 +256,10 @@
   z-index: 8;
 
   &-top {
-    top: 40px;
+    top: 30px;
   }
   &-bottom {
-    bottom: 40px;
+    bottom: 30px;
   }
 
   &-item {
@@ -342,12 +276,31 @@
     }
   }
 }
+.page-box-1 {
+  .page-locator {
+    &-bottom {
+      .page-locator-item:nth-of-type(1) {
+        right: 0;
+        left: auto;
+      }
+    }
+    &-item {
+      &:nth-of-type(1) {
+        left: 96px;
+      }
+      &:nth-of-type(2) {
+        right: 0;
+      }
+    }
+  }
+}
 // page-number
 .page-number {
   position: absolute;
-  bottom: 40px;
+  bottom: 30px;
   &-rect {
-    left: 252px;
+    left: 25%;
+    transform: translateX(-50%);
   }
   &-rect-list {
     font-size: 0;
@@ -375,6 +328,11 @@
     line-height: 16px;
   }
 }
+.page-box-A4 {
+  .page-number-rect {
+    left: 50%;
+  }
+}
 
 // elem
 .elem {
@@ -1469,6 +1427,22 @@
     }
   }
 }
+// elem-forbid-area
+.elem-forbid-area {
+  height: 100%;
+  position: relative;
+
+  .text-body {
+    position: absolute;
+    width: 100%;
+    left: 0;
+    top: 50%;
+    transform: translateY(-50%);
+
+    font-size: 30px;
+    text-align: center;
+  }
+}
 
 // card-free-preview
 .card-free-preview {

+ 29 - 5
card/components/CardDesign.vue

@@ -28,10 +28,15 @@
         <div class="action-part-title"><h2>试题配置</h2></div>
         <div class="action-part-body">
           <div class="type-list">
+            <div class="type-item" v-for="item in TOPIC_LIST" :key="item.type">
+              <el-button @click="addNewTopic(item)"
+                ><i class="el-icon-plus"></i>{{ item.name }}</el-button
+              >
+            </div>
             <div
               class="type-item"
-              v-for="(item, index) in TOPIC_LIST"
-              :key="index"
+              v-for="item in NOT_TOPIC_LIST"
+              :key="item.type"
             >
               <el-button @click="addNewTopic(item)"
                 ><i class="el-icon-plus"></i>{{ item.name }}</el-button
@@ -255,6 +260,8 @@ import {
   getCardHeadModel,
   ELEMENT_LIST,
   TOPIC_LIST,
+  NOT_TOPIC_LIST,
+  OTHER_ELEMENT,
 } from "../elementModel";
 import { CARD_VERSION } from "../enumerate";
 // import CardConfigPropEdit from "../components/CardConfigPropEdit";
@@ -302,6 +309,7 @@ export default {
     return {
       ELEMENT_LIST,
       TOPIC_LIST,
+      NOT_TOPIC_LIST,
       topicList: [],
       steps: ["添加标题", "基本设置", "试题配置", "预览生成"],
       columnWidth: 0,
@@ -350,6 +358,7 @@ export default {
       "modifyElement",
       "rebuildPages",
       "initTopicsFromPages",
+      "scrollToElementPage",
     ]),
     async initCard() {
       const { cardConfig, pages, paperParams } = this.content;
@@ -383,9 +392,24 @@ export default {
       let element = getElementModel(item.type);
       element.w = document.getElementById("topic-column").offsetWidth;
 
-      this.setCurElement(element);
-      this.$refs.ElementPropEdit.open();
-      // to elementPropEdit/ElementPropEdit open topic edit dialog
+      if (item.type === "FORBID_AREA") {
+        const lastTopicElement = this.topics.findLast(
+          (item) => !OTHER_ELEMENT.includes(item.type)
+        );
+        element.sign = lastTopicElement.sign;
+        this.addElement(element);
+        this.setCurElement(element);
+        this.$nextTick(() => {
+          this.rebuildPages();
+          this.$nextTick(() => {
+            this.scrollToElementPage(element);
+          });
+        });
+      } else {
+        this.setCurElement(element);
+        this.$refs.ElementPropEdit.open();
+        // to elementPropEdit/ElementPropEdit open topic edit dialog
+      }
     },
     insetNewTopic({ id, type }) {
       console.log(id, type);

+ 47 - 12
card/components/RightClickMenu.vue

@@ -8,14 +8,16 @@
       v-if="visible"
     >
       <ul>
-        <li @click="toEdit">
-          <i class="el-icon-edit-outline"></i>
-          {{ IS_CONTAINER_ELEMENT ? "编辑元素" : "编辑大题" }}
-        </li>
-        <li class="li-danger" @click="toDelete">
-          <i class="el-icon-delete"></i>
-          {{ IS_CONTAINER_ELEMENT ? "删除元素" : "删除大题" }}
-        </li>
+        <template v-if="!IS_NOT_TOPIC">
+          <li @click="toEdit">
+            <i class="el-icon-edit-outline"></i>
+            {{ IS_CONTAINER_ELEMENT ? "编辑元素" : "编辑大题" }}
+          </li>
+          <li class="li-danger" @click="toDelete">
+            <i class="el-icon-delete"></i>
+            {{ IS_CONTAINER_ELEMENT ? "删除元素" : "删除大题" }}
+          </li>
+        </template>
         <li
           v-if="IS_CONTAINER_ELEMENT && (IS_EXPLAIN || IS_COMPOSITION)"
           @click="toCopyExplainElement"
@@ -46,9 +48,15 @@
         <li v-if="CAN_MOVE_DOWN" @click="toMoveDownTopic">
           <i class="el-icon-download"></i> 下移大题
         </li>
-        <li v-if="!IS_CONTAINER_ELEMENT" @click="toInsetTopic">
+        <li v-if="!IS_CONTAINER_ELEMENT && !IS_NOT_TOPIC" @click="toInsetTopic">
           <i class="el-icon-add-location"></i> 插入大题
         </li>
+        <li @click="toInsertForbidAnswer">
+          <i class="el-icon-crop"></i> 插入禁答区
+        </li>
+        <li v-if="IS_NOT_TOPIC" class="li-danger" @click="toDelete">
+          <i class="el-icon-delete"></i> 删除禁答区
+        </li>
       </ul>
     </div>
   </div>
@@ -59,6 +67,7 @@ import { mapState, mapMutations, mapActions } from "vuex";
 import { deepCopy } from "../plugins/utils";
 import { fetchSameSerialNumberChildrenPositionInfo } from "../store/card";
 import Clickoutside from "element-ui/src/utils/clickoutside";
+import { getElementModel, EDITABLE_NOT_TOPIC } from "../elementModel";
 
 export default {
   name: "right-click-menu",
@@ -94,7 +103,7 @@ export default {
       );
     },
     CAN_MOVE_UP() {
-      if (this.IS_CONTAINER_ELEMENT) return false;
+      if (this.IS_CONTAINER_ELEMENT || this.IS_NOT_TOPIC) return false;
 
       const curTopicPos = this.topicSeries.findIndex(
         (item) => item.id === this.curElement.parent.id
@@ -107,7 +116,7 @@ export default {
       );
     },
     CAN_MOVE_DOWN() {
-      if (this.IS_CONTAINER_ELEMENT) return false;
+      if (this.IS_CONTAINER_ELEMENT || this.IS_NOT_TOPIC) return false;
 
       const curTopicPos = this.topicSeries.findIndex(
         (item) => item.id === this.curElement.parent.id
@@ -119,6 +128,9 @@ export default {
           this.topicSeries[curTopicPos].sign
       );
     },
+    IS_NOT_TOPIC() {
+      return EDITABLE_NOT_TOPIC.includes(this.curElement.type);
+    },
   },
   mounted() {
     this.init();
@@ -134,6 +146,8 @@ export default {
       "copyExplainChildren",
       "deleteExplainChildren",
       "topicMoveUp",
+      "addForbidArea",
+      "scrollToElementPage",
     ]),
     init() {
       // 注册自定义右键事件菜单
@@ -226,7 +240,14 @@ export default {
     },
     toDelete() {
       this.close();
-      this.$confirm("确定要删除当前元素吗?", "提示", {
+
+      if (this.IS_NOT_TOPIC) {
+        this.removeSelectElement();
+        return;
+      }
+
+      const name = this.IS_CONTAINER_ELEMENT ? "元素" : "大题";
+      this.$confirm(`确定要删除当前${name}吗?`, "提示", {
         type: "warning",
       })
         .then(() => {
@@ -295,6 +316,20 @@ export default {
         type: this.curElement.type,
       });
     },
+    toInsertForbidAnswer() {
+      this.close();
+      let element = getElementModel("FORBID_AREA");
+      element.w = document.getElementById("topic-column").offsetWidth;
+      element.sign = this.curElement.sign;
+      this.addForbidArea({ element, beforeElementId: this.curElement.id });
+
+      this.$nextTick(() => {
+        this.rebuildPages();
+        this.$nextTick(() => {
+          this.scrollToElementPage(element);
+        });
+      });
+    },
     toRebuildPages() {
       this.$nextTick(() => {
         this.rebuildPages();

+ 2 - 0
card/components/TopicElementEdit.vue

@@ -44,6 +44,7 @@ import EditFillQuestion from "../elements/fill-question/ElemFillQuestion";
 import EditFillLine from "../elements/fill-line/ElemFillLine";
 import EditExplain from "../elements/explain/ElemExplainEdit";
 import EditComposition from "../elements/composition/ElemCompositionEdit";
+import EditForbidArea from "../elements/forbid-area/ElemForbidArea.vue";
 import EditTopicHead from "../elements/topic-head/TopicHead";
 import ElementResize from "./common/ElementResize";
 import TopicNumber from "./common/TopicNumber";
@@ -56,6 +57,7 @@ export default {
     EditFillQuestion,
     EditFillLine,
     EditExplain,
+    EditForbidArea,
     EditComposition,
     ElementResize,
     TopicNumber,

+ 2 - 0
card/components/TopicElementPreview.vue

@@ -17,6 +17,7 @@ import PreviewExplain from "../elements/explain/ElemExplain";
 import PreviewComposition from "../elements/composition/ElemComposition";
 import PreviewFillQuestion from "../elements/fill-question/ElemFillQuestion";
 import PreviewFillLine from "../elements/fill-line/ElemFillLine";
+import PreviewForbidArea from "../elements/forbid-area/ElemForbidArea.vue";
 import PreviewTopicHead from "../elements/topic-head/TopicHead";
 
 export default {
@@ -28,6 +29,7 @@ export default {
     PreviewFillLine,
     PreviewExplain,
     PreviewComposition,
+    PreviewForbidArea,
   },
   props: {
     data: {

+ 19 - 0
card/elementModel.js

@@ -24,6 +24,7 @@ import {
   getModel as createExplain,
   getFullModel as getExplainElements,
 } from "./elements/explain/model";
+import { getModel as createForbidArea } from "./elements/forbid-area/model";
 
 // page relate ------------------- >
 // 页面
@@ -65,8 +66,12 @@ const EDITABLE_ELEMENT = [
   "GRIDS",
 ];
 
+const OTHER_ELEMENT = ["TOPIC_HEAD", "CARD_HEAD"];
+
 const EDITABLE_TOPIC = ["FILL_QUESTION", "FILL_LINE", "EXPLAIN", "COMPOSITION"];
 
+const EDITABLE_NOT_TOPIC = ["FORBID_AREA"];
+
 const ELEMENT_INFOS = {
   LINES: {
     name: "多横线",
@@ -108,6 +113,10 @@ const ELEMENT_INFOS = {
     name: "作文题",
     getModel: createComposition,
   },
+  FORBID_AREA: {
+    name: "禁答区",
+    getModel: createForbidArea,
+  },
 };
 
 const ELEMENT_LIST = EDITABLE_ELEMENT.map((type) => {
@@ -123,6 +132,12 @@ const TOPIC_LIST = EDITABLE_TOPIC.map((type) => {
     type,
   };
 });
+const NOT_TOPIC_LIST = EDITABLE_NOT_TOPIC.map((type) => {
+  return {
+    ...ELEMENT_INFOS[type],
+    type,
+  };
+});
 
 // 获取元件默认数据结构
 const getElementModel = (type) => {
@@ -184,4 +199,8 @@ export {
   getCompositionElements,
   ELEMENT_LIST,
   TOPIC_LIST,
+  NOT_TOPIC_LIST,
+  EDITABLE_TOPIC,
+  EDITABLE_NOT_TOPIC,
+  OTHER_ELEMENT,
 };

+ 63 - 0
card/elements/forbid-area/EditForbidArea.vue

@@ -0,0 +1,63 @@
+<template>
+  <div class="edit-text">
+    <el-form
+      ref="modalFormComp"
+      :model="modalForm"
+      :rules="rules"
+      :key="modalForm.id"
+      label-width="100px"
+    >
+      <el-form-item prop="content" label="内容:">
+        <el-input placeholder="请输入内容" v-model="modalForm.content">
+        </el-input>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+const initModalForm = {
+  id: "",
+  content: "",
+};
+
+export default {
+  name: "edit-forbid-area",
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+  },
+  data() {
+    return {
+      modalForm: { ...initModalForm },
+      isBold: false,
+      rules: {
+        content: [
+          {
+            required: true,
+            message: "请输入文本内容",
+            trigger: "change",
+          },
+        ],
+      },
+    };
+  },
+  mounted() {
+    this.initData(this.instance);
+  },
+  methods: {
+    initData(val) {
+      this.modalForm = { ...val };
+    },
+    async submit() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+      this.$emit("modified", this.modalForm);
+    },
+  },
+};
+</script>

+ 25 - 0
card/elements/forbid-area/ElemForbidArea.vue

@@ -0,0 +1,25 @@
+<template>
+  <div class="elem-forbid-area">
+    <div class="text-body">{{ contentStr }}</div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "elem-forbid-area",
+  props: {
+    data: {
+      type: Object,
+    },
+  },
+  computed: {
+    contentStr() {
+      return this.data.content || "该区域严禁作答";
+    },
+  },
+  data() {
+    return {};
+  },
+  methods: {},
+};
+</script>

+ 21 - 0
card/elements/forbid-area/model.js

@@ -0,0 +1,21 @@
+import { getElementId, randomCode } from "../../plugins/utils";
+
+const MODEL = {
+  type: "FORBID_AREA",
+  x: 0,
+  y: 0,
+  w: 200,
+  h: 200,
+  sign: "",
+  content: "",
+};
+
+const getModel = () => {
+  return {
+    id: getElementId(),
+    key: randomCode(),
+    ...MODEL,
+  };
+};
+
+export { MODEL, getModel };

+ 16 - 0
card/store/card.js

@@ -214,6 +214,9 @@ const createFunc = {
   COMPOSITION(element) {
     return [getCompositionElements(element)];
   },
+  FORBID_AREA(element) {
+    return [element];
+  },
 };
 
 const actions = {
@@ -327,6 +330,14 @@ const actions = {
 
     commit("setCurElement", element);
   },
+  addForbidArea({ state, commit }, { element, beforeElementId }) {
+    const beforeElementPos = fetchElementPositionInfos(
+      { id: beforeElementId },
+      state.topics
+    );
+    state.topics.splice(beforeElementPos + 1, 0, element);
+    commit("setCurElement", element);
+  },
   // 修改试题 --------------->
   modifyTopic({ state }, element) {
     // 单独编辑某个细分题
@@ -478,6 +489,11 @@ const actions = {
   },
   // 删除试题 --------------->
   removeElement({ state, commit, dispatch }, element) {
+    if (!element.parent) {
+      state.topics = state.topics.filter((item) => item.id !== element.id);
+      commit("setCurElement", {});
+      return;
+    }
     const positionInfos = fetchAllRelateParentElementPositionInfos(
       element.parent,
       state.topics