Pārlūkot izejas kodu

Merge branch 'master' of http://smartcost.f3322.net:3000/SmartCost/ConstructionCost

zhangyin 8 gadi atpakaļ
vecāks
revīzija
6801f897bf

+ 20 - 14
modules/reports/rpt_component/Jpc_CrossTab.js

@@ -349,7 +349,7 @@ JpcCrossTabSrv.prototype.createNew = function(){
         return rst;
     };
     JpcCrossTabResult.outputColTab = function(rptTpl, dataObj, page, bands, unitFactor, controls) {
-        var me = this, rst = [];
+        var me = this, rst = [], firstTextOutput = true;
         var tab = rptTpl[JV.NODE_CROSS_INFO][JV.NODE_CROSS_COL];
         var band = bands[tab[JV.PROP_BAND_NAME]];
         if (band) {
@@ -366,15 +366,18 @@ JpcCrossTabSrv.prototype.createNew = function(){
                         for (var colIdx = 0; colIdx < cols; colIdx++) {
                             rst.push(me.outputTabField(band, tab_field, data_field, valuesIdx[colIdx], -1, 1, 0, cols, colIdx, unitFactor, false, controls));
                             //2. output texts
-                            if (tab[JV.PROP_TEXT]) {
-                                rst.push(JpcTextHelper.outputText(tab[JV.PROP_TEXT], band, unitFactor, 1, 0, cols, colIdx, 1, 0));
-                            }
-                            if (tab[JV.PROP_TEXTS]) {
-                                for (var j = 0; j < tab[JV.PROP_TEXTS].length; j++) {
-                                    rst.push(JpcTextHelper.outputText(tab[JV.PROP_TEXTS][j], band, unitFactor, 1, 0, cols, colIdx, 1, 0));
+                            if (firstTextOutput) {
+                                if (tab[JV.PROP_TEXT]) {
+                                    rst.push(JpcTextHelper.outputText(tab[JV.PROP_TEXT], band, unitFactor, 1, 0, cols, colIdx, 1, 0));
+                                }
+                                if (tab[JV.PROP_TEXTS]) {
+                                    for (var j = 0; j < tab[JV.PROP_TEXTS].length; j++) {
+                                        rst.push(JpcTextHelper.outputText(tab[JV.PROP_TEXTS][j], band, unitFactor, 1, 0, cols, colIdx, 1, 0));
+                                    }
                                 }
                             }
                         }
+                        firstTextOutput = false;
                     }
                 }
             }
@@ -447,7 +450,7 @@ JpcCrossTabSrv.prototype.createNew = function(){
         return rst;
     };
     JpcCrossTabResult.outputTabExt = function (rptTpl, dataObj, page, bands, unitFactor, controls) {
-        var me = this, rst = [],
+        var me = this, rst = [], firstTextOutput = true,
             tab = rptTpl[JV.NODE_CROSS_INFO][JV.NODE_CROSS_ROW_EXT];
         var band = bands[tab[JV.PROP_BAND_NAME]];
         if (band) {
@@ -464,15 +467,18 @@ JpcCrossTabSrv.prototype.createNew = function(){
                         for (var colIdx = 0; colIdx < cols; colIdx++) {
                             rst.push(me.outputTabField(band, tab_field, data_field, valuesIdx[colIdx], -1, 1, 0, cols, colIdx, unitFactor, false, controls));
                             //2. output texts if has
-                            if (tab[JV.PROP_TEXT]) {
-                                rst.push(JpcTextHelper.outputText(tab[JV.PROP_TEXT], band, unitFactor, 1, 0, cols, colIdx, 1, 0));
-                            }
-                            if (tab[JV.PROP_TEXTS]) {
-                                for (var j = 0; j < tab[JV.PROP_TEXTS].length; j++) {
-                                    rst.push(JpcTextHelper.outputText(tab[JV.PROP_TEXTS][j], band, unitFactor, 1, 0, cols, colIdx, 1, 0));
+                            if (firstTextOutput) {
+                                if (tab[JV.PROP_TEXT]) {
+                                    rst.push(JpcTextHelper.outputText(tab[JV.PROP_TEXT], band, unitFactor, 1, 0, cols, colIdx, 1, 0));
+                                }
+                                if (tab[JV.PROP_TEXTS]) {
+                                    for (var j = 0; j < tab[JV.PROP_TEXTS].length; j++) {
+                                        rst.push(JpcTextHelper.outputText(tab[JV.PROP_TEXTS][j], band, unitFactor, 1, 0, cols, colIdx, 1, 0));
+                                    }
                                 }
                             }
                         }
+                        firstTextOutput = false;
                     }
                 }
             }

+ 87 - 57
modules/reports/util/rpt_excel_util.js

@@ -154,7 +154,7 @@ function writeStyles(stylesObj){
             rst.push('<' + borderDirection.toLowerCase() + '/>');
         } else {
             var bW = 'thin';
-            if (border[borderDirection][JV.PROP_LINE_WEIGHT] = 2) bW = 'medium';
+            if (border[borderDirection][JV.PROP_LINE_WEIGHT] == 2) bW = 'medium';
             if (border[borderDirection][JV.PROP_LINE_WEIGHT] > 2) bW = 'thick';
             rst.push('<' + borderDirection.toLowerCase() + ' style="' + bW + '">' + '<color indexed="64"/>' + '</' + borderDirection.toLowerCase() + '>');
         }
@@ -229,6 +229,7 @@ function writeSheets(pageData, sharedStrList, stylesObj){
 }
 function writeSheet(pageData, sheetData, sharedStrList, stylesObj){
     var rst = [], xPos = [], yPos = [], headerStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+    var cacheBorderCell = {};
     xPos.push(0);
     yPos.push(0);
     private_pre_analyze_pos = function(){
@@ -320,29 +321,29 @@ function writeSheet(pageData, sheetData, sharedStrList, stylesObj){
         }
         return rst;
     };
-    private_checkBorder = function(border, sheetBorder) {
+    private_checkBorder = function(cell, border, sheetBorder) {
         var rst = true, borderLineWidths = [], sheetBorderLineWidths = [];
         borderLineWidths.push(border[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT]);
         borderLineWidths.push(border[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT]);
         borderLineWidths.push(border[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]);
         borderLineWidths.push(border[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]);
         if (sheetBorder[JV.PROP_LEFT] && sheetBorder[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT]) {
-            sheetBorderLineWidths.push(parseInt(sheetBorder[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT]));
+            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_LEFT));
         } else {
             sheetBorderLineWidths.push(0);
         }
         if (sheetBorder[JV.PROP_RIGHT] && sheetBorder[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT]) {
-            sheetBorderLineWidths.push(parseInt(sheetBorder[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT]));
+            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_RIGHT));
         } else {
             sheetBorderLineWidths.push(0);
         }
         if (sheetBorder[JV.PROP_TOP] && sheetBorder[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]) {
-            sheetBorderLineWidths.push(parseInt(sheetBorder[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]));
+            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_TOP));
         } else {
             sheetBorderLineWidths.push(0);
         }
         if (sheetBorder[JV.PROP_BOTTOM] && sheetBorder[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]) {
-            sheetBorderLineWidths.push(parseInt(sheetBorder[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]));
+            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_BOTTOM));
         } else {
             sheetBorderLineWidths.push(0);
         }
@@ -354,41 +355,53 @@ function writeSheet(pageData, sheetData, sharedStrList, stylesObj){
         }
         return rst;
     };
+    private_chkAndGetMergeLine = function(cell, sheetBorder, borderStr) {
+        var rst = sheetBorder[borderStr][JV.PROP_LINE_WEIGHT], mergeBorder = pageData[JV.BAND_PROP_MERGE_BAND];
+        if (cell[JV.PROP_AREA][borderStr] == mergeBorder[borderStr]) {
+            var destStyle = pageData[JV.NODE_STYLE_COLLECTION][mergeBorder[JV.PROP_STYLE][JV.PROP_ID]];
+            rst = destStyle[borderStr][JV.PROP_LINE_WEIGHT];
+        }
+        return parseInt(rst);
+    };
+    private_getIniBorder = function() {
+        var rst = {};
+        rst[JV.PROP_LEFT] = {};
+        rst[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT] = 0;
+        rst[JV.PROP_RIGHT] = {};
+        rst[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT] = 0;
+        rst[JV.PROP_TOP] = {};
+        rst[JV.PROP_TOP][JV.PROP_LINE_WEIGHT] = 0;
+        rst[JV.PROP_BOTTOM] = {};
+        rst[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT] = 0;
+        return rst;
+    };
     private_getBorderId = function(cell) {
         var rst = 0, hasBorder = false;
         if (!(stylesObj.borders)) {
             stylesObj.borders = [];
         }
-        var sheetBorder = pageData.style_collection[cell.style];
+        var sheetBorder = pageData[JV.NODE_STYLE_COLLECTION][cell.style];
         for (var i = 0; i < stylesObj.borders.length; i++) {
             var border = stylesObj.borders[i];
-            if (private_checkBorder(border, sheetBorder)) {
+            if (private_checkBorder(cell, border, sheetBorder)) {
                 hasBorder = true;
                 rst = i;
                 break;
             }
         }
         if (!hasBorder) {
-            var border = {};
-            border[JV.PROP_LEFT] = {};
-            border[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT] = 0;
-            border[JV.PROP_RIGHT] = {};
-            border[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT] = 0;
-            border[JV.PROP_TOP] = {};
-            border[JV.PROP_TOP][JV.PROP_LINE_WEIGHT] = 0;
-            border[JV.PROP_BOTTOM] = {};
-            border[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT] = 0;
+            var border = private_getIniBorder();
             if (sheetBorder && sheetBorder[JV.PROP_LEFT]) {
-                border[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT] = parseInt(sheetBorder[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT]);
+                border[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_LEFT);
             }
             if (sheetBorder && sheetBorder[JV.PROP_RIGHT]) {
-                border[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT] = parseInt(sheetBorder[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT]);
+                border[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_RIGHT);
             }
             if (sheetBorder && sheetBorder[JV.PROP_TOP]) {
-                border[JV.PROP_TOP][JV.PROP_LINE_WEIGHT] = parseInt(sheetBorder[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]);
+                border[JV.PROP_TOP][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_TOP);
             }
             if (sheetBorder && sheetBorder[JV.PROP_BOTTOM]) {
-                border[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT] = parseInt(sheetBorder[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]);
+                border[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_BOTTOM);
             }
             stylesObj.borders.push(border);
             rst = stylesObj.borders.length - 1;
@@ -462,12 +475,55 @@ function writeSheet(pageData, sheetData, sharedStrList, stylesObj){
         rst[startIdx] = '<mergeCells count="' + cnt + '">';
         rst.push('</mergeCells>');
     };
+    private_chkIfNeedCacheCell = function(cell){
+        var rst = false;
+        if (cell[JV.PROP_AREA][JV.PROP_LEFT] == pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_LEFT] ||
+            cell[JV.PROP_AREA][JV.PROP_RIGHT] == pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_RIGHT] ||
+            cell[JV.PROP_AREA][JV.PROP_TOP] == pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_TOP] ||
+            cell[JV.PROP_AREA][JV.PROP_BOTTOM] == pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_BOTTOM]){
+            if (cell[JV.PROP_AREA][JV.PROP_LEFT] >= pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_LEFT] &&
+                cell[JV.PROP_AREA][JV.PROP_RIGHT] <= pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_RIGHT] &&
+                cell[JV.PROP_AREA][JV.PROP_TOP] >= pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_TOP] &&
+                cell[JV.PROP_AREA][JV.PROP_BOTTOM] <= pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_BOTTOM]) {
+                rst = true;
+            }
+        }
+        return rst;
+    };
+    private_cacheMergeBandBorderIdxs = function() {
+        var cell, idxR, idxL, idxT, idxB;
+        for (var i = 0; i < sheetData.cells.length; i++) {
+            cell = sheetData.cells[i];
+            idxR = xPos.indexOf(cell[JV.PROP_AREA][JV.PROP_RIGHT]);
+            idxL = xPos.indexOf(cell[JV.PROP_AREA][JV.PROP_LEFT]);
+            idxB = yPos.indexOf(cell[JV.PROP_AREA][JV.PROP_BOTTOM]);
+            idxT = yPos.indexOf(cell[JV.PROP_AREA][JV.PROP_TOP]);
+            if (idxR - idxL > 1 || idxB - idxT > 1) {
+                if (private_chkIfNeedCacheCell(cell)) {
+                    for (var xi = idxL; xi < idxR; xi++) {
+                        for (var yj = idxT; yj < idxB; yj++) {
+                            cacheBorderCell[private_getCellIdxStr(xi - 1) + yj] = cell;
+                        }
+                    }
+                }
+            }
+        }
+    };
+    private_getMergedCellStyleId = function(preStyleId, colIdxStr) {
+        var rst = preStyleId;
+        if (cacheBorderCell[colIdxStr]) {
+            rst = private_getStyleId(cacheBorderCell[colIdxStr]);
+        }
+        return rst;
+    };
     private_setSheetData = function(){
         //remark: 1 excel height = 0.3612 mm
         rst.push('<sheetData>');
         var spanX = xPos.length - 2, cellIdx = 0, h = 0,
             hasMoreCols = true, nextColIdx = -1,
-            nextRowIdx = yPos.indexOf(sheetData.cells[cellIdx][JV.PROP_AREA][JV.PROP_TOP]);
+            nextRowIdx = yPos.indexOf(sheetData.cells[cellIdx][JV.PROP_AREA][JV.PROP_TOP])
+            ;
+        private_cacheMergeBandBorderIdxs();
         for (var i = 1; i < yPos.length - 1; i++) {
             h = 1.0 * (yPos[i+1] - yPos[i]) / DPI * 25.4 / 0.3612;
             h = Math.round(h * 1000) / 1000;
@@ -487,11 +543,13 @@ function writeSheet(pageData, sheetData, sharedStrList, stylesObj){
                 hasMoreCols = false;
             }
             nextColIdx = xPos.indexOf(sheetData.cells[cellIdx][JV.PROP_AREA][JV.PROP_LEFT]);
-            for (var j = 1; j < xPos.length; j++) {
+            var preStyleIdx = 1;
+            for (var j = 1; j < xPos.length - 1; j++) {
                 colIdxStr = private_getCellIdxStr(j - 1);
                 if (hasMoreCols) {
                     if (nextColIdx == j) {
                         var styleIdx = private_getStyleId(sheetData.cells[cellIdx]);
+                        preStyleIdx = styleIdx;
                         if (strUtil.isEmptyString(sheetData.cells[cellIdx][JV.PROP_VALUE])) {
                             rst.push('<c r="' + colIdxStr + i + '" s="' + styleIdx + '"/>');
                             //should setup the right style instead!
@@ -517,10 +575,12 @@ function writeSheet(pageData, sheetData, sharedStrList, stylesObj){
                         console.log('has abnormal case!');
                         hasMoreCols = false;
                     } else {
-                        rst.push('<c r="' + colIdxStr + i + '" s="1"/>');
+                        //rst.push('<c r="' + colIdxStr + i + '" s="' + preStyleIdx + '"/>');
+                        rst.push('<c r="' + colIdxStr + i + '" s="' + private_getMergedCellStyleId(preStyleIdx, colIdxStr + i) + '"/>');
                     }
                 } else {
-                    rst.push('<c r="' + colIdxStr + i + '" s="1"/>');
+                    //rst.push('<c r="' + colIdxStr + i + '" s="' + preStyleIdx + '"/>');
+                    rst.push('<c r="' + colIdxStr + i + '" s="' + private_getMergedCellStyleId(preStyleIdx, colIdxStr + i) + '"/>');
                 }
             }
             rst.push('</row>');
@@ -550,7 +610,7 @@ function writeSheet(pageData, sheetData, sharedStrList, stylesObj){
 }
 
 module.exports = {
-    exportExcel: function (pageData, options) {
+    exportExcel: function (pageData, fName, options) {
         var rptOptions = (options || {singlePage: false, fileName: 'report'});
         var sheets = [];
         for (var i = 0; i < pageData.items.length; i++) {
@@ -605,7 +665,7 @@ module.exports = {
 
         zip.generateNodeStream({type:'nodebuffer',streamFiles:true})
             //.pipe(fs.createWriteStream('../../../tmp/outExcel.xlsx'))
-            .pipe(fs.createWriteStream('../../../tmp/outExcel.zip'))
+            .pipe(fs.createWriteStream('../../../tmp/' + fName + '.zip'))
             .on('finish', function () {
                 // JSZip generates a readable stream with a "end" event,
                 // but is piped here in a writable stream which emits a "finish" event.
@@ -613,34 +673,4 @@ module.exports = {
             }
         );
     }
-    ,testWriteContentTypes: function(sheets) {
-        return writeContentTypes(sheets);
-    }
-    ,testWriteRootRels: function() {
-        return writeRootRels();
-    }
-    ,testWriteApp: function(sheets) {
-        return writeApp(sheets);
-    }
-    ,testWriteCore: function() {
-        return writeCore();
-    }
-    ,testWriteXlWorkBook: function(sheets) {
-        return writeXlWorkBook(sheets);
-    }
-    ,testWriteXlRels: function(sheets) {
-        return writeXlRels(sheets);
-    }
-    ,testWriteSheets: function(pageData, sharedStrList, stylesObj){
-        return writeSheets(pageData, sharedStrList, stylesObj);
-    }
-    ,testWriteSharedString: function(sharedStrList){
-        return writeSharedString(sharedStrList);
-    }
-    ,testWriteTheme: function() {
-        return writeTheme();
-    }
-    ,testWriteStyles: function(stylesObj) {
-        return writeStyles(stylesObj);
-    }
 }

+ 42 - 0
modules/templates/controllers/bills_template_controller.js

@@ -0,0 +1,42 @@
+/**
+ * Created by Mai on 2017/4/17.
+ */
+var BillsTemplateData = require('../models/bills_template');
+
+//ͳһ»Øµ÷º¯Êý
+var callback = function(req, res, err, message, data){
+    res.json({error: err, message: message, data: data});
+};
+
+module.exports = {
+    getBillsTemplate: function(req, res){
+        var data = JSON.parse(req.body.data);
+        BillsTemplateData.getTemplate(data.tempType, function(err, message, templates){
+            if (templates) {
+                callback(req, res, err, message, templates);
+            } else {
+                callback(req, res, err, message, null);
+            }
+        });
+    },
+    updateBillsTemplate: function (req, res) {
+        var data = JSON.parse(req.body.data);
+        BillsTemplateData.updateTemplate(data.user_id, data.tempType, data.updateData, function (err, message, data) {
+            if (err === 0) {
+                callback(req, res, err, message, data);
+            } else {
+                callback(req, res, err, message, null);
+            }
+        });
+    },
+    getNewBillsTemplateID: function (req, res) {
+        var data = JSON.parse(req.body.data);
+        BillsTemplateData.getNewBillsTemplateID(data.count, function (err, message, data) {
+            if (err === 0) {
+                callback(req, res, err, message, data);
+            } else {
+                callback(req, res, err, message, null);
+            }
+        });
+    }
+}

+ 81 - 0
modules/templates/models/bills_template.js

@@ -0,0 +1,81 @@
+/**
+ * Created by Mai on 2017/4/14.
+ * 清单模板,新建项目使用
+ */
+var counter = require("../../../public/counter/counter.js");
+
+var mongoose = require('mongoose');
+var dbm = require("../../../config/db/db_manager");
+var templatesDB = dbm.getCfgConnection("templates");
+var Schema = mongoose.Schema;
+var deleteSchema = require('../../../public/models/deleteSchema');
+var BillsTemplateSchema = new Schema({
+    ID: Number,
+    ParentID: Number,
+    NextSiblingID: Number,
+    code: String,
+    name: String,
+    unit: String,
+    deleteInfo: deleteSchema,
+    tempType: Number
+});
+var BillsTemplates = templatesDB.model('temp_bills', BillsTemplateSchema);
+
+var BillsTemplateDAO = function(){};
+
+BillsTemplateDAO.prototype.getTemplate = function (type, callback) {
+    BillsTemplates.find({'$or': [{tempType: type, deleteInfo: null}, {tempType: type, 'deleteInfo.deleted': {$in: [null, false]}}]}, '-_id', function(err, template){
+        if (err) {
+            callback(1, '找不到模板', null);
+        } else {
+            callback(0, '', template);
+        }
+    });
+};
+BillsTemplateDAO.prototype.updateTemplate = function (userID, tempType, datas, callback) {
+    var data, project, updateLength = 0, hasError = false, deleteInfo = null;
+    var updateAll = function (err) {
+        if (!err){
+            updateLength += 1;
+            if (updateLength === datas.length) {
+                callback(0, '', datas);
+            }
+        } else {
+            hasError = true;
+            callback(1, '升级数据出错', null);
+        }
+    };
+    if (datas){
+        for (var i = 0; i < datas.length && !hasError; i++){
+            data = datas[i];
+            if (data.type === 'update') {
+                BillsTemplates.update({tempType: tempType, ID: data.data.ID}, data.data, updateAll)
+            } else if (data.type === 'new') {
+                data.data['tempType'] = tempType;
+                newProject = new BillsTemplates(data.data);
+                newProject.save(updateAll);
+            } else if (data.type === 'delete') {
+                deleteInfo = {};
+                deleteInfo['deleted'] = true;
+                deleteInfo['deleteDateTime'] = new Date();
+                deleteInfo['deleteBy'] = userID;
+                BillsTemplates.update({ID: data.data.ID}, {deleteInfo: deleteInfo}, updateAll);
+            } else {
+                hasError = true;
+                callback(1, '升级数据出错', null)
+            }
+        }
+    }
+};
+BillsTemplateDAO.prototype.getNewBillsTemplateID = function (count, callback) {
+    counter.counterDAO.getIDAfterCount(counter.moduleName.template_bills, count, function (err, result) {
+        var highID = result.value.sequence_value;
+        if (!err) {
+            callback(0, '', {lowID: highID - count + 1, highID: highID});
+        } else {
+            callback(1, '获取主键失败', null);
+        }
+    });
+}
+
+module.exports = new BillsTemplateDAO();

+ 13 - 0
modules/templates/routes/bills_template_router.js

@@ -0,0 +1,13 @@
+/**
+ * Created by Mai on 2017/4/17.
+ */
+
+var express = require('express');
+var billsTemplateRouter = express.Router();
+var billsTemplateController = require('./../controllers/bills_template_controller');
+
+billsTemplateRouter.post('/getBillsTemplate', billsTemplateController.getBillsTemplate);
+billsTemplateRouter.post('/updateBillsTemplate', billsTemplateController.updateBillsTemplate);
+billsTemplateRouter.post('/getNewBillsTemplateID', billsTemplateController.getNewBillsTemplateID);
+
+module.exports = billsTemplateRouter;

+ 21 - 3
public/counter/counter.js

@@ -15,11 +15,26 @@ counterSchema.statics.findAndModify = function (query, sort, doc, options, callb
 };
 var counterModel = projectdb.model("counters", counterSchema);
 
-const PROJECT_COUNTER = 'projects', USER_COUNTER = 'users', BILL_COUNTER = 'bills', RATION_COUNTER = 'rations',
-    REPORT_COUNTER = 'rptTemplates', FEE_COUNTER = 'fees'
+// All counter Must predefine in DB
+const COUNTER_MODULE_NAME = {
+    project: 'projects',
+    user: 'users',
+    bills: 'bills',
+    ration: 'rations',
+    report: 'rptTemplates',
+    fee: 'fees',
+    template_bills: 'temp_bills'
+}
+/*const PROJECT_COUNTER = 'projects', USER_COUNTER = 'users', BILL_COUNTER = 'bills', RATION_COUNTER = 'rations',
+    REPORT_COUNTER = 'rptTemplates', FEE_COUNTER = 'fees'*/
 
 var counterDAO = function(){};
 
+/*
+ * callback = function (err, result) {
+ *     result.value.sequence_value ΪÐ޸ĺóµÄid
+ * }
+ */
 counterDAO.prototype.getIDAfterCount = function(moduleName, stepCount, callback) {
     var sc = stepCount;
     if (isNaN(stepCount) || (stepCount < 0)) {
@@ -46,4 +61,7 @@ counterDAO.prototype.getCurrentID = function(moduleName, callback) {
     }
 }
 
-module.exports = new counterDAO();
+module.exports = {
+    counterDAO: new counterDAO(),
+    moduleName: COUNTER_MODULE_NAME
+};

+ 15 - 0
public/models/deleteSchema.js

@@ -0,0 +1,15 @@
+/**
+ * Created by Mai on 2017/4/17.
+ */
+
+var mongoose = require("mongoose");
+var Schema = mongoose.Schema;
+
+// ·ÑÓÃ×Ö¶Î
+var deleteSchema = new Schema({
+    deleted: Boolean,
+    deleteDateTime: Date,
+    deleteBy: Number // userID
+});
+
+module.exports = deleteSchema;

+ 6 - 6
public/web/idTree.js

@@ -108,7 +108,7 @@ var idTree = {
                     } else if (arguments.length === 3) {
                         children.push(nodes[i]);
                     }
-                    nodes[i].parent = parent;
+                    nodes[i].parent = parent ? parent : null;
                 }
             },
             sortTreeItems: function (tree) {
@@ -411,7 +411,7 @@ var idTree = {
             if (this.rangeNodeID() === -1) {
                 return this.maxNodeID() + 1;
             } else {
-                if (this.maxNodeID() >= this.rangeNodeID()) {
+                if (this.maxNodeID() < this.rangeNodeID()) {
                     return this.maxNodeID() + 1;
                 } else {
                     return -1;
@@ -480,8 +480,8 @@ var idTree = {
             if (newID !== -1) {
                 data = {};
                 data[this.setting.id] = newID;
-                data[this.setting.pid] = parentID;
-                data[this.setting.nid] = nextSiblingID;
+                data[this.setting.pid] = parent ? parent.getID() : this.setting.rootId;
+                data[this.setting.nid] = nextSibling ? nextSibling.getID() : this.setting.rootId;
                 node = new Node(this, data);
                 if (nextSibling) {
                     tools.addNodes(this, parent, [node], nextSibling.siblingIndex());
@@ -500,11 +500,11 @@ var idTree = {
             var parent = parentID === -1 ? null : this.nodes[this.prefix + parentID];
             var nextSibling = nextSiblingID === -1 ? null: this.nodes[this.prefix + nextSiblingID];
             if (newID !== -1) {
-                data.push({type: 'new', data: this.getDataTemplate(newID, parentID, nextSiblingID)});
+                data.push({type: 'new', data: this.getDataTemplate(newID, parent ? parent.getID() : this.setting.rootId, nextSibling ? nextSibling.getID() : this.setting.rootId)});
 
                 if (nextSibling && nextSibling.preSibling) {
                     tools.addUpdateDataForNextSibling(data, nextSibling.preSibling, newID);
-                } else if (parent && parent.childrent.length !== 0) {
+                } else if (parent && parent.children.length !== 0) {
                     tools.addUpdateDataForNextSibling(data, parent.lastChild(), newID);
                 } else if (!parent && this.roots.length !== 0) {
                     tools.addUpdateDataForNextSibling(data, this.roots[this.roots.length - 1], newID);

+ 9 - 2
public/web/tree_sheet_controller.js

@@ -10,12 +10,12 @@ var TREE_SHEET_CONTROLLER = {
             this.setting = setting;
             this.event = {
                 refreshBaseActn: null
-            }
+            };
+            TREE_SHEET_HELPER.loadSheetHeader(this.setting, this.sheet);
         };
 
         controller.prototype.showTreeData = function () {
             var that = this;
-            TREE_SHEET_HELPER.loadSheetHeader(this.setting, this.sheet);
             TREE_SHEET_HELPER.showTreeData(this.setting, this.sheet, this.tree);
             this.sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, function (e, info) {
                 that.setTreeSelected(that.tree.findNode(info.sheet.getTag(info.newSelections[0].row, info.newSelections[0].col)));
@@ -119,6 +119,13 @@ var TREE_SHEET_CONTROLLER = {
             }
         };
 
+        controller.prototype.refreshTreeNode = function (nodes, recursive) {
+            var that = this;
+            TREE_SHEET_HELPER.massOperationSheet(this.sheet, function () {
+                TREE_SHEET_HELPER.refreshTreeNodeData(that.setting, that.sheet, nodes, recursive)
+            })
+        }
+
         controller.prototype.setTreeSelected = function (node) {
             this.tree.selected = node;
             if (this.event.refreshBaseActn) {

+ 19 - 8
server.js

@@ -36,18 +36,29 @@ app.use(session({
     //*/
 }));
 
+app.use(function (req, res, next) {
+    var url = req.originalUrl;
+    if (req.originalUrl !== "/login" && !req.session.userAccount) {
+        return res.redirect("/login");
+    }
+    next();
+});
+
 app.use('/', require('./modules/users/routes/users_route'));
 app.use('/fees', require('./modules/fees/routes/fees_router'));
 
+app.get('/template/bills', function (req, res) {
+    res.render('templates/html/bills.html',
+        {userAccount: req.session.userAccount,
+            userID: req.session.userID});
+});
+var billsTemplateRouter = require('./modules/templates/routes/bills_template_router');
+app.use('/template/bills', billsTemplateRouter);
+
 app.get('/pm', function(req, res){
-    if(!req.session.userAccount){
-        res.redirect('/login');
-    }
-    else{
-        res.render('pm/html/project-management.html',
-            {userAccount: req.session.userAccount,
-                userID: req.session.userID});
-    }
+    res.render('pm/html/project-management.html',
+        {userAccount: req.session.userAccount,
+            userID: req.session.userID});
 });
 
 var pmRouter = require('./modules/pm/routes/pm_route');

+ 3 - 3
test/unit/counter/testCounter.js

@@ -6,7 +6,7 @@ var counter = require('../../../public/counter/counter');
 var mongoose = require('mongoose');
 
 test('test counter\'s usage 0:', function(t) {
-    var promise = counter.getCurrentID("rptTemplates",function(result, err) {
+    var promise = counter.counterDAO.getCurrentID(counter.moduleName.report,function(result, err) {
         console.log('callback result 0: ' + result.sequence_value);
     });
     if (promise) {
@@ -19,7 +19,7 @@ test('test counter\'s usage 0:', function(t) {
 })
 
 test('test counter\'s usage 1:', function(t) {
-    var promise = counter.getCurrentID("rptTemplates", null);
+    var promise = counter.counterDAO.getCurrentID(counter.moduleName.report, null);
     if (promise) {
         promise.then(function(rst){
             console.log('promise result 1: ' + rst.sequence_value);
@@ -30,7 +30,7 @@ test('test counter\'s usage 1:', function(t) {
 })
 
 test('test counter\'s usage 2:', function(t) {
-    counter.getIDAfterCount("rptTemplates",1, function(err, result){
+    counter.counterDAO.getIDAfterCount(counter.moduleName.report, 1, function(err, result){
         console.log('result 2: ' + result.value.sequence_value);
         t.equal(result.value.sequence_value, 1);
         t.end();

+ 7 - 53
test/unit/excel_export/rpt_excel_export_test.js

@@ -7,60 +7,14 @@ var fsUtil = require('../../../public/fsUtil');
 var rpt_xl_util = require('../../../modules/reports/util/rpt_excel_util');
 
 test('check real function.', function(t){
-    var data = fs.readFileSync('../../../tmp/07_1.page.js', 'utf8', 'r');
-    //var data = fs.readFileSync('../../../tmp/08_2.page.js', 'utf8', 'r');
+    var fName = '08_2.page_tuned1';
+    //var fName = '07_1.page';
+    //var data = fs.readFileSync('../../../tmp/07_1.page.js', 'utf8', 'r');
+    var data = fs.readFileSync('../../../tmp/' + fName + '.js', 'utf8', 'r');
     eval(data);
-    rpt_xl_util.exportExcel(testReport07_1, null);
+    var pageObj = testReport08_2;
+    //console.log(pageObj.items[0].cells.length);
+    rpt_xl_util.exportExcel(pageObj, fName, null);
     t.pass('pass exportExcel');
     t.end();
 });
-
-//test('check excel output', function(t){
-//    var data = fs.readFileSync('../../../tmp/07_1.page.js', 'utf8', 'r');
-//    eval(data);
-//    //console.log(testReport07_1);
-//    var sheets = [];
-//    for (var i = 0; i < testReport07_1.items.length; i++) {
-//        sheets.push({sheetName: '第' + (i + 1) + '页'});
-//    }
-//    var ct = rpt_xl_util.testWriteContentTypes(sheets);
-//    fsUtil.writeArrayToFile(ct, '../../../tmp/[Content_Types].xml');
-//    t.pass('pass content types');
-//    var rootRels = rpt_xl_util.testWriteRootRels();
-//    fsUtil.writeArrayToFile(rootRels, '../../../tmp/.rels');
-//    t.pass('pass root rels');
-//    var app = rpt_xl_util.testWriteApp(sheets);
-//    fsUtil.writeArrayToFile(app, '../../../tmp/app.xml');
-//    t.pass('pass app');
-//    var core = rpt_xl_util.testWriteCore(sheets);
-//    fsUtil.writeArrayToFile(core, '../../../tmp/core.xml');
-//    t.pass('pass core');
-//    var xlWBs = rpt_xl_util.testWriteXlWorkBook(sheets);
-//    fsUtil.writeArrayToFile(xlWBs, '../../../tmp/workbook.xml');
-//    t.pass('pass workbook');
-//    //workbook.xml.rels
-//    var xlRels = rpt_xl_util.testWriteXlRels(sheets);
-//    fsUtil.writeArrayToFile(xlRels, '../../../tmp/workbook.xml.rels');
-//    t.pass('pass xl sheet rels');
-//    var sharedStrList = [], stylesObj = {};
-//    var sheetsArr = rpt_xl_util.testWriteSheets(testReport07_1, sharedStrList, stylesObj);
-//    for (var i = 0; i < sheetsArr.length; i++) {
-//        fsUtil.writeArrayToFile(sheetsArr[i], '../../../tmp/sheet' + (i + 1) + '.xml');
-//        t.pass('pass sheet' + (i + 1));
-//    }
-//    var sharedStr = rpt_xl_util.testWriteSharedString(sharedStrList);
-//    fsUtil.writeArrayToFile(sharedStr, '../../../tmp/sharedStrings.xml');
-//    t.pass('pass shared string');
-//
-//    var styleStr = rpt_xl_util.testWriteStyles(stylesObj);
-//    fsUtil.writeArrayToFile(styleStr, '../../../tmp/styles.xml');
-//    t.pass('pass styles');
-//
-//    var theme = rpt_xl_util.testWriteTheme();
-//    //console.log(theme);
-//    var themeArr = [];
-//    themeArr.push(theme)
-//    fsUtil.writeArrayToFile(themeArr, '../../../tmp/theme1.xml');
-//    t.pass('pass theme');
-//    t.end();
-//});

+ 4 - 0
web/css/main.css

@@ -261,3 +261,7 @@ body {
   width:inherit;
   height: inherit;
 }
+.modal-fixed-height {
+  height: 400px;
+  overflow-y: auto;
+}

+ 41 - 6
web/main/html/main.html

@@ -658,7 +658,6 @@
 
             if (!selected || selected.sourceType === project.Bills.getSourceType()) {
                 newSource = project.Bills.tree.insert(selected ? selected.source.getParentID() : -1, selected ? selected.source.getNextSiblingID() : -1);
-                newSource.data.Name = 'aaa';
                 newNode = project.mainTree.insert(selected.getParentID(), selected.getNextSiblingID());
             } else if (selected.sourceType === project.Rations.getSourceType()) {
 
@@ -685,19 +684,55 @@
             }
         });
         $('#delete').click(function () {
-            controller.delete();
+            var selected = controller.tree.selected;
+            if (selected) {
+                if (selected.sourceType === project.Bills.getSourceType()) {
+                    project.Bills.delete(selected.source.getID());
+                    controller.delete();
+                } else if (selected.sourceType === project.Rations.getSourceType()) {
+                    project.Rations.delete(selected.source);
+                    controller.delete();
+                };
+            }
         });
         $('#upLevel').click(function () {
-            controller.upLevel()
+            console.log(project.Bills.tree.getInsertData(project.Bills.tree.selected.getParentID(), project.Bills.tree.selected.getNextSiblingID()));
+            var selected = controller.tree.selected;
+            if (selected && selected.sourceType === project.Bills.getSourceType()) {
+                selected.source.upLevel();
+                controller.upLevel();
+            }
         });
         $('#downLevel').click(function () {
-            controller.downLevel();
+            var selected = controller.tree.selected;
+            if (selected && selected.sourceType === project.Bills.getSourceType()) {
+                selected.source.upLevel();
+                controller.downLevel();
+            }
         });
         $('#upMove').click(function () {
-            controller.upMove();
+            var selected = controller.tree.selected;
+            if (selected) {
+                if (selected.sourceType === project.Bills.getSourceType()) {
+                    selected.source.upLevel();
+                    controller.upMove();
+                } else if (selected.sourceType === project.Rations.getSourceType()) {
+                    // to Do
+                    controller.upMove();
+                }
+            }
         });
         $('#downMove').click(function () {
-            controller.downMove();
+            var selected = controller.tree.selected;
+            if (selected) {
+                if (selected.sourceType === project.Bills.getSourceType()) {
+                    selected.source.downLevel();
+                    controller.downMove();
+                } else if (selected.sourceType === project.Rations.getSourceType()) {
+                    // to Do
+                    controller.downMove();
+                }
+            }
         });
     });
 </script>

+ 1 - 1
web/main/js/models/project.js

@@ -18,7 +18,7 @@ var PROJECT = {
 
             this.Bills = Bills.createNew(this);
             this.Rations = Rations.createNew(this);
-            this.GLJ = GLJs.createNew(this);
+            this.GLJs = GLJs.createNew(this);
 
 
             this.masterField = {ration: 'BillsID'};

+ 1 - 1
web/scripts/tree_table.js

@@ -593,7 +593,7 @@
  		init: function(obj, setting, arrData){
             var _treeSetting, _tree;
             _treeSetting = _data.clone(_setting);
-            $.extend(true, _treeSetting, setting)
+            $.extend(true, _treeSetting, setting);
  			var _tree = new Tree(obj, _treeSetting);
  			_tree.loadData(arrData);
  			_tree.refreshTreeDom();

+ 105 - 0
web/templates/html/bills.html

@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html>
+<head lang="en">
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>模板清单-Smartcost</title>
+    <link rel="stylesheet" href="/web/css/bootstrap/bootstrap.min.css">
+    <link rel="stylesheet" href="/web/css/main.css">
+    <link rel="stylesheet" href="/web/css/font-awesome/font-awesome.min.css">
+    <!--SpreadJs-->
+    <link rel="stylesheet" href="/web/css/spreadjs/gc.spread.sheets.excel2013lightGray.10.0.1.css" type="text/css">
+    <script>
+        // 这里的变量供页面调用
+        var userAccount = '<%- userAccount %>';
+        var userID = '<%- userID %>';
+    </script>
+</head>
+<body>
+    <div class="header">
+        <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 justify-content-between">
+            <span class="header-logo px-2">Smartcost</span>
+            <div class="float-lg-right navbar-text pt-0">
+                <div class="dropdown d-inline-block">
+                    <button class="btn btn-link btn-sm dropdown-toggle" type="button" data-toggle="dropdown"><%- userAccount %></button>
+                    <div class="dropdown-menu dropdown-menu-right">
+                        <a class="dropdown-item" href="/user/info" target="_blank">账号资料</a>
+                        <a class="dropdown-item" href="/user/buy" target="_blank">产品购买</a>
+                        <a class="dropdown-item" href="/user/set" target="_blank">偏好设置</a>
+                    </div>
+                </div>
+                    <span class="btn btn-link btn-sm new-msg">
+                        <i class="fa fa-envelope-o" aria-hidden="true"></i>&nbsp;2
+                    </span>
+                    <a class="btn btn-link btn-sm" href="/logout">注销</a>
+            </div>
+        </nav>
+    </div>
+<div class="main">
+    <div class="content">
+        <div class="toolsbar px-1 d-flex justify-content-between">
+            <div class="tools-btn btn-group align-top">
+                <a href="" class="btn btn-sm"><i class="fa fa-files-o" aria-hidden="true"></i> 复制</a>
+                <a href="" class="btn btn-sm"><i class="fa fa-scissors" aria-hidden="true"></i> 剪切</a>
+                <a href="" class="btn btn-sm"><i class="fa fa-clipboard" aria-hidden="true"></i> 粘贴</a>
+                <a href="javascript:void(0)" class="btn btn-sm" id="insert"><i class="fa fa-sign-in" aria-hidden="true"></i> 插入</a>
+                <a href="javascript:void(0)" class="btn btn-sm" id="delete"><i class="fa fa-remove" aria-hidden="true"></i> 删除</a>
+                <a href="javascript:void(0)" class="btn btn-sm" id="upLevel"><i class="fa fa-arrow-left" aria-hidden="true"></i> 升级</a>
+                <a href="javascript:void(0)" class="btn btn-sm" id="downLevel"><i class="fa fa-arrow-right" aria-hidden="true"></i> 降级</a>
+                <a href="javascript:void(0)" class="btn btn-sm" id="downMove"><i class="fa fa-arrow-down" aria-hidden="true"></i> 下移</a>
+                <a href="javascript:void(0)" class="btn btn-sm" id="upMove"><i class="fa fa-arrow-up" aria-hidden="true"></i> 上移</a>
+            </div>
+            <div class="side-tabs">
+                <ul class="nav nav-tabs" role="tablist">
+                    <li class="nav-item">
+                        <a class="nav-link active px-3" data-toggle="tab" href="#qd" role="tab">清单规则</a>
+                    </li>
+                </ul>
+            </div>
+        </div>
+        <div class="container-fluid">
+            <div class="row">
+                <div class="main-content col-lg-9 p-0">
+                    <div class="main-data" id="billsSpread" style="height: 600px">
+                    </div>
+                </div>
+                <div class="main-side col-lg-3 p-0">
+                    <div class="tab-content">
+                        <!--清单规则-->
+                        <div class="tab-pane active" id="qd" role="tabpanel">
+                            <div class="warp-p2">
+                                <div>
+                                    <select class="form-control form-control-sm" id="exampleSelect1">
+                                        <option>重庆市房屋建筑与装饰工程工程量计算规则(2013)</option>
+                                    </select>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+</body>
+<!-- JS. -->
+<script src="/lib/jquery/jquery.min.js"></script>
+<script src="/lib/tether/tether.min.js"></script>
+<script src="/lib/bootstrap/bootstrap.min.js"></script>
+<script src="/lib/global.js"></script>
+<!-- SpreadJs -->
+<script type="text/javascript" src="/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
+<script>GC.Spread.Sheets.LicenseKey = "559432293813965#A0y3iTOzEDOzkjMyMDN9UTNiojIklkI1pjIEJCLi4TPB9mM5AFNTd4cvZ7SaJUVy3CWKtWYXx4VVhjMpp7dYNGdx2ia9sEVlZGOTh7NRlTUwkWR9wEV4gmbjBDZ4ElR8N7cGdHVvEWVBtCOwIGW0ZmeYVWVr3mI0IyUiwCMzETN8kzNzYTM0IicfJye&Qf35VfiEzRwEkI0IyQiwiIwEjL6ByUKBCZhVmcwNlI0IiTis7W0ICZyBlIsIyNyMzM5ADI5ADNwcTMwIjI0ICdyNkIsIibj9SbvNmL4N7bjRnch56ciojIz5GRiwiI8+Y9sWY9QmZ0Jyp96uL9v6L0wap9biY9qiq95q197Wr9g+89iojIh94Wiqi";</script>
+<!-- Models -->
+<script type="text/javascript" src="/public/web/idTree.js"></script>
+<!-- Controller -->
+<script type="text/javascript" src="/public/web/tree_sheet_controller.js"></script>
+<script type="text/javascript" src="/public/web/tree_sheet_helper.js"></script>
+<!-- service -->
+<script type="text/javascript" src="/web/templates/js/bills.js"></script>
+<script type="text/javascript" src="/web/templates/js/tp_bills_setting.js"></script>
+<script type="text/javascript">
+    autoFlashHeight();
+</script>
+</html>

+ 196 - 0
web/templates/js/bills.js

@@ -0,0 +1,196 @@
+/**
+ * Created by Mai on 2017/4/17.
+ */
+$(document).ready(function () {
+    var tempType = 3;
+    var PostData = function (url, data, successCallback, errorCallback) {
+        $.ajax({
+            type:"POST",
+            url: url,
+            data: {'data': JSON.stringify(data)},
+            dataType: 'json',
+            cache: false,
+            timeout: 50000,
+            success: function(result){
+                if (result.error === 0) {
+                    successCallback(result.data);
+                } else {
+                    alert('error: ' + result.message);
+                    if (errorCallback) {
+                        errorCallback();
+                    }
+                }
+            },
+            error: function(jqXHR, textStatus, errorThrown){
+                alert('error ' + textStatus + " " + errorThrown);
+                if (errorCallback) {
+                    errorCallback();
+                }
+            }
+        });
+    };
+    var FormatUpdateData = function (data) {
+        var updateData = {};
+        updateData['user_id'] = userID;
+        updateData['tempType'] = tempType;
+        updateData['updateData'] = data;
+        return updateData;
+    };
+    var RefreshBaseActn = function (tree) {
+        var showButton = function (show, btn) {
+            if (show) {
+                btn.show();
+            } else {
+                btn.hide();
+            }
+        };
+        showButton(tree.selected && tree.selected.canUpLevel(), $('#upLevel'));
+        showButton(tree.selected && tree.selected.canDownLevel(), $('#downLevel'));
+        showButton(tree.selected && tree.selected.canUpMove(), $('#upMove'));
+        showButton(tree.selected && tree.selected.canDownMove(), $('#downMove'));
+        showButton(tree.selected ? true : false, $('#delete'));
+    }
+    var RefreshBillsData = function (datas) {
+        datas.forEach(function (data) {
+            bills.forEach(function (billsData) {
+                if (data.data.ID === billsData.ID) {
+                    $.extend(true, billsData, data.data);
+                }
+            })
+        })
+    }
+
+    var bills;
+    var tree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1});
+    var billsSpread = new GC.Spread.Sheets.Workbook($('#billsSpread')[0], { sheetCount: 1 });
+    var controller = TREE_SHEET_CONTROLLER.createNew(tree, billsSpread.getActiveSheet(), TEMPLATE_BILLS_SETTING);
+
+    GC.Spread.Common.CultureManager.culture("zh-cn");
+
+    billsSpread.options.tabStripVisible = false;
+    billsSpread.options.scrollbarMaxAlign = true;
+    controller.bind('refreshBaseActn', RefreshBaseActn);
+
+    billsSpread.bind(GC.Spread.Sheets.Events.EditEnded, function (sender, info) {
+        var node = controller.tree.findNode(info.sheet.getTag(info.row, info.col));
+        var fieldName = controller.setting.cols[info.col].data.field;
+        var data = {type: 'update', data: {ID: node.getID()}};
+        data.data[fieldName] = info.editingText;
+        var updateData = FormatUpdateData([data]);
+        PostData('/template/bills/updateBillsTemplate', updateData, function (data) {
+            node.data[fieldName] = info.editingText;
+            controller.refreshTreeNode([node], false);
+        }, function () {
+            controller.refreshTreeNode([node], false);
+        });
+    });
+    billsSpread.bind(GC.Spread.Sheets.Events.ClipboardPasted, function (e, info) {
+        var node, iRow, iCol, curRow, curCol, datas = [], data, fieldName, updateData;
+        for (iRow = 0; iRow < info.cellRange.rowCount; iRow ++) {
+            curRow = info.cellRange.row + iRow;
+            node = controller.tree.findNode(info.sheet.getTag(curRow, 0));
+            if (node) {
+                data = {type: 'update', data: {ID: node.getID()}};
+                for (iCol = 0; iCol < info.cellRange.colCount; iCol++) {
+                    curCol = info.cellRange.col + iCol;
+                    fieldName = controller.setting.cols[curCol].data.field;
+                    data.data[fieldName] = info.sheet.getText(curRow, curCol);
+                }
+                datas.push(data);
+            }
+        };
+        PostData('/template/bills/updateBillsTemplate', FormatUpdateData(datas), function (data) {
+            RefreshBillsData(data);
+            controller.showTreeData();
+        }, function () {
+            controller.showTreeData();
+        })
+    });
+
+    PostData('/template/bills/getBillsTemplate', {tempType: tempType}, function (data) {
+        bills = data;
+        tree.loadDatas(bills);
+        controller.showTreeData();
+        RefreshBaseActn(tree);
+    }, function () {
+        controller.showTreeData();
+        RefreshBaseActn(tree);
+    });
+
+    $('#insert').click(function () {
+        PostData('/template/bills/getNewBillsTemplateID', {count: 1}, function (data) {
+            var selected = controller.tree.selected, updateData;
+            controller.tree.maxNodeID(data.lowID - 1);
+            controller.tree.rangeNodeID(data.highID);
+            if (selected) {
+                updateData = FormatUpdateData(controller.tree.getInsertData(selected.getParentID(), selected.getNextSiblingID()));
+            } else {
+                updateData = FormatUpdateData(controller.tree.getInsertData());
+            }
+            if (updateData.updateData.length > 0) {
+                PostData('/template/bills/updateBillsTemplate', updateData, function (data) {
+                    controller.insert();
+                    RefreshBillsData(data);
+                    controller.showTreeData();
+                });
+            } else {
+                alert('新增节点失败, 请重试.');
+            }
+        });
+    });
+    $('#delete').click(function () {
+        var selected = controller.tree.selected, updateData;
+        if (selected) {
+            updateData = FormatUpdateData(controller.tree.getDeleteData(selected));
+            PostData('/template/bills/updateBillsTemplate', updateData, function (data) {
+                controller.delete();
+                RefreshBillsData(data);
+                controller.showTreeData();
+            });
+        }
+    });
+    $('#upLevel').click(function () {
+        var selected = controller.tree.selected, updateData;
+        if (selected) {
+            updateData = FormatUpdateData(selected.getUpLevelData());
+            PostData('/template/bills/updateBillsTemplate', updateData, function (data) {
+                controller.upLevel();
+                RefreshBillsData(data);
+                controller.showTreeData();
+            });
+        }
+    });
+    $('#downLevel').click(function () {
+        var selected = controller.tree.selected, updateData;
+        if (selected) {
+            updateData = FormatUpdateData(selected.getDownLevelData());
+            PostData('/template/bills/updateBillsTemplate', updateData, function (data) {
+                controller.downLevel();
+                RefreshBillsData(data);
+                controller.showTreeData();
+            });
+        }
+    });
+    $('#upMove').click(function () {
+        var selected = controller.tree.selected, updateData;
+        if (selected) {
+            updateData = FormatUpdateData(selected.getUpMoveData());
+            PostData('/template/bills/updateBillsTemplate', updateData, function (data) {
+                controller.upMove();
+                RefreshBillsData(data);
+                controller.showTreeData();
+            });
+        }
+    });
+    $('#downMove').click(function () {
+        var selected = controller.tree.selected, updateData;
+        if (selected) {
+            updateData = FormatUpdateData(selected.getDownMoveData());
+            PostData('/template/bills/updateBillsTemplate', updateData, function (data) {
+                controller.downMove();
+                RefreshBillsData(data);
+                controller.showTreeData();
+            });
+        }
+    });
+});

+ 184 - 0
web/templates/js/tp_bills_setting.js

@@ -0,0 +1,184 @@
+/**
+ * Created by Mai on 2017/4/17.
+ */
+var TEMPLATE_BILLS_SETTING = {
+    "emptyRows":1,
+    "headRows":1,
+    "headRowHeight":[20],
+    "treeCol": 0,
+    "cols":[{
+        "width":200,
+        "readOnly":null,
+        "head":{
+            "titleNames":[
+                "编号"
+            ],
+            "spanCols":[
+                1
+            ],
+            "spanRows":[
+                1
+            ],
+            "vAlign":[
+                1
+            ],
+            "hAlign":[
+                1
+            ],
+            "font":[
+                "12px Arial"
+            ]
+        },
+        "data":{
+            "field":"code",
+            "vAlign":0,
+            "hAlign":3,
+            "font":"14.6667px Calibri"
+        }
+    }, {
+        "width":300,
+        "readOnly":null,
+        "head":{
+            "titleNames":[
+                "名称"
+            ],
+            "spanCols":[
+                1
+            ],
+            "spanRows":[
+                1
+            ],
+            "vAlign":[
+                1
+            ],
+            "hAlign":[
+                1
+            ],
+            "font":[
+                "12px Arial"
+            ]
+        },
+        "data":{
+            "field":"name",
+            "vAlign":0,
+            "hAlign":3,
+            "font":"14.6667px Calibri"
+        }
+    }, {
+        "width":50,
+        "readOnly":null,
+        "head":{
+            "titleNames":[
+                "单位"
+            ],
+            "spanCols":[
+                1
+            ],
+            "spanRows":[
+                1
+            ],
+            "vAlign":[
+                1
+            ],
+            "hAlign":[
+                1
+            ],
+            "font":[
+                "12px Arial"
+            ]
+        },
+        "data":{
+            "field":"unit",
+            "vAlign":0,
+            "hAlign":1,
+            "font":"14.6667px Calibri"
+        }
+    }, {
+        "width":50,
+        "readOnly":null,
+        "head":{
+            "titleNames":[
+                "ID"
+            ],
+            "spanCols":[
+                1
+            ],
+            "spanRows":[
+                1
+            ],
+            "vAlign":[
+                1
+            ],
+            "hAlign":[
+                1
+            ],
+            "font":[
+                "12px Arial"
+            ]
+        },
+        "data":{
+            "field":"ID",
+            "vAlign":0,
+            "hAlign":1,
+            "font":"14.6667px Calibri"
+        }
+    }, {
+        "width":50,
+        "readOnly":null,
+        "head":{
+            "titleNames":[
+                "ParentID"
+            ],
+            "spanCols":[
+                1
+            ],
+            "spanRows":[
+                1
+            ],
+            "vAlign":[
+                1
+            ],
+            "hAlign":[
+                1
+            ],
+            "font":[
+                "12px Arial"
+            ]
+        },
+        "data":{
+            "field":"ParentID",
+            "vAlign":0,
+            "hAlign":1,
+            "font":"14.6667px Calibri"
+        }
+    }, {
+        "width":50,
+        "readOnly":null,
+        "head":{
+            "titleNames":[
+                "NextSiblingID"
+            ],
+            "spanCols":[
+                1
+            ],
+            "spanRows":[
+                1
+            ],
+            "vAlign":[
+                1
+            ],
+            "hAlign":[
+                1
+            ],
+            "font":[
+                "12px Arial"
+            ]
+        },
+        "data":{
+            "field":"NextSiblingID",
+            "vAlign":0,
+            "hAlign":1,
+            "font":"14.6667px Calibri"
+        }
+    }]
+};