Kaynağa Gözat

完善table组件

zhoucg 1 yıl önce
ebeveyn
işleme
d4c57d6abb

+ 31 - 53
src/components/config/globalConfig.ts

@@ -1,4 +1,4 @@
-import {deepCopy} from '@/utils/html-util';
+import System from '@/utils/system';
 
 /** 纸张方向 */
 export const pageDirectionList = [
@@ -52,15 +52,29 @@ export const elementBands = [
     {name: 'Summary', code: 'summary', height: 30, isDefaultShow: false},
 ]
 
-const tableConfigTemplate = {
-    rowTemplate: {
-        rowNo: 1,
-        cols: {
-            1: {
-                colspan: 1,
-                rowspan: 1,
-                element: {}
-            }
+export const tableBands = [
+    {name: 'tableHeader', code: 'tableHeader'},
+    {name: 'columnHeader', code: 'columnHeader'},
+    {name: 'detail', code: 'detail'},
+    {name: 'columnFooter', code: 'columnFooter'},
+    {name: 'tableFooter', code: 'tableFooter'},
+]
+
+const tableColTemplate = {
+    colspan: 1,
+    rowspan: 1,
+    style: {
+        width: 80,
+        height: 30
+    },
+    element: {}
+}
+
+const tableRowTemplate = {
+    rowNo: 1,
+    cols: {
+        1: {
+            ...System.deepCopy(tableColTemplate)
         }
     }
 }
@@ -127,43 +141,6 @@ export const elementList = [
         },
         groupStyle: {}
     },
-    // {
-    //     icon: 'fa fa-text-height',
-    //     code: 'long-text',
-    //     name: '长文本',
-    //     component: 'YvanRichText',
-    //     propValue:
-    //         '<p><span style="font-size: 16pt;">双击</span><span style="color: rgb(255, 255, 255); background-color: #009688; font-size: 16pt; font-family: 仿宋;">编辑</span><span style="font-size: 16pt;">文本</span></p>',
-    //     style: {
-    //         width: 500,
-    //         height: 200,
-    //         fontSize: 12,
-    //         background: '#FFFFFF',
-    //         rotate: 0,
-    //         padding: '0',
-    //         borderWidth: 0,
-    //         borderPosition: [],
-    //         borderColor: '#FFFFFF',
-    //     },
-    //     groupStyle: {}
-    // },
-    // {
-    //     icon: 'fa fa-th',
-    //     code: 'table',
-    //     name: '简单表格',
-    //     component: 'YvanSimpleTable',
-    //     propValue: {},
-    //     style: {
-    //         width: 'auto',
-    //         height: 'auto',
-    //         fontSize: 12,
-    //         background: '#FFFFFF',
-    //         borderWidth: 2,
-    //         borderColor: '#212121',
-    //         rotate: 0
-    //     },
-    //     groupStyle: {}
-    // },
     {
         icon: 'fa fa-table',
         code: 'complex-table',
@@ -176,35 +153,35 @@ export const elementList = [
             tableHeader: {
                 rows: [
                     {
-                        ...deepCopy(tableConfigTemplate.rowTemplate)
+                        ...System.deepCopy(tableRowTemplate)
                     }
                 ]
             },
             columnHeader: {
                 rows: [
                     {
-                        ...deepCopy(tableConfigTemplate.rowTemplate)
+                        ...System.deepCopy(tableRowTemplate)
                     }
                 ]
             },
             detail: {
                 rows: [
                     {
-                        ...deepCopy(tableConfigTemplate.rowTemplate)
+                        ...System.deepCopy(tableRowTemplate)
                     }
                 ]
             },
             columnFooter: {
                 rows: [
                     {
-                        ...deepCopy(tableConfigTemplate.rowTemplate)
+                        ...System.deepCopy(tableRowTemplate)
                     }
                 ]
             },
             tableFooter: {
                 rows: [
                     {
-                        ...deepCopy(tableConfigTemplate.rowTemplate)
+                        ...System.deepCopy(tableRowTemplate)
                     }
                 ]
             },
@@ -434,6 +411,7 @@ export const componentList = [
 ]
 
 export {
-    tableConfigTemplate,
+    tableRowTemplate,
+    tableColTemplate,
     tableInnerElementCodes
 }

+ 28 - 17
src/components/elements/yvan-table/YvanComplexCell.vue

@@ -19,7 +19,7 @@
 import {globalStore} from "@/store";
 import System from "@/utils/system"
 import commonMixin from "@/mixin/commonMixin";
-import {tableInnerElementCodes} from "@/components/config/globalConfig";
+import {tableColTemplate, tableInnerElementCodes} from "@/components/config/globalConfig";
 
 export default {
   name: "YvanComplexCell",
@@ -51,6 +51,12 @@ export default {
       default: () => {
 
       }
+    },
+    col: {
+      type: Object,
+      default: () => {
+        return tableColTemplate
+      }
     }
   },
   data() {
@@ -59,27 +65,27 @@ export default {
       // mousedown的时候设置为其他值 否则都是-1
       // selectionHold: -1,
       // element: {}
-      tableCellWidth: 80,
-      tableCellHeight: 30,
+      // tableCellWidth: this.col.style.width,
+      // tableCellHeight: this.col.style.height,
     }
   },
   computed: {
     defaultStyle() {
-      console.log('defaultStyle > 222')
-      return `width: ${this.tableCellWidth}px; height: ${this.tableCellHeight}px;`;
+      return `width: ${this.col.style.width}px; height: ${this.col.style.height}px;`;
     }
   },
   mounted() {
-    const innerEle = this.innerElement;
-    if (!innerEle || !innerEle?.style) {
-      return;
-    }
-    this.tableCellWidth = innerEle.style?.width;
-    this.tableCellHeight = innerEle.style?.height;
+    // console.log('defaultStyle > ', this.col)
+    // const innerEle = this.innerElement;
+    // if (!innerEle || !innerEle?.style) {
+    //   return;
+    // }
+    // this.tableCellWidth = innerEle.style?.width;
+    // this.tableCellHeight = innerEle.style?.height;
   },
   methods: {
-    getIsActiveCell(row, col) {
-      return this.selectedCells.includes((row - 1) * this.tableConfig.cols + col - 1)
+    getActiveCell(row, col) {
+      // return this.selectedCells.includes((row - 1) * this.tableConfig.cols + col - 1)
     },
     handleDragOver(event) {
       event.dataTransfer.dropEffect = 'copy'
@@ -103,10 +109,10 @@ export default {
       element.id = this.getUuid()
       element.label = `${element.name}-${element.id}`
       element.bandCode = this.bandCode
-      element.style.width = this.tableCellWidth
-      element.style.height = this.tableCellHeight
+      element.style.width = this.col.style.width
+      element.style.height = this.col.style.height
       if (this.isQrCodeElement(element)) {
-        const defaultSize = Math.min(this.tableCellWidth, this.tableCellHeight)
+        const defaultSize = Math.min(this.col.style.width, this.col.style.height)
         element.style.width = defaultSize
         element.style.height = defaultSize
       }
@@ -123,7 +129,12 @@ export default {
       globalStore().recordSnapshot()
     },
     handleClick() {
-      console.log("=>", this.bandRowName, this.rowNo, this.colNo, this.innerElement)
+      globalStore().setSelectedTableCell({
+        bandRowName: this.bandRowName,
+        rowNo: this.rowNo,
+        colNo: this.colNo,
+        element: this.innerElement
+      })
     }
   },
 }

+ 4 - 0
src/components/elements/yvan-table/YvanComplexCol.vue

@@ -5,6 +5,7 @@
         :elementId="element.id"
         :bandRowName="bandRowName"
         :rowNo="row.rowNo"
+        :col="row.cols[col]"
         :colNo="col"
         :inner-element="row.cols[col]?.element"/>
   </td>
@@ -40,6 +41,9 @@ export default {
     columnTotal() {
       return this.element.config.columnNum
     },
+  },
+  methods: {
+
   }
 }
 </script>

+ 7 - 5
src/components/elements/yvan-table/YvanComplexTable.vue

@@ -2,11 +2,11 @@
   <div v-if="initCompleted" class="yvan-complex-table">
     <StyledComplexTable v-bind="style">
       <table class="yvan-complex-table__container" border="1">
-        <yvan-complex-row band-row-name="tableHeader" :element="element"/>
-        <yvan-complex-row band-row-name="columnHeader" :element="element"/>
-        <yvan-complex-row band-row-name="detail" :element="element"/>
-        <yvan-complex-row band-row-name="columnFooter" :element="element"/>
-        <yvan-complex-row band-row-name="tableFooter" :element="element"/>
+        <yvan-complex-row v-for="tableBand in tableBands" :band-row-name="tableBand.code" :element="element"/>
+        <!--<yvan-complex-row band-row-name="columnHeader" :element="element"/>-->
+        <!--<yvan-complex-row band-row-name="detail" :element="element"/>-->
+        <!--<yvan-complex-row band-row-name="columnFooter" :element="element"/>-->
+        <!--<yvan-complex-row band-row-name="tableFooter" :element="element"/>-->
       </table>
     </StyledComplexTable>
   </div>
@@ -16,6 +16,7 @@
 import {mapState} from 'pinia'
 import {globalStore} from "@/store"
 import commonMixin from '@/mixin/commonMixin'
+import {tableBands} from '@/components/config/globalConfig'
 import {StyledComplexTable} from '@/components/elements/style'
 import ResizeObserver from '@/components/elements/yvan-table/ResizeObserver'
 import YvanComplexCell from '@/components/elements/yvan-table/YvanComplexCell.vue'
@@ -137,6 +138,7 @@ export default {
   },
   data() {
     return {
+      tableBands,
       initCompleted: false,
       prefixTextElement: {},
       suffixTextElement: {},

+ 23 - 5
src/components/elements/yvan-table/YvanComplexTablePropsAttr.vue

@@ -1,7 +1,8 @@
 <template>
   <el-form ref="form" label-position="top">
     <el-form-item label="列数">
-      <el-input-number v-model="activeComponent.config.columnNum" :min="1" controls-position="right"/>
+      <el-input-number v-model="activeComponent.config.columnNum" :min="1" controls-position="right"
+                       @change="handleColNumChange"/>
     </el-form-item>
     <el-form-item label="设置数据源">
       <el-select v-model="activeComponent.config.datasetName" placeholder="请选择数据源" filterable>
@@ -65,7 +66,7 @@
 import {mapState} from "pinia";
 import {globalStore} from "@/store";
 import commonMixin from "@/mixin/commonMixin";
-import {fontList, borderTypeList, tableConfigTemplate} from "@/components/config/globalConfig";
+import {fontList, borderTypeList, tableRowTemplate} from "@/components/config/globalConfig";
 
 export default {
   name: "YvanComplexTablePropsAttr",
@@ -98,7 +99,7 @@ export default {
       return this.columnOptions[bandRowName];
     },
     addRow(bandRowName) {
-      const rowTemplate = this.deepCopy(tableConfigTemplate.rowTemplate)
+      const rowTemplate = this.deepCopy(tableRowTemplate)
       const rows = this.activeComponent.config[bandRowName].rows;
       rowTemplate.rowNo = rows.length + 1;
       this.activeComponent.config[bandRowName].rows.push(rowTemplate);
@@ -120,10 +121,27 @@ export default {
       this.activeComponent.config[bandRowName] = {
         rows: [
           {
-            ...tableConfigTemplate.rowTemplate
+            ...tableRowTemplate
           }
         ]
       }
+    },
+    handleColNumChange(newVal, oldVal) {
+      if (newVal > oldVal) {
+        console.log('handleColNumChange => ', newVal, oldVal)
+        globalStore().addTableCol({
+          bandCode: this.activeComponent.bandCode,
+          elementIdx: globalStore().curComponentIndex,
+          colNo: newVal
+        });
+        console.log('element >', globalStore().elementBands)
+        return;
+      }
+      globalStore().removeTableCol({
+        bandCode: this.activeComponent.bandCode,
+        elementIdx: globalStore().curComponentIndex,
+        colNo: oldVal
+      });
     }
   }
 }
@@ -137,4 +155,4 @@ export default {
 .fa:hover {
   cursor: pointer;
 }
-</style>
+</style>

+ 18 - 2
src/components/elements/yvan-table/YvanComplexTablePropsStyle.vue

@@ -1,5 +1,13 @@
 <template>
   <el-form ref="form" label-position="top">
+    <el-form-item label="单元格宽度">
+      <el-input-number :min="0" controls-position="right"/>
+    </el-form-item>
+    <el-form-item label="单元格高度">
+      <el-input-number :min="0" controls-position="right"/>
+    </el-form-item>
+
+
     <el-form-item label="背景颜色">
       <el-color-picker v-model="activeComponent.style.background"/>
     </el-form-item>
@@ -28,7 +36,7 @@
   </el-form>
 </template>
 
-<script>
+<script lang="js">
 import {mapState} from "pinia";
 import {globalStore} from "@/store";
 import {fontList, borderTypeList} from "@/components/config/globalConfig";
@@ -44,10 +52,18 @@ export default {
   computed: {
     ...mapState(globalStore, {
       activeComponent: (state) => {
-        console.log("activeComponent => ", state.curComponent)
         return state.curComponent
       }
     }),
+    activeCell() {
+      const selectedCell = globalStore().getSelectedTableCell();
+      // console.log("activeCell 1 => ", this.activeComponent, selectedCell)
+      // console.log("activeCell 2 => ", this.activeComponent.config[selectedCell.bandRowName].rows[selectedCell.rowNo - 1].cols[selectedCell.colNo].style.width)
+      // const cell = this.activeComponent.config[selectedCell.bandRowName].rows[selectedCell.rowNo].cols[selectedCell.colNo]
+      // console.log('activeCell 2 =>', cell)
+      // return cell
+      return this.activeComponent.config[selectedCell.bandRowName].rows[selectedCell.rowNo - 1].cols[selectedCell.colNo]
+    }
   },
 }
 </script>

+ 3 - 3
src/store/copy.ts

@@ -1,6 +1,6 @@
 import Utils from '@/utils/utils'
 import system from '@/utils/system'
-import {deepCopy} from '@/utils/html-util'
+import System from '@/utils/system'
 
 export default {
     state: {
@@ -73,7 +73,7 @@ export default {
 // 恢复上一次剪切的数据
 function restorePreCutData() {
     if (this.isCut && this.copyData) {
-        const data = deepCopy(this.copyData.data)
+        const data = System.deepCopy(this.copyData.data)
         const index = this.copyData.index
         // store.commit('addComponent', { component: data, index })
         if (this.curComponentIndex >= index) {
@@ -85,7 +85,7 @@ function restorePreCutData() {
 
 function copyData() {
     this.copyData = {
-        data: deepCopy(this.curComponent),
+        data: System.deepCopy(this.curComponent),
         index: this.curComponentIndex
     }
 }

+ 56 - 42
src/store/global.ts

@@ -1,3 +1,4 @@
+import _ from 'lodash'
 import {defineStore} from 'pinia'
 import copy from '@/store/copy'
 import lock from '@/store/lock'
@@ -8,6 +9,7 @@ import snapshot from '@/store/snapshot'
 import Constant from "@/utils/constant";
 import EditorUtils from '@/utils/EditorUtils'
 import {ruleStore} from "@/store/ruler-things";
+import {tableBands, tableColTemplate} from "@/components/config/globalConfig";
 
 export const globalStore = defineStore('global', {
     state: () => {
@@ -64,6 +66,12 @@ export const globalStore = defineStore('global', {
             // 如果没点中组件,并且在画布空白处弹起鼠标,则取消当前组件的选中状态
             isClickComponent: false,
             curTableSettingId: null,
+            selectedTableCell: {
+                bandRowName: "",
+                rowNo: -1,
+                colNo: -1,
+                element: {}
+            },
             editorMenuInfo: {
                 visible: false,
                 style: {
@@ -100,18 +108,18 @@ export const globalStore = defineStore('global', {
             this.curComponentIndex = index
             this.curTableCell = null
         },
-
-        setCurTableCell({component}) {
-            this.curTableCell = component
+        setSelectedTableCell({bandRowName, rowNo, colNo, element}) {
+            this.selectedTableCell = {bandRowName, rowNo, colNo, element}
+        },
+        getSelectedTableCell() {
+            return this.selectedTableCell;
         },
-
         setPageSize({pageWidth, pageHeight}) {
             this.pageConfig.pageWidth = pageWidth
             this.pageConfig.pageHeight = pageHeight
             ruleStore().setRect({pageWidth, pageHeight})
             ruleStore().setReDrawRuler()
         },
-
         togglePageDirection(pageDirection) {
             const pageConfig = this.pageConfig
             pageConfig.pageDirection = pageDirection
@@ -134,7 +142,6 @@ export const globalStore = defineStore('global', {
         updateDataValue({data, key, value}) {
             data[key] = value
         },
-
         setExpression({bandCode, expression, id}) {
             const elementBand = this.elementBands.get(bandCode)
             if (elementBand) {
@@ -155,7 +162,6 @@ export const globalStore = defineStore('global', {
             }
             this.curComponent.expression = expression;
         },
-
         setPropValue({propValue, id}) {
             const componentData = this.componentData
             if (this.componentData.length) {
@@ -197,15 +203,6 @@ export const globalStore = defineStore('global', {
         addDataSource(dataSource) {
             this.dataSources.push(dataSource);
         },
-
-        setDataSet(dataset) {
-            this.dataset = dataset
-        },
-
-        setCurTableSettingId(id) {
-            this.curTableSettingId = id
-        },
-
         setShapeStyle({top, left, width, height, rotate}) {
             if (top) {
                 this.curComponent.style.top = Math.round(top)
@@ -223,11 +220,9 @@ export const globalStore = defineStore('global', {
                 this.curComponent.style.rotate = Math.round(rotate)
             }
         },
-
         setShapeSingleStyle({key, value}) {
             this.curComponent.style[key] = value
         },
-
         setComponentData(componentData = []) {
             this.componentData = componentData
         },
@@ -299,27 +294,6 @@ export const globalStore = defineStore('global', {
                 elementBand.elements.splice(elementIdx, 1)
             }
         },
-        // addComponent({component, index}) {
-        //     if (index !== undefined) {
-        //         this.componentData.splice(index, 0, component)
-        //     } else {
-        //         this.componentData.push(component)
-        //     }
-        // },
-        // deleteComponent(index) {
-        //     if (index === undefined) {
-        //         index = this.curComponentIndex
-        //     }
-        //
-        //     if (index === this.curComponentIndex) {
-        //         this.curComponentIndex = null
-        //         this.curComponent = null
-        //     }
-        //
-        //     if (/\d/.test(index)) {
-        //         this.componentData.splice(index, 1)
-        //     }
-        // },
         addTableCellElement({bandCode, elementId, bandRowName, rowNo, colNo, element}) {
             const elementBand = this.elementBands.get(bandCode);
             // 数组角标从0开始
@@ -332,10 +306,8 @@ export const globalStore = defineStore('global', {
                 }
                 const col = tableElement.config[bandRowName].rows[rowNo].cols[colNo];
                 if (col) {
-                    console.log('col 1 =>>', col)
                     col.element = element
                 } else {
-                    console.log('col 2 =>>', col)
                     tableElement.config[bandRowName].rows[rowNo].cols[colNo] = {
                         colspan: 1,
                         rowspan: 1,
@@ -347,6 +319,48 @@ export const globalStore = defineStore('global', {
         deleteTableCellElement({bandRowName, rowNo, colNo}) {
 
         },
+        addTableCol({bandCode, elementIdx, colNo}) {
+            if (_.isEmpty(bandCode) || _.isNull(elementIdx)) {
+                console.error("bandCode or elementIdx must be not null");
+                return;
+            }
+            const element = this.elementBands.get(bandCode).elements[elementIdx];
+            if (!element) {
+                console.error("elementBand not found");
+                return;
+            }
+            for (let tableBand of tableBands) {
+                const tableBandCode = tableBand.code;
+                if (!Reflect.has(element.config, tableBandCode)) {
+                    continue
+                }
+                const rows = element.config[tableBandCode].rows
+                for (let row of rows) {
+                    row.cols[colNo] = tableColTemplate
+                }
+            }
+        },
+        removeTableCol({bandCode, elementIdx, colNo}) {
+            if (_.isEmpty(bandCode) || _.isNull(elementIdx)) {
+                console.error("bandCode or elementIdx must be not null");
+                return;
+            }
+            const element = this.elementBands.get(bandCode).elements[elementIdx];
+            if (!element) {
+                console.error("elementBand not found");
+                return;
+            }
+            for (let tableBand of tableBands) {
+                const tableBandCode = tableBand.code;
+                if (!Reflect.has(element.config, tableBandCode)) {
+                    continue
+                }
+                const rows = element.config[tableBandCode].rows
+                for (let row of rows) {
+                    Reflect.deleteProperty(row.cols, colNo)
+                }
+            }
+        },
         showEditorMenu({top, left}) {
             const editorMenuPos = EditorUtils.getEditorMenuPos(top, left);
             this.editorMenuInfo = {
@@ -372,4 +386,4 @@ export const globalStore = defineStore('global', {
             return this.pageConfig
         },
     }
-})
+})

+ 1 - 28
src/utils/html-util.js

@@ -1,31 +1,4 @@
-export function deepCopy(obj, cache = []) {
-    if (obj === null || typeof obj !== 'object') {
-        return obj
-    }
-    const objType = Object.prototype.toString.call(obj).slice(8, -1)
-    // 考虑 正则对象的copy
-    if (objType === 'RegExp') {
-        return new RegExp(obj)
-    }
-    // 考虑 Date 实例 copy
-    if (objType === 'Date') {
-        return new Date(obj)
-    }
-    // 考虑 Error 实例 copy
-    if (objType === 'Error') {
-        return new Error(obj)
-    }
-    const hit = cache.filter((c) => c.original === obj)[0]
-    if (hit) {
-        return hit.copy
-    }
-    const copy = Array.isArray(obj) ? [] : {}
-    cache.push({original: obj, copy})
-    Object.keys(obj).forEach((key) => {
-        copy[key] = deepCopy(obj[key], cache)
-    })
-    return copy
-}
+
 
 const components = ['YvanText', 'YvanRect', 'YvanCircle', 'YvanTran']
 

+ 30 - 1
src/utils/system.ts

@@ -65,6 +65,35 @@ class System {
         })
     }
 
+    public deepCopy(obj, cache = []) {
+        if (obj === null || typeof obj !== 'object') {
+            return obj
+        }
+        const objType = Object.prototype.toString.call(obj).slice(8, -1)
+        // 考虑 正则对象的copy
+        if (objType === 'RegExp') {
+            return new RegExp(obj)
+        }
+        // 考虑 Date 实例 copy
+        if (objType === 'Date') {
+            return new Date(obj)
+        }
+        // 考虑 Error 实例 copy
+        if (objType === 'Error') {
+            return new Error(obj)
+        }
+        const hit = cache.filter((c) => c.original === obj)[0]
+        if (hit) {
+            return hit.copy
+        }
+        const copy = Array.isArray(obj) ? [] : {}
+        cache.push({original: obj, copy})
+        Object.keys(obj).forEach((key) => {
+            copy[key] = this.deepCopy(obj[key], cache)
+        })
+        return copy
+    }
+
     /**
      * 打开对话框
      * @param fileUrl       转向网页的地址;
@@ -95,4 +124,4 @@ export default new System()
 export interface DialogProps {
     title: String,
     width: Number,
-}
+}