Parcourir la source

报表导出Excel样式调整

zhuth il y a 6 ans
Parent
commit
82a27fbfe1
3 fichiers modifiés avec 152 ajouts et 22 suppressions
  1. 1 1
      .webpackrc
  2. 2 2
      src/models/dashboardDesigner.js
  3. 149 19
      src/utils/exportor.js

+ 1 - 1
.webpackrc

@@ -3,7 +3,7 @@
         ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": true }]
     ],
     "disableCSSModules": true,
-    "hash": true,
+    "hash": false,
     "html": {
         "favicon": "./static/images/favicon.png",
         "template": "./src/index.ejs"

+ 2 - 2
src/models/dashboardDesigner.js

@@ -744,7 +744,7 @@ export default {
             const dashboardDesigner = yield select(state => state.present.dashboardDesigner);
             const { name, creatorCode, filters, items } = dashboardDesigner;
             try {
-                yield put({ type: 'dashboardDesigner/setField', name: 'loading', value: true });
+                yield put({ type: 'setField', name: 'loading', value: true });
 
                 let sheets = [];
                 for(let i = 0; i < items.length; i++) {
@@ -923,7 +923,7 @@ export default {
             }catch(e) {
                 message.error('报表导出错误: ' + e);
             }finally {
-                yield put({ type: 'dashboardDesigner/setField', name: 'loading', value: false });
+                yield put({ type: 'setField', name: 'loading', value: false });
             }
         }
     },

+ 149 - 19
src/utils/exportor.js

@@ -9,23 +9,51 @@
                 + '<Author>{author}</Author>'
                 + '<Created>{created}</Created>'
             +'</DocumentProperties>'
-            + '{styles}'
+            + '<Styles>{styles}</Styles>'
             + '{worksheets}'
         + '</Workbook>',
-    tmpStyleXML = '<Styles>'
-        + '<Style ss:ID="Bold"><Font ss:Bold="1"/></Style>'
-        + '<Style ss:ID="Currency"><NumberFormat ss:Format="Currency"></NumberFormat></Style>'
-        + '<Style ss:ID="Date"><NumberFormat ss:Format="yyyy-mm-dd"></NumberFormat></Style>'
-        + '<Style ss:ID="Center"><Alignment ss:Horizontal="Center" ss:Vertical="Center"/></Style>'
-    + '</Styles>',
     tmplWorksheetXML = '<Worksheet ss:Name="{nameWS}"><Table>{columnWidth}{rows}</Table></Worksheet>',
     tmplColumnWidthXML = '<Column ss:Width="{width}"/>',
-    tmplTableHeaderXML = '<Row><Cell ss:StyleID="Center" ss:MergeAcross="{columnCount}"><Data ss:Type="String">{header}</Data></Cell></Row>',
+    tmplTableHeaderXML = '<Row><Cell ss:StyleID="{styleID}" ss:MergeAcross="{columnCount}"><Data ss:Type="String">{header}</Data></Cell></Row>',
     tmplRowXML = '<Row>{cells}</Row>',
     tmplCellXML = '<Cell{attributeStyleID}{attributeFormula}><Data ss:Type="{nameType}">{data}</Data></Cell>',
     _defaultStyleIDs = {
-        DateTime: 'Date',
+        DateTime: 'date',
     },
+    tmplStyleXML = '<Style ss:ID="{styleID}">{styleNode}</Style>',
+    tmplStyleNodeXML = '<{nodeName} {attributes}></{nodeName}>',
+    tmplStyleNodeAttributeXML = 'ss:{key}="{value}"',
+    styleConfig = [{
+        name: "Date",
+        tag: "NumberFormat",
+        key: "Format",
+        value: "yyyy-mm-dd"
+    }, {
+        name: "bold",
+        tag: "Font",
+        key: "Bold",
+        value: "1"
+    }, {
+        name: "center",
+        tag: ["Alignment"],
+        key: [["Horizontal", "Vertical"]],
+        value: [["Center", "Center"]]
+    }, {
+        name: "header",
+        tag: ["Font", "Interior"],
+        key: ["Color", ["Color", "Pattern"]],
+        value: ["#FFFFFF", ["#70AD47", "Solid"]]
+    }, {
+        name: "even",
+        tag: ["Interior"],
+        key: [["Color", "Pattern"]],
+        value: [["#C6E0B4", "Solid"]]
+    }, {
+        name: "odd",
+        tag: ["Interior"],
+        key: [["Color", "Pattern"]],
+        value: [["#A9D08E", "Solid"]]
+    }],
     _format = function(s, c) { return s.replace(/{(\w+)}/g, function(m, p) { return c[p]; }) },
     _export = function(workbookXML, wbname) {
         var eleLink = document.createElement('a');
@@ -47,18 +75,28 @@
         this.json = json;
         this.wbname = wbname;
         this.workbookXML = '';
+        this.styleID = 1;
+        this.styles = [];
     };
 
     Exportor.prototype.generateWorkbookXML = function() {
         let ctx = {
             worksheets: this.generateWorksheetsXML(),
-            styles: tmpStyleXML,
-            author: 'zhuth',
-            created: 'zhuth'
+            styles: this.generateStylesXML(),
+            author: 'usoftchina',
+            created: new Date().getTime()
         };
         return _format(tmplWorkbookXML, ctx);
     };
 
+    Exportor.prototype.generateStylesXML = function() {
+        let str = '';
+        for(let i = 0; i < this.styles.length; i++) {
+            str += this.generateStyles(this.styles[i].styleID, this.styles[i].styleNames);
+        }
+        return str;
+    };
+
     Exportor.prototype.generateWorksheetsXML = function() {
         let str = '',
             sheets = this.json.sheets;
@@ -85,7 +123,9 @@
     Exportor.prototype.generateTableHeaderXML = function(header, columnCount) {
         let str = '';
         if(!!header) {
+            let styleID = this.addStyle(['center', 'header']);
             let ctx = {
+                styleID: styleID,
                 columnCount: columnCount - 1,
                 header
             }
@@ -106,7 +146,7 @@
     };
 
     Exportor.prototype.generateHeaderRowsXML = function(columns) {
-        let cells = columns.map(c => ({ type: 'String', value: c.name, styleID: 'Bold' }));
+        let cells = columns.map(c => ({ type: 'String', value: c.name, styleNames: ['header', 'bold'] }));
         let ctx = {
             cells: this.generateCellsXML(cells)
         };
@@ -115,16 +155,18 @@
     };
 
     Exportor.prototype.generateRowsXML = function(columns, rows) {
-        let cols = columns.map(c => ({ type: c.type, name: c.name, styleID: c.styleID }));
+        let cols = columns.map(c => ({ type: c.type, name: c.name, styleNames: c.styleNames }));
         let str = '';
         for(let i = 0; i < rows.length; i++) {
             let r = rows[i];
             let cells = [];
+            let s = (i&1) === 0 ? 'even' : 'odd';
             for(let j = 0; j < cols.length; j++) {
+                cols[j].styleNames = cols[j].styleNames && cols[j].styleNames.length>0 ? cols[j].styleNames: [];
                 cells.push({
                     type: cols[j].type,
                     value: r[j],
-                    styleID: cols[j].styleID || _defaultStyleIDs[cols[j].type]
+                    styleNames: [s].concat(cols[j].styleNames.concat(_defaultStyleIDs[cols[j].type] ? [_defaultStyleIDs[cols[j].type]] : []))
                 });
             }
             let ctx = {
@@ -138,9 +180,10 @@
     Exportor.prototype.generateCellsXML = function(cells) {
         let str = '';
         for(let i = 0; i < cells.length; i++) {
+            let styleID = this.addStyle(cells[i].styleNames);
             let ctx = {
-                attributeStyleID: cells[i].styleID ? _format(' ss:StyleID="{styleID}"', {
-                    styleID: cells[i].styleID
+                attributeStyleID: cells[i].styleNames && cells[i].styleNames.length > 0 ? _format(' ss:StyleID="{styleID}"', {
+                    styleID: styleID
                 }) : '',
                 attributeFormula: '',
                 nameType: cells[i].type || 'String',
@@ -151,10 +194,97 @@
         return str;
     };
 
+    Exportor.prototype.addStyle = function(styleNames) {
+        if(!styleNames || styleNames.length === 0) {
+            return;
+        }
+        let s1 = styleNames.sort();
+        let idx = -1; // 是否已存在
+        outer:
+        for(let i = 0; i < this.styles.length; i++) {
+            let style = this.styles[i];
+            let s2 = style.styleNames.sort();
+            if(s1.length !== s2.length) {
+                continue;
+            }
+            for(let j = 0; j < s1.length; j++) {
+                if(s1[j] !== s2[j]) {
+                    continue outer;
+                }
+            }
+            idx = i;
+        }
+        if(idx === -1) {
+            let styleID = 's' + this.styleID++
+            this.styles.push({
+                styleID: styleID,
+                styleNames: styleNames
+            });
+            return styleID;
+        }else {
+            return this.styles[idx].styleID;
+        }
+    };
+
+    Exportor.prototype.generateStyles = function(styleID, styleNames) {
+        let configs = styleNames.map(name => styleConfig.find(s => s.name === name)).filter(c => !!c);
+        let str = '';
+        let obj = {};
+        for(let i = 0; i < configs.length; i++) {
+            let config = configs[i];
+            let tags = Object.prototype.toString.call(config.tag) === "[object Array]" ? config.tag : [config.tag];
+            let keyss = Object.prototype.toString.call(config.key) === "[object Array]" ? config.key : [config.key];
+            let valuess = Object.prototype.toString.call(config.value) === "[object Array]" ? config.value : [config.value];
+            for(let t = 0; t < tags.length; t++) {
+                let tag = tags[t];
+                let keys = Object.prototype.toString.call(keyss[t]) === "[object Array]" ? keyss[t] : [keyss[t]];
+                let values = Object.prototype.toString.call(valuess[t]) === "[object Array]" ? valuess[t] : [valuess[t]];
+                for(let k = 0; k < keys.length; k++) {
+                    let key = keys[k];
+                    let value = values[k];
+                    obj[tag] = obj[tag] || {};
+                    obj[tag][key] = value;
+                }
+            }
+        }
+        str = this.generateStyle(styleID, obj);
+        return str;
+    };
+
+    Exportor.prototype.generateStyle = function(styleID, styleConfig) {
+        let str = '';
+        str = _format(tmplStyleXML, {
+            styleID: styleID,
+            styleNode: this.generateStyleNode(styleConfig)
+        })
+        return str;
+    };
+
+    Exportor.prototype.generateStyleNode = function(styleConfig) {
+        let str = '';
+        for(let k in styleConfig) {
+            str += _format(tmplStyleNodeXML, {
+                nodeName: k,
+                attributes: this.generateStyleNodeAttribute(styleConfig[k])
+            })
+        }
+        return str;
+    };
+
+    Exportor.prototype.generateStyleNodeAttribute = function(styleNodeConfig) {
+        let str = '';
+        for(let k in styleNodeConfig) {
+            str += _format(tmplStyleNodeAttributeXML, {
+                key: k,
+                value: styleNodeConfig[k]
+            })
+        }
+        return str;
+    };
+
     Exportor.prototype.export = function() {
-        console.log(this.workbookXML);
         _export(this.workbookXML, this.wbname);
-    }
+    };
 
     return Exportor;