TonyKang 8 lat temu
rodzic
commit
94be063ac5

+ 2 - 0
config/cacheCfg.js

@@ -2,11 +2,13 @@
  * Created by Tony on 2017/3/24.
  */
 var rptUtil = require("../modules/reports/util/rpt_util");
+var stdTypesUtil = require("../public/cache/std_glj_type_util");
 //rptUtil.setReportDefaultCache();
 
 module.exports = {
     setupDftCache: function() {
         rptUtil.setReportDefaultCache();
+        stdTypesUtil.setStdGljTypeCache();
         //and others...(if any)
     }
 }

+ 23 - 0
modules/reports/controllers/rpt_cfg_controller.js

@@ -0,0 +1,23 @@
+/**
+ * Created by Tony on 2017/7/5.
+ */
+
+let cache = require('../../../public/cache/cacheUtil');
+let rpt_util = require('../util/rpt_util');
+let Rpt_Cfg_Mdl = require('../models/rpt_cfg');
+
+const RPT_CFG_GRP = 'rpt_cfg';
+
+//统一回调函数
+let callback = function(req, res, err, message, data){
+    res.json({error: err, message: message, data: data});
+}
+
+module.exports = {
+    getReportUserCfg: function(req, res){
+        let userId = req.body.userId;
+        rpt_util.getReportCacheByUser(userId, function(rst_cfg){
+            callback(req,res,false,"", rst_cfg);
+        });
+    }
+};

+ 5 - 0
modules/reports/controllers/rpt_tpl_controller.js

@@ -10,6 +10,8 @@ let TreeNodeModel = require('../models/tpl_tree_node');
 let rptTplDef = require("../../../public/rpt_tpl_def").getUtil();
 let stringUtil = require("../../../public/stringUtil");
 
+//let test_glj_type_util = require("../../../public/cache/std_glj_type_util");
+
 //统一回调函数
 let callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});
@@ -33,6 +35,9 @@ module.exports = {
                 callback(req,res, true,"", null);
             } else callback(req,res,false,"", data);
         });
+        // let obj = test_glj_type_util.getStdGljTypeCacheObj();
+        // console.log(obj.toArray());
+        // console.log(obj.getItemById(1));
     },
     updateTreeNodes: function(req, res) {
         let params = JSON.parse(req.body.params),

+ 3 - 0
modules/reports/routes/rpt_tpl_router.js

@@ -1,6 +1,7 @@
 let express = require("express");
 let rptTplRouter = express.Router();
 let reportTplController = require('./../controllers/rpt_tpl_controller');
+let reportCfgController = require('./../controllers/rpt_cfg_controller');
 
 rptTplRouter.post('/createTplTreeNode', reportTplController.createTplTreeNode);
 rptTplRouter.post('/getRptTplTree', reportTplController.getRptTplTree);
@@ -9,4 +10,6 @@ rptTplRouter.post('/deleteRptTplNodes', reportTplController.deleteRptTplNodes);
 rptTplRouter.post('/createDftRptTpl', reportTplController.createDftRptTpl);
 rptTplRouter.post('/getRefRptTpl', reportTplController.getRefRptTpl);
 
+rptTplRouter.post('/getUserRptCfg', reportCfgController.getReportUserCfg);
+
 module.exports = rptTplRouter;

+ 29 - 14
modules/reports/util/rpt_util.js

@@ -8,9 +8,9 @@ const RPT_CFG_GRP = 'rpt_cfg';
 
 module.exports = {
     setReportDefaultCache: function () {
-        Rpt_Cfg_Mdl.find({userId: "Administrator"}, '-_id', function(err, templates){
-            if(templates.length){
-                cache.setCache(RPT_CFG_GRP,'admin_cfg',templates[0]);
+        Rpt_Cfg_Mdl.find({userId: "Administrator"}, '-_id', function(err, cfgs){
+            if(cfgs.length){
+                cache.setCache(RPT_CFG_GRP,'admin_cfg',cfgs[0]);
             }
         })
     },
@@ -26,28 +26,43 @@ module.exports = {
     },
     setReportCacheByUser: function (userId) {
         let me = this;
-        Rpt_Cfg_Mdl.find({userId: userId}, '-_id', function(err, templates){
-            if(templates.length){
-                cache.setCache(RPT_CFG_GRP, userId + '_cfg',templates[0]);
-            } else {
-                me.setReportDefaultCache();
-            }
-        })
+        let user_cfg = cache.getCache(RPT_CFG_GRP,userId + '_cfg');
+        if (!(user_cfg)) {
+            Rpt_Cfg_Mdl.find({userId: userId}, '-_id', function(err, cfgs){
+                if(cfgs.length){
+                    cache.setCache(RPT_CFG_GRP, userId + '_cfg',cfgs[0]);
+                } else {
+                    me.setReportDefaultCache();
+                }
+            })
+        }
     },
-    getReportCacheByUser: function (userId) {
+    getReportCacheByUser: function (userId, cb) {
         let me = this,
             rst = {ctrls: null, fonts: null, styles: null},
             user_cfg = cache.getCache(RPT_CFG_GRP,userId + '_cfg');
         ;
         if (!(user_cfg)) {
-            rst = null;
-            rst = me.getReportDefaultCache();
+            Rpt_Cfg_Mdl.find({userId: userId}, '-_id', function(err, cfgs){
+                if(cfgs.length){
+                    cache.setCache(RPT_CFG_GRP, userId + '_cfg',cfgs[0]);
+                    user_cfg = cache.getCache(RPT_CFG_GRP,userId + '_cfg');
+                    rst.ctrls = user_cfg.formats;
+                    rst.fonts = user_cfg.fonts;
+                    rst.styles = user_cfg.borders;
+                    user_cfg = null;
+                    cb(rst);
+                } else {
+                    user_cfg = null;
+                    cb(me.getReportDefaultCache());
+                }
+            })
         } else {
             rst.ctrls = user_cfg.formats;
             rst.fonts = user_cfg.fonts;
             rst.styles = user_cfg.borders;
             user_cfg = null;
+            cb(rst);
         }
-        return rst;
     }
 }

+ 78 - 0
public/cache/std_glj_type_util.js

@@ -0,0 +1,78 @@
+/**
+ * Created by Tony on 2017/7/6.
+ */
+let cache = require('./cacheUtil');
+let std_glj_type_mdl = require('../models/std_glj_types');
+
+const STD_GLJ_GRP = 'std_glj_grp';
+
+function getStdGljTypeCache() {
+    let rst = cache.getCache(STD_GLJ_GRP,'default');
+    return rst;
+};
+
+class StdGljTypeClass{
+    //根据id获取临时数据
+    constructor() {
+        this.innerGljTypeObj = null;
+    };
+
+    build(cache){
+        let me = this, rst = {};
+        rst.items = [];
+        let private_combine_glj_type = function (item) {
+            let tmpItem = {};
+            tmpItem.ID = item.ID;
+            tmpItem.fullName = item.fullName;
+            tmpItem.shortName = item.shortName;
+            rst["typeId" + item.ID] = tmpItem;
+            rst.items.push(tmpItem);
+            if (item.items) {
+                for (let subItem of item.items) {
+                    private_combine_glj_type(subItem);
+                }
+            }
+        }
+        for (let item of cache.typesDefine) {
+            private_combine_glj_type(item);
+        }
+        me.innerGljTypeObj = rst;
+    };
+
+    getItemById(Id) {
+        let me = this, rst = null;
+        if (me.innerGljTypeObj) {
+            rst = me.innerGljTypeObj["typeId" + Id];
+        }
+        return rst;
+    };
+
+    toArray(){
+        let me = this, rst = null;
+        return me.innerGljTypeObj.items;
+    }
+};
+
+module.exports = {
+    stdGljTypeObj: null,
+    setStdGljTypeCache: function () {
+        std_glj_type_mdl.find({typeName: "默认"}, '-_id', function(err, typeObj){
+            if(typeObj.length){
+                cache.setCache(STD_GLJ_GRP,'default',typeObj[0]);
+            }
+        })
+    },
+    getStdGljTypeCacheObj: function () {
+        let me = this,
+            rst = null,
+            cache = getStdGljTypeCache();
+        if (me.stdGljTypeObj) {
+            rst = me.stdGljTypeObj;
+        } else if (cache) {
+            rst = new StdGljTypeClass();
+            rst.build(cache);
+            me.stdGljTypeObj = rst;
+        }
+        return rst;
+    }
+}

+ 25 - 0
public/models/std_glj_types.js

@@ -0,0 +1,25 @@
+/**
+ * Created by Tony on 2017/7/6.
+ */
+let mongoose = require('mongoose');
+let dbm = require("../../config/db/db_manager");
+let smartcostdb = dbm.getCfgConnection("scConstruct");
+let Schema = mongoose.Schema;
+
+let RptCfgSchema = new Schema({
+    "typeName" : String,
+    "typesDefine": [{
+        "ID": Number,
+        "fullName": String,
+        "shortName": String,
+        "items": [{
+            "ID": Number,
+            "fullName": String,
+            "shortName": String
+        }]
+    }],
+});
+
+let std_glj_type_mdl = smartcostdb.model("std_glj_type", RptCfgSchema, "std_glj_type");
+
+module.exports = std_glj_type_mdl;

+ 27 - 0
public/web/string_util_light.js

@@ -0,0 +1,27 @@
+/**
+ * Created by Tony on 2017/7/5.
+ * 字符串工具类简化版本
+ */
+
+let stringUtil = {
+    isEmptyString: function(str) {
+        var rst = false;
+        if (str == null || str == undefined) {
+            rst = true;
+        } else if (typeof str) {
+            var reg = /^\s*$/;
+            rst = reg.test(str);
+        }
+        return rst;
+    },
+    convertStrToBoolean: function(str) {
+        var rst = false, me = this;
+        if (!me.isEmptyString(str)) {
+            var upperStr = str.toUpperCase();
+            if (upperStr == 'T' || upperStr == 'Y' || upperStr == 'YES' || upperStr == 'TRUE') {
+                rst = true;
+            }
+        }
+        return rst;
+    }
+}

+ 23 - 0
test/public/testStdGljTypes.js

@@ -0,0 +1,23 @@
+/**
+ * Created by Tony on 2017/7/6.
+ */
+
+let test = require('tape');
+let stdgljutil = require("../../public/cache/std_glj_type_util");
+
+test('std glj types test1', function(t){
+    stdgljutil.setStdGljTypeCache();
+    t.end();
+})
+
+test('std glj types test2', function(t){
+    //stdgljutil.setStdGljTypeCache();
+    let cacheObj = stdgljutil.getStdGljTypeCacheObj();
+    t.equal(cacheObj != null, true);
+    let rgItem = cacheObj.getItemById(1);
+    t.equal(rgItem != null, true);
+    let arr = cacheObj.toArray();
+    t.equal(arr.length, 11);
+    t.end();
+})
+

+ 51 - 12
web/maintain/report/js/cfg_const.js

@@ -49,14 +49,14 @@ let bandSetting = {
         expandSpeed: "",
         selectedMulti: false
     },
-    // edit: {
-    //     enable: true,
-    //     editNameSelectAll: true,
-    //     showRemoveBtn: true,
-    //     showRenameBtn: true,
-    //     removeTitle: "删除节点",
-    //     renameTitle: "更改名称"
-    // },
+    edit: {
+        enable: true,
+        editNameSelectAll: true,
+        showRemoveBtn: false,
+        showRenameBtn: true,
+        //removeTitle: "删除节点",
+        renameTitle: "更改名称"
+    },
     data: {
         keep: {
             parent:true,
@@ -67,10 +67,49 @@ let bandSetting = {
             name: "Name"
         },
         simpleData: {
-            enable: true,
-            idKey: "ID",
-            pIdKey: "ParentID",
-            rootPId: -1
+            enable: true
+            //,idKey: "ID",
+            //pIdKey: "ParentID",
+            //rootPId: -1
         }
+    },
+    callback:{
+        onClick: bandTreeOprObj.onClick
+    }
+};
+
+let fieldMapSetting = {
+    view: {
+        showIcon: true,
+        expandSpeed: "",
+        selectedMulti: false
+    },
+    edit: {
+        enable: true,
+        editNameSelectAll: true,
+        showRemoveBtn: true,
+        showRenameBtn: true,
+        removeTitle: "删除",
+        renameTitle: "更改名称"
+    },
+    data: {
+        keep: {
+            parent:true,
+            leaf:true
+        },
+        key: {
+            children: 'items',
+            name: "Name"
+        },
+        simpleData: {
+            enable: true
+        }
+    },
+    callback:{
+        onClick: fieldMapTreeOprObj.onClick,
+        beforeRename: fieldMapTreeOprObj.beforeRename,
+        beforeRemove: fieldMapTreeOprObj.onBeforeRemove,
+        onRemove: fieldMapTreeOprObj.onRemove,
+        onRename: fieldMapTreeOprObj.onRename
     }
 };

+ 236 - 14
web/maintain/report/js/rpt_tpl_main.js

@@ -4,13 +4,13 @@ let rptTplObj = {
     iniPage: function() {
         let me = this
         zTreeOprObj.getReportTemplateTree(RT.GrpType.CONSTRUCT);
+        bandTreeOprObj.getReportTplCfg();
         preview_util.drawBorder($("#tplCanvas")[0]);
     }
 }
 
 let zTreeOprObj = {
     treeObj: null,
-    bandTreeObj: null,
     currentNode: null,
     getReportTemplateTree: function(grpType) {
         let me = zTreeOprObj, params = {};
@@ -18,9 +18,9 @@ let zTreeOprObj = {
         params.userId = userID;
         params.tplType = RT.TplType.ALL;
         CommonAjax.postEx("report_tpl_api/getRptTplTree", params, 20000, true, function(result){
-            zTreeHelper.createTree(result, setting, "rptTplTree", me);
-            me.refreshNodes();
-        }, null, null
+                zTreeHelper.createTree(result, setting, "rptTplTree", me);
+                me.refreshNodes();
+            }, null, null
         );
     },
     refreshNodes: function() {
@@ -271,6 +271,7 @@ let zTreeOprObj = {
     onClick: function(event,treeId,treeNode) {
         let me = zTreeOprObj;
         me.currentNode = treeNode;
+        bandTreeOprObj.currentNode = null;
         if (treeNode.nodeType == RT.NodeType.NODE) {
             $("#rpt_tpl_display_label")[0].innerText = "...";
         } else if (treeNode.nodeType == RT.NodeType.TEMPLATE) {
@@ -342,21 +343,40 @@ let zTreeOprObj = {
             $("#rptTplMarginTop")[0].value = rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_TOP];
             $("#rptTplMarginBottom")[0].value = rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_BOTTOM];
             //2. 模板布局
-            let bandList = rptTpl[JV.NODE_BAND_COLLECTION];
-            me.buildTreeData(bandList);
-            me.bandTreeObj = $.fn.zTree.init($("#band_tree_reversed"), bandSetting, bandList);
-            me.bandTreeObj.expandAll(true);
+            bandTreeOprObj.iniTree(rptTpl);
             //3. 指标映射
+            fieldMapTreeOprObj.iniTree(rptTpl);
             //4. 指标摆放
             //5. 计算式
         }
     },
+    previewRptTpl: function (rptTpl) {
+        let me = zTreeOprObj;
+        if (rptTpl) {
+            //
+        }
+    }
+};
+
+let bandTreeOprObj = {
+    treeObj : null,
+    currentNode: null,
+    innerCounter: 1,
+    reportCfg: null,
+    canTrickEvent: false,
+    iniTree: function(rptTpl) {
+        var me = this;
+        let bandList = rptTpl[JV.NODE_BAND_COLLECTION];
+        me.buildTreeData(bandList);
+        me.treeObj = $.fn.zTree.init($("#band_tree_reversed"), bandSetting, bandList);
+        me.treeObj.expandAll(true);
+    },
     buildTreeData: function(bandList){
         let rst = [], startIdx = 1;
         //zTreeHelper.createTree(result, setting, "rptTplTree", me);
         let private_setBandId = function (parentBand) {
-            if (parentBand.band_s) {
-                for (let band of parentBand.band_s) {
+            if (parentBand[JV.BAND_PROP_SUB_BANDS]) {
+                for (let band of parentBand[JV.BAND_PROP_SUB_BANDS]) {
                     band.ID = startIdx;
                     band.ParentID = parentBand.ID;
                     startIdx++;
@@ -373,10 +393,212 @@ let zTreeOprObj = {
 
         return rst;
     },
-    previewRptTpl: function (rptTpl) {
-        let me = zTreeOprObj;
+    getReportTplCfg: function() {
+        let me = this, params = {};
+        params.userId = userID;
+        CommonAjax.postEx("report_tpl_api/getUserRptCfg", params, 20000, true, function(result){
+                me.reportCfg = result;
+                me.refreshRptCfgs();
+            }, null, null
+        );
+    },
+    refreshRptCfgs: function () {
+        let me = this;
+        if (me.reportCfg) {
+            me.reportCfg.borderArr = [];
+            for (let style of me.reportCfg.styles) {
+                me.reportCfg.borderArr.push(style.ID);
+                $("#borderStyles").append("<option value='" + style.ID + "'>" + style.CfgDispName + "</option>");
+            }
+        }
+        let pf = $("#pageFrequency");
+        pf.append("<option value='" + JV.PAGE_STATUS[0] + "'>每页</option>");
+        pf.append("<option value='" + JV.PAGE_STATUS[1] + "'>首页</option>");
+        pf.append("<option value='" + JV.PAGE_STATUS[2] + "'>尾页</option>");
+        pf.append("<option value='" + JV.PAGE_STATUS[3] + "'>章首页</option>");
+        pf.append("<option value='" + JV.PAGE_STATUS[4] + "'>章尾页</option>");
+        pf.append("<option value='" + JV.PAGE_STATUS[5] + "'>分组</option>");
+        pf.append("<option value='" + JV.PAGE_STATUS[6] + "'>交叉行尾页</option>");
+        pf.append("<option value='" + JV.PAGE_STATUS[7] + "'>交叉列尾页</option>");
+        let ba = $("#bandAlignment");
+        ba.append("<option value='" + JV.LAYOUT[0] + "'>上</option>");
+        ba.append("<option value='" + JV.LAYOUT[1] + "'>下</option>");
+        ba.append("<option value='" + JV.LAYOUT[2] + "'>左</option>");
+        ba.append("<option value='" + JV.LAYOUT[3] + "'>右</option>");
+        ba.append("<option value='" + JV.LAYOUT[4] + "'>填充</option>");
+    },
+    extractBands: function (rptTpl) {
+        let me = this;
         if (rptTpl) {
-            //
+            let newBandList = [];
+            for (let node of me.treeObj.getNodes()) {
+                newBandList.push(me.createBandFromNode(node));
+            }
+            rptTpl[JV.NODE_BAND_COLLECTION] = newBandList;
+        }
+        return rst;
+    },
+    createBandFromNode: function(node) {
+        let me = this, rst = {};
+        rst[JV.BAND_PROP_ALIGNMENT] = node[JV.BAND_PROP_ALIGNMENT];
+        rst[JV.BAND_PROP_DISPLAY_TYPE] = node[JV.BAND_PROP_DISPLAY_TYPE];
+        rst[JV.BAND_PROP_HEIGHT] = node[JV.BAND_PROP_HEIGHT];
+        rst[JV.PROP_NAME] = node[JV.PROP_NAME];
+        rst[JV.PROP_CONTROL] = node[JV.PROP_CONTROL];
+        rst[JV.PROP_STYLE] = node[JV.PROP_STYLE];
+        if (node[JV.BAND_PROP_SUB_BANDS]) {
+            rst[JV.BAND_PROP_SUB_BANDS] = [];
+            for (let subNode of node[JV.BAND_PROP_SUB_BANDS]) {
+                rst[JV.BAND_PROP_SUB_BANDS].push(me.createBandFromNode(subNode));
+            }
+        }
+        return rst;
+    },
+    createDftBand: function () {
+        let me = this, rst = {};
+        rst[JV.BAND_PROP_ALIGNMENT] = 'Top';
+        rst[JV.BAND_PROP_DISPLAY_TYPE] = 'EveryPage';
+        rst[JV.BAND_PROP_HEIGHT] = '3';
+        rst[JV.PROP_NAME] = 'newBand_' + me.innerCounter;
+        me.innerCounter++;
+        rst[JV.PROP_CONTROL] = 'Default';
+        rst[JV.PROP_STYLE] = 'Default_None';
+        return rst;
+    },
+    addRootBand: function (rptTpl) {
+        let me = this;
+        if (rptTpl) {
+            let newBand = me.createDftBand();
+            let newNodes = [], isSilent = false;
+            newNodes.push(newBand);
+            if (me.treeObj) {
+                me.treeObj.addNodes(null, -1, newNodes, isSilent);
+            } else {
+                me.treeObj = $.fn.zTree.init($("#band_tree_reversed"), bandSetting, newNodes);
+            }
+        }
+    },
+    addSubBand: function (rptTpl) {
+        let me = this;
+        if (rptTpl && me.currentNode != null) {
+            let newBand = me.createDftBand();
+            let newNodes = [], isSilent = false;
+            newNodes.push(newBand);
+            me.treeObj.addNodes(me.currentNode, -1, newNodes, isSilent);
+        }
+    },
+    moveDownBand: function (rptTpl) {
+        let me = bandTreeOprObj;
+        if (rptTpl && me.currentNode && me.currentNode.getNextNode()) {
+            let nextNode = me.currentNode.getNextNode();
+            me.treeObj.moveNode(nextNode, me.currentNode, "next", true);
+        }
+    },
+    moveUpBand: function (rptTpl) {
+        let me = bandTreeOprObj;
+        if (rptTpl && me.currentNode && me.currentNode.getPreNode()) {
+            let preNode = me.currentNode.getPreNode();
+            me.treeObj.moveNode(preNode, me.currentNode, "prev", true);
+        }
+    },
+    onClick: function(event,treeId,treeNode) {
+        let me = bandTreeOprObj;
+        me.currentNode = treeNode;
+        me.canTrickEvent = false;
+        //then refresh the band tab properties
+        //边框样式borderStyles
+        $("#borderStyles ").get(0).selectedIndex = me.reportCfg.borderArr.indexOf(treeNode[JV.PROP_STYLE]);
+        //边框合并
+        $("#mergeBandBorder").get(0).checked = stringUtil.convertStrToBoolean(treeNode[JV.BAND_PROP_MERGE_BORDER]);
+        //位置
+        let posIdx = JV.LAYOUT.indexOf(treeNode[JV.BAND_PROP_ALIGNMENT])
+        $("#bandAlignment").get(0).selectedIndex = posIdx;
+        //高宽
+        switch(posIdx) {
+            case 0:
+            case 1:
+                $("#bandHeight").get(0).disabled = false;
+                $("#bandHeight").get(0).value = treeNode[JV.BAND_PROP_HEIGHT];
+                $("#bandWidth").get(0).disabled = true;
+                $("#bandWidth").get(0).value = "";
+                break;
+            case 2:
+            case 3:
+                $("#bandHeight").get(0).disabled = true;
+                $("#bandHeight").get(0).value = "";
+                $("#bandWidth").get(0).disabled = false;
+                $("#bandWidth").get(0).value = treeNode[JV.BAND_PROP_WIDTH];
+                break;
+            default:
+                $("#bandHeight").get(0).disabled = true;
+                $("#bandHeight").get(0).value = "";
+                $("#bandWidth").get(0).disabled = true;
+                $("#bandWidth").get(0).value = "";
+                break;
+        }
+        //频率
+        $("#pageFrequency").get(0).selectedIndex = JV.PAGE_STATUS.indexOf(treeNode[JV.BAND_PROP_DISPLAY_TYPE])
+        //
+        me.canTrickEvent = true;
+    },
+    bandStyleChange: function (e) {
+        //alert('You changed the band style to: ' + e.selectedOptions[0].text + '(' + e.selectedOptions[0].value + ')');
+    }
+};
+
+let fieldMapTreeOprObj = {
+    treeObj : null,
+    iniTree: function(rptTpl) {
+        var me = this;
+        let fieldMapList = me.buildTreeData(rptTpl);
+        me.treeObj = $.fn.zTree.init($("#field_map_tree_reversed"), fieldMapSetting, fieldMapList);
+        me.treeObj.expandAll(true);
+    },
+    buildTreeData: function (rptTpl) {
+        let rst = [];
+        let private_setSubFields = function (parent, fieldList) {
+            for (let field of fieldList) {
+                parent.items.push(field);
+            }
+        }
+
+        if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DISCRETE_FIELDS]) {
+            rst.push({Name: JV.NODE_DISCRETE_FIELDS, items: [], isParent: true});
+            private_setSubFields(rst[rst.length - 1], rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DISCRETE_FIELDS])
         }
+        if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS]) {
+            rst.push({Name: JV.NODE_MASTER_FIELDS, items: [], isParent: true});
+            private_setSubFields(rst[rst.length - 1], rptTpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS])
+        }
+        if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS]) {
+            rst.push({Name: JV.NODE_DETAIL_FIELDS, items: [], isParent: true});
+            private_setSubFields(rst[rst.length - 1], rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS])
+        }
+
+        return rst;
+    },
+    onClick: function () {
+        //
+    },
+    onBeforeRemove: function(treeId, treeNode){
+        if (treeNode.level === 0) {
+            return false;
+        }
+        return true;
+    },
+    beforeRename: function(treeId, treeNode, newName, isCancel) {
+        if (isCancel) {
+            return true;
+        }
+        if (treeNode.level === 0) {
+            return false;
+        }
+        return true;
+    },
+    onRemove: function () {
+        //
+    },
+    onRename: function () {
+        //
     }
-}
+};

+ 12 - 5
web/maintain/report/js/rpt_tpl_preview_util.js

@@ -114,13 +114,17 @@ let preview_util = {
             }
             return rstArea;
         };
-        let private_showBand = function (band, myArea) {
+        let private_showBand = function (band, myArea, onlyMe, isHighlight) {
             //1. draw band border
             ctx.save();
             ctx.beginPath();
             ctx.translate(0.5,0.5);
             ctx.lineWidth = 1;
-            ctx.setLineDash([3, 6]);
+            if (isHighlight) {
+                ctx.strokeStyle="#0000ff";
+            } else {
+                ctx.setLineDash([3, 6]);
+            }
             ctx.moveTo((me.offsetX + myArea[JV.IDX_LEFT]) * shrinkFactor, (me.offsetY + myArea[JV.IDX_TOP]) * shrinkFactor );
             ctx.lineTo((me.offsetX + myArea[JV.IDX_RIGHT]) * shrinkFactor, (me.offsetY + myArea[JV.IDX_TOP]) * shrinkFactor);
             ctx.lineTo((me.offsetX + myArea[JV.IDX_RIGHT]) * shrinkFactor, (me.offsetY + myArea[JV.IDX_BOTTOM]) * shrinkFactor);
@@ -129,11 +133,11 @@ let preview_util = {
             ctx.stroke();
             ctx.restore();
             //2. then draw sub bands border if have.
-            if (band[JV.BAND_PROP_SUB_BANDS]) {
+            if (band[JV.BAND_PROP_SUB_BANDS] && !onlyMe) {
                 for (let subBand of band[JV.BAND_PROP_SUB_BANDS]) {
                     if (!(subBand[JV.PROP_CALCULATION])) subBand[JV.PROP_CALCULATION] = JV.CAL_TYPE_ABSTRACT;
                     let area = private_setupBandArea(band, myArea);
-                    private_showBand(subBand, area);
+                    private_showBand(subBand, area, false, false);
                 }
             }
         };
@@ -142,7 +146,10 @@ let preview_util = {
         for (let band of rptTpl[JV.NODE_BAND_COLLECTION]) {
             if (!(band[JV.PROP_CALCULATION])) band[JV.PROP_CALCULATION] = JV.CAL_TYPE_ABSTRACT;
             let area = private_setupBandArea(band, orgArea);
-            private_showBand(band, area);
+            private_showBand(band, area, false, false);
+        }
+        if (bandTreeOprObj.currentNode) {
+            //need to high-light the band?
         }
     }
 }

+ 24 - 27
web/maintain/report/rpt_tpl_main.html

@@ -158,53 +158,49 @@
                                             <div class="tab-pane" id="rpttpllayout" role="tabpanel">
                                                 <div class="main-data">
                                                     <div class="p-3">
+                                                        <div class="tab-bar">
+                                                            <a onclick="bandTreeOprObj.addRootBand(zTreeOprObj.getRefTpl())" class="btn btn-secondary btn-sm fa fa-plus-square">根节点框</a>
+                                                            <a onclick="bandTreeOprObj.addSubBand(zTreeOprObj.getRefTpl())" class="btn btn-secondary btn-sm fa fa-plus-square">子节点框</a>
+                                                            <a onclick="bandTreeOprObj.moveDownBand(zTreeOprObj.getRefTpl())" class="btn btn-sm" id="downMoveBand"><i class="fa fa-arrow-down" aria-hidden="true"></i>下移</a>
+                                                            <a onclick="bandTreeOprObj.moveUpBand(zTreeOprObj.getRefTpl())" class="btn btn-sm" id="upMoveBand"><i class="fa fa-arrow-up" aria-hidden="true"></i>上移</a>
+                                                        </div>
                                                         <div class="ztree-warp">
                                                             <ul id="band_tree_reversed" class="ztree"></ul>
                                                         </div>
-                                                        <div class="form-group">
+                                                        <div class="form-group" style="display: none">
                                                             <label>Band名称</label>
                                                             <input class="form-control" placeholder="输入Band名称">
                                                             <small class="form-text text-muted">提示文字文字</small>
                                                         </div>
                                                         <div class="form-group">
                                                             <label>边框样式</label>
-                                                            <select class="form-control"><option> </option></select>
+                                                            <select class="form-control" id="borderStyles" onchange="bandTreeOprObj.bandStyleChange(this)"></select>
                                                         </div>
                                                         <div class="form-group">
-                                                            <label>高度</label>
-                                                            <div class=" form-inline">
-                                                                <input class="form-control mr-2" disabled>
-                                                                <div class="form-check">
-                                                                    <label class="form-check-label">
-                                                                        <input class="form-check-input" type="checkbox" checked> 自动填充
-                                                                    </label>
-                                                                </div>
-                                                            </div>
+                                                            <label>位置</label>
+                                                            <select class="form-control" id="bandAlignment"></select>
                                                         </div>
-                                                        <div class="form-group">
-                                                            <label>宽度</label>
-                                                            <div class=" form-inline">
-                                                                <input class="form-control mr-2" placeholder="">
-                                                                <div class="form-check">
-                                                                    <label class="form-check-label">
-                                                                        <input class="form-check-input" type="checkbox"> 自动填充
-                                                                    </label>
-                                                                </div>
+
+                                                        <div class="row">
+                                                            <div class="form-group col-md-6">
+                                                                <label>高度</label>
+                                                                <input class="form-control mr-2" id="bandHeight" type="number" step="0.1" disabled>
+                                                            </div>
+                                                            <div class="form-group col-md-6">
+                                                                <label>宽度</label>
+                                                                <input class="form-control mr-2" id="bandWidth"  type="number" step="0.1" disabled>
                                                             </div>
                                                         </div>
+
                                                         <div class="form-group">
                                                             <label>出现频率</label>
-                                                            <select class="form-control"><option>每页</option><option>首页</option><option>尾页</option><option>章首页</option><option>章尾页</option><option>分组</option><option>交叉行尾页</option><option>交叉列尾页</option></select>
-                                                        </div>
-                                                        <div class="form-group">
-                                                            <label>位置</label>
-                                                            <select class="form-control"><option>上</option><option>下</option><option>左</option><option>右</option><option>填充</option></select>
+                                                            <select class="form-control" id="pageFrequency"></select>
                                                         </div>
                                                         <div class="form-group">
                                                             <label>边框合并</label>
                                                             <div class="form-check">
                                                                 <label class="form-check-label">
-                                                                    <input type="checkbox" class="form-check-input">
+                                                                    <input type="checkbox" class="form-check-input" id="mergeBandBorder">
                                                                     合并
                                                                 </label>
                                                             </div>
@@ -217,7 +213,7 @@
                                                 <div class="main-data">
                                                     <div class="p-3">
                                                         <div class="ztree-warp">
-                                                            ztree 保留空间
+                                                            <ul id="field_map_tree_reversed" class="ztree"></ul>
                                                         </div>
                                                         <div class="row">
                                                             <div class="form-group col-md-6">
@@ -363,6 +359,7 @@
     <script type="text/javascript" src="/public/web/treeDataHelper.js"></script>
     <script type="text/javascript" src="/public/web/ztree_common.js"></script>
     <script type="text/javascript" src="/public/web/rpt_value_define.js"></script>
+    <script type="text/javascript" src="/public/web/string_util_light.js"></script>
 </body>
 <script type="text/javascript">
     autoFlashHeight();