Browse Source

表格导出功能

yuliang 3 years ago
parent
commit
b227f7e9a9
5 changed files with 3215 additions and 61 deletions
  1. 2 1
      package.json
  2. 3 0
      src/Defaults.ts
  3. 167 1
      src/controls/grid.js
  4. 19 3
      src/controls/stores.js
  5. 3024 56
      yarn.lock

+ 2 - 1
package.json

@@ -49,6 +49,7 @@
     "echarts": "^5.1.2",
     "echarts": "^5.1.2",
     "recast": "^0.20.4",
     "recast": "^0.20.4",
     "jquery": "^3.6.0",
     "jquery": "^3.6.0",
-    "json5": "^2.2.0"
+    "json5": "^2.2.0",
+    "lay-excel": "^1.7.5"
   }
   }
 }
 }

+ 3 - 0
src/Defaults.ts

@@ -147,6 +147,9 @@ export const grid = {
     enableColumnResize: true,
     enableColumnResize: true,
     hidden: false,
     hidden: false,
     disabled: false,
     disabled: false,
+    exportExcelPageSize: 100,
+    exportExcelCurrentPage: 1,
+    exportExcelTotal: 0,
 }
 }
 
 
 export const fieldContainer = {
 export const fieldContainer = {

+ 167 - 1
src/controls/grid.js

@@ -2,6 +2,7 @@ import _ from 'lodash'
 import {grid} from '../Defaults'
 import {grid} from '../Defaults'
 import {baseConfig} from "./base";
 import {baseConfig} from "./base";
 import {lookupFn, lookupScope} from "../lib/lib";
 import {lookupFn, lookupScope} from "../lib/lib";
+import LAY_EXCEL from "lay-excel"
 import {serverInvokeUrlTransform} from "../lib/config";
 import {serverInvokeUrlTransform} from "../lib/config";
 import {calcObject, calcObjectFlat} from "../lib/systemLib";
 import {calcObject, calcObjectFlat} from "../lib/systemLib";
 import {
 import {
@@ -48,7 +49,10 @@ export default function () {
                 buttons.push({
                 buttons.push({
                     xtype: 'button',
                     xtype: 'button',
                     tooltip: '导出Excel',
                     tooltip: '导出Excel',
-                    iconCls: 'x-fa fa-download'
+                    iconCls: 'x-fa fa-download',
+                    listeners: {
+                        click: this.exportExcel
+                    },
                 })
                 })
             }
             }
             if (!newConfig.hideAutoSize) {
             if (!newConfig.hideAutoSize) {
@@ -218,6 +222,84 @@ export default function () {
             }
             }
         },
         },
 
 
+        exportExcel1(excelExportParams){
+            const me = this
+            const {config} = me
+            excelExportParams.isExcelExport = true
+            const scope = lookupScope(me)
+            const {dataSource} = config
+
+            let excelFileName = config.excelFileName || scope.vjson.title || _.uniqueId("excel-")
+
+            gridInvokeBuild(scope, me, config, dataSource, excelExportParams, true, (responseData)=>{
+                let page = parseInt(responseData.pagination.current)
+                const size = parseInt(responseData.pagination.size)
+                const total = parseInt(responseData.pagination.total)
+
+                me.exportExcelCurrentPage = page
+                me.exportExcelPageSize = size
+                me.exportExcelTotal = total
+
+                if (excelFileName.endsWith(".xlsx")) {
+                    excelFileName = excelFileName.split(".xlsx")[0]
+                }
+                excelFileName += "(第" + me.exportExcelCurrentPage + "页,共" + Math.ceil(total/size) + "页、" + total + "条)"
+                excelFileName += ".xlsx"
+                const excelData = me.makeExcelData(responseData.data)
+                LAY_EXCEL.exportExcel(excelData, excelFileName, 'xlsx')
+
+                if (page < total/size) {
+                    page ++
+                }
+            })
+        },
+
+        makeExcelData(jsonData) {
+
+            if (!Array.isArray(jsonData) || jsonData.length === 0) {
+                return
+            }
+            const me = this
+            const data = [];
+            // 获取表格的列定义
+            const headerTextArr = []
+            const headers = []
+            for (let i = 0; i < me.headerCt.getGridColumns().length; i++) {
+                const header = me.headerCt.getGridColumns()[i]
+                if (!header.isHidden()) {
+                    const textStr = _.trim(header.text)
+                    const dataIndexStr = _.trim(header.dataIndex)
+                    if (dataIndexStr) {
+                        if (textStr === '') {
+                            headerTextArr.push(dataIndexStr)
+                        } else {
+                            headerTextArr.push(textStr)
+                        }
+                        headers.push(header)
+                    }
+                }
+            }
+            if (headers.length === 0) {
+                return
+            }
+
+            data.push(headerTextArr)
+            for (let i = 0; i < jsonData.length; i++) {
+                const dataRow = jsonData[i]
+                const row = []
+                for (let j = 0; j < headers.length; j++) {
+                    const key = headers[j].dataIndex
+                    let value = dataRow[key]
+                    if (typeof headers[j].renderer === 'function') {
+                        value = headers[j].renderer(value)
+                    }
+                    row.push(value||"")
+                }
+                data.push(row)
+            }
+            return data
+        },
+
         initComponent() {
         initComponent() {
             const me = this
             const me = this
             const {config} = me
             const {config} = me
@@ -316,6 +398,90 @@ export default function () {
             }
             }
         },
         },
 
 
+        exportExcel(sender) {
+            const rect = sender.btnEl.dom.getBoundingClientRect()
+            const scope = lookupScope(this)
+            const grid = sender.up('grid')
+            const treeMenu = new Ext.menu.Menu(
+                {
+                    xtype: 'menu',
+                    floated: false,
+                    width: 300,
+                    docked: 'left',
+                    items: [{
+                        xtype: "textfield",
+                        fieldLabel: '当前导出页',
+                        maskRe: /[0-9]/,
+                        value: grid.exportExcelCurrentPage,
+                        listeners: {
+                            render: (sender)=>{
+                                grid.exportExcelCurrentPageCmp = sender
+                            },
+                            change: (sender, value)=> {
+                                let v = parseInt(value)
+                                if (isNaN(v) || v === 0) {
+                                    window['system'].msg("页码不能为0")
+                                    v = 1
+                                    sender.setValue(v)
+                                }
+                                const size = parseInt(grid.exportExcelPageSize)
+                                const total = parseInt(grid.exportExcelTotal)
+                                if (v > total/size) {
+                                    v = parseInt(total/size + "")
+                                }
+                                grid.exportExcelCurrentPage = v + ""
+                            }
+                        }
+                    }, {
+                        xtype: "textfield",
+                        fieldLabel: '导出页大小',
+                        maskRe: /[0-9]/,
+                        value: grid.exportExcelPageSize,
+                        listeners: {
+                            render: (sender)=>{
+                                grid.exportExcelPageSizeCmp = sender
+                            },
+                            change: (sender, value)=> {
+                                let v = parseInt(value)
+                                if (isNaN(v) || v === 0) {
+                                    window['system'].msg("导出页大小不能为0")
+                                    v = 1000
+                                    sender.setValue(v);
+                                }
+                                let page = parseInt(grid.exportExcelCurrentPage)
+                                const total = parseInt(grid.exportExcelTotal)
+                                if (page > total/v) {
+                                    page = parseInt(total/v + "") + 1
+                                    grid.exportExcelCurrentPageCmp.setValue(page)
+                                }
+                                grid.exportExcelPageSize = v + ""
+                            }
+                        }
+                    }, {
+                        xtype: "textfield",
+                        fieldLabel: '总条数',
+                        value: grid.exportExcelTotal,
+                        readOnly: true
+                    }, {
+
+                        text: '导出',
+                        iconCls: 'x-fa fa-download',
+                        listeners: {
+                            click: (sender, value)=> {
+                                grid.exportExcel1({exportExcelPageSize: grid.exportExcelPageSize, exportExcelCurrentPage: grid.exportExcelCurrentPage})
+                            }
+                        }
+                    }]
+                }
+            );
+            treeMenu.showAt(rect.left, rect.top - 120);
+
+            // for (let i = 1; i < grid.headerCt.getColumnCount(); i++) {
+            //     grid.headerCt.getGridColumns()[i].autoSize(i);
+            //     grid.headerCt.getGridColumns()[i].setWidth(grid.headerCt.getGridColumns()[i].getWidth() + 15);
+            // }
+        }
+
         // reload() {
         // reload() {
         //     dataSourceReload(this)
         //     dataSourceReload(this)
         // },
         // },

+ 19 - 3
src/controls/stores.js

@@ -6,7 +6,7 @@ import {calcObjectFlat} from '../lib/systemLib'
 /**
 /**
  * 构建一个 grid 支持的 dataSource
  * 构建一个 grid 支持的 dataSource
  */
  */
-export function gridInvokeBuild(scope, grid, config, dataSource, reloadParams = {}) {
+export function gridInvokeBuild(scope, grid, config, dataSource, reloadParams = {}, isExcelExport = false, excelExportCallBack = null) {
     const me = grid
     const me = grid
     const params = calcObjectFlat(scope.viewModel.data, dataSource.params)
     const params = calcObjectFlat(scope.viewModel.data, dataSource.params)
     let storeOption = {}
     let storeOption = {}
@@ -42,7 +42,18 @@ export function gridInvokeBuild(scope, grid, config, dataSource, reloadParams =
             },
             },
             listeners: {
             listeners: {
                 load: function (store, records, successful, operation) {
                 load: function (store, records, successful, operation) {
-                    me.fireEvent('dataLoadComplete', me, successful, records);
+                    const rep = operation.getResponse().responseJson
+                    me.exportExcelTotal = rep.pagination.total
+                    if (isExcelExport) {
+                        if (typeof excelExportCallBack === 'function') {
+                            excelExportCallBack(rep);
+                        } else if (excelExportCallBack) {
+                            console.error("导出回调方法错误!")
+                        }
+                        me.fireEvent('excelDataLoadComplete', me, successful, records);
+                    } else {
+                        me.fireEvent('dataLoadComplete', me, successful, records);
+                    }
                 }
                 }
             }
             }
         }
         }
@@ -55,7 +66,12 @@ export function gridInvokeBuild(scope, grid, config, dataSource, reloadParams =
         throw new TypeError("不支持的 API 请求方式")
         throw new TypeError("不支持的 API 请求方式")
     }
     }
 
 
-    me.setStore(new Ext.data.Store(storeOption))
+    if (isExcelExport) {
+        const excelStore = new Ext.data.Store(storeOption);
+        excelStore.load()
+    } else {
+        me.setStore(new Ext.data.Store(storeOption))
+    }
 }
 }
 
 
 export default function () {
 export default function () {

File diff suppressed because it is too large
+ 3024 - 56
yarn.lock