zhangjie il y a 2 ans
Parent
commit
b3465d9bd7

+ 16 - 0
src/modules/paper-export/api.js

@@ -5,3 +5,19 @@ import { QUESTION_API } from "@/constants/constants.js";
 export const paperTemplateListApi = (datas) => {
   return $httpWithMsg.post(`${QUESTION_API}/paper/template/page`, datas);
 };
+export const paperTemplateDetailApi = (tid) => {
+  return $httpWithMsg.post(
+    `${QUESTION_API}/paper/template/page`,
+    {},
+    {
+      params: { id: tid },
+    }
+  );
+};
+
+export const savePaperTemplateApi = (datas) => {
+  return $httpWithMsg.post(
+    QUESTION_API + "/paper/template/save/structure",
+    datas
+  );
+};

+ 25 - 32
src/modules/paper-export/components/ElementPropEdit.vue

@@ -9,20 +9,17 @@
     :close-on-press-escape="false"
     :before-close="cancel"
     append-to-body
-    destroy-on-close
   >
     <component
       :is="curEditComponent"
-      ref="ElementPropEditComp"
+      ref="ComponentForm"
       :key="curElement.id"
       :instance="curElement"
       @modified="modified"
     ></component>
 
     <div slot="footer">
-      <el-button type="primary" :disabled="loading" @click="submit"
-        >确认</el-button
-      >
+      <el-button type="primary" @click="submit">确认</el-button>
       <el-button @click="cancel">取消</el-button>
     </div>
   </el-dialog>
@@ -31,34 +28,38 @@
 <script>
 import { mapState, mapMutations, mapActions } from "vuex";
 import { getElementName } from "../elementModel";
-import EditComposition from "../elements/composition/EditComposition";
-import EditExplain from "../elements/explain/EditExplain";
-import EditFillLine from "../elements/fill-line/EditFillLine";
-import EditFillQuestion from "../elements/fill-question/EditFillQuestion";
-import EditText from "../elements/text/EditText";
-import EditImage from "../elements/image/EditImage";
-import EditLine from "../elements/line/EditLine";
-import EditLines from "../elements/lines/EditLines";
-import EditGrids from "../elements/grids/EditGrids";
+import EditText from "../../card/elements/text/EditText";
+import EditImage from "../../card/elements/image/EditImage";
+import EditLine from "../../card/elements/line/EditLine";
+import EditLines from "../../card/elements/lines/EditLines";
+import EditGrids from "../../card/elements/grids/EditGrids";
+import EditPane from "../../card/elements/pane/EditPane";
+import EditGutter from "../../card/elements/gutter/EditGutter";
+import EditFillField from "../../card/elements/fill-field/EditFillField";
+import EditFillTable from "../../card/elements/fill-table/EditFillTable";
+import EditFillPane from "../../card/elements/fill-pane/EditFillPane";
+import EditPaneBox from "../elements/pane-box/EditPaneBox.vue";
 
 export default {
   name: "ElementPropEdit",
   components: {
-    EditComposition,
-    EditExplain,
-    EditFillLine,
-    EditFillQuestion,
     EditText,
     EditImage,
     EditLine,
     EditLines,
     EditGrids,
+    EditPane,
+    EditGutter,
+    EditFillField,
+    EditFillTable,
+    EditFillPane,
+    EditPaneBox,
   },
   data() {
-    return { loading: false };
+    return {};
   },
   computed: {
-    ...mapState("card", ["curElement", "openElementEditDialog"]),
+    ...mapState("paper-export", ["curElement", "openElementEditDialog"]),
     title() {
       return this.curElement.type
         ? getElementName(this.curElement.type)
@@ -72,9 +73,8 @@ export default {
     },
   },
   methods: {
-    ...mapMutations("card", ["setOpenElementEditDialog"]),
-    ...mapActions("card", [
-      "addElement",
+    ...mapMutations("paper-export", ["setOpenElementEditDialog"]),
+    ...mapActions("paper-export", [
       "modifyElement",
       "modifyElementChild",
       "rebuildPages",
@@ -86,17 +86,9 @@ export default {
       this.setOpenElementEditDialog(true);
     },
     submit() {
-      if (this.loading) return;
-      this.loading = true;
-      setTimeout(() => {
-        this.loading = false;
-      }, 500);
-      this.$refs.ElementPropEditComp.submit();
+      this.$refs.ComponentForm.submit();
     },
     modified(element) {
-      this.cancel();
-      // 编辑试题
-      // 属性存在的条件:parent:大题的小题,container:题目内的子元素
       if (this.curElement["_edit"]) {
         if (element["container"]) {
           this.modifyElementChild(element);
@@ -106,6 +98,7 @@ export default {
       } else {
         this.addElement(element);
       }
+      this.cancel();
       this.$nextTick(() => {
         this.rebuildPages();
       });

+ 1 - 1
src/modules/paper-export/components/PaperTemplateDesign.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="paper-template-design">
+  <div class="paper-template-design card-design">
     <!-- actions -->
     <div class="design-action">
       <div class="design-logo">

+ 80 - 0
src/modules/paper-export/components/PaperTemplateView.vue

@@ -0,0 +1,80 @@
+<template>
+  <div class="paper-template-view card-view">
+    <template v-for="(page, pageNo) in pages">
+      <div
+        :key="pageNo"
+        :class="[
+          'page-box',
+          `page-box-${cardConfig.pageSize}`,
+          `page-box-${pageNo % 2}`,
+        ]"
+      >
+        <!-- inner edit area -->
+        <div class="page-main-inner">
+          <div
+            :class="['page-main', `page-main-${page.columns.length}`]"
+            :style="{ margin: `0 -${page.columnGap / 2}px` }"
+          >
+            <div
+              v-for="(column, columnNo) in page.columns"
+              :key="columnNo"
+              class="page-column"
+              :style="{ padding: `0 ${page.columnGap / 2}px` }"
+            >
+              <div
+                :id="[`column-${pageNo}-${columnNo}`]"
+                class="page-column-main"
+              >
+                <div class="page-column-body">
+                  <topic-element-preview
+                    v-for="element in column.elements"
+                    :key="element.id"
+                    class="page-column-element"
+                    :data="element"
+                  ></topic-element-preview>
+                </div>
+              </div>
+              <page-number
+                type="text"
+                :total="pages.length * 2"
+                :current="pageNo * 2 + columnNo + 1"
+              ></page-number>
+            </div>
+          </div>
+        </div>
+        <!-- side edit erea -->
+        <div class="page-main-side">
+          <box-element-preview
+            v-for="element in page.sides"
+            :key="element.id"
+            class="page-side-element"
+            :data="element"
+          ></box-element-preview>
+        </div>
+      </div>
+    </template>
+  </div>
+</template>
+
+<script>
+import TopicElementPreview from "./TopicElementPreview";
+import BoxElementPreview from "./BoxElementPreview.vue";
+import PageNumber from "./PageNumber";
+
+export default {
+  name: "PaperTemplateView",
+  components: { TopicElementPreview, BoxElementPreview, PageNumber },
+  props: {
+    pages: {
+      type: Array,
+      default() {
+        return [];
+      },
+    },
+  },
+  data() {
+    return {};
+  },
+  methods: {},
+};
+</script>

+ 23 - 66
src/modules/paper-export/components/RightClickMenu.vue

@@ -8,19 +8,18 @@
       :style="styles"
     >
       <ul>
-        <li v-if="IS_CONTAINER_ELEMENT" @click="toEdit">
-          <i class="el-icon-edit-outline"></i>编辑元素
+        <li @click="toEdit">
+          <i class="el-icon-edit-outline"></i>
+          {{ IS_CONTAINER_ELEMENT ? "编辑元素" : "编辑编辑框" }}
         </li>
-        <li v-if="IS_CONTAINER_ELEMENT" class="li-danger" @click="toDelete">
-          <i class="el-icon-delete"></i>删除元素
+        <li class="li-danger" @click="toDelete">
+          <i class="el-icon-delete"></i>
+          {{ IS_CONTAINER_ELEMENT ? "删除元素" : "删除编辑框" }}
         </li>
-        <li v-if="IS_CONTAINER_ELEMENT" @click="toCopyExplainElement">
+        <li v-if="IS_CONTAINER_ELEMENT" @click="toCopyElementChild">
           <i class="el-icon-copy-document"></i> 复制元素
         </li>
-        <li
-          v-if="IS_CONTAINER && curCopyElement"
-          @click="toPasteExplainElement"
-        >
+        <li v-if="IS_CONTAINER && curCopyElement" @click="toPasteElementChild">
           <i class="el-icon-document-copy"></i> 粘贴元素
         </li>
       </ul>
@@ -31,7 +30,6 @@
 <script>
 import { mapState, mapMutations, mapActions } from "vuex";
 import { deepCopy } from "../plugins/utils";
-import { fetchSameSerialNumberChildrenPositionInfo } from "../store/card";
 import Clickoutside from "element-ui/src/utils/clickoutside";
 
 export default {
@@ -48,7 +46,7 @@ export default {
     };
   },
   computed: {
-    ...mapState("card", ["curElement", "topics"]),
+    ...mapState("paper-export", ["curElement", "topics"]),
     IS_CONTAINER_ELEMENT() {
       return !!this.curElement.container;
     },
@@ -68,16 +66,13 @@ export default {
     document.removeEventListener("mouseup", this.docMouseUp);
   },
   methods: {
-    ...mapMutations("card", ["setOpenElementEditDialog"]),
-    ...mapActions("card", [
+    ...mapMutations("paper-export", ["setOpenElementEditDialog"]),
+    ...mapActions("paper-export", [
       "actElementById",
       "removeElement",
       "removeElementChild",
-      "pasteExplainElementChild",
+      "pasteElementChild",
       "rebuildPages",
-      "copyExplainChildren",
-      "deleteExplainChildren",
-      "topicMoveUp",
     ]),
     init() {
       // 注册自定义右键事件菜单
@@ -103,7 +98,7 @@ export default {
 
       this.actElementById(id);
       let curElement = this.curElement;
-      const TYPES = ["EXPLAIN", "COMPOSITION"];
+      const TYPES = ["PANE_BOX"];
       if (
         TYPES.includes(curElement.type) ||
         (curElement.container && TYPES.includes(curElement.container.type))
@@ -114,13 +109,7 @@ export default {
           );
           curElement = this.topics[pos];
         }
-        const positionInfos = fetchSameSerialNumberChildrenPositionInfo(
-          curElement,
-          this.topics
-        );
-        this.showDeleteChildBtn = positionInfos.length >= 2;
       }
-      // todo:
       this.show();
 
       this.$nextTick(() => {
@@ -151,19 +140,14 @@ export default {
         !(
           (parentNode["id"] && parentNode["id"].includes("element-")) ||
           parentNode.className.includes("page-column-body") ||
-          parentNode.className.includes("card-design")
+          parentNode.className.includes("paper-template-design")
         )
       ) {
         parentNode = parentNode.parentNode;
       }
       const elementType = parentNode.getAttribute("data-type");
-      const unValidElement = ["TOPIC_HEAD", "CARD_HEAD"];
 
-      return parentNode["id"] &&
-        elementType &&
-        !unValidElement.includes(elementType)
-        ? parentNode["id"]
-        : null;
+      return parentNode["id"] && elementType ? parentNode["id"] : null;
     },
     toEdit() {
       this.curElement._edit = true;
@@ -180,26 +164,19 @@ export default {
         })
         .catch(() => {});
     },
-    toCopyChildren() {
-      this.close();
-      this.copyExplainChildren(this.curElement);
-      this.toRebuildPages();
-    },
-    toDeleteChildren() {
-      this.close();
-      this.deleteExplainChildren(this.curElement);
-      this.toRebuildPages();
-    },
     removeSelectElement() {
-      if (!this.curElement["container"]) return;
-      this.removeElementChild(this.curElement);
+      if (this.curElement["container"]) {
+        this.removeElementChild(this.curElement);
+      } else {
+        this.removeElement(this.curElement);
+      }
       this.toRebuildPages();
     },
-    toCopyExplainElement() {
+    toCopyElementChild() {
       this.close();
       this.curCopyElement = deepCopy(this.curElement);
     },
-    toPasteExplainElement() {
+    toPasteElementChild() {
       this.close();
       const id = this.curElement.container
         ? this.curElement.container.id
@@ -211,32 +188,12 @@ export default {
             })
           : this.curCopyElement;
 
-      this.pasteExplainElementChild({
+      this.pasteElementChild({
         curElement: this.curElement,
         pasteElement,
       });
       this.toRebuildPages();
     },
-    toMoveUpTopic() {
-      this.close();
-      this.topicMoveUp(this.curElement.parent.id);
-      this.toRebuildPages();
-    },
-    toMoveDownTopic() {
-      this.close();
-      const curTopicPos = this.topicSeries.findIndex(
-        (item) => item.id === this.curElement.parent.id
-      );
-      this.topicMoveUp(this.topicSeries[curTopicPos + 1].id);
-      this.toRebuildPages();
-    },
-    toInsetTopic() {
-      this.close();
-      this.$emit("inset-topic", {
-        id: this.curElement.parent.id,
-        type: this.curElement.type,
-      });
-    },
     toRebuildPages() {
       this.$nextTick(() => {
         this.rebuildPages();

+ 34 - 0
src/modules/paper-export/router/index.js

@@ -0,0 +1,34 @@
+export const menuRoutes = [
+  {
+    path: "/paper-template/manage",
+    name: "PaperTemplateManage",
+    component: () =>
+      import(
+        /* webpackChunkName: "paperTemp" */ "../views/PaperTemplateManage.vue"
+      ),
+  },
+];
+
+export const editRoutes = [
+  {
+    path: "/paper-template/edit/:idType/:paperOrCardId",
+    name: "PaperTemplateEdit",
+    component: () =>
+      import(/* webpackChunkName: "card" */ "../views/PaperTemplateEdit.vue"),
+  },
+  {
+    // viewType::: view:预览,print:打印,frame:iframe嵌套
+    path: "/paper-template/preview/:cardId/:viewType",
+    name: "PaperTemplatePreview",
+    component: () =>
+      import(
+        /* webpackChunkName: "card" */ "../views/PaperTemplatePreview.vue"
+      ),
+  },
+  {
+    path: "/paper-template/build",
+    name: "PaperTemplateBuild",
+    component: () =>
+      import(/* webpackChunkName: "card" */ "../views/PaperTemplateBuild.vue"),
+  },
+];

+ 1 - 19
src/modules/paper-export/store/paper-export.js

@@ -64,24 +64,6 @@ const fetchElementPositionInfos = (element, topics) => {
   return topics.findIndex((item) => item.id === element.id);
 };
 
-const fetchSameSerialNumberChildrenPositionInfo = (
-  elementChildernElement,
-  topics
-) => {
-  let postionInfos = [];
-  const elementId = elementChildernElement.parent.id;
-
-  topics.forEach((item, eindex) => {
-    if (item.parent && item.parent.id === elementId) {
-      postionInfos.push({
-        _elementNo: eindex,
-        _elementId: item.id,
-      });
-    }
-  });
-  return postionInfos;
-};
-
 const findElementById = (id, topics) => {
   let curElement = null;
   topics.forEach((element) => {
@@ -300,7 +282,7 @@ const actions = {
   },
 };
 
-export { fetchSameSerialNumberChildrenPositionInfo, checkElementisCovered };
+export { checkElementisCovered };
 
 export default {
   namespaced: true,

+ 150 - 3
src/modules/paper-export/views/PaperTemplateEdit.vue

@@ -1,13 +1,160 @@
 <template>
-  <div class="paper-template-edit">paper-template-edit</div>
+  <div class="paper-template-edit card-edit">
+    <paper-template-design
+      v-if="dataReady"
+      ref="PaperTemplateDesign"
+      :content="tempContent"
+      @on-preview="toPreview"
+      @on-save="toSave"
+      @on-submit="toSubmit"
+      @on-exit="toExit"
+    ></paper-template-design>
+
+    <!-- paper-template-view-frame -->
+    <div v-if="tempPreviewUrl" class="design-preview-frame">
+      <iframe :src="tempPreviewUrl" frameborder="0"></iframe>
+    </div>
+  </div>
 </template>
 
 <script>
+import { paperTemplateDetailApi, savePaperTemplateApi } from "../api";
+import PaperTemplateDesign from "../components/PaperTemplateDesign.vue";
 export default {
   name: "PaperTemplateEdit",
+  components: {
+    PaperTemplateDesign,
+  },
   data() {
-    return {};
+    return {
+      tid: this.$route.params.tid,
+      tempContent: {},
+      tempPreviewUrl: "",
+      dataReady: false,
+    };
+  },
+  computed: {
+    isEdit() {
+      return !!this.cardId;
+    },
+  },
+  beforeDestroy() {
+    delete window.submitCardTemp;
+  },
+  mounted() {
+    this.initData();
+    // todo:不需要预览了获取html了
+    this.registWindowSubmit();
+  },
+  methods: {
+    initData() {
+      this.dataReady = false;
+      if (this.isEdit) {
+        this.getPaperTemplate();
+      } else {
+        this.initTempContent();
+      }
+    },
+    async getPaperTemplate() {
+      const detDataRes = await paperTemplateDetailApi(this.tid);
+
+      if (!detDataRes.data || !detDataRes.data.content) {
+        this.$message.error("无模板内容");
+        return;
+      }
+
+      this.tempContent = JSON.parse(detDataRes.data.content);
+    },
+    initTempContent() {
+      this.tempContent = {
+        papes: [],
+      };
+    },
+    // 操作
+    async toPreview(datas) {
+      await this.toSave(datas);
+
+      const { href } = this.$router.resolve({
+        name: "PaperTemplatePreview",
+        params: {
+          tid: this.tid,
+          viewType: "view",
+        },
+      });
+      window.open(href);
+    },
+    // save
+    async toSave(infos) {
+      let datas = { ...infos };
+      datas.id = this.tid;
+      datas.formal = false;
+      let result = await savePaperTemplateApi(datas).catch(() => {});
+      this.$refs.PaperTemplateDesign.unloading();
+      if (!result) return;
+      this.tid = result.data;
+      this.$message.success("保存成功!");
+    },
+    async toSubmit(paperTempData) {
+      const res = await this.$confirm("确定要提交当前模板吗?", "提示", {
+        type: "warning",
+      }).catch(() => {});
+      if (res !== "confirm") return;
+
+      window.paperTempData = paperTempData;
+      this.$refs.PaperTemplateDesign.loading();
+      const { href } = this.$router.resolve({
+        name: "PaperTemplatePreview",
+        params: {
+          tid: 1,
+          viewType: "frame",
+        },
+        query: {
+          t: Date.now(),
+        },
+      });
+      this.tempPreviewUrl = href;
+    },
+    registWindowSubmit() {
+      window.submitCardTemp = async (tempContent) => {
+        if (!tempContent) {
+          this.$refs.PaperTemplateDesign.unloading();
+          window.paperTempData = null;
+          this.tempPreviewUrl = "";
+          this.$message.error("提交失败,请重新尝试!");
+          return;
+        }
+
+        let datas = {
+          content: tempContent,
+        };
+        datas.id = this.tid;
+        datas.formal = true;
+        let result = await savePaperTemplateApi(datas).catch(() => {});
+        this.tempPreviewUrl = "";
+        window.paperTempData = null;
+        this.$refs.PaperTemplateDesign.unloading();
+        if (result) {
+          this.tid = result.data;
+          this.$message.success("提交成功!");
+          this.goback();
+        } else {
+          this.$message.error("提交失败,请重新尝试!");
+        }
+      };
+    },
+    toExit() {
+      this.$confirm(
+        "请确保当前模板已经正常保存,确定要退出当前模板编辑吗?",
+        "提示",
+        {
+          type: "warning",
+        }
+      )
+        .then(() => {
+          this.goback();
+        })
+        .catch(() => {});
+    },
   },
-  methods: {},
 };
 </script>

+ 58 - 3
src/modules/paper-export/views/PaperTemplatePreview.vue

@@ -1,13 +1,68 @@
 <template>
-  <div class="paper-template-preview">paper-template-preview</div>
+  <div :class="classes">
+    <paper-template-view
+      v-if="pages.length"
+      ref="PaperTemplateView"
+      class="preview-body"
+      :pages="pages"
+    ></paper-template-view>
+  </div>
 </template>
 
 <script>
+import PaperTemplateView from "../components/PaperTemplateView.vue";
+import { deepCopy } from "../../card/plugins/utils";
+import { paperTemplateDetailApi } from "../api";
+
 export default {
   name: "PaperTemplatePreview",
+  components: {
+    PaperTemplateView,
+  },
   data() {
-    return {};
+    return {
+      isPrint: this.$route.params.viewType !== "view",
+      isFrame: this.$route.params.viewType === "frame",
+      tid: this.$route.params.tid,
+      pages: [],
+    };
+  },
+  computed: {
+    classes() {
+      return [
+        "card-preview",
+        {
+          "card-print": this.isPrint,
+        },
+      ];
+    },
+  },
+  mounted() {
+    if (this.isFrame) {
+      this.initFrame();
+    } else {
+      this.init();
+    }
+  },
+  methods: {
+    initFrame() {
+      const paperTempData = window.parent.paperTempData;
+      if (!paperTempData) return;
+
+      const { pages } = deepCopy(paperTempData);
+      this.pages = pages;
+    },
+    async init() {
+      const detDataRes = await paperTemplateDetailApi(this.tid);
+
+      if (!detDataRes.data || !detDataRes.data.content) {
+        this.$message.error("无模板内容");
+        return;
+      }
+
+      const { pages } = JSON.parse(detDataRes.data.content);
+      this.pages = pages;
+    },
   },
-  methods: {},
 };
 </script>