|
@@ -0,0 +1,307 @@
|
|
|
+<template>
|
|
|
+ <div class="yvan-component-band">
|
|
|
+ <div
|
|
|
+ ref="topLineRef"
|
|
|
+ v-if="isFirst"
|
|
|
+ name="topLine"
|
|
|
+ class="yvan-component-layout__top"
|
|
|
+ :style="getTopLineStyle"
|
|
|
+ @mouseenter.stop="handleLineMouseEnter($event)"
|
|
|
+ @mousedown.stop="handleLineMouseDown($event)"/>
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="yvan-component-layout__main"
|
|
|
+ :style="getBandStyle"
|
|
|
+ @dragover.prevent="handleDragOver"
|
|
|
+ @drop.stop.prevent="handleDrop"
|
|
|
+ @mousedown.stop="handleMouseDown"
|
|
|
+ @mouseup="deselectCurComponent">
|
|
|
+
|
|
|
+ <span
|
|
|
+ class="yvan-component-layout__title"
|
|
|
+ :style="getBandTitleStyle">{{ bandName }}</span>
|
|
|
+
|
|
|
+ <div class="yvan-component-adjuster">
|
|
|
+ <ComponentAdjuster
|
|
|
+ v-for="(item, index) in getElements"
|
|
|
+ :key="item.id"
|
|
|
+ :bandCode="bandCode"
|
|
|
+ :active="item.id === (curComponent || {}).id"
|
|
|
+ :class="{ lock: item.isLock }"
|
|
|
+ :default-style="item.style"
|
|
|
+ :element="item"
|
|
|
+ :index="index"
|
|
|
+ :scale="scale"
|
|
|
+ :style="getShapeStyle(item.style)"
|
|
|
+ >
|
|
|
+ <component
|
|
|
+ :is="item.component"
|
|
|
+ :id="'yvan-print-component-' + item.id"
|
|
|
+ :active="item.id === (curComponent || {}).id"
|
|
|
+ :bind-value="item.bindValue"
|
|
|
+ :element="item"
|
|
|
+ :prop-value="item.propValue"
|
|
|
+ :scale="scale"
|
|
|
+ />
|
|
|
+ </ComponentAdjuster>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ ref="bottomLineRef"
|
|
|
+ name="bottomLine"
|
|
|
+ class="yvan-component-layout__bottom"
|
|
|
+ :style="getBottomLineStyle"
|
|
|
+ @mouseenter.stop="handleLineMouseEnter($event)"
|
|
|
+ @mousedown.stop="handleLineMouseDown($event)"/>
|
|
|
+
|
|
|
+ <!--<div-->
|
|
|
+ <!-- class="yvan-component-layout__mark"-->
|
|
|
+ <!-- :style="calcMarkStyle"-->
|
|
|
+ <!--/>-->
|
|
|
+
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import Big from "big.js";
|
|
|
+import {mapActions, mapState} from "pinia";
|
|
|
+import {globalStore, modeStore, ruleStore} from "@/store";
|
|
|
+import commonMixin from '@/mixin/commonMixin';
|
|
|
+import {getComponentRotatedStyle, getShapeStyle} from '@/utils/style-util.js';
|
|
|
+import ComponentAdjuster from '@/components/yvan-editor/ComponentAdjuster.vue';
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: "ComponentBand",
|
|
|
+ mixins: [commonMixin],
|
|
|
+ components: {
|
|
|
+ ComponentAdjuster
|
|
|
+ },
|
|
|
+ props: {
|
|
|
+ bandName: {
|
|
|
+ type: String,
|
|
|
+ default: ""
|
|
|
+ },
|
|
|
+ bandCode: {
|
|
|
+ type: String,
|
|
|
+ default: ""
|
|
|
+ },
|
|
|
+ bandHeight: {
|
|
|
+ type: Number,
|
|
|
+ default: 40
|
|
|
+ },
|
|
|
+ usedHeight: {
|
|
|
+ type: Number,
|
|
|
+ default: 0
|
|
|
+ },
|
|
|
+ isFirst: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ index: {
|
|
|
+ type: Number,
|
|
|
+ default: 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ layoutRef: null,
|
|
|
+ topLineRef: null,
|
|
|
+ bottomLineRef: null,
|
|
|
+ innerBandTop: 0,
|
|
|
+ innerBandHeight: 0,
|
|
|
+ activeLine: null,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ...mapState(globalStore, {
|
|
|
+ componentData: (state) => state.componentData,
|
|
|
+ elementBands: (state) => state.elementBands,
|
|
|
+ curComponent: (state) => state.curComponent,
|
|
|
+ editor: (state) => state.editor,
|
|
|
+ isClickComponent: (store) => store.isClickComponent,
|
|
|
+ pageConfig: (state) => state.pageConfig
|
|
|
+ }),
|
|
|
+ ...mapState(ruleStore, {
|
|
|
+ realScale: (state) => state.scale,
|
|
|
+ rectWidth: (state) => state.rectWidth,
|
|
|
+ rectHeight: (state) => state.rectHeight,
|
|
|
+ needReDrawRuler: (state) => state.needReDrawRuler,
|
|
|
+ showRuler: (state) => state.showRuler,
|
|
|
+ }),
|
|
|
+ scale() {
|
|
|
+ return new Big(this.realScale).div(new Big(5)).toNumber()
|
|
|
+ },
|
|
|
+ getElements(){
|
|
|
+ const elementBand = this.elementBands ? this.elementBands.get(this.bandCode) : {}
|
|
|
+ return elementBand?.elements;
|
|
|
+ },
|
|
|
+ getTopLineStyle() {
|
|
|
+ const bandTop = this.innerBandTop;
|
|
|
+ return `top: ${bandTop}px;`;
|
|
|
+ },
|
|
|
+ getBottomLineStyle() {
|
|
|
+ const bottomLineTop = Number(this.innerBandTop) + Number(this.innerBandHeight);
|
|
|
+ return `top: ${bottomLineTop}px;`;
|
|
|
+ },
|
|
|
+ getBandStyle() {
|
|
|
+ const styles = [];
|
|
|
+ styles.push(`top: ${this.innerBandTop}px`)
|
|
|
+ styles.push(`height: ${this.innerBandHeight}px`)
|
|
|
+ return styles.join(';');
|
|
|
+ },
|
|
|
+ getBandTitleStyle() {
|
|
|
+ const styles = [];
|
|
|
+ styles.push(`line-height: ${this.innerBandHeight}px`)
|
|
|
+ return styles.join(';');
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.layoutRef = this.$refs.layoutRef;
|
|
|
+ this.topLineRef = this.$refs.topLineRef;
|
|
|
+ this.bottomLineRef = this.$refs.bottomLineRef;
|
|
|
+
|
|
|
+ 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)
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ ...mapActions(globalStore, ['getElementBandByCode']),
|
|
|
+ getShapeStyle,
|
|
|
+ handleDragOver(event) {
|
|
|
+ event.dataTransfer.dropEffect = 'copy'
|
|
|
+ },
|
|
|
+ handleDrop(event) {
|
|
|
+ const elementCode = event.dataTransfer.getData('componentCode')
|
|
|
+ const rectInfo = document.querySelector('#designer-page').getBoundingClientRect()
|
|
|
+ if (elementCode) {
|
|
|
+ const element = this.deepCopy(this.findElementByCode(elementCode))
|
|
|
+ element.style = element.style ?? {}
|
|
|
+ element.style.top = event.clientY - rectInfo.y - this.innerBandTop
|
|
|
+ element.style.y = event.clientY - rectInfo.y
|
|
|
+ element.style.left = event.clientX - rectInfo.x
|
|
|
+ element.style.x = element.style.left
|
|
|
+ element.id = this.getUuid()
|
|
|
+ element.label = `${element.name}-${element.id}`
|
|
|
+ globalStore().addElement({bandCode: this.bandCode, element: element})
|
|
|
+ globalStore().recordSnapshot()
|
|
|
+ } else {
|
|
|
+ window['system'].toast('拖拽元素非页面组件,此次拖拽无效', 'info')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleMouseDown(event) {
|
|
|
+ globalStore().setClickComponentStatus(false)
|
|
|
+ globalStore().setInEditorStatus(false)
|
|
|
+ },
|
|
|
+ deselectCurComponent() {
|
|
|
+ if (!this.isClickComponent) {
|
|
|
+ globalStore().hideEditorMenu()
|
|
|
+ globalStore().setCurComponent({component: null, index: null})
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleLineMouseDown(event) {
|
|
|
+ // 获取画布位移信息
|
|
|
+ const editorRectInfo = this.editor.getBoundingClientRect();
|
|
|
+ // 获取 point 与实际拖动基准点的差值
|
|
|
+ // const pointRect = event.target.getBoundingClientRect();
|
|
|
+
|
|
|
+ const targetName = event.target.attributes['name'].value;
|
|
|
+ const pageHeight = this.pageConfig.pageHeight * this.realScale;
|
|
|
+ const innerBandHeight = this.innerBandHeight;
|
|
|
+ let changeHeight = 0;
|
|
|
+
|
|
|
+ const move = (moveEvent) => {
|
|
|
+ let curPosY = (moveEvent.clientY - Math.round(editorRectInfo.top)) / this.scale;
|
|
|
+ // const curPosX = (moveEvent.clientX - Math.round(editorRectInfo.left)) / this.scale;
|
|
|
+ if (curPosY <= 0) {
|
|
|
+ curPosY = 0
|
|
|
+ }
|
|
|
+ if (curPosY >= pageHeight) {
|
|
|
+ curPosY = pageHeight;
|
|
|
+ }
|
|
|
+ // const curPosition = {x: curPosX, y: curPosY}
|
|
|
+ if (targetName === 'bottomLine') {
|
|
|
+ if (curPosY <= this.innerBandTop) {
|
|
|
+ curPosY = this.innerBandTop + 2;
|
|
|
+ }
|
|
|
+ changeHeight = curPosY - (this.innerBandTop + innerBandHeight)
|
|
|
+ this.innerBandHeight = curPosY - this.innerBandTop;
|
|
|
+ }
|
|
|
+ if (targetName === 'topLine') {
|
|
|
+ const originBandTop = this.innerBandTop;
|
|
|
+ const originBottomLineTop = this.innerBandHeight + originBandTop;
|
|
|
+ if (curPosY >= originBottomLineTop) {
|
|
|
+ curPosY = originBottomLineTop - 2;
|
|
|
+ }
|
|
|
+ this.innerBandTop = curPosY;
|
|
|
+ this.innerBandHeight = this.innerBandHeight + originBandTop - curPosY;
|
|
|
+ }
|
|
|
+ event.target.style.top = `${curPosY}px`;
|
|
|
+ globalStore().changeBandHeight({
|
|
|
+ code: this.bandCode,
|
|
|
+ height: new Big(this.innerBandHeight).div(this.realScale).toNumber()
|
|
|
+ });
|
|
|
+ }
|
|
|
+ const up = () => {
|
|
|
+ document.removeEventListener('mousemove', move)
|
|
|
+ document.removeEventListener('mouseup', up)
|
|
|
+ this.$emit("changeElementBandTop", {
|
|
|
+ currentElementBand: {},
|
|
|
+ changeHeight: changeHeight,
|
|
|
+ movePos: targetName,
|
|
|
+ index: this.index
|
|
|
+ })
|
|
|
+ }
|
|
|
+ document.addEventListener('mousemove', move)
|
|
|
+ document.addEventListener('mouseup', up)
|
|
|
+ },
|
|
|
+ handleLineMouseEnter(event) {
|
|
|
+ if (!this.isFirst) {
|
|
|
+ event.target.style.cursor = "n-resize";
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const targetName = event.target.attributes['name'].value;
|
|
|
+ if (this.isFirst && targetName !== 'topLine') {
|
|
|
+ event.target.style.cursor = "n-resize";
|
|
|
+ }
|
|
|
+ },
|
|
|
+ changeTop(changeHeight) {
|
|
|
+ const originBandTop = this.innerBandTop;
|
|
|
+ this.innerBandTop = originBandTop + changeHeight;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="less">
|
|
|
+
|
|
|
+.yvan-component-band {
|
|
|
+
|
|
|
+ .yvan-component-layout__top, .yvan-component-layout__bottom {
|
|
|
+ position: absolute;
|
|
|
+ border-top: 1px dashed #ccc;
|
|
|
+ width: 100%;
|
|
|
+ z-index: 100;
|
|
|
+ }
|
|
|
+
|
|
|
+ .yvan-component-layout__main {
|
|
|
+ border-left: 3px solid var(--yvan-menu-bar-background);
|
|
|
+ position: absolute;
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ .yvan-component-layout__title {
|
|
|
+ margin: auto;
|
|
|
+ color: #ccc;
|
|
|
+ user-select: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .yvan-component-layout__mark {
|
|
|
+ border-left: 3px solid var(--yvan-menu-bar-background);
|
|
|
+ margin-left: -3px;
|
|
|
+ width: 3px;
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|