Ver Fonte

add element band

zhoucg há 1 ano atrás
pai
commit
fe0d17e6ba

+ 54 - 33
src/components/YvanPrintDesignerLeftLayout.vue

@@ -2,27 +2,34 @@
   <section :style="asideStyle" class="yvan-print-designer-left-structure__main">
     <div class="yvan-print-designer-left-structure__content">
       <yvan-print-main class="yvan-page-toc">
-        <div class="yvan-page-element" v-for="(elementBand, idx) in elementBands" :key="idx">
+        <div
+            v-for="(elementBand, idx) in originElementBands"
+            :key="idx"
+            class="yvan-page-element">
+
           <div class="yvan-element-band__list" @click="handleElementBandClick">
-            <i class="fa fa-list-ul" style="padding-right: 5px"></i>
+            <i class="fa fa-list-ul" style="padding-right: 5px"/>
             <span class="yvan-element-band_label">{{ elementBand.name }}</span>
             <div class="yvan-element-band__buttons">
-              <span class="fa fa-plus-square" @click.stop="addElementBand"></span>
-              <span class="fa fa-trash" @click.stop="deleteElementBand"></span>
+              <span v-if="!hasElementBand(elementBand.code)" class="fa fa-plus-square"
+                    @click.stop="addElementBand(elementBand)"/>
+              <span v-else class="fa fa-trash" @click.stop="deleteElementBand(elementBand.code)"/>
             </div>
           </div>
+
           <div
-              v-for="(item, idx) in componentData"
+              v-for="(element, idx) in getElements(elementBand.code)"
               :key="idx"
-              :class="{ activated: transformIndex(idx) === curComponentIndex }"
+              :class="{ activated: element.id === curComponent?.id }"
               class="yvan-page-toc__list"
-              @click="onClick(transformIndex(idx))">
-            <i :class="getComponent(idx).icon" style="padding-right: 5px"></i>
-            <span class="yvan-page-toc__label">{{ getComponent(idx).label }}</span>
+              @click="handleClick(element, idx)">
+
+            <i :class="element.icon" style="padding-right: 5px"></i>
+            <span class="yvan-page-toc__label">{{ element.label }}</span>
             <div class="yvan-page-toc__buttons">
-              <span class="fa fa-arrow-up" @click.stop="upComponent(transformIndex(idx))"></span>
-              <span class="fa fa-arrow-down" @click.stop="downComponent(transformIndex(idx))"></span>
-              <span class="fa fa-trash" @click.stop="deleteComponent(transformIndex(idx))"></span>
+              <!--<span class="fa fa-arrow-up" @click.stop="upComponent(transformIndex(idx))"></span>-->
+              <!--<span class="fa fa-arrow-down" @click.stop="downComponent(transformIndex(idx))"></span>-->
+              <span class="fa fa-trash" @click.stop="deleteComponent(element, idx)"/>
             </div>
           </div>
         </div>
@@ -35,6 +42,7 @@
 import {mapState} from "pinia";
 import {globalStore} from "@/store";
 import commonMixin from '@/mixin/commonMixin'
+import ElementUtils from '@/utils/ElementUtils'
 import {elementBands} from "@/components/config/globalConfig"
 import YvanPrintMain from "@/components/yvan-ui/YvanPrintMain.vue";
 
@@ -47,7 +55,7 @@ export default {
   data() {
     return {
       isNightMode: false,
-      elementBands,
+      originElementBands: elementBands,
     }
   },
   props: {
@@ -59,6 +67,8 @@ export default {
   computed: {
     ...mapState(globalStore, {
       componentData: (state) => state.componentData,
+      elementBands: (state) => state.elementBands,
+      elementBandCodes: (state) => state.elementBandCodes,
       curComponentIndex: (state) => state.curComponentIndex,
       curComponent: (state) => state.curComponent
     }),
@@ -67,19 +77,12 @@ export default {
     }
   },
   methods: {
-    getComponent(index) {
-      return this.componentData[this.componentData.length - 1 - index]
+    handleClick(element, index) {
+      this.setCurComponent(element, index)
     },
-
-    transformIndex(index) {
-      return this.componentData.length - 1 - index
-    },
-    onClick(index) {
-      this.setCurComponent(index)
-    },
-    deleteComponent() {
+    deleteComponent(element, idx) {
       setTimeout(() => {
-        globalStore().deleteComponent();
+        globalStore().deleteElement({element, elementIdx: idx});
         globalStore().recordSnapshot();
       })
     },
@@ -97,21 +100,39 @@ export default {
         globalStore().recordSnapshot();
       })
     },
-
-    setCurComponent(index) {
+    setCurComponent(element, index) {
       globalStore().setCurComponent({
-        component: this.componentData[index],
+        component: element,
         index
       })
     },
+    hasElementBand(bandCode) {
+      return this.elementBands.has(bandCode);
+    },
     handleElementBandClick() {
-      console.log('>>> click')
+
     },
-    addElementBand() {
-      console.log(">>> add")
+    addElementBand(elementBand) {
+      globalStore().addElementBand(elementBand)
+      globalStore().setElementBandCode({
+        elementBandIdx: ElementUtils.getElementBandIdx(elementBand.code),
+        elementBandCode: elementBand.code
+      })
     },
-    deleteElementBand() {
-      console.log(">>>> delete")
+    deleteElementBand(bandCode) {
+      const elementBands = this.elementBands;
+      if (!elementBands.has(bandCode)) {
+        return;
+      }
+      globalStore().deleteElementBand(bandCode)
+      globalStore().deleteElementBandCode({elementBandCode: bandCode})
+    },
+    getElements(bandCode) {
+      const elementBands = this.elementBands;
+      if (!elementBands.has(bandCode)) {
+        return [];
+      }
+      return elementBands.get(bandCode)?.elements;
     }
   },
   mounted() {
@@ -167,7 +188,7 @@ export default {
 
       .yvan-element-band__list {
         height: 30px;
-        cursor: pointer;
+        //cursor: pointer;
         text-align: center;
         color: var(--yvan-text-color-primary);
         display: flex;

+ 3 - 3
src/components/elements/YvanLine.vue

@@ -37,9 +37,9 @@ export default {
   methods: {
     initMounted() {}
   },
-  install(Vue) {
-    Vue.component(this.name, this)
-    Vue.component(YvanLineProps.name, YvanLineProps)
+  install(app) {
+    app.component(this.name, this)
+    app.component(YvanLineProps.name, YvanLineProps)
   },
   mounted() {
     this.initMounted()

+ 2 - 2
src/components/elements/YvanTextField.vue

@@ -33,7 +33,7 @@ import system from '@/utils/system';
 import Constant from '@/utils/constant'
 import commonMixin from '@/mixin/commonMixin';
 import {StyledTextField} from '@/components/elements/style';
-import {obtainExpression} from "@/utils/ExpressionUtils";
+import ExpressionUtils from "@/utils/ExpressionUtils";
 import YvanTextFieldProps from "@/components/elements/YvanTextFieldProps.vue";
 
 export default {
@@ -109,7 +109,7 @@ export default {
       if (fieldCode) {
         globalStore().setExpression({
           bandCode: this.element.bandCode,
-          expression: obtainExpression(fieldCode),
+          expression: ExpressionUtils.obtainExpression(fieldCode),
           id: this.element.id
         })
         this.canEdit = false

+ 14 - 12
src/components/elements/index.js

@@ -10,16 +10,18 @@ import YvanSimpleText from "@/components/elements/YvanSimpleText.vue";
 import YvanSimpleTable from "@/components/elements/yvan-table/YvanSimpleTable.vue";
 import YvanComplexTable from "@/components/elements/yvan-table/YvanComplexTable.vue";
 
-export const install = (Vue) => {
-    YvanLine.install(Vue)
-    YvanRect.install(Vue)
-    YvanImage.install(Vue)
-    YvanCircle.install(Vue)
-    YvanQrcode.install(Vue)
-    YvanBarcode.install(Vue)
-    YvanRichText.install(Vue)
-    YvanTextField.install(Vue)
-    YvanSimpleText.install(Vue)
-    YvanSimpleTable.install(Vue)
-    YvanComplexTable.install(Vue)
+export default {
+    install(app, options) {
+        YvanLine.install(app)
+        YvanRect.install(app)
+        YvanImage.install(app)
+        YvanCircle.install(app)
+        YvanQrcode.install(app)
+        YvanBarcode.install(app)
+        YvanRichText.install(app)
+        YvanTextField.install(app)
+        YvanSimpleText.install(app)
+        YvanSimpleTable.install(app)
+        YvanComplexTable.install(app)
+    }
 }

+ 1 - 1
src/components/elements/yvan-table/YvanComplexTable.vue

@@ -4,7 +4,7 @@
       <table class="yvan-complex-table__container">
         <tr class="1234">
           <td>
-            <div class="yvan-complex-table__prefix" tyle="border: #0a0a0a 1px solid">
+            <div class="yvan-complex-table__prefix" style="border: #0a0a0a 1px solid">
               <YvanSimpleTextInTable
                 key="prefix"
                 :element="prefixTextElement"

+ 0 - 284
src/components/yvan-context/components/Context.vue

@@ -1,284 +0,0 @@
-<template>
-  <ul v-show="visible" ref="contextmenu" :class="contextmenuCls" :style="style">
-    <slot></slot>
-  </ul>
-</template>
-
-<script>
-import eventBus from "@/utils/eventBus";
-
-export default {
-  name: 'yvan-print-context',
-  provide() {
-    return {
-      $$contextmenu: this
-    }
-  },
-  props: {
-    eventType: {
-      type: String,
-      default: 'contextmenu'
-    },
-    theme: {
-      type: String,
-      default: 'default'
-    },
-    autoPlacement: {
-      type: Boolean,
-      default: true
-    },
-    disabled: Boolean
-  },
-
-  data() {
-    return {
-      visible: false,
-      references: [],
-      style: {
-        top: 0,
-        left: 0
-      }
-    }
-  },
-  computed: {
-    clickOutsideHandler() {
-      return this.visible ? this.hide : () => {
-      }
-    },
-    isClick() {
-      return this.eventType === 'click'
-    },
-    contextmenuCls() {
-      return ['yvan-print-context', `yvan-print-context--${this.theme}`]
-    }
-  },
-
-  watch: {
-    visible(value) {
-      if (value) {
-        this.$emit('show', this)
-        document.body.addEventListener('click', this.handleBodyClick)
-      } else {
-        this.$emit('hide', this)
-        document.body.removeEventListener('click', this.handleBodyClick)
-      }
-    }
-  },
-  mounted() {
-    document.body.appendChild(this.$el)
-    eventBus.on("showContextMenu", (position) => {
-      this.show(position)
-    })
-    if (window.$$VContextmenu) {
-      window.$$VContextmenu[this.$contextmenuId] = this
-    } else {
-      window.$$VContextmenu = {[this.$contextmenuId]: this}
-    }
-  },
-  beforeDestroy() {
-    document.body.removeChild(this.$el)
-    delete window.$$VContextmenu[this.$contextmenuId]
-    this.references.forEach((ref) => {
-      ref.el.removeEventListener(this.eventType, this.handleReferenceContextmenu)
-    })
-    document.body.removeEventListener('click', this.handleBodyClick)
-  },
-
-  methods: {
-    addRef(ref) {
-      // FIXME: 如何处理 removeRef?
-      this.references.push(ref)
-      ref.el.addEventListener(this.eventType, this.handleReferenceContextmenu)
-    },
-    handleReferenceContextmenu(event) {
-      event.preventDefault()
-      if (this.disabled) {
-        return
-      }
-      const reference = this.references.find((ref) => ref.el.contains(event.target))
-      this.$emit('contextmenu', reference ? reference.vnode : null)
-      const eventX = event.pageX
-      const eventY = event.pageY
-      this.show()
-      this.$nextTick(() => {
-        const contextmenuPosition = {
-          top: eventY,
-          left: eventX
-        }
-        if (this.autoPlacement) {
-          const contextmenuWidth = this.$refs.contextmenu.clientWidth
-          const contextmenuHeight = this.$refs.contextmenu.clientHeight
-          if (contextmenuHeight + eventY >= window.innerHeight) {
-            contextmenuPosition.top -= contextmenuHeight
-          }
-          if (contextmenuWidth + eventX >= window.innerWidth) {
-            contextmenuPosition.left -= contextmenuWidth
-          }
-        }
-        this.style = {
-          top: `${contextmenuPosition.top}px`,
-          left: `${contextmenuPosition.left}px`
-        }
-      })
-    },
-    handleBodyClick(event) {
-      const notOutside =
-          this.$el.contains(event.target) ||
-          (this.isClick && this.references.some((ref) => ref.el.contains(event.target)))
-
-      if (!notOutside) {
-        this.visible = false
-      }
-    },
-    show(position) {
-      Object.keys(window.$$VContextmenu).forEach((key) => {
-        if (key !== this.$contextmenuId) {
-          window.$$VContextmenu[key].hide()
-        }
-      })
-      if (position) {
-        this.style = {
-          top: `${position.top}px`,
-          left: `${position.left}px`
-        }
-      }
-      this.visible = true
-    },
-    hide() {
-      this.visible = false
-    },
-    hideAll() {
-      Object.keys(window.$$VContextmenu).forEach((key) => {
-        window.$$VContextmenu[key].hide()
-      })
-    }
-  }
-}
-</script>
-
-<style>
-.yvan-print-context {
-  position: absolute;
-  padding: 5px 0;
-  margin: 0;
-  background-color: #fff;
-  border: 1px solid #e8e8e8;
-  border-radius: 4px;
-  box-shadow: 2px 2px 8px 0 rgba(150, 150, 150, 0.2);
-  list-style: none;
-  font-size: 14px;
-  white-space: nowrap;
-  cursor: pointer;
-  z-index: 2800;
-  -webkit-tap-highlight-color: transparent;
-}
-
-.yvan-print-context .yvan-print-context-item {
-  padding: 5px 14px;
-  line-height: 1;
-  color: #333;
-  display: flex;
-  align-items: center;
-  cursor: pointer;
-}
-
-.yvan-print-context .yvan-print-context-item.yvan-print-context-item--hover {
-  color: #fff;
-}
-
-.yvan-print-context .yvan-print-context-item.yvan-print-context-item--disabled {
-  color: #ccc;
-  cursor: not-allowed;
-}
-
-.yvan-print-context .yvan-print-context-divider {
-  height: 0;
-  margin: 5px 0;
-  border-bottom: 1px solid #e8e8e8;
-}
-
-.yvan-print-context .yvan-print-context-group__menus {
-  padding: 0 5px;
-  margin: 0;
-  list-style: none;
-}
-
-.yvan-print-context .yvan-print-context-group__menus .yvan-print-context-item {
-  display: inline-block;
-  padding: 5px 9px;
-}
-
-.yvan-print-context .yvan-print-context-submenu {
-  position: relative;
-}
-
-.yvan-print-context .yvan-print-context-submenu > .yvan-print-context {
-  position: absolute;
-}
-
-.yvan-print-context .yvan-print-context-submenu > .yvan-print-context.left {
-  left: 0;
-  transform: translateX(-100%);
-}
-
-.yvan-print-context .yvan-print-context-submenu > .yvan-print-context.right {
-  right: 0;
-  transform: translateX(100%);
-}
-
-.yvan-print-context .yvan-print-context-submenu > .yvan-print-context.top {
-  top: -6px;
-}
-
-.yvan-print-context .yvan-print-context-submenu > .yvan-print-context.bottom {
-  bottom: -6px;
-}
-
-.yvan-print-context .yvan-print-context-submenu .yvan-print-context-submenu__title {
-  margin-right: 10px;
-}
-
-.yvan-print-context .yvan-print-context-submenu .yvan-print-context-submenu__icon {
-  position: absolute;
-  right: 5px;
-}
-
-.yvan-print-context .yvan-print-context-submenu .yvan-print-context-submenu__icon::before {
-  content: '\e622';
-}
-
-.yvan-print-context--default .yvan-print-context-item--hover {
-  background-color: #4579e1;
-}
-
-.yvan-print-context--bright .yvan-print-context-item--hover {
-  background-color: #ef5350;
-}
-
-.yvan-print-context--dark .yvan-print-context-item--hover {
-  background-color: #2d3035;
-}
-
-.yvan-print-context--dark {
-  background: #222222;
-  box-shadow: 2px 2px 8px 0 rgba(0, 0, 0, 0.2);
-  border: 1px solid #111111;
-}
-
-.yvan-print-context--dark .yvan-print-context-item {
-  color: #ccc;
-}
-
-.yvan-print-context-item i {
-  padding: 0 10px 0 0;
-}
-
-.yvan-print-context--danger {
-  color: #f54536 !important;
-}
-
-.yvan-print-context--danger:hover {
-  background: #f54536;
-  color: #fff !important;
-}
-</style>

+ 0 - 33
src/components/yvan-context/components/ContextGroup.vue

@@ -1,33 +0,0 @@
-<template>
-  <li class="v-contextmenu-group">
-    <ul :style="menusStyle" class="v-contextmenu-group__menus">
-      <slot></slot>
-    </ul>
-  </li>
-</template>
-
-<script>
-export default {
-  name: 'ContextGroup',
-
-  props: {
-    maxWidth: {
-      type: [Number, String],
-      default: undefined
-    }
-  },
-
-  computed: {
-    menusStyle() {
-      if (!this.maxWidth) {
-        return null
-      }
-
-      return {
-        'max-width': typeof this.maxWidth === 'number' ? `${this.maxWidth}px` : this.maxWidth,
-        'overflow-x': 'auto'
-      }
-    }
-  }
-}
-</script>

+ 0 - 74
src/components/yvan-context/components/ContextItem.vue

@@ -1,74 +0,0 @@
-<template>
-  <li v-if="divider" class="yvan-print-context-divider"></li>
-
-  <li
-      v-else
-      :class="classname"
-      @click="handleClick"
-      @mouseenter="handleMouseenter"
-      @mouseleave="handleMouseleave"
-  >
-    <slot></slot>
-  </li>
-</template>
-
-<script>
-export default {
-  name: 'ContextItem',
-
-  inject: ['$$contextmenu'],
-
-  props: {
-    divider: Boolean,
-    disabled: Boolean,
-    autoHide: {
-      type: Boolean,
-      default: true
-    }
-  },
-
-  data() {
-    return {
-      hover: false
-    }
-  },
-  computed: {
-    classname() {
-      return {
-        'yvan-print-context-item': !this.divider,
-        'yvan-print-context-item--hover': this.hover,
-        'yvan-print-context-item--disabled': this.disabled
-      }
-    }
-  },
-
-  methods: {
-    handleMouseenter(event) {
-      if (this.disabled) {
-        return
-      }
-
-      this.hover = true
-
-      this.$emit('mouseenter', this, event)
-    },
-    handleMouseleave(event) {
-      if (this.disabled) {
-        return
-      }
-
-      this.hover = false
-
-      this.$emit('mouseleave', this, event)
-    },
-
-    handleClick(event) {
-      if (this.disabled) {
-        return
-      }
-      this.$emit('handle-click', this, event)
-      this.autoHide && this.$$contextmenu.hide()
-    }
-  }
-}
-</script>

+ 0 - 91
src/components/yvan-context/components/ContextSubmenu.vue

@@ -1,91 +0,0 @@
-<template>
-  <li :class="classname" @mouseenter="handleMouseenter" @mouseleave="handleMouseleave">
-    <span class="v-contextmenu-submenu__title">
-      <slot name="title">{{ title }}</slot>
-
-      <span class="v-contextmenu-iconfont v-contextmenu-submenu__icon"></span>
-    </span>
-
-    <ul v-show="hover" ref="submenu" :class="submenuCls">
-      <slot></slot>
-    </ul>
-  </li>
-</template>
-
-<script>
-export default {
-  name: 'VContextmenuSubmenu',
-
-  props: {
-    title: {
-      type: String,
-      default: ''
-    },
-    disabled: Boolean
-  },
-
-  data() {
-    return {
-      hover: false,
-      submenuPlacement: []
-    }
-  },
-  computed: {
-    classname() {
-      return {
-        'v-contextmenu-item': true,
-        'v-contextmenu-submenu': true,
-        'v-contextmenu-item--hover': this.hover,
-        'v-contextmenu-item--disabled': this.disabled
-      }
-    },
-    submenuCls() {
-      return ['v-contextmenu', ...this.submenuPlacement]
-    }
-  },
-
-  methods: {
-    handleMouseenter(event) {
-      if (this.disabled) {
-        return
-      }
-
-      const { target } = event
-      const targetDimension = target.getBoundingClientRect()
-
-      this.hover = true
-
-      this.$emit('mouseenter', this, event)
-
-      this.$nextTick(() => {
-        const submenuWidth = this.$refs.submenu.clientWidth
-        const submenuHeight = this.$refs.submenu.clientHeight
-        const submenuPlacement = []
-
-        if (targetDimension.right + submenuWidth >= window.innerWidth) {
-          submenuPlacement.push('left')
-        } else {
-          submenuPlacement.push('right')
-        }
-
-        if (targetDimension.bottom + submenuHeight >= window.innerHeight) {
-          submenuPlacement.push('bottom')
-        } else {
-          submenuPlacement.push('top')
-        }
-
-        this.submenuPlacement = submenuPlacement
-      })
-    },
-    handleMouseleave(event) {
-      if (this.disabled) {
-        return
-      }
-
-      this.hover = false
-
-      this.$emit('mouseleave', this, event)
-    }
-  }
-}
-</script>

+ 0 - 8
src/components/yvan-context/directive.js

@@ -1,8 +0,0 @@
-export default {
-  mounted(el, binding, vnode) {
-    const node = vnode.ctx.refs[binding.arg] || vnode.ctx.refs[binding.value]
-    const contextmenu = Object.prototype.toString.call(node) === '[object Array]' ? node[0] : node
-    contextmenu.addRef({ el, vnode })
-    contextmenu.$contextmenuId = el.id || contextmenu._uid
-  }
-}

+ 0 - 7
src/components/yvan-context/index.js

@@ -1,7 +0,0 @@
-import directive from './directive'
-import Context from './components/Context.vue'
-import ContextItem from './components/ContextItem.vue'
-import ContextGroup from './components/ContextGroup.vue'
-import ContextSubmenu from './components/ContextSubmenu.vue'
-
-export { directive, Context, ContextItem, ContextGroup, ContextSubmenu }

+ 1 - 1
src/components/yvan-editor/ComponentBand.vue

@@ -163,7 +163,7 @@ export default {
     this.innerBandTop = (this.pageConfig.topMargin + this.usedHeight) * this.realScale;
     this.innerBandHeight = this.bandHeight * this.realScale;
     const elementBand = {name: this.bandName, code: this.bandCode, height: this.bandHeight}
-    globalStore().addElementBand(elementBand)
+    // globalStore().addElementBand(elementBand)
   },
   methods: {
     getShapeStyle,

+ 35 - 133
src/components/yvan-editor/Editor.vue

@@ -28,15 +28,15 @@
             @mousedown="handleMouseDown"
         >
           <ComponentBand
-              v-for="(elementBand, idx) in getElementBands"
+              v-for="(elementBandCode, idx) in getElementBandCodes"
               :key="idx"
               :ref="getComponentBandRef(idx)"
               :is-first="idx === 0"
               :index="idx"
-              :band-name="elementBand.name"
-              :band-code="elementBand.code"
-              :band-height="elementBand.height"
-              :used-height="getUsedHeight(elementBand)"
+              :band-name="getElementBand(elementBandCode)?.name"
+              :band-code="elementBandCode"
+              :band-height="getElementBandFormStore(elementBandCode)?.band?.height"
+              :used-height="getUsedHeight(elementBandCode)"
               @changeElementBandTop="changeElementBandTop"/>
 
           <!-- 选中区域 -->
@@ -50,7 +50,7 @@
       </div>
     </div>
     <!-- 菜单-->
-    <EditorMenu />
+    <EditorMenu/>
     <!--<Context ref="contextmenu" :theme="contextTheme">-->
     <!--  <ContextItem-->
     <!--      v-for="item in contextMenu"-->
@@ -72,11 +72,11 @@ import Big from 'big.js'
 import {mapActions, mapState} from "pinia";
 import {globalStore, ruleStore, modeStore} from "@/store";
 import eventBus from "@/utils/eventBus";
-import CONSTANT from '@/utils/constant'
+import Constant from '@/utils/constant'
 import commonMixin from '@/mixin/commonMixin'
 import {isPreventDrop} from '@/utils/html-util'
+import ElementUtils from '@/utils/ElementUtils'
 import {elementBands} from "@/components/config/globalConfig"
-// import {Context, ContextItem, directive} from '@/components/yvan-context'
 import {getComponentRotatedStyle, getShapeStyle} from '@/utils/style-util'
 import Area from '@/components/yvan-editor/Area.vue'
 import SketchRuler from '../sketch-ruler/sketchRuler.vue'
@@ -86,23 +86,18 @@ import ComponentBand from '@/components/yvan-editor/ComponentBand.vue'
 import EditorCoordinate from '@/components/yvan-editor/EditorCoordinate.vue'
 import ComponentAdjuster from '@/components/yvan-editor/ComponentAdjuster.vue'
 
-const {MIN_SCALE, MAX_SCALE} = CONSTANT
+const {MIN_SCALE, MAX_SCALE} = Constant
 
 let elementUsedHeight = 0;
 
 export default {
   name: 'yvan-print-designer-editor',
-  // directives: {
-  //   contextmenu: directive
-  // },
   mixins: [commonMixin],
   components: {
     Area,
     EditorMenu,
     EditorLine,
     SketchRuler,
-    // Context,
-    // ContextItem,
     ComponentBand,
     EditorCoordinate,
     ComponentAdjuster,
@@ -148,12 +143,14 @@ export default {
       height: 0,
       isShowArea: false,
       svgFilterAttrs: ['width', 'height', 'top', 'left', 'rotate'],
+      elementBands,
     }
   },
   computed: {
     ...mapState(globalStore, {
       componentData: (state) => state.componentData,
       curComponent: (state) => state.curComponent,
+      curElementBands: (state) => state.elementBands,
       editor: (state) => state.editor,
       pageConfig: (state) => state.pageConfig
     }),
@@ -164,119 +161,6 @@ export default {
       needReDrawRuler: (state) => state.needReDrawRuler,
       showRuler: (state) => state.showRuler,
     }),
-    contextTheme() {
-      return this.isNightMode ? 'dark' : 'default'
-    },
-    contextMenu() {
-      if (!this.curComponent) {
-        return [
-          {
-            code: 'paste',
-            icon: 'fa fa-paste',
-            label: '粘贴',
-            status: 'default',
-            event: () => {
-              globalStore().paste(true)
-              globalStore().recordSnapshot()
-            }
-          }
-        ]
-      }
-      if (this.curComponent.isLock) {
-        const curComponent = this.curComponent
-        return [
-          {
-            code: 'unlock',
-            icon: 'fa fa-unlock',
-            label: '解锁',
-            status: 'default',
-            event: () => {
-              globalStore().unlock({curComponent})
-            }
-          }
-        ]
-      }
-      const curComponent = this.curComponent
-      return [
-        {
-          code: 'copy',
-          icon: 'fa fa-copy',
-          label: '复制',
-          status: 'default',
-          event: () => {
-            globalStore().copy()
-          }
-        },
-        {
-          code: 'cut',
-          icon: 'fa fa-cut',
-          label: '剪切',
-          status: 'default',
-          event: () => {
-            globalStore().cut()
-          }
-        },
-        {
-          code: 'del',
-          icon: 'fa fa-trash',
-          label: '删除',
-          status: 'danger',
-          event: () => {
-            globalStore().deleteComponent(globalStore().curComponentIndex)
-            globalStore().recordSnapshot()
-          }
-        },
-        {
-          code: 'lock',
-          icon: 'fa fa-lock',
-          label: '锁定',
-          status: 'default',
-          event: () => {
-            globalStore().lock({curComponent})
-          }
-        },
-        {
-          code: 'top',
-          icon: 'fa fa-angle-double-up',
-          label: '置顶',
-          status: 'default',
-          event: () => {
-            // this.$store.commit('printTemplateModule/topComponent')
-            // this.$store.commit('printTemplateModule/recordSnapshot')
-          }
-        },
-        {
-          code: 'bottom',
-          icon: 'fa fa-angle-double-down',
-          label: '置底',
-          status: 'default',
-          event: () => {
-            // this.$store.commit('printTemplateModule/bottomComponent')
-            // this.$store.commit('printTemplateModule/recordSnapshot')
-          }
-        },
-        {
-          code: 'up',
-          icon: 'fa fa-arrow-circle-up',
-          label: '上移',
-          status: 'default',
-          event: () => {
-            // this.$store.commit('printTemplateModule/upComponent')
-            // this.$store.commit('printTemplateModule/recordSnapshot')
-          }
-        },
-        {
-          code: 'down',
-          icon: 'fa fa-arrow-circle-down',
-          label: '下移',
-          status: 'default',
-          event: () => {
-            // this.$store.commit('printTemplateModule/downComponent')
-            // this.$store.commit('printTemplateModule/recordSnapshot')
-          }
-        }
-      ]
-    },
     scale() {
       return new Big(this.realScale).div(new Big(5)).toNumber()
     },
@@ -307,12 +191,28 @@ export default {
       return this.showRight ? 'width: calc(100% - 315px - 315px);' : 'width: calc(100% - 95px - 95px);'
     },
     getElementBands() {
-      return elementBands.filter(band => band.isDefaultShow);
-    }
+      const distElementBands = [];
+      this.curElementBands.forEach((value, bandCode) => {
+        distElementBands.push({
+          code: bandCode,
+          height: value?.band?.height
+        })
+      });
+      return distElementBands;
+    },
+    getElementBandCodes() {
+      return globalStore().getElementBandCodes();
+    },
   },
   methods: {
     ...mapActions(ruleStore, ['setReDrawRuler', 'setScale']),
     getShapeStyle,
+    getElementBand(bandCode) {
+      return elementBands.findLast(elementBand => elementBand.code === bandCode);
+    },
+    getElementBandFormStore(bandCode) {
+      return ElementUtils.getElementBandFromStore(bandCode);
+    },
     handleMouseDown(e) {
       // 如果没有选中组件 在画布上点击时需要调用 e.preventDefault() 防止触发 drop 事件
       if (!this.curComponent || isPreventDrop(this.curComponent.component)) {
@@ -503,17 +403,19 @@ export default {
       })
     },
     getComponentBandRef(idx) {
-      // return `componentBandRef_${idx}`;
       return `componentBandRef`;
     },
-    getUsedHeight(elementBand) {
+    getUsedHeight(elementBandCode) {
+      if (ElementUtils.isFirstElementBandCode(elementBandCode)) {
+        elementUsedHeight = 0;
+      }
+      const elementBand = ElementUtils.getElementBandFromStore(elementBandCode);
       const resultUsedHeight = elementUsedHeight;
-      elementUsedHeight = resultUsedHeight + elementBand.height;
+      elementUsedHeight = Number(resultUsedHeight) + Number(elementBand?.band?.height ?? 0)
       return resultUsedHeight;
     },
     changeElementBandTop({currentElementBand, changeHeight, movePos, index}) {
       if (movePos === 'bottomLine') {
-        console.log(' >>> bottomLine')
         const componentBandRefs = this.$refs.componentBandRef;
         for (let i in componentBandRefs) {
           if (i <= index) {

+ 2 - 1
src/globalConfig.ts

@@ -1,5 +1,6 @@
-import {AxiosInstance, AxiosRequestConfig} from "axios";
 import {router} from "@/router";
+import ElementUtils from "@/utils/ElementUtils";
+import {AxiosInstance, AxiosRequestConfig} from "axios";
 
 const httpStatus = {
     200: "服务器成功返回请求的数据",

+ 11 - 0
src/initialize.ts

@@ -0,0 +1,11 @@
+import * as Icons from '@ant-design/icons-vue'
+import ElementUtils from "@/utils/ElementUtils";
+
+export default {
+    install: (app, options) => {
+        for (const i in Icons) {
+            app.component(i, Icons[i])
+        }
+        ElementUtils.initElementBandCode();
+    }
+}

+ 4 - 10
src/main.ts

@@ -5,17 +5,11 @@ import '@/style.css'
 import '@/assets/style/main.less'
 import '@/assets/style/variable.css'
 import 'element-plus/theme-chalk/index.css'
-import * as Icons from '@ant-design/icons-vue'
+
 import App from '@/App.vue'
-import {install} from "@/components/elements"
+import elements from "@/components/elements"
+import initialize from "@/initialize"
 
 const pinia = createPinia()
 
-const app = createApp(App)
-for (const i in Icons) {
-    app.component(i, Icons[i])
-}
-
-app.use({install})
-
-app.use(pinia).use(ElementPlus, {}).mount('#app')
+createApp(App).use(elements).use(pinia).use(ElementPlus, {}).use(initialize).mount('#app');

+ 29 - 0
src/store/global.ts

@@ -6,6 +6,7 @@ import compose from '@/store/compose'
 import snapshot from '@/store/snapshot'
 import {ruleStore} from "@/store/ruler-things";
 import {getEditorMenuPos} from '@/utils/editorUtils'
+import Constant from "@/utils/constant";
 
 export const globalStore = defineStore('global', {
     state: () => {
@@ -51,6 +52,7 @@ export const globalStore = defineStore('global', {
             isInEditor: false,
             componentData: [],
             elementBands: new Map(),
+            elementBandCodes: [],
             dataSource: [],
             dataset: {},
             curComponent: null,
@@ -237,6 +239,33 @@ export const globalStore = defineStore('global', {
                 elements: []
             })
         },
+        setElementBandCode({elementBandIdx, elementBandCode}) {
+            const elementBandCodes = this.elementBandCodes;
+            elementBandCodes.splice(elementBandIdx, 1, elementBandCode);
+            this.elementBandCodes = elementBandCodes;
+        },
+        deleteElementBandCode({elementBandCode}) {
+            const elementBandCodes = this.elementBandCodes;
+            for (let elementBandIdx in elementBandCodes) {
+                const bandCode = elementBandCodes[elementBandIdx];
+                if (bandCode === elementBandCode) {
+                    this.elementBandCodes.splice(Number(elementBandIdx), 1, Constant.NONE)
+                }
+            }
+        },
+        getElementBandCodes() {
+            const elementBandCodes = this.elementBandCodes;
+            if (!elementBandCodes) {
+                return [];
+            }
+            const distElementBandCodes = [];
+            for (let elementBandCode of elementBandCodes) {
+                if (elementBandCode !== Constant.NONE) {
+                    distElementBandCodes.push(elementBandCode)
+                }
+            }
+            return distElementBandCodes;
+        },
         changeBandHeight({code, height}) {
             const originElementBand = this.elementBands.get(code)
             if (originElementBand !== undefined) {

+ 43 - 0
src/utils/ElementUtils.ts

@@ -0,0 +1,43 @@
+import {globalStore} from "@/store";
+import Constant from "@/utils/constant";
+import {elementBands} from "@/components/config/globalConfig";
+
+export default class ElementUtils {
+
+    /**
+     * 获取元素Band的索引
+     * @param elementBandCode
+     */
+    public static getElementBandIdx(elementBandCode): Number {
+        return elementBands.findLastIndex(band => band.code === elementBandCode)
+    }
+
+    /**
+     * 从GlobalStore中获取元素Band对象
+     * @param elementBandCode
+     */
+    public static getElementBandFromStore(elementBandCode) {
+        return globalStore().elementBands.get(elementBandCode)
+    }
+
+    public static isFirstElementBandCode(elementBandCode) {
+        return globalStore().getElementBandCodes().findLastIndex((bandCode) => bandCode === elementBandCode) === 0
+    }
+
+    public static initElementBandCode() {
+        const elementBands = ElementUtils.getAllElementBand()
+        if (!elementBands) {
+            return;
+        }
+        for (let index in elementBands) {
+            globalStore().setElementBandCode({
+                elementBandIdx: index,
+                elementBandCode: Constant.NONE
+            });
+        }
+    }
+
+    public static getAllElementBand() {
+        return elementBands;
+    }
+}

+ 12 - 4
src/utils/ExpressionUtils.ts

@@ -5,9 +5,17 @@ class ExpressionConstant {
     public static readonly EXPRESSION_SUFFIX = "}";
 }
 
-export function obtainExpression(fieldCode) {
-    if (!fieldCode) {
-        return fieldCode;
+
+export default class ExpressionUtils {
+
+    /**
+     * 构建表达式 => ${fieldCode}
+     * @param fieldCode
+     */
+    public static obtainExpression(fieldCode): String {
+        if (!fieldCode) {
+            return fieldCode;
+        }
+        return ExpressionConstant.EXPRESSION_PREFIX + fieldCode + ExpressionConstant.EXPRESSION_SUFFIX;
     }
-    return ExpressionConstant.EXPRESSION_PREFIX + fieldCode + ExpressionConstant.EXPRESSION_SUFFIX;
 }

+ 3 - 1
src/utils/constant.js

@@ -3,5 +3,7 @@ export default {
     MIN_SCALE: 0.25,
     MAX_SCALE: 2,
 
-    DATASOURCE_DRAG_KEY: "fieldCode"
+    DATASOURCE_DRAG_KEY: "fieldCode",
+
+    NONE: 'none'
 }