Browse Source

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

caiaolin 8 years ago
parent
commit
ee6987b52f
79 changed files with 6025 additions and 1257 deletions
  1. 2 1
      .gitignore
  2. 13 0
      Dockerfile
  3. 2 0
      config/cacheCfg.js
  4. 15 0
      config/db/db_manager.js
  5. 87 29
      modules/bills_lib/controllers/bills_lib_controllers.js
  6. 1244 232
      modules/bills_lib/models/bills_lib_interfaces.js
  7. 8 8
      modules/bills_lib/models/bills_lib_model.js
  8. 5 5
      modules/bills_lib/models/bills_lib_schemas.js
  9. 64 28
      modules/bills_lib/routes/bills_lib_routes.js
  10. 47 0
      modules/common/fileUtils.js
  11. 3 3
      modules/ration_repository/models/coe.js
  12. 3 3
      modules/ration_repository/models/glj_repository.js
  13. 0 45
      modules/ration_repository/models/rationAssist.js
  14. 0 35
      modules/ration_repository/models/rationCoe.js
  15. 2 2
      modules/ration_repository/models/ration_item.js
  16. 2 2
      modules/ration_repository/models/ration_section_tree.js
  17. 3 3
      modules/ration_repository/models/repository_map.js
  18. 66 32
      modules/ration_repository/routes/ration_rep_routes.js
  19. 33 0
      modules/reports/controllers/rpt_cfg_controller.js
  20. 53 66
      modules/reports/controllers/rpt_controller.js
  21. 127 11
      modules/reports/controllers/rpt_tpl_controller.js
  22. 2 25
      modules/reports/models/rpt_cfg.js
  23. 22 0
      modules/reports/models/rpt_mapping_field.js
  24. 4 19
      modules/reports/models/rpt_template.js
  25. 2 2
      modules/reports/models/rpt_tpl_data.js
  26. 2 77
      modules/reports/models/tpl_tree_node.js
  27. 15 3
      modules/reports/routes/report_router.js
  28. 24 5
      modules/reports/routes/rpt_tpl_router.js
  29. 2 1
      modules/reports/rpt_component/jpc_ex.js
  30. 2 4
      modules/reports/rpt_component/jpc_value_define.js
  31. 43 0
      modules/reports/util/rpt_data_util.js
  32. 45 4
      modules/reports/util/rpt_util.js
  33. 34 30
      modules/users/routes/users_route.js
  34. 21 62
      operation.js
  35. 2 1
      package.json
  36. 91 0
      public/cache/std_glj_type_util.js
  37. 193 0
      public/calc_util.js
  38. 2 0
      public/counter/counter.js
  39. 25 0
      public/models/std_glj_types.js
  40. 1 2
      public/rpt_tpl_def.js
  41. 8 3
      public/web/calculation/calc_util.js
  42. 1 1
      public/web/common_ajax.js
  43. 1 1
      public/web/rpt_value_define.js
  44. 27 0
      public/web/string_util_light.js
  45. 3 1
      public/web/treeDataHelper.js
  46. 452 0
      test/calculation/testCalc.js
  47. 65 0
      test/demo/stringTest.js
  48. 19 0
      test/public/testLoadDateFormat.js
  49. 30 0
      test/public/testStdGljTypes.js
  50. 10 9
      web/maintain/bills_lib/html/main.html
  51. 71 7
      web/maintain/bills_lib/html/neirong.html
  52. 192 48
      web/maintain/bills_lib/html/qingdan.html
  53. 140 16
      web/maintain/bills_lib/html/tezheng.html
  54. 161 36
      web/maintain/bills_lib/scripts/bills_lib_ajax.js
  55. 40 40
      web/maintain/bills_lib/scripts/bills_lib_setting.js
  56. 1154 181
      web/maintain/bills_lib/scripts/db_controller.js
  57. 18 6
      web/maintain/bills_lib/scripts/set_sheets.js
  58. 1 1
      web/maintain/ration_repository/dinge.html
  59. 4 4
      web/maintain/ration_repository/js/coe.js
  60. 1 1
      web/maintain/ration_repository/js/ration_glj.js
  61. 23 5
      web/maintain/report/css/main.css
  62. 0 0
      web/maintain/report/css/templates/css/main.css
  63. 4 4
      web/maintain/templates/html/bills.html
  64. 0 0
      web/maintain/report/css/templates/js/bills.js
  65. 0 0
      web/maintain/report/css/templates/js/global.js
  66. 0 0
      web/maintain/report/css/templates/js/tp_bills_setting.js
  67. 121 0
      web/maintain/report/js/cfg_const.js
  68. 2 6
      web/maintain/report/js/global.js
  69. 1 1
      web/maintain/report/js/jpc_output.js
  70. 1 1
      web/maintain/report/js/jpc_output_value_define.js
  71. 248 0
      web/maintain/report/js/rpt_tpl_band.js
  72. 31 0
      web/maintain/report/js/rpt_tpl_calculation.js
  73. 31 0
      web/maintain/report/js/rpt_tpl_field_cfg.js
  74. 167 0
      web/maintain/report/js/rpt_tpl_field_map.js
  75. 66 0
      web/maintain/report/js/rpt_tpl_helper.js
  76. 121 13
      web/maintain/report/js/rpt_tpl_main.js
  77. 167 0
      web/maintain/report/js/rpt_tpl_preview_util.js
  78. 26 32
      web/maintain/report/rpt_test.html
  79. 307 100
      web/maintain/report/rpt_tpl_main.html

+ 2 - 1
.gitignore

@@ -1,4 +1,5 @@
 node_modules/
 .git/
 dist/
-.idea/
+.idea/
+tmp/

+ 13 - 0
Dockerfile

@@ -0,0 +1,13 @@
+FROM server:2.0
+
+COPY . ConstructionOperation
+
+WORKDIR ConstructionOperation
+
+RUN cnpm install 
+
+EXPOSE 6080
+
+ENTRYPOINT node operation.js
+
+

+ 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)
     }
 }

+ 15 - 0
config/db/db_manager.js

@@ -45,5 +45,20 @@ module.exports = {
         mg.connect('mongodb://' + config.current.server + ":" + config.current.port + '/' + dbName);
         return mg;
         //*/
+    },
+    connect:function () {
+        var config = require("../config.js");
+        var dbURL = 'mongodb://' + config.current.server + ":" + config.current.port + '/scConstruct';
+
+        var db = mg.connect(dbURL, config.options, function(err) {
+            if (err) {
+                console.log('Could not connect to MongoDB!');
+                console.log(err);
+            }
+        });
+        mg.connection.on('error', function(err) {
+            console.log('MongoDB connection error:', err);
+            process.exit(-1);
+        });
     }
 };

+ 87 - 29
modules/bills_lib/controllers/bills_lib_controllers.js

@@ -2,165 +2,223 @@
  * Created by vian on 2017/3/22.
  */
 
-var billsLibDao = require("./../models/bills_lib_interfaces");
+let billsLibDao = require("./../models/bills_lib_interfaces");
 //----
-var model = require("./../models/bills_lib_model");
+/*let model = require("./../models/bills_lib_model");
 var counter = require("../../../public/counter/counter");
 var StdBillsLib = model.stdBillsLibMod;
 var Bills = model.billsMod;
 var JobContent = model.jobContentMod;
-var ItemCharacter = model.itemCharacterMod;
+var ItemCharacter = model.itemCharacterMod;*/
 //---
 //ͳһ�ص�����
-var callback = function(req, res, err, message, data){
+let callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});
 }
 
 module.exports = {
     getMaxNumber: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.getMaxNumber(data, function(err, message, maxNumber){
             callback(req, res, err, message, maxNumber);
         });
     },
     getABillsLib: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.getABillsLib(data, function(err, message, data){
             callback(req, res, err, message, data);
         });
     },
     getStdBillsLib: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.getStdBillsLib(data, function(err, message, stdBillsLib){
             callback(req, res, err, message, stdBillsLib );
         });
     },
     createStdBillsLib: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
          billsLibDao.createStdBillsLib(data, function(err, message, info){
             callback(req, res, err, message, info);
          });
     },
     deleteStdBillsLib: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.deleteStdBillsLib(data.billsLibId, function(err, message){
             callback(req, res, err, message, null);
         });
     },
     renameStdBillsLib: function(req, res) {
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.renameStdBillsLib(data, function (err, message) {
             callback(req, res, err ,message, null);
         });
     },
     getStdBillsLibName: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.getStdBillsLibName(data.billsLibId, function(err, message, info){
             callback(req, res, err, message, info);
         });
     },
+    getCurrentUniqId: function(req, res){
+        billsLibDao.getCurrentUniqId(function(err, message, id){
+            callback(req, res, err, message, id);
+        });
+    },
     getBills: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.getBills(data.billsLibId, function(err, message, bills){
             callback(req, res, err, message, bills);
         });
     },
     createBills: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.createBills(data, function(err, message){
             callback(req, res, err, message, null);
         });
     },
+    upMove: function(req, res){
+        let data = JSON.parse(req.body.data);
+        billsLibDao.upMove(data, function(err, message){
+            callback(req, res, err, message, null);
+        });
+    },
     updatePNId: function (req, res) {
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.updatePNId(data, function(err, message){
             callback(req, res, err, message, null);
         });
     },
     updateBills: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.updateBills(data, function(err, message){
             callback(req, res, err, message, null);
         });
     },
     updateBillsArr: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.updateBillsArr(data, function(err, message){
            callback(req, res, err, message, null);
         });
     },
     pasteBills: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.pasteBills(data, function(err, message){
             callback(req, res, err, message, null);
         });
     },
     updateRecharge: function(req, res){
-      var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.updateRecharge(data, function(err, message){
             callback(req, res, err, message, null);
         });
     },
+    pasteRel: function(req, res){
+        let data = JSON.parse(req.body.data);
+        billsLibDao.pasteRel(data, function(err, message, datas){
+            callback(req, res, err, message, datas);
+        });
+    },
     deleteBills: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.deleteBills(data, function(err, message){
             callback(req, res, err, message, null);
         });
     },
     getJobContent: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.getJobContent(data, function(err, message, jobs){
             callback(req, res, err, message, jobs);
         });
     },
     createJobContent: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.createJobContent(data, function(err, message, id){
             callback(req, res, err, message, id);
         });
     },
     updateJobContent: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.updateJobContent(data, function(err, message, id){
             callback(req, res, err, message, id);
         });
     },
     updateValue: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.updateValue(data, function(err, message){
             callback(req, res, err, message, null);
         })
     },
     deleteJobContent: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.deleteJobContent(data, function(err, message){
             callback(req, res, err, message, null);
         });
     },
+    pasteJobs: function (req, res) {
+        let data = JSON.parse(req.body.data);
+        billsLibDao.pasteJobs(data, function(err, message, datas){
+            callback(req, res, err, message, datas);
+        });
+    },
+    edCreateJob: function(req, res){
+        let data = JSON.parse(req.body.data);
+        billsLibDao.edCreateJob(data, function(err, message, id){
+            callback(req, res, err, message, id);
+        })
+    },
+    edUpdateJob: function(req, res){
+        let data = JSON.parse(req.body.data);
+        billsLibDao.edUpdateJob(data, function(err, message, id){
+            callback(req, res, err, message, id);
+        })
+    },
     getItemCharacter: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.getItemCharacter(data, function(err, message, items){
             callback(req, res, err, message, items);
         });
     },
     createItemCharacter: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.createItemCharacter(data, function(err, message, id){
             callback(req, res, err, message, id);
         });
     },
     updateItemCharacter: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.updateItemCharacter(data, function(err, message){
             callback(req, res, err, message, null);
         });
     },
     deleteItemCharacter: function(req, res){
-        var data = JSON.parse(req.body.data);
+        let data = JSON.parse(req.body.data);
         billsLibDao.deleteItemCharacter(data, function(err, message){
             callback(req, res, err, message, null);
         });
+    },
+    pasteItems: function(req, res){
+        let data = JSON.parse(req.body.data);
+        billsLibDao.pasteItems(data, function(err, message, datas){
+            callback(req, res, err, message, datas);
+        });
+    },
+    pasteValues: function(req, res){
+        let data = JSON.parse(req.body.data);
+        billsLibDao.pasteValues(data, function(err, message, datas){
+            callback(req, res, err, message, datas);
+        });
+    },
+    edCreateItem: function(req, res){
+        let data = JSON.parse(req.body.data);
+        billsLibDao.edCreateItem(data, function(err, message, id){
+            callback(req, res, err, message, id);
+        })
+    },
+    edUpdateItem: function(req, res){
+        let data = JSON.parse(req.body.data);
+        billsLibDao.edUpdateItem(data, function(err, message, id){
+            callback(req, res, err, message, id);
+        })
     }
-
 }
 

File diff suppressed because it is too large
+ 1244 - 232
modules/bills_lib/models/bills_lib_interfaces.js


+ 8 - 8
modules/bills_lib/models/bills_lib_model.js

@@ -1,14 +1,14 @@
 /**
  * Created by vian on 2017/3/17.
  */
-var dbm = require("../../../config/db/db_manager");
-var schemas = require("./bills_lib_schemas.js");
-//var db = dbm.getLocalConnection("stdBillsEditor");
-var db = dbm.getCfgConnection("stdBillsEditor");
-var stdBillsLibMod = db.model("stdBillsLib", schemas.stdBillsLibSchema);
-var billsMod = db.model("billsLib", schemas.billsSchema);
-var jobContentMod = db.model("jobContent", schemas.jobContentSchema);
-var itemCharacterMod = db.model("itemCharacter", schemas.itemCharacterSchema);
+let dbm = require("../../../config/db/db_manager");
+let schemas = require("./bills_lib_schemas.js");
+let db = dbm.getCfgConnection("scConstruct");
+//let db = dbm.getLocalConnection("stdBillsEditor");
+let stdBillsLibMod = db.model("std_bills_lib_list", schemas.stdBillsLibSchema);
+let billsMod = db.model("std_bills_lib_bills", schemas.billsSchema);
+let jobContentMod = db.model("std_bills_lib_jobContent", schemas.jobContentSchema);
+let itemCharacterMod = db.model("std_bills_lib_itemCharacter", schemas.itemCharacterSchema);
 
 module.exports = {
     stdBillsLibMod: stdBillsLibMod,

+ 5 - 5
modules/bills_lib/models/bills_lib_schemas.js

@@ -1,6 +1,6 @@
-var mongoose = require('mongoose');
+let mongoose = require('mongoose');
 
-var stdBillsLibSchema =mongoose.Schema({
+let stdBillsLibSchema =mongoose.Schema({
     userId: Number,
     billsLibId: Number,
     billsLibName: String,
@@ -10,7 +10,7 @@ var stdBillsLibSchema =mongoose.Schema({
     {versionKey: false}
 );
 
-var billsSchema = mongoose.Schema({
+let billsSchema = mongoose.Schema({
     ID: Number,
     ParentID: Number,
     NextSiblingID: Number,
@@ -28,7 +28,7 @@ var billsSchema = mongoose.Schema({
     {versionKey: false}
 );
 
-var jobContentSchema = mongoose.Schema({
+let jobContentSchema = mongoose.Schema({
     id: Number,
     code: Number,
     content: String,
@@ -38,7 +38,7 @@ var jobContentSchema = mongoose.Schema({
     {versionKey: false}
 );
 
-var itemCharacterSchema = mongoose.Schema({
+let itemCharacterSchema = mongoose.Schema({
     id: Number,
     code: Number,
     content: String,

+ 64 - 28
modules/bills_lib/routes/bills_lib_routes.js

@@ -1,33 +1,69 @@
 /**
  * Created by vian on 2017/3/17.
  */
-var express = require("express");
-var billsController = require("./../controllers/bills_lib_controllers");
-var billsRouter =express.Router();
+let express = require("express");
+let billsController = require("./../controllers/bills_lib_controllers");
+let billsRouter =express.Router();
+
+module.exports =function (app) {
+
+    app.get("/stdBillsmain", function(req, res){
+        if(!req.session.userAccount){
+            res.redirect('/login');
+        }
+        else {
+            res.render("maintain/bills_lib/html/main.html",
+                {userAccount: req.session.userAccount,
+                    userID: req.session.userID});
+        }
+    });
+    app.get("/stdBills", function(req, res){
+        res.render("maintain/bills_lib/html/qingdan.html");
+    });
+    app.get('/stdJobs', function(req, res){
+        res.render('maintain/bills_lib/html/neirong.html');
+    });
+    app.get('/stdItems', function(req, res){
+        res.render('maintain/bills_lib/html/tezheng.html');
+    });
+
+    billsRouter.post('/getMaxNumber', billsController.getMaxNumber);
+    billsRouter.post('/getABillsLib', billsController.getABillsLib);
+    billsRouter.post("/getStdBillsLib", billsController.getStdBillsLib);
+    billsRouter.post("/createStdBillsLib", billsController.createStdBillsLib);
+    billsRouter.post("/upMove", billsController.upMove);
+    billsRouter.post("/deleteStdBillsLib", billsController.deleteStdBillsLib);
+    billsRouter.post("/renameStdBillsLib", billsController.renameStdBillsLib);
+    billsRouter.post("/getStdBillsLibName", billsController.getStdBillsLibName);
+    billsRouter.post("/getCurrentUniqId", billsController.getCurrentUniqId);
+    billsRouter.post("/getBills", billsController.getBills);
+    billsRouter.post("/createBills", billsController.createBills);
+    billsRouter.post("/updatePNId", billsController.updatePNId);
+    billsRouter.post("/updateBills", billsController.updateBills);
+    billsRouter.post("/updateBillsArr", billsController.updateBillsArr);
+    billsRouter.post("/pasteBills", billsController.pasteBills);
+    billsRouter.post('/updateRecharge', billsController.updateRecharge);
+    billsRouter.post('/pasteRel', billsController.pasteRel);
+    billsRouter.post("/deleteBills", billsController.deleteBills);
+    billsRouter.post("/getJobContent", billsController.getJobContent);
+    billsRouter.post("/createJobContent", billsController.createJobContent);
+    billsRouter.post("/updateJobContent", billsController.updateJobContent);
+    billsRouter.post("/deleteJobContent", billsController.deleteJobContent);
+    billsRouter.post("/pasteJobs", billsController.pasteJobs);
+    billsRouter.post("/edCreateJob", billsController.edCreateJob);
+    billsRouter.post("/edUpdateJob", billsController.edUpdateJob);
+    billsRouter.post("/getItemCharacter", billsController.getItemCharacter);
+    billsRouter.post("/createItemCharacter", billsController.createItemCharacter);
+    billsRouter.post("/updateItemCharacter", billsController.updateItemCharacter);
+    billsRouter.post("/updateValue", billsController.updateValue);
+    billsRouter.post("/deleteItemCharacter", billsController.deleteItemCharacter);
+    billsRouter.post("/pasteItems", billsController.pasteItems);
+    billsRouter.post("/pasteValues", billsController.pasteValues);
+    billsRouter.post("/edCreateItem", billsController.edCreateItem);
+    billsRouter.post("/edUpdateItem", billsController.edUpdateItem);
+
+    app.use("/stdBillsEditor", billsRouter);
+
+}
 
-billsRouter.post('/getMaxNumber', billsController.getMaxNumber);
-billsRouter.post('/getABillsLib', billsController.getABillsLib);
-billsRouter.post("/getStdBillsLib", billsController.getStdBillsLib);
-billsRouter.post("/createStdBillsLib", billsController.createStdBillsLib);
-billsRouter.post("/deleteStdBillsLib", billsController.deleteStdBillsLib);
-billsRouter.post("/renameStdBillsLib", billsController.renameStdBillsLib);
-billsRouter.post("/getStdBillsLibName", billsController.getStdBillsLibName);
-billsRouter.post("/getBills", billsController.getBills);
-billsRouter.post("/createBills", billsController.createBills);
-billsRouter.post("/updatePNId", billsController.updatePNId);
-billsRouter.post("/updateBills", billsController.updateBills);
-billsRouter.post("/updateBillsArr", billsController.updateBillsArr);
-billsRouter.post("/pasteBills", billsController.pasteBills);
-billsRouter.post('/updateRecharge', billsController.updateRecharge);
-billsRouter.post("/deleteBills", billsController.deleteBills);
-billsRouter.post("/getJobContent", billsController.getJobContent);
-billsRouter.post("/createJobContent", billsController.createJobContent);
-billsRouter.post("/updateJobContent", billsController.updateJobContent);
-billsRouter.post("/deleteJobContent", billsController.deleteJobContent);
-billsRouter.post("/getItemCharacter", billsController.getItemCharacter);
-billsRouter.post("/createItemCharacter", billsController.createItemCharacter);
-billsRouter.post("/updateItemCharacter", billsController.updateItemCharacter);
-billsRouter.post("/updateValue", billsController.updateValue);
-billsRouter.post("/deleteItemCharacter", billsController.deleteItemCharacter);
 
-module.exports = billsRouter;

+ 47 - 0
modules/common/fileUtils.js

@@ -0,0 +1,47 @@
+'use strict';
+
+/**
+ * Module dependencies.
+ */
+var _ = require('lodash'),
+	glob = require('glob');
+
+
+/**
+ * Get files by glob patterns
+ */
+module.exports.getGlobbedFiles = function(globPatterns, removeRoot) {
+	// For context switching
+	var _this = this;
+
+	// URL paths regex
+	var urlRegex = new RegExp('^(?:[a-z]+:)?\/\/', 'i');
+
+	// The output array
+	var output = [];
+
+	// If glob pattern is array so we use each pattern in a recursive way, otherwise we use glob
+	if (_.isArray(globPatterns)) {
+		globPatterns.forEach(function(globPattern) {
+			output = _.union(output, _this.getGlobbedFiles(globPattern, removeRoot));
+		});
+	} else if (_.isString(globPatterns)) {
+		if (urlRegex.test(globPatterns)) {
+			output.push(globPatterns);
+		} else {
+			glob(globPatterns, {
+				sync: true
+			}, function(err, files) {
+				if (removeRoot) {
+					files = files.map(function(file) {
+						return file.replace(removeRoot, '');
+					});
+				}
+
+				output = _.union(output, files);
+			});
+		}
+	}
+
+	return output;
+};

+ 3 - 3
modules/ration_repository/models/coe.js

@@ -5,13 +5,13 @@
 
 var mongoose = require("mongoose");
 var dbm = require("../../../config/db/db_manager");
-var db = dbm.getCfgConnection("rationRepository");
+var db = dbm.getCfgConnection("scConstruct");
 var counter = require('../../../public/counter/counter');
 
 var coeSchema = mongoose.Schema({
     coeType: String,                // 系数类型,指作用范围:
                                     // 单个(如:111量0.001)、人工类、材料类、机械类、全部(如:定额×0.925)。
-    gljID: Number,                  // 要调整的工料机ID(当coeType=0时有效)
+    gljCode: String,                  // 要调整的工料机Code(当coeType=0时有效)
     operator: String,               // 运算符(*、+、-、=)
     amount: String,                 // 调整的量
     _id: false
@@ -25,7 +25,7 @@ var coeListSchema = mongoose.Schema({
     coes: [coeSchema]
 }, {versionKey: false});
 
-var coeListModel = db.model("coeLists",coeListSchema, "coeLists")
+var coeListModel = db.model("std_ration_lib_coe_list",coeListSchema, "std_ration_lib_coe_list")
 
 var coeListDAO = function(){};
 

+ 3 - 3
modules/ration_repository/models/glj_repository.js

@@ -5,7 +5,7 @@
 
 var mongoose = require("mongoose");
 var dbm = require("../../../config/db/db_manager");
-var db = dbm.getCfgConnection("rationRepository")
+var db = dbm.getCfgConnection("scConstruct");
 var async = require("async");
 var Schema = mongoose.Schema;
 
@@ -30,8 +30,8 @@ var gljSchema = mongoose.Schema({
     gljType: Number, //这个是UI显示上的详细分类,对应gljTypeSchema
     gljDistType: String  //人工,材料,机械
 });
-var gljTypeModel = db.model("gljType",gljTypeSchema, "gljType");
-var gljItemModel = db.model("gljRepository",gljSchema, "gljRepository");
+var gljTypeModel = db.model("std_ration_lib_glj_type",gljTypeSchema, "std_ration_lib_glj_type");
+var gljItemModel = db.model("std_ration_lib_glj_list",gljSchema, "std_ration_lib_glj_list");
 var repositoryMap = require('./repository_map');
 var counter = require('../../../public/counter/counter');
 

+ 0 - 45
modules/ration_repository/models/rationAssist.js

@@ -1,45 +0,0 @@
-/**
- * Created by CSL on 2017/5/5.
- * 辅助定额调整。
- */
-
-var mongoose = require("mongoose");
-var dbm = require("../../../config/db/db_manager");
-var db = dbm.getCfgConnection("rationRepository")
-
-// eg:重庆CQJZDE-2008,P28,AA0116机械装运土方全程运距100米内(主定额)20米内(会根据用户实际录入值变化),AA0117每增加10米(辅助定额)。
-// 建筑中的主定额只有一条辅助定额。(公路的主定额会对应多条辅助定额)
-var assistSchema = mongoose.Schema({
-    libID: Number,                      // 所属定额定ID
-    mainRationID: Number,               // 主定额ID
-    assistRationID: Number,             // 辅助定额ID
-    assistDisplayName: String,          // 辅助定额显示名称 (eg:每增加10米)
-    minValue: String,                   // 下限值(eg:20)
-    maxValue: String,                   // 上限值(eg:100,也可能没有)
-    stepValue: String                   // 步距值 (eg:10)
-});
-
-var assistModel = db.model("rationAssists",assistSchema, "rationAssists")
-
-var assistDAO = function(){};
-
-assistDAO.prototype.getAssist = function (data, callback) {
-    assistModel.findOne({
-            "libID": data.libID,
-            "mainRationID": data.mainRationID,
-            "$or": [{"isDeleted": null}, {"isDeleted": false}]
-        },
-        function (err, doc) {
-            if (err) callback(true, "获取辅助定额错误!", "")
-            else callback(false, "获取辅助定额成功", doc);
-        })
-};
-
-// test datas.
-//function callbackExec(err) {if (err) {console.log(err);} else {console.log('saved.')};};
-//assistModel.create({"libID": 1, "mainRationID":1, assistRationID: 2, assistDisplayName: "每增加10米", minValue:"20", maxValue: "100", stepValue:"10"}, callbackExec);
-//assistModel.create({"libID": 1, "mainRationID":3, assistRationID: 4, assistDisplayName: "每增加100米", minValue:"200", maxValue: "500", stepValue:"100"}, callbackExec);
-//assistModel.create({"libID": 1, "mainRationID":5, assistRationID: 6, assistDisplayName: "每增加100米", minValue:"1000", maxValue: null, stepValue:"1000"}, callbackExec);
-
-
-module.exports = new assistDAO();

+ 0 - 35
modules/ration_repository/models/rationCoe.js

@@ -1,35 +0,0 @@
-/**
- * Created by CSL on 2017/5/3.
- * 定额系数关系表。(即附注条件。系数会被定额公用,如同一个分枝下的兄弟定额。)
- * 公路上,定额章节点上也会挂系数(关系数据库可减少数据冗余),该系数作用于该章节下的所有定额。每条定额还有自己特有的系数。
- * 建筑上,简化逻辑设计,把章节点上的系数移到具体的定额上。
- */
-var mongoose = require("mongoose");
-var dbm = require("../../../config/db/db_manager");
-var db = dbm.getCfgConnection("rationRepository")
-
-var rationCoeSchema = mongoose.Schema({
-    ID:Number,
-    libID: Number,
-    rationID: Number,
-    coeIDs: Array
-});
-
-var rationCoeModel = db.model("rationCoes",rationCoeSchema, "rationCoes")
-
-var rationCoeDAO = function(){};
-
-rationCoeDAO.prototype.getRationCoes = function (data, callback) {
-    rationCoeModel.findOne({
-            "libID": data.libID,
-            "rationID": data.rationID,
-            "$or": [{"isDeleted": null}, {"isDeleted": false}]
-        },
-        function (err, doc) {
-            if (err) callback(true, "获取定额调整系数错误!", "")
-            else callback(false, "获取定额调整系数成功", doc);
-        })
-};
-
-module.exports = new rationCoeDAO();
-

+ 2 - 2
modules/ration_repository/models/ration_item.js

@@ -3,7 +3,7 @@
  */
 var mongoose = require("mongoose");
 var dbm = require("../../../config/db/db_manager");
-var db = dbm.getCfgConnection("rationRepository")
+var db = dbm.getCfgConnection("scConstruct");
 var async = require("async");
 var Schema = mongoose.Schema;
 
@@ -39,7 +39,7 @@ var rationItemSchema = mongoose.Schema({
     rationCoeList: Array,
     rationAssList: [rationAssItemSchema]
 });
-var rationItemModel = db.model("rationItems",rationItemSchema, "rationItems")
+var rationItemModel = db.model("std_ration_lib_ration_items",rationItemSchema, "std_ration_lib_ration_items")
 var counter = require('../../../public/counter/counter');
 
 var rationItemDAO = function(){};

+ 2 - 2
modules/ration_repository/models/ration_section_tree.js

@@ -4,7 +4,7 @@
 
 var mongoose = require("mongoose");
 var dbm = require("../../../config/db/db_manager");
-var chapterTreeDb = dbm.getCfgConnection("rationRepository")
+var chapterTreeDb = dbm.getCfgConnection("scConstruct");
 var async = require("async");
 var Schema = mongoose.Schema;
 
@@ -16,7 +16,7 @@ var rationChapterTreeSchema = new Schema({//章节树  //生成唯一id改为sec
     name: String,
     isDeleted: Boolean
 });
-var rationChapterTreeModel = chapterTreeDb.model("rationChapterTrees",rationChapterTreeSchema, "rationChapterTrees")
+var rationChapterTreeModel = chapterTreeDb.model("std_ration_lib_ration_chapter_trees", rationChapterTreeSchema, "std_ration_lib_ration_chapter_trees");
 var counter = require('../../../public/counter/counter');
 
 var rationChapterTreeDAO = function(){};

+ 3 - 3
modules/ration_repository/models/repository_map.js

@@ -5,7 +5,7 @@
 var mongoose = require('mongoose');
 var dbm = require("../../../config/db/db_manager");
 //var stringUtil = require('../../../public/stringUtil');
-var rationLibdb = dbm.getCfgConnection("rationRepository");
+var rationLibdb = dbm.getCfgConnection("scConstruct");
 var Schema = mongoose.Schema;
 var RepositoryMapSchema = new Schema({
     "ID": Number,
@@ -17,7 +17,7 @@ var RepositoryMapSchema = new Schema({
 });
 var counter = require('../../../public/counter/counter');
 
-var rationRepository = rationLibdb.model("repositoryMap", RepositoryMapSchema, "repositoryMap");
+var rationRepository = rationLibdb.model("std_ration_lib_map", RepositoryMapSchema, "std_ration_lib_map");
 
 function createNewLibModel(rationLibObj){
     var rst = {};
@@ -29,7 +29,7 @@ function createNewLibModel(rationLibObj){
     return rst;
 }
 
-rationRepositoryDao = function(){};
+var rationRepositoryDao = function(){};
 
 rationRepositoryDao.prototype.getRealLibName = function(dispName,callback){
     if (callback) {

+ 66 - 32
modules/ration_repository/routes/ration_rep_routes.js

@@ -12,35 +12,69 @@ var repositoryGljController = require("../controllers/repository_glj_controller"
 var coeListController = require("../controllers/coe_controller");
 var searchController = require('../controllers/search_controller');
 
-apiRouter.post("/getRationDisplayNames",rationRepositoryController.getDisPlayRationLibs);
-apiRouter.post("/editRationLibs",rationRepositoryController.updateRationRepositoryName);
-apiRouter.post("/addRationRepository",rationRepositoryController.addRationRepository);
-apiRouter.post("/deleteRationLibs",rationRepositoryController.deleteRationLib);
-apiRouter.post("/getRealLibName",rationRepositoryController.getRealLibName);
-apiRouter.post("/getLibIDByName",rationRepositoryController.getLibIDByName);
-
-apiRouter.post("/getRationTree",rationChapterTreeController.getRationChapterTree);
-apiRouter.post("/createNewNode",rationChapterTreeController.createNewNode);
-apiRouter.post("/updateNodes",rationChapterTreeController.updateNodes);
-apiRouter.post("/deleteNodes",rationChapterTreeController.deleteNodes);
-
-apiRouter.post("/getRationItems",rationController.getRationItemsBySection);
-apiRouter.post("/mixUpdateRationItems",rationController.mixUpdateRationItems);
-
-apiRouter.post("/createNewGljTypeNode",repositoryGljController.createNewGljTypeNode);
-apiRouter.post("/updateGljNodes",repositoryGljController.updateGljNodes);
-apiRouter.post("/deleteGljNodes",repositoryGljController.deleteGljNodes);
-apiRouter.post("/getGljTree",repositoryGljController.getGljTree);
-apiRouter.post("/getGljItems",repositoryGljController.getGljItems);
-apiRouter.post("/mixUpdateGljItems",repositoryGljController.mixUpdateGljItems);
-apiRouter.post("/getGljItemsByIds",repositoryGljController.getGljItemsByIds);
-apiRouter.post("/getGljItemsByCodes",repositoryGljController.getGljItemsByCodes);
-
-apiRouter.post("/getCoeList",coeListController.getCoeList);
-apiRouter.post("/saveCoeList",coeListController.saveCoeList);
-apiRouter.post("/getCoeItemsByIDs",coeListController.getCoeItemsByIDs);
-
-apiRouter.post('/getRationItem', searchController.getRationItem);
-apiRouter.post('/findRation', searchController.findRation);
-
-module.exports = apiRouter;
+
+module.exports =  function (app) {
+
+    app.get('/rationRepository/main', function(req, res) {
+        res.render('maintain/ration_repository/main.html',
+            {
+                userAccount: req.session.userAccount,
+                userID: req.session.userID
+            });
+    });
+    app.get('/rationRepository/ration', function(req, res) {
+        res.render('maintain/ration_repository/dinge.html',
+            {
+                userAccount: req.session.userAccount,
+                userID: req.session.userID
+            });
+    });
+    app.get('/rationRepository/lmm', function(req, res) {
+        res.render('maintain/ration_repository/gongliao.html',
+            {
+                userAccount: req.session.userAccount,
+                userID: req.session.userID
+            });
+    });
+
+    app.get('/rationRepository/coeList', function(req, res) {
+        res.render('maintain/ration_repository/fuzhu.html',
+            {
+                userAccount: req.session.userAccount,
+                userID: req.session.userID
+            });
+    });
+
+    apiRouter.post("/getRationDisplayNames",rationRepositoryController.getDisPlayRationLibs);
+    apiRouter.post("/editRationLibs",rationRepositoryController.updateRationRepositoryName);
+    apiRouter.post("/addRationRepository",rationRepositoryController.addRationRepository);
+    apiRouter.post("/deleteRationLibs",rationRepositoryController.deleteRationLib);
+    apiRouter.post("/getRealLibName",rationRepositoryController.getRealLibName);
+    apiRouter.post("/getLibIDByName",rationRepositoryController.getLibIDByName);
+
+    apiRouter.post("/getRationTree",rationChapterTreeController.getRationChapterTree);
+    apiRouter.post("/createNewNode",rationChapterTreeController.createNewNode);
+    apiRouter.post("/updateNodes",rationChapterTreeController.updateNodes);
+    apiRouter.post("/deleteNodes",rationChapterTreeController.deleteNodes);
+
+    apiRouter.post("/getRationItems",rationController.getRationItemsBySection);
+    apiRouter.post("/mixUpdateRationItems",rationController.mixUpdateRationItems);
+
+    apiRouter.post("/createNewGljTypeNode",repositoryGljController.createNewGljTypeNode);
+    apiRouter.post("/updateGljNodes",repositoryGljController.updateGljNodes);
+    apiRouter.post("/deleteGljNodes",repositoryGljController.deleteGljNodes);
+    apiRouter.post("/getGljTree",repositoryGljController.getGljTree);
+    apiRouter.post("/getGljItems",repositoryGljController.getGljItems);
+    apiRouter.post("/mixUpdateGljItems",repositoryGljController.mixUpdateGljItems);
+    apiRouter.post("/getGljItemsByIds",repositoryGljController.getGljItemsByIds);
+    apiRouter.post("/getGljItemsByCodes",repositoryGljController.getGljItemsByCodes);
+
+    apiRouter.post("/getCoeList",coeListController.getCoeList);
+    apiRouter.post("/saveCoeList",coeListController.saveCoeList);
+    apiRouter.post("/getCoeItemsByIDs",coeListController.getCoeItemsByIDs);
+
+    apiRouter.post('/getRationItem', searchController.getRationItem);
+    apiRouter.post('/findRation', searchController.findRation);
+
+    app.use("/rationRepository/api",apiRouter);
+}

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

@@ -0,0 +1,33 @@
+/**
+ * Created by Tony on 2017/7/5.
+ */
+
+let rpt_util = require('../util/rpt_util');
+let Rpt_Map_Fld_Mdl = require('../models/rpt_mapping_field');
+
+//统一回调函数
+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);
+        });
+    },
+
+    getAllMappingFields: function (req, res) {
+        Rpt_Map_Fld_Mdl.find({}, '-_id', {sort: {'seq': 1}}, function(err, mapFields){
+            if(mapFields.length){
+                if (err) {
+                    callback(req,res,true,"no mapping fields were found!", mapFields);
+                } else {
+                    callback(req,res,false,"", mapFields);
+                }
+            }
+        })
+
+    }
+};

+ 53 - 66
modules/reports/controllers/rpt_controller.js

@@ -4,7 +4,7 @@
 
 let JV = require('../rpt_component/jpc_value_define');
 let Template = require('../models/rpt_template');
-let TemplateData = require('../models/rpt_tpl_data');
+let TemplateData = require('../models/rpt_tpl_data_demo');
 let JpcEx = require('../rpt_component/jpc_ex');
 //let cache = require('../../../public/cache/cacheUtil');
 let rptUtil = require("../util/rpt_util");
@@ -23,77 +23,64 @@ let callback = function(req, res, err, data){
     }
 };
 
-module.exports = {
-    getReportAllPages: function(req, res){
-        let grp_id = req.body.grp_id;
-        let tpl_id = req.body.tpl_id;
-        let pageSize = req.body.pageSize;
-        let rptTpl = null;
-        Template.getPromise(grp_id, tpl_id).then(function(rst) {
-            rptTpl = rst;
-            if (rptTpl) {
-                return TemplateData.getPromise(tpl_id);
+function getAllPagesCommon(req, res, rpt_id, pageSize, cb) {
+    let rptTpl = null;
+    Template.findOne({ID: rpt_id}, '-_id').exec().then(function(rst) {
+        rptTpl = rst;
+        if (rptTpl) {
+            if (rptTpl.ID_KEY) {
+                return TemplateData.getPromise(rptTpl.ID_KEY);
             } else {
-                callback(req, res, 'No report template was found!', null);
+                callback(req, res, 'No report template data were found!', null);
             }
-        }).then(function(tplData){
-                if (tplData) {
-                    let printCom = JpcEx.createNew();
-                    rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pageSize;
-                    let defProperties = rptUtil.getReportDefaultCache();
-                    printCom.initialize(rptTpl);
-                    printCom.analyzeData(rptTpl, tplData, defProperties);
-                    let maxPages = printCom.totalPages;
-                    let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
-                    if (pageRst) {
-                        callback(req, res, null, pageRst);
-                    } else {
-                        callback(req, res, "Have errors while on going...", null);
-                    }
+        } else {
+            callback(req, res, 'No report template was found!', null);
+        }
+    }).then(function(tplData){
+            if (tplData) {
+                let printCom = JpcEx.createNew();
+                rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pageSize;
+                let defProperties = rptUtil.getReportDefaultCache();
+                printCom.initialize(rptTpl);
+                printCom.analyzeData(rptTpl, tplData, defProperties);
+                let maxPages = printCom.totalPages;
+                let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
+                if (pageRst) {
+                    cb(pageRst);
                 } else {
-                    callback(req, res, 'No report data were found!', null);
+                    callback(req, res, "Have errors while on going...", null);
                 }
+            } else {
+                callback(req, res, 'No report data were found!', null);
             }
-        );
+        }
+    );
+};
+
+module.exports = {
+    getReportAllPages: function(req, res){
+        let rpt_id = req.body.ID;
+        let pageSize = req.body.pageSize;
+        getAllPagesCommon(req, res, rpt_id, pageSize, function(pageRst){
+            callback(req, res, null, pageRst);
+        })
     },
     getExcel: function(req, res) {
-        let grp_id = req.params.id, tpl_id = req.params.pm, pageSize = req.params.size, rptName = req.params.rptName;
-        let rptTpl = null;
-        Template.getPromise(grp_id, tpl_id).then(function(rst) {
-            rptTpl = rst;
-            if (rptTpl) {
-                return TemplateData.getPromise(tpl_id);
-            } else {
-                callback(req, res, 'No report template was found!', null);
-            }
-        }).then(function(tplData){
-                if (tplData) {
-                    let printCom = JpcEx.createNew();
-                    rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pageSize;
-                    let defProperties = rptUtil.getReportDefaultCache();
-                    printCom.initialize(rptTpl);
-                    printCom.analyzeData(rptTpl, tplData, defProperties);
-                    let maxPages = printCom.totalPages;
-                    let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
-                    if (pageRst) {
-                        rpt_xl_util.exportExcel(pageRst, rptName, null, function(newName){
-                            res.setHeader('Content-Type', 'application/vnd.openxmlformats');
-                            res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".xlsx");
-                            let filestream = fs.createReadStream(__dirname.slice(0, __dirname.length - 28) + '/tmp/' + newName + '.xlsx');
-                            filestream.on('data', function(chunk) {
-                                res.write(chunk);
-                            });
-                            filestream.on('end', function() {
-                                res.end();
-                            });
-                        });
-                    } else {
-                        callback(req, res, "Have errors while on going...", null);
-                    }
-                } else {
-                    callback(req, res, 'No report data were found!', null);
-                }
-            }
-        );
+        let rpt_id = req.params.id,
+            pageSize = req.params.size,
+            rptName = req.params.rptName;
+        getAllPagesCommon(req, res, rpt_id, pageSize, function(pageRst){
+            rpt_xl_util.exportExcel(pageRst, rptName, null, function(newName){
+                res.setHeader('Content-Type', 'application/vnd.openxmlformats');
+                res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".xlsx");
+                let filestream = fs.createReadStream(__dirname.slice(0, __dirname.length - 28) + '/tmp/' + newName + '.xlsx');
+                filestream.on('data', function(chunk) {
+                    res.write(chunk);
+                });
+                filestream.on('end', function() {
+                    res.end();
+                });
+            });
+        })
     }
 };

+ 127 - 11
modules/reports/controllers/rpt_tpl_controller.js

@@ -2,7 +2,16 @@
  * Created by Tony on 2017/6/1.
  */
 
-let TplNode = require('../models/tpl_tree_node');
+let async = require("async");
+let counter = require('../../../public/counter/counter');
+
+let RptTplModel = require('../models/rpt_template');
+let TreeNodeModel = require('../models/tpl_tree_node');
+let rptTplDef = require("../../../public/rpt_tpl_def").getUtil();
+let stringUtil = require("../../../public/stringUtil");
+let JV = require('../rpt_component/jpc_value_define');
+
+//let test_glj_type_util = require("../../../public/cache/std_glj_type_util");
 
 //统一回调函数
 let callback = function(req, res, err, message, data){
@@ -15,32 +24,139 @@ module.exports = {
             grpType = params.grpType,
             userId = params.userId,
             tplType = params.tplType;
-        TplNode.getTplTreeNodes(grpType, userId, tplType, function(err, data){
-            callback(req,res,err,"", data);
-        })
+        let filter = {"grpType": grpType, "$or": [{"isDeleted": null}, {"isDeleted": false} ]};
+        if (userId) {
+            filter.userId = userId;
+        }
+        if ((tplType && tplType !== rptTplDef.TplType.ALL)) {
+            filter.tplType = tplType;
+        }
+        TreeNodeModel.find(filter, '-_id', function(err, data){
+            if (err) {
+                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),
             nodes = params.nodes;
-        TplNode.updateTreeNodes(nodes, function(err,results){
-            callback(req,res, err, "", results)
+        let functions = [];
+        for (let node of nodes) {
+            functions.push((function(doc) {
+                return function(cb) {
+                    TreeNodeModel.update({ID: doc.ID}, doc, cb);
+                };
+            })(node));
+        }
+        async.parallel(functions, function(err, results) {
+            callback(req,res, err, "", results);
         });
     },
-    deleteTptTplNodes: function(req, res){
+    deleteRptTplNodes: function(req, res){
         let params = JSON.parse(req.body.params),
             nodeIds = params.nodeIds,
             preNodeId = params.preNodeId,
             preNodeNextId = params.preNodeNextId;
-        TplNode.removeNodes(nodeIds, preNodeId, preNodeNextId, function(err,results){
-            callback(req,res, err, "", results)
+        let functions = [];
+        if (preNodeId !== -1) {
+            functions.push((function(nodeId, nextId) {
+                return function(cb) {
+                    TreeNodeModel.update({ID: nodeId}, {"NextSiblingID": nextId}, cb);
+                };
+            })(preNodeId, preNodeNextId));
+        }
+        for (let nId of nodeIds) {
+            functions.push((function(nodeId) {
+                return function(cb) {
+                    TreeNodeModel.update({ID: nodeId}, {"isDeleted": true}, cb);
+                };
+            })(nId));
+        }
+        async.parallel(functions, function(err, results) {
+            callback(req,res, err, "", results);
         });
     },
     createTplTreeNode: function(req, res){
         let params = JSON.parse(req.body.params),
             lastNodeId = params.lastNodeId,
             nodeData = params.rawNodeData;
-        TplNode.createTplTreeNode(nodeData, lastNodeId, function(err, data){
-            callback(req,res,err,"", data);
+        counter.counterDAO.getIDAfterCount(counter.moduleName.report, 1, function(err, result){
+            nodeData.ID = result.value.sequence_value;
+            let node = new TreeNodeModel(nodeData);
+            node.save(function (err, result) {
+                if (err) {
+                    callback(req,res, "树节点错误!", "", null);
+                } else {
+                    if (lastNodeId > 0) {
+                        TreeNodeModel.update({ID: lastNodeId}, {"NextSiblingID": nodeData.ID}, function(err, rst){
+                            if (err) {
+                                callback(req,res, "树节点错误!", "", null);
+                            } else {
+                                callback(req,res, false, "", result);
+                            }
+                        });
+                    } else callback(req,res, false, "", result);
+                }
+            });
+        });
+    },
+    createDftRptTpl: function(req, res) {
+        let params = JSON.parse(req.body.params),
+            treeNodeId = params.treeNodeId,
+            //grpChars = stringUtil.getPinYinFullChars(params.grpChars),
+            rptDftTplId = params.rptDftTplId;
+        let filter = {"ID": rptDftTplId};
+        RptTplModel.findOne(filter, '-_id').exec().then(function(dftTplRst) {
+            if (dftTplRst) {
+                let _doc = dftTplRst["_doc"];
+                _doc["ID"] = treeNodeId;
+                _doc["GROUP_KEY"] = "";
+                _doc["ID_KEY"] = "";
+                let rptTpl = new RptTplModel(_doc);
+                rptTpl.save(function (err, actTplRst) {
+                    if (err) {
+                        callback(req,res, "报表模板创建错误", "", null);
+                    } else {
+                        //TreeNodeModel.update();
+                        TreeNodeModel.update({ID: treeNodeId}, {"refId": treeNodeId}, function(err, rst){
+                            if (err) {
+                                callback(req,res, "报表模板创建错误", "", null);
+                            } else {
+                                callback(req,res, false, "", actTplRst);
+                            }
+                        });
+                    }
+                });
+            } else {
+                callback(req, res, 'Create report template failed!', null);
+            }
         })
+    },
+    getRefRptTpl: function (req, res) {
+        let params = JSON.parse(req.body.params),
+            rptTplId = params.rptTplId;
+        let filter = {"ID": rptTplId};
+        RptTplModel.findOne(filter, '-_id').exec().then(function(rstTpl) {
+            if (rstTpl) {
+                callback(req,res, false, "", rstTpl);
+            } else {
+                callback(req, res, 'The report template was not found!', null);
+            }
+        })
+    },
+    updateRptTpl: function (req, res) {
+        let params = JSON.parse(req.body.params),
+            rptTpl = JSON.parse(params.rptTpl);
+        let filter = {"ID": parseInt(rptTpl[JV.PROP_ID])};
+        RptTplModel.update(filter, rptTpl, function (err, rst) {
+            if (err) {
+                callback(req, res, true, 'The report template was updated failed!', false);
+            } else {
+                callback(req, res, false, 'The report template was updated successfully!', true);
+            }
+        });
     }
 }

+ 2 - 25
modules/reports/models/rpt_cfg.js

@@ -3,7 +3,7 @@
  */
 let mongoose = require('mongoose');
 let dbm = require("../../../config/db/db_manager");
-let smartcostdb = dbm.getCfgConnection("Reports");
+let smartcostdb = dbm.getCfgConnection("scConstruct");
 let Schema = mongoose.Schema;
 let FormatSchema = new Schema({
     "ID" : String,
@@ -46,27 +46,4 @@ let RptCfgSchema = new Schema({
 
 let Rpt_Cfg_Mdl = smartcostdb.model("rpt_cfg", RptCfgSchema, "rpt_cfg");
 
-class RptCfgDAO {
-    getByUserId(userId, callback){
-        Rpt_Cfg_Mdl.find({userId: userId}, '-_id', function(err, templates){
-            if(templates.length){
-                callback(false, templates[0]);
-            }
-            else{
-                callback('no record was found!');
-            }
-        })
-    };
-    getAll(id, callback){
-        Rpt_Cfg_Mdl.find({}, '-_id', function(err, templates){
-            if(templates.length){
-                callback(false, templates);
-            }
-            else{
-                callback('no record was found!');
-            }
-        })
-    };
-};
-
-module.exports = new RptCfgDAO();
+module.exports = Rpt_Cfg_Mdl;

+ 22 - 0
modules/reports/models/rpt_mapping_field.js

@@ -0,0 +1,22 @@
+/**
+ * Created by Tony on 2017/7/11.
+ */
+let mongoose = require('mongoose');
+let dbm = require("../../../config/db/db_manager");
+let smartcostdb = dbm.getCfgConnection("scConstruct");
+let MapFieldSchema = new mongoose.Schema({
+    "fieldMapGrpName" : String,
+    "dispName": String,
+    "remark" : String,
+    "seq" : Number,
+    "items" : [{
+        mapId: Number,
+        dispName: String,
+        mapExpression: String,
+        descr: String
+    }]
+});
+
+let Rpt_Map_Field_Mdl = smartcostdb.model("rpt_mapping_field", MapFieldSchema, "rpt_mapping_field");
+
+module.exports = Rpt_Map_Field_Mdl;

+ 4 - 19
modules/reports/models/rpt_template.js

@@ -3,15 +3,17 @@
  */
 let mongoose = require('mongoose');
 let dbm = require("../../../config/db/db_manager");
-let smartcostdb = dbm.getCfgConnection("Reports");
+let smartcostdb = dbm.getCfgConnection("scConstruct");
 let Schema = mongoose.Schema;
 let RptTemplateSchema = new Schema({
+    "ID" : Number,
     "GROUP_KEY": String,
     "ID_KEY": String,
     "主信息": Schema.Types.Mixed,
     "指标_数据_映射": Schema.Types.Mixed,
     "布局框_集合": Array,
     "流水式表_信息": Schema.Types.Mixed,
+    "账单式表_信息": Schema.Types.Mixed,
     "交叉表_信息": Schema.Types.Mixed,
     "无映射离散指标_集合": Schema.Types.Mixed,
     "离散参数_集合": Schema.Types.Mixed,
@@ -20,21 +22,4 @@ let RptTemplateSchema = new Schema({
 
 let Template = smartcostdb.model("rpt_templates", RptTemplateSchema, "rpt_templates");
 
-class RplTplDAO{
-    get(grpId, id, callback){
-        Template.find({GROUP_KEY: grpId, ID_KEY: id}, '-_id', function(err, templates){
-            if(templates.length){
-                callback(false, templates[0]);
-            }
-            else{
-                callback('查找不到报表模板!');
-            }
-        })
-    };
-    getPromise(grpId, id){
-        let rst = Template.findOne({GROUP_KEY: grpId, ID_KEY: id}, '-_id').exec() ;
-        return rst;
-    }
-}
-
-module.exports = new RplTplDAO();
+module.exports = Template;

+ 2 - 2
modules/reports/models/rpt_tpl_data.js

@@ -3,7 +3,7 @@
  */
 let mongoose = require('mongoose');
 let dbm = require("../../../config/db/db_manager");
-let smartcostdb = dbm.getCfgConnection("Reports");
+let smartcostdb = dbm.getCfgConnection("scConstruct");
 let Schema = mongoose.Schema;
 let RptTemplateDataSchema = new Schema({
     "Data_Key": String,
@@ -12,7 +12,7 @@ let RptTemplateDataSchema = new Schema({
     "detail_data": Array
 });
 
-let TemplateData = smartcostdb.model("temp_tpl_data", RptTemplateDataSchema, "temp_tpl_data");
+let TemplateData = smartcostdb.model("temp_tpl_data", RptTemplateDataSchema, "rpt_temp_tpl_data");
 
 class RplTplDataDAO{
     //根据id获取临时数据

+ 2 - 77
modules/reports/models/tpl_tree_node.js

@@ -3,9 +3,7 @@
  */
 var mongoose = require('mongoose');
 var dbm = require("../../../config/db/db_manager");
-var db = dbm.getCfgConnection("Reports");
-var async = require("async");
-var rptTplDef = require("../../../public/rpt_tpl_def").getUtil();
+var db = dbm.getCfgConnection("scConstruct");
 var Schema = mongoose.Schema;
 var TreeNodeSchema = new Schema({
     ID:Number,
@@ -21,78 +19,5 @@ var TreeNodeSchema = new Schema({
 });
 
 var TreeNodeModel = db.model("rpt_tpl_tree", TreeNodeSchema, "rpt_tpl_tree");
-var counter = require('../../../public/counter/counter');
 
-//var RplTplTreeDAO = function(){};
-class RplTplTreeDAO{
-    getTplTreeNodes(grpType, userId, tplType, callback) {
-        var filter = {"grpType": grpType, "$or": [{"isDeleted": null}, {"isDeleted": false} ]};
-        if (userId) {
-            filter.userId = userId;
-        }
-        if ((tplType && tplType !== rptTplDef.TplType.ALL)) {
-            filter.tplType = tplType;
-        }
-        TreeNodeModel.find(filter, '-_id', function(err, data){
-            if (err) {
-                callback(true, null);
-            } else callback(false,data);
-        });
-    };
-    updateTreeNodes(nodes, callback) {
-        var functions = [];
-        for (let node of nodes) {
-            functions.push((function(doc) {
-                return function(cb) {
-                    TreeNodeModel.update({ID: doc.ID}, doc, cb);
-                };
-            })(node));
-        }
-        async.parallel(functions, function(err, results) {
-            callback(err, results);
-        });
-    };
-    removeNodes(nodeIds, preNodeId, preNodeNextId, callback) {
-        var functions = [];
-        if (preNodeId != -1) {
-            functions.push((function(nodeId, nextId) {
-                return function(cb) {
-                    TreeNodeModel.update({ID: nodeId}, {"NextSiblingID": nextId}, cb);
-                };
-            })(preNodeId, preNodeNextId));
-        }
-        for (let nId of nodeIds) {
-            functions.push((function(nodeId) {
-                return function(cb) {
-                    TreeNodeModel.update({ID: nodeId}, {"isDeleted": true}, cb);
-                };
-            })(nId));
-        }
-        async.parallel(functions, function(err, results) {
-            callback(err, results);
-        });
-    };
-    createTplTreeNode(nodeData, lastNodeId, callback) {
-        counter.counterDAO.getIDAfterCount(counter.moduleName.report, 1, function(err, result){
-            nodeData.ID = result.value.sequence_value;
-            var node = new TreeNodeModel(nodeData);
-            node.save(function (err, result) {
-                if (err) {
-                    callback("树节点错误!", false);
-                } else {
-                    if (lastNodeId > 0) {
-                        TreeNodeModel.update({ID: lastNodeId}, {"NextSiblingID": nodeData.ID}, function(err, rst){
-                            if (err) {
-                                callback("树节点错误!", false);
-                            } else {
-                                callback(false, result);
-                            }
-                        });
-                    } else callback(false, result);
-                }
-            });
-        });
-    };
-}
-
-module.exports = new RplTplTreeDAO();
+module.exports = TreeNodeModel;

+ 15 - 3
modules/reports/routes/report_router.js

@@ -6,7 +6,19 @@ let express = require('express');
 let rptRouter = express.Router();
 let reportController = require('./../controllers/rpt_controller');
 
-rptRouter.post('/getReport', reportController.getReportAllPages);
-rptRouter.get('/getExcel/:id/:pm/:size/:rptName', reportController.getExcel);
+module.exports =function (app) {
 
-module.exports = rptRouter;
+    app.get('/report',  function(req, res) {
+        if (!req.session.userAccount) {
+            res.redirect('/login');
+        }
+        else {
+            res.render('maintain/report/rpt_test.html',
+                {userAccount: req.session.userAccount,
+                    userID: req.session.userID});
+        }
+    });
+    rptRouter.post('/getReport', reportController.getReportAllPages);
+    rptRouter.get('/getExcel/:id/:size/:rptName', reportController.getExcel);
+    app.use("/report_api", rptRouter);
+}

+ 24 - 5
modules/reports/routes/rpt_tpl_router.js

@@ -1,10 +1,29 @@
 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);
-rptTplRouter.post('/updateTptTplNodes', reportTplController.updateTreeNodes);
-rptTplRouter.post('/deleteTptTplNodes', reportTplController.deleteTptTplNodes);
+module.exports = function (app) {
+    app.get('/rpt_tpl',  function(req, res) {
+        if (!req.session.userAccount) {
+            res.redirect('/login');
+        }
+        else {
+            res.render('maintain/report/rpt_tpl_main.html',
+                {userAccount: req.session.userAccount,
+                    userID: req.session.userID});
+        }
+    });
 
-module.exports = rptTplRouter;
+    rptTplRouter.post('/createTplTreeNode', reportTplController.createTplTreeNode);
+    rptTplRouter.post('/getRptTplTree', reportTplController.getRptTplTree);
+    rptTplRouter.post('/updateRptTplNodes', reportTplController.updateTreeNodes);
+    rptTplRouter.post('/deleteRptTplNodes', reportTplController.deleteRptTplNodes);
+    rptTplRouter.post('/createDftRptTpl', reportTplController.createDftRptTpl);
+    rptTplRouter.post('/getRefRptTpl', reportTplController.getRefRptTpl);
+    rptTplRouter.post('/updateRptTpl', reportTplController.updateRptTpl);
+
+    rptTplRouter.post('/getUserRptCfg', reportCfgController.getReportUserCfg);
+    rptTplRouter.post('/getMappingFields', reportCfgController.getAllMappingFields);
+    app.use("/report_tpl_api", rptTplRouter);
+}

+ 2 - 1
modules/reports/rpt_component/jpc_ex.js

@@ -8,7 +8,7 @@ let JpcParam = require('./jpc_param');
 let JpcFunc = require('./jpc_function');
 let JpcData = require('./jpc_data');
 let JpcCommonHelper = require('./helper/jpc_helper_common');
-let JE = require('./jpc_rte'); //Important: for self-define function execution purpose
+let $JE = require('./jpc_rte'); //Important: for self-define function execution purpose
 
 let JpcExSrv = function(){};
 JpcExSrv.prototype.createNew = function(){
@@ -144,6 +144,7 @@ JpcExSrv.prototype.createNew = function(){
             if (me.formulas[i][JV.PROP_RUN_TYPE] === runType) {
                 let expression = me.formulas[i][JV.PROP_EXPRESSION];
                 if (expression) {
+                    let $ME = me.formulas[i];
                     eval(expression);
                 }
             }

+ 2 - 4
modules/reports/rpt_component/jpc_value_define.js

@@ -1,12 +1,10 @@
 const fs = require('fs');
 let VAL_DEF = null;
 
-getValDefine = function() {
+let getValDefine = function() {
     if (!(VAL_DEF)) {
         let data = fs.readFileSync(__dirname.slice(0, __dirname.length - 30) + '/public/web/rpt_value_define.js', 'utf8', 'r');
-        eval(data);
-        VAL_DEF = JV;
-        JV = null;
+        eval(data + ' ; VAL_DEF = JV;');
     }
     return VAL_DEF;
 }

+ 43 - 0
modules/reports/util/rpt_data_util.js

@@ -0,0 +1,43 @@
+/**
+ * Created by Tony on 2017/7/14.
+ * 报表数据提取class,是协助报表模板里指标字段自主提取数据的工具类
+ */
+class Rpt_Common{
+    initialize(Projects) {
+        this.Projects = Projects;
+    };
+};
+
+class Rpt_Data_Extractor {
+    initialize(Projects) {
+        this.Projects = Projects;
+        //Projects对象从前端传送过来,无需在后端重复查询及构建
+        /* 结构:
+         {
+            currentPrjId: int,
+            topPrj: [
+                //单项工程
+                {
+                    subPrjName: String,
+                    subPrjId: int,
+                    detailPrj: [
+                        //单位工程
+                        {
+                            detailPrjName: String,
+                            subPrjId: int,
+                        }
+                        ...
+                    ]
+                }
+                ...
+            ]
+         }
+         */
+    };
+
+    prepare($CURRENT_RPT) {
+        //在报表提取数据前的准备工作,主要有:
+        //1. 确认指标数据的类型,
+    };
+
+}

+ 45 - 4
modules/reports/util/rpt_util.js

@@ -2,15 +2,15 @@
  * Created by Tony on 2017/3/24.
  */
 let cache = require('../../../public/cache/cacheUtil');
-let rpt_cfg = require('../models/rpt_cfg');
+let Rpt_Cfg_Mdl = require('../models/rpt_cfg');
 
 const RPT_CFG_GRP = 'rpt_cfg';
 
 module.exports = {
     setReportDefaultCache: function () {
-        rpt_cfg.getByUserId("Administrator", function (err, cfgs) {
-            if (cfgs) {
-                cache.setCache(RPT_CFG_GRP,'admin_cfg',cfgs);
+        Rpt_Cfg_Mdl.find({userId: "Administrator"}, '-_id', function(err, cfgs){
+            if(cfgs.length){
+                cache.setCache(RPT_CFG_GRP,'admin_cfg',cfgs[0]);
             }
         })
     },
@@ -23,5 +23,46 @@ module.exports = {
         rst.styles = admin_cfg.borders;
         admin_cfg = null;
         return rst;
+    },
+    setReportCacheByUser: function (userId) {
+        let me = this;
+        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, cb) {
+        let me = this,
+            rst = {ctrls: null, fonts: null, styles: null},
+            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]);
+                    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);
+        }
     }
 }

+ 34 - 30
modules/users/routes/users_route.js

@@ -5,33 +5,37 @@ var uc = require('../controllers/users_controller');
 
 var htmlPath = path.join(__dirname,'../../../','web/users/');
 
-router.get('/', function(req, res) {
-    if(!req.session.userAccount){
-        res.redirect('/login');
-    }
-    else{
-        res.redirect('/pm');
-    }
-});
-
-router.get('/login', function(req, res) {
-  res.render('users/login', {});
-});
-
-router.post('/login', uc.userLogin);
-
-router.get('/reg', function(req, res, next) {
-  res.render('reg',{});
-});
-
-router.post('/reg', uc.userReg);
-
-router.get("/logout",function(req,res){
-    delete req.session.userID;
-    delete req.session.userAccount;
-    delete req.session.userEmail;
-    delete req.session.userMobile;
-    res.redirect("/");
-});
-
-module.exports = router;
+module.exports =function (app) {
+    router.get('/', function(req, res) {
+        if(!req.session.userAccount){
+            res.redirect('/login');
+        }
+        else{
+            res.redirect('/pm');
+        }
+    });
+
+    router.get('/login', function(req, res) {
+        res.render('users/login', {});
+    });
+
+    router.post('/login', uc.userLogin);
+
+    router.get('/reg', function(req, res, next) {
+        res.render('reg',{});
+    });
+
+    router.post('/reg', uc.userReg);
+
+    router.get("/logout",function(req,res){
+        delete req.session.userID;
+        delete req.session.userAccount;
+        delete req.session.userEmail;
+        delete req.session.userMobile;
+        res.redirect("/");
+    });
+    app.use('/',router);
+};
+
+
+

+ 21 - 62
operation.js

@@ -5,16 +5,21 @@ config.setToQaDb();
 //config.setupCache();
 let cfgCacheUtil = require("./config/cacheCfg");
 cfgCacheUtil.setupDftCache();
+let dbm = require("./config/db/db_manager");
 
 let path = require('path');
 let session = require('express-session');
 let DBStore = require('connect-mongo')(session);
+let fileUtils = require("./modules/common/fileUtils");
 
-let URL = require('url')
+let URL = require('url');
+let fs = require('fs');
 
 let app = express();
 let _rootDir = __dirname;
 
+dbm.connect();
+
 app.use(express.static(_rootDir));
 
 app.set('views', path.join(__dirname, 'web'));
@@ -30,6 +35,7 @@ app.use(session({
     secret: 'session users secret',
     cookie: {maxAge: 1000*60*30},
     resave: false,
+    rolling: true,
     saveUninitialized: true
     //*
     ,store: new DBStore({
@@ -51,67 +57,10 @@ app.use(function (req, res, next) {
     next();
 });
 
-app.use('/', require('./modules/users/routes/users_route'));
-
-let rpt_Router = require("./modules/reports/routes/report_router");
-app.get('/report',  function(req, res) {
-    if (!req.session.userAccount) {
-        res.redirect('/login');
-    }
-    else {
-        res.render('maintain/report/rpt_test.html',
-            {userAccount: req.session.userAccount,
-                userID: req.session.userID});
-    }
-});
-app.use("/report_api", rpt_Router);
-
-let rptTpl_Router = require("./modules/reports/routes/rpt_tpl_router");
-app.get('/rpt_tpl',  function(req, res) {
-    if (!req.session.userAccount) {
-        res.redirect('/login');
-    }
-    else {
-        res.render('maintain/report/rpt_tpl_main.html',
-            {userAccount: req.session.userAccount,
-                userID: req.session.userID});
-    }
-});
-app.use("/report_tpl_api", rptTpl_Router);
-
-let rationRepository_Router = require("./modules/ration_repository/routes/ration_rep_routes");
-app.get('/rationRepository/main', function(req, res) {
-    res.render('maintain/ration_repository/main.html',
-        {
-            userAccount: req.session.userAccount,
-            userID: req.session.userID
-        });
-});
-app.get('/rationRepository/ration', function(req, res) {
-    res.render('maintain/ration_repository/dinge.html',
-        {
-            userAccount: req.session.userAccount,
-            userID: req.session.userID
-        });
-});
-app.get('/rationRepository/lmm', function(req, res) {
-    res.render('maintain/ration_repository/gongliao.html',
-        {
-            userAccount: req.session.userAccount,
-            userID: req.session.userID
-        });
-});
-
-app.get('/rationRepository/coeList', function(req, res) {
-    res.render('maintain/ration_repository/fuzhu.html',
-        {
-            userAccount: req.session.userAccount,
-            userID: req.session.userID
-        });
-});
-
-app.use("/rationRepository/api",rationRepository_Router);
-
+//加载路由文件
+fileUtils.getGlobbedFiles('./modules/**/routes/*.js').forEach(function(modelPath) {
+    require(path.resolve(modelPath))(app);
+})
 
 app.use(function(req, res, next) {
     res.status(404).send('404 Error');
@@ -120,6 +69,16 @@ app.use(function(err, req, res, next) {
     console.error(err.stack);
     res.status(500).send('500 Error');
 });
+
+//设置Date Format函数
+fs.readFile(__dirname + '/public/web/date_util.js', 'utf8', 'r', function (err, data) {
+    eval(data);
+    // let dt = new Date();
+    // console.log(dt.Format('yyyy-M-dd'));
+    // console.log(dt.Format('yyyy 年 M 月 dd 日'));
+    // console.log(dt.Format('yyyy 年 M 月 20 日'));
+});
+
 app.listen(6080, function(){
     console.log("server started!");
 });

+ 2 - 1
package.json

@@ -15,7 +15,8 @@
     "ejs": "~2.5.5",
     "express-session": "^1.15.1",
     "request": "^2.79.0",
-    "tape": "^4.6.3"
+    "tape": "^4.6.3",
+    "glob": "~4.0.5"
   },
   "dependencies": {
     "bluebird": "^3.5.0",

+ 91 - 0
public/cache/std_glj_type_util.js

@@ -0,0 +1,91 @@
+/**
+ * Created by Tony on 2017/7/6.
+ */
+let cacheUtil = require('./cacheUtil');
+let std_glj_type_mdl = require('../models/std_glj_types');
+
+const STD_GLJ_GRP = 'std_glj_grp';
+
+function getStdGljTypeCache() {
+    let rst = cacheUtil.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, topParentId, parentId) {
+            let tmpItem = {};
+            tmpItem.ID = item.ID;
+            tmpItem.TopParentID = topParentId;
+            tmpItem.ParentID = parentId;
+            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, topParentId, item.ID);
+                }
+            }
+        }
+        for (let item of cache.typesDefine) {
+            private_combine_glj_type(item, item.ID, -1);
+        }
+        me.innerGljTypeObj = rst;
+    };
+
+    getItemById(Id) {
+        let me = this, rst = null;
+        if (me.innerGljTypeObj) {
+            rst = me.innerGljTypeObj["typeId" + Id];
+        }
+        return rst;
+    };
+
+    getTopParentIdByItemId(itemId) {
+        let me = this, rst = itemId;
+        if (me.innerGljTypeObj) {
+            let item = me.innerGljTypeObj["typeId" + itemId];
+            if (item) {
+                rst = item.TopParentID;
+            }
+        }
+        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){
+                cacheUtil.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;
+    }
+}

+ 193 - 0
public/calc_util.js

@@ -0,0 +1,193 @@
+/**
+ * Created by Tony on 2017/6/21.
+ */
+let calcBaseCodeCollection = ["定额基价人工费", "定额基价材料费", "定额基价机械费"
+    , "定额基价人工费(调整后)", "定额基价材料费(调整后)", "定额基价机械费(调整后)"
+    , "市场价格人工费", "市场价格材料费", "市场价格机械费"
+    , "定额基价机上人工费", "主材费", "设备费"
+];
+let dummyCalcBaseCodeTypeCollection = [[2], [6], [64]
+    , [], [], []
+    , [], [], []
+    , [], [], []
+];
+
+let executeObj = {
+    currentTpl : null,
+    currentRationItem: null,
+    currentFeeRateFile: null,
+    at: function(code) {
+        let me = executeObj,
+            rst = 0;
+        rst = me.currentTpl.compileAssistantObj[code].execRst;
+        return rst;
+    },
+    base: function(calcBaseCode) {
+        let me = executeObj, rst = 0,
+            idx = calcBaseCodeCollection.indexOf(calcBaseCode);
+        if (idx >= 0) {
+            if (dummyCalcBaseCodeTypeCollection[idx].length > 0) {
+                let tmpSum = 0;
+                for (let glj of me.currentRationItem.rationGljList) {
+                    if (dummyCalcBaseCodeTypeCollection[idx].indexOf(glj["glj"]["gljType"]) >= 0) {
+                        tmpSum += glj["glj"]["basePrice"] * glj["consumeAmt"];
+                    }
+                }
+                rst = tmpSum;
+            } else {
+                //rst = 10 + idx; //随便给个数
+            }
+        }
+        //rst = idx; //暂时返回值,测试用
+        return rst;
+    },
+    fee: function(feeID) {
+        let me = executeObj, rst = 0;
+        /*
+        for (let fee of me.currentFeeRateFile) {
+            if (fee.ID == feeID) {
+                rst = fee.rate;
+                break;
+            }
+        }
+        /*/
+        if (me.compiledFeeRateFile["fee_" + feeID]) rst = me.compiledFeeRateFile["fee_" + feeID].rate;
+        //*/
+        return rst;
+    },
+    factor: function(factorCode) {
+        let me = executeObj;
+        let rst = 0.89; //暂时固定输出,测试用
+        return rst;
+    }
+};
+
+class calculation {
+    init(calcTpl, calFee){
+        let me = this;
+        me.calcTpl = calcTpl;
+        me.calFee = calFee;
+        me.hasCompiled = false;
+    };
+
+    compile(){
+        let me = this;
+        me.hasCompiled = false;
+        me.errs = [];
+        let private_extract_code = function(str, idx){
+            let rst = '', lBracket = 0, rBracket = 0, firstIdx = idx, lastIdx = 0;
+            for (let i = idx; i < str.length; i++) {
+                if (str[i] === '(') {
+                    lBracket++;
+                    if (lBracket == 1) firstIdx = i + 1;
+                }
+                if (str[i] === ')') {
+                    rBracket++;
+                    if (lBracket == rBracket) {
+                        lastIdx = i - 1;
+                        if (lastIdx > firstIdx) {
+                            if (str[firstIdx] === "'") firstIdx++;
+                            if (str[lastIdx] !== "'") lastIdx++;
+                            if (lastIdx > firstIdx) {
+                                rst = str.slice(firstIdx, lastIdx);
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+            return rst;
+        };
+        let private_parse_ref = function(item, itemIdx){
+            let expr = item.expression.split('at(').join('@(');
+            item.expression = expr;
+            //console.log('expression: ' + expr);
+            let idx = expr.indexOf('@(', 0);
+            while (idx >= 0) {
+                let code = private_extract_code(expr, idx);
+                //console.log('提取code: ' + code);
+                if (code.length > 0) {
+                    let subItem = me.compileAssistantObj[code];
+                    if (subItem) {
+                        if (subItem.code !== item.code) {
+                            private_parse_ref(subItem, me.compileAssistantObj[code + "_idx"]);
+                        } else {
+                            me.errs.push("There exists the self refer code: " + code);
+                        }
+                    } else {
+                        me.errs.push("There exists the invalid code by which could not find the item: " + code);
+                        console.log('invalid code: ' + code);
+                    }
+                }
+                idx = expr.indexOf('@(', idx + code.length + 3);
+            }
+            if (me.calcTpl.compiledSeq.indexOf(itemIdx) < 0) {
+                //console.log('the code ready to push: ' + item.code);
+                me.calcTpl.compiledSeq.push(itemIdx);
+            }
+        };
+        let private_setup_seq = function(item, itemIdx){
+            if (me.calcTpl.compiledSeq.indexOf(itemIdx) < 0) {
+                private_parse_ref(item, itemIdx);
+            }
+        };
+        let private_compile_items = function() {
+            for (let idx of me.calcTpl.compiledSeq) {
+                let item = me.calcTpl.calcItems[idx];
+                item.compiledExpr = item.expression.split('@(').join('$CE.at(');
+                item.compiledExpr = item.compiledExpr.split('base(').join('$CE.base(');
+                item.compiledExpr = item.compiledExpr.split('fee(').join('$CE.fee(');
+                item.compiledExpr = item.compiledExpr.split('factor(').join('$CE.factor(');
+                //console.log(item.compiledExpr);
+            }
+        };
+        let private_comile_feeFile = function() {
+            if (me.calFee) {
+                me.compiledFee = {};
+                for (let fee of me.calFee) {
+                    me.compiledFee["fee_" + fee.ID] = fee;
+                }
+            }
+        };
+
+        if (me.calcTpl && me.calcTpl.calcItems && me.calcTpl.calcItems.length > 0) {
+            me.calcTpl.compiledSeq = [];
+            me.compileAssistantObj = {};
+            //1. first round -> prepare
+            private_comile_feeFile();
+            for (let i = 0; i < me.calcTpl.calcItems.length; i++) {
+                let item = me.calcTpl.calcItems[i];
+                me.compileAssistantObj[item.code] = item;
+                me.compileAssistantObj[item.code + "_idx"] = i;
+            }
+            //2. second round -> go!
+            for (let i = 0; i < me.calcTpl.calcItems.length; i++) {
+                private_setup_seq(me.calcTpl.calcItems[i], i);
+            }
+            if (me.errs.length == 0) {
+                private_compile_items();
+                if (me.errs.length == 0) me.hasCompiled = true;
+            } else {
+                console.log('errors: ' + me.errs.toString());
+            }
+        }
+        //console.log(me.compileAssistantObj);
+        //console.log(me.calcTpl.compiledSeq);
+    };
+    calculate( $RATION){
+        let me = this;
+        if ($RATION && me.hasCompiled) {
+            let $CE = executeObj;
+            $CE.currentRationItem = $RATION;
+            $CE.currentTpl = me;
+            $CE.currentFeeRateFile = me.calFee;
+            $CE.compiledFeeRateFile = me.compiledFee;
+            for (let idx of me.calcTpl.compiledSeq) {
+                let item = me.calcTpl.calcItems[idx];
+                item.execRst = eval(item.compiledExpr);
+            }
+        }
+    }
+}
+
+module.exports = new calculation();

+ 2 - 0
public/counter/counter.js

@@ -30,6 +30,8 @@ const COUNTER_MODULE_NAME = {
     unitPriceGLJ: 'unitPriceGLJ',
     template_bills: 'temp_bills',
     billsLib: 'billsLib',
+    billsLib_jobs: 'billsLib_jobs',
+    billsLib_items: 'billsLib_items',
     coeList: 'coeList'
 }
 /*const PROJECT_COUNTER = 'projects', USER_COUNTER = 'users', BILL_COUNTER = 'bills', RATION_COUNTER = 'rations',

+ 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;

+ 1 - 2
public/rpt_tpl_def.js

@@ -8,8 +8,7 @@ var rptTplDef = null;
 getTreeNodeUtil = function() {
     if (!(rptTplDef)) {
         var data = fs.readFileSync(__dirname + '/web/rpt_tpl_def.js', 'utf8', 'r');
-        eval(data);
-        rptTplDef = RT;
+        eval(data + ' ; rptTplDef = RT;');
     }
     return rptTplDef;
 }

+ 8 - 3
public/web/calculation/calc_util.js

@@ -3,16 +3,21 @@
  */
 
 class calculation {
-    constructor(calcTpl) {
+    init(calcTpl, calFee){
         let me = this;
         me.calcTpl = calcTpl;
+        me.calFee = calFee;
         me.hasCompiled = false;
     };
+
     compile(){
         let me = this;
         me.hasCompiled = false;
-        if (me.calcTpl && me.calcTpl.length > 0) {
-            //
+        if (me.calcTpl && me.calcTpl.calcItems && me.calcTpl.calcItems.length > 0) {
+            me.calcTpl.compiledSeq = [];
         }
+    };
+    calculate(){
+        //
     }
 }

+ 1 - 1
public/web/common_ajax.js

@@ -81,7 +81,7 @@ var CommonAjax = {
                 }
             },
             error: function(jqXHR, textStatus, errorThrown){
-                alert('url: ' + url +' error ' + textStatus + " " + errorThrown);
+                alert('url: ' + url +', error: ' + textStatus + ", " + errorThrown);
                 if (exceptionCallback) {
                     exceptionCallback();
                 }

+ 1 - 1
public/web/rpt_value_define.js

@@ -1,7 +1,7 @@
 /**
  * Created by Tony on 2017/6/7.
  */
-var JV = {
+let JV = {
     NODE_CROSS_INFO: "交叉表_信息",
     NODE_CROSS_ROW: "交叉行",
     NODE_CROSS_COL: "交叉列",

+ 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;
+    }
+}

+ 3 - 1
public/web/treeDataHelper.js

@@ -43,7 +43,9 @@ var tree_Data_Helper = {
         }
         for (var i = 0; i < data.length; i++) {
             if (data[i][NEXT_ID] != EMPTY_ID_VAL) {
-                tmpNodes[prefix + data[i][NEXT_ID]][ADHOC_PRE_ID] = data[i][NODE_ID];
+                if (tmpNodes[prefix + data[i][NEXT_ID]] !== undefined){
+                    tmpNodes[prefix + data[i][NEXT_ID]][ADHOC_PRE_ID] = data[i][NODE_ID];
+                }
             }
             if (data[i][P_ID] != EMPTY_ID_VAL) {
                 tmpNodes[prefix + data[i][P_ID]][SUB_ID].push(data[i][NODE_ID]);

+ 452 - 0
test/calculation/testCalc.js

@@ -0,0 +1,452 @@
+/**
+ * Created by Tony on 2017/6/21.
+ */
+var test = require('tape');
+var calcUtil = require('../../public/calc_util');
+
+let dummyFee = [
+    {
+        "ID" : 1,
+        "ParentID" : null,
+        "name" : "企业管理费",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 2,
+        "ParentID" : 1,
+        "name" : "建筑工程",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 3,
+        "ParentID" : 2,
+        "name" : "一类工程",
+        "rate" : 16.03,
+        "memo" : null
+    },
+    {
+        "ID" : 4,
+        "ParentID" : 2,
+        "name" : "二类工程",
+        "rate" : 14.95,
+        "memo" : null
+    },
+    {
+        "ID" : 5,
+        "ParentID" : 2,
+        "name" : "三类工程",
+        "rate" : 12.47,
+        "memo" : null
+    },
+    {
+        "ID" : 6,
+        "ParentID" : 2,
+        "name" : "四类工程",
+        "rate" : 9.3,
+        "memo" : null
+    },
+    {
+        "ID" : 7,
+        "ParentID" : 1,
+        "name" : "市政工程",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 8,
+        "ParentID" : 7,
+        "name" : "一类工程",
+        "rate" : 16.33,
+        "memo" : null
+    },
+    {
+        "ID" : 9,
+        "ParentID" : 7,
+        "name" : "二类工程",
+        "rate" : 15,
+        "memo" : null
+    },
+    {
+        "ID" : 10,
+        "ParentID" : 7,
+        "name" : "三类工程",
+        "rate" : 12.5,
+        "memo" : null
+    },
+    {
+        "ID" : 11,
+        "ParentID" : 7,
+        "name" : "四类工程",
+        "rate" : 9.5,
+        "memo" : null
+    },
+    {
+        "ID" : 12,
+        "ParentID" : 1,
+        "name" : "机械土石方",
+        "rate" : 15.5,
+        "memo" : null
+    },
+    {
+        "ID" : 13,
+        "ParentID" : 1,
+        "name" : "仿古建筑工程",
+        "rate" : 12,
+        "memo" : null
+    },
+    {
+        "ID" : 14,
+        "ParentID" : 1,
+        "name" : "建筑修缮工程",
+        "rate" : 12.47,
+        "memo" : null
+    },
+    {
+        "ID" : 15,
+        "ParentID" : 1,
+        "name" : "炉窑砌筑工程",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 16,
+        "ParentID" : 15,
+        "name" : "一类工程",
+        "rate" : 14.25,
+        "memo" : null
+    },
+    {
+        "ID" : 17,
+        "ParentID" : 15,
+        "name" : "二类工程",
+        "rate" : 12.47,
+        "memo" : null
+    },
+    {
+        "ID" : 18,
+        "ParentID" : 15,
+        "name" : "三类工程",
+        "rate" : 10.8,
+        "memo" : null
+    },
+    {
+        "ID" : 19,
+        "ParentID" : 15,
+        "name" : "四类工程",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 20,
+        "ParentID" : null,
+        "name" : "规费",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 21,
+        "ParentID" : 20,
+        "name" : "建筑工程",
+        "rate" : 4.87,
+        "memo" : null
+    },
+    {
+        "ID" : 22,
+        "ParentID" : 20,
+        "name" : "市政工程",
+        "rate" : 3.61,
+        "memo" : null
+    },
+    {
+        "ID" : 23,
+        "ParentID" : 20,
+        "name" : "机械土石方",
+        "rate" : 2.15,
+        "memo" : null
+    },
+    {
+        "ID" : 24,
+        "ParentID" : 20,
+        "name" : "仿古建筑工程",
+        "rate" : 2.84,
+        "memo" : null
+    },
+    {
+        "ID" : 25,
+        "ParentID" : 20,
+        "name" : "建筑修缮工程",
+        "rate" : 2.84,
+        "memo" : null
+    },
+    {
+        "ID" : 26,
+        "ParentID" : 20,
+        "name" : "炉窑砌筑工程",
+        "rate" : 3.61,
+        "memo" : null
+    },
+    {
+        "ID" : 27,
+        "ParentID" : null,
+        "name" : "利润",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 28,
+        "ParentID" : 27,
+        "name" : "建筑工程",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 29,
+        "ParentID" : 28,
+        "name" : "一类工程",
+        "rate" : 8.73,
+        "memo" : null
+    },
+    {
+        "ID" : 30,
+        "ParentID" : 28,
+        "name" : "二类工程",
+        "rate" : 6.94,
+        "memo" : null
+    }
+]
+
+let dummyCalcTpl = {
+    calType: 3,
+    calTypeName: "测试用_重庆",
+    compiledSeq: [],
+    calcItems: [{
+        code: "1",
+        name: "基价直接工程费",
+        dispExpr: "1.1+1.2+1.3+1.4",
+        expression: "@('1.1') + @('1.2') + @('1.3') + @('1.4')",
+        compiledExpr: "",
+        statement: "基价人工费+基价材料费+基价机械费+未计价材料费"
+    },{
+        code: "1.1",
+        name: "基价人工费",
+        dispExpr: "1.1.1+1.1.2",
+        expression: "@('1.1.1') + @('1.1.2')",
+        compiledExpr: "",
+        statement: "定额基价人工费+定额人工单价(基价)调整"
+    },{
+        code: "1.1.1",
+        name: "定额基价人工费",
+        dispExpr: "定额基价人工费",
+        //expression: "base('定额基价人工费')",
+        expression: "base('定额基价人工费').toFixed(2)",
+        compiledExpr: "",
+        statement: "定额基价人工费"
+    },{
+        code: "1.1.2",
+        name: "定额人工单价(基价)调整",
+        dispExpr: "1.1.1*[1.89-1]",
+        expression: "@('1.1.1') * fee('3')",
+        compiledExpr: "",
+        statement: "定额基价人工费*[定额人工单价(基价)调整系数-1]"
+    },{
+        code: "1.2",
+        name: "基价材料费",
+        dispExpr: "定额基价材料费",
+        expression: "base('定额基价材料费')",
+        compiledExpr: "",
+        statement: "定额基价材料费"
+    },{
+        code: "1.3",
+        name: "基价机械费",
+        dispExpr: "1.3.1+1.3.2",
+        expression: "@('1.3.1') + @('1.3.2')",
+        compiledExpr: "",
+        statement: "定额基价机械费+定额机上人工单价(基价)调整"
+    },{
+        code: "1.3.1",
+        name: "定额基价机械费",
+        dispExpr: "定额基价机械费",
+        expression: "base('定额基价机械费')",
+        compiledExpr: "",
+        statement: "定额基价机械费"
+    },{
+        code: "1.3.1.1",
+        name: "其中:定额基价机上人工费",
+        dispExpr: "定额基价机上人工费",
+        expression: "base('定额基价机上人工费')",
+        compiledExpr: "",
+        statement: "定额基价机上人工费"
+    },{
+        code: "1.3.2",
+        name: "定额人工单价(基价)调整",
+        dispExpr: "1.3.1.1*[1.89-1]",
+        expression: "@('1.3.1.1') * fee('30')",
+        compiledExpr: "",
+        statement: "定额基价人工费*[定额人工单价(基价)调整系数-1]"
+    },{
+        code: "1.4",
+        name: "未计价材料费",
+        dispExpr: "主材费+设备费",
+        expression: "base('主材费') + base('设备费')",
+        compiledExpr: "",
+        statement: "主材费+设备费"
+    },{
+        code: "2",
+        name: "企业管理费",
+        dispExpr: "1.1.1",
+        expression: "@('1.1.1')",
+        compiledExpr: "",
+        statement: "定额基价人工费"
+    },{
+        code: "3",
+        name: "利润",
+        dispExpr: "1.1.1",
+        expression: "@('1.1.1')",
+        compiledExpr: "",
+        statement: "定额基价人工费"
+    },{
+        code: "4",
+        name: "风险因素",
+        dispExpr: "",
+        expression: "0",
+        compiledExpr: "",
+        statement: ""
+    },{
+        code: "5",
+        name: "人材机价差",
+        dispExpr: "5.1+5.2+5.3",
+        expression: "@('5.1') + @('5.2') + @('5.3')",
+        compiledExpr: "",
+        statement: "人工费价差+材料费价差+机械费价差"
+    },{
+        code: "5.1",
+        name: "人工费价差",
+        dispExpr: "信息价或市场价格-调整后的定额人工费(基价)",
+        expression: "base('市场价格人工费') - base('定额基价人工费(调整后)')",
+        compiledExpr: "",
+        statement: "市场价格人工费-调整后的定额人工费(基价)"
+    },{
+        code: "5.2",
+        name: "材料费价差",
+        dispExpr: "信息价或市场价格-定额基价材料费",
+        expression: "base('市场价格材料费') - base('定额基价材料费(调整后)')",
+        compiledExpr: "",
+        statement: "市场价格材料费-定额基价材料费"
+    },{
+        code: "5.3",
+        name: "机械费价差",
+        dispExpr: "信息价或市场价格-调整后的定额基价机械费(基价)",
+        expression: "base('市场价格机械费') - base('定额基价机械费(调整后)')",
+        compiledExpr: "",
+        statement: "市场价格机械费-调整后的定额基价机械费(基价)"
+    },{
+        code: "6",
+        name: "综合单价",
+        dispExpr: "1+2+3+4+5",
+        expression: "@('1') + @('2') + @('3') + @('4') + @('5')",
+        compiledExpr: "",
+        statement: "基价直接工程费+企业管理费+利润+风险因素+人材机价差"
+    }
+    ]
+};
+
+let dummyRation = {
+    "sectionId" : 76,
+    "ID" : 15,
+    "code" : "AA0001",
+    "name" : "人工挖土方",
+    "unit" : "100m3",
+    "basePrice" : 840.84,
+    "caption" : "人工挖土方",
+    "feeType" : 2,
+    "rationGljList" : [
+        {
+            "glj" : {
+                "repositoryId" : 3,
+                "ID" : 17,
+                "code" : "00010201",
+                "name" : "土石方综合工日",
+                "specs" : null,
+                "unit" : "工日",
+                "basePrice" : 22,
+                "gljDistType" : "人工",
+                "gljType" : 2
+            },
+            "consumeAmt" : 38.22,
+            "proportion" : 0
+        },{
+            "glj": {
+                "repositoryId" : 3,
+                "ID" : 68,
+                "code" : "85030207",
+                "name" : "履带式起重机",
+                "specs" : "50t",
+                "unit" : "台班",
+                "basePrice" : 1194.05,
+                "gljDistType" : "机械",
+                "gljType" : 64
+            },
+            "consumeAmt" : 1.22,
+            "proportion" : 0
+        },{
+            "glj": {
+                "repositoryId" : 3,
+                "ID" : 200,
+                "code" : "36290101",
+                "name" : "水",
+                "specs" : "",
+                "unit" : "m3",
+                "basePrice" : 2,
+                "gljDistType" : "材料",
+                "gljType" : 6
+            },
+            "consumeAmt" : 9.2,
+            "proportion" : 0
+        }
+    ],
+    "rationRepId" : 3
+}
+
+/*
+test('计算式测试', function(t){
+    calcUtil.init(dummyCalcTpl, dummyFee);
+    calcUtil.compile();
+    calcUtil.calculate(dummyRation);
+    for (let idx of dummyCalcTpl.compiledSeq) {
+        let item = dummyCalcTpl.calcItems[idx];
+        console.log('code: ' + item.code + ' | expression: ' + item.compiledExpr +  ' | result: ' + item.execRst);
+    }
+    t.pass('just pass for calculation initialization!');
+    t.end();
+})
+
+/*/
+let cnt = 100000;
+test('极限计算式测试:' + cnt + '次', function(t){
+    let dt0 = new Date();
+    calcUtil.init(dummyCalcTpl, dummyFee);
+    calcUtil.compile();
+
+    let exRlist = [];
+
+    let rStr = JSON.stringify(dummyRation);
+    for (let i = 0; i < cnt; i++) {
+        exRlist.push(JSON.parse(rStr));
+    }
+
+    let dt1 = new Date();
+    for (let i = 0; i < cnt; i++) {
+        calcUtil.calculate(exRlist[i]);
+    }
+    let dt2 = new Date();
+    console.log("准备对象时间(毫秒): " + (dt1 - dt0));
+    console.log("总计算时间(毫秒): " + (dt2 - dt1));
+    console.log("总测试时间(毫秒): " + (dt2 - dt0));
+    t.pass('just pass for calculation initialization!');
+    t.end();
+})
+
+
+//*/

+ 65 - 0
test/demo/stringTest.js

@@ -0,0 +1,65 @@
+/**
+ * Created by Tony on 2017/6/21.
+ */
+/**
+ * Created by Tony on 2017/6/21.
+ */
+var test = require('tape');
+
+test('string test1', function(t){
+    let str = "at('1.1') + at('1.2') + at('1.3') + at('1.4')";
+    //let re = /at(/g;
+    //let re = new RegExp("at\(", "g");
+    //let str1 = str.replaceAll('re', '@(');
+    //let str1 = str.replace('at(', '@(');
+    var str1 = str.split('at1(').join('@(');
+    //t.equal(str1, "@('1.1') + @('1.2') + @('1.3') + @('1.4')");
+    t.equal(str1, "at('1.1') + at('1.2') + at('1.3') + at('1.4')");
+    t.end();
+})
+
+test('string test2', function(t){
+    var str="hello(world)";
+    var nstr = str.replace(/\([^\)]*\)/g,"");
+
+    t.equal(nstr , "hello");
+    t.end();
+})
+
+test('string test3', function(t){
+    var str="共 (%S) 页";
+    var nstr = str.replace("(%S)",10);
+
+    t.equal(nstr , "共 10 页");
+    t.end();
+})
+
+test('test extract', function(t){
+    let private_extract_code = function(str, idx){
+        let rst = '', lBracket = 0, rBracket = 0, firstIdx = idx, lastIdx = 0;
+        for (let i = idx; i < str.length; i++) {
+            if (str[i] === '(') {
+                lBracket++;
+                if (lBracket == 1) firstIdx = i + 1;
+            }
+            if (str[i] === ')') {
+                rBracket++;
+                if (lBracket == rBracket) {
+                    lastIdx = i - 1;
+                    if (lastIdx > firstIdx) {
+                        if (str[firstIdx] === "'") firstIdx++;
+                        if (str[lastIdx] !== "'") lastIdx++;
+                        if (lastIdx > firstIdx) {
+                            rst = str.slice(firstIdx, lastIdx);
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+        return rst;
+    };
+    let code = private_extract_code("at('1.1') + at('1.2')", 10);
+    t.equal(code , "1.2");
+    t.end();
+})

+ 19 - 0
test/public/testLoadDateFormat.js

@@ -0,0 +1,19 @@
+/**
+ * Created by Tony on 2017/7/13.
+ */
+let test = require('tape');
+let fs = require("fs");
+
+test('std glj types test1', function(t){
+    //console.log(__dirname.slice(0, __dirname.length - 12) + '/public/web/date_util.js');
+    fs.readFile(__dirname.slice(0, __dirname.length - 12) + '/public/web/date_util.js', 'utf8', 'r', function (err, data) {
+        eval(data);
+        let dt = new Date();
+        //dt.setMonth(dt.getMonth() + 3);
+        t.equal(dt.Format('yyyy-M-dd'), "2017-7-13");
+        t.equal(dt.Format('yyyy年M月dd日'), "2017年7月13日");
+        t.equal(dt.Format('yyyy年M月20日'), "2017年7月20日");
+        t.end();
+    });
+});
+

+ 30 - 0
test/public/testStdGljTypes.js

@@ -0,0 +1,30 @@
+/**
+ * Created by Tony on 2017/7/6.
+ */
+
+let test = require('tape');
+let mongoose = require('mongoose');
+
+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){
+    setTimeout(function(){
+        let cacheObj = stdgljutil.getStdGljTypeCacheObj();
+        t.equal(cacheObj != null, true);
+        let rgItem = cacheObj.getItemById(301);
+        t.equal(rgItem != null, true);
+        let tPId = cacheObj.getTopParentIdByItemId(301);
+        t.equal(tPId, 3);
+        let arr = cacheObj.toArray();
+        t.equal(arr.length, 13);
+        mongoose.disconnect();
+        t.pass('closing db connection');
+        t.end();
+    }, 500);
+})
+

+ 10 - 9
web/maintain/bills_lib/html/main.html

@@ -120,7 +120,7 @@
     <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="/web/maintain/js/global.js"></script>
+    <script src="/web/maintain/bills_lib/scripts/global.js"></script>
     <script src="/web/maintain/bills_lib/scripts/bills_lib_ajax.js"></script>
     <script src="/web/maintain/bills_lib/scripts/tools.js"></script>
 
@@ -129,13 +129,13 @@
     autoFlashHeight();
 </script>
 <script>
-    var userId = '<%= userID %>';
-    var userAccount = '<%= userAccount %>';
+    let userId = '<%= userID %>';
+    let userAccount = '<%= userAccount %>';
     mainAjax.getStdBillsLib(userId);
     $(document).ready(function(){
         //main 增删改
         $("#createA").click(function(){
-            var billsLibName = $("#createText").val();
+            let billsLibName = $("#createText").val();
             if(billsLibName){
                 mainAjax.createStdBillsLib(userId, billsLibName);
                 $("#createText").val("");
@@ -146,23 +146,23 @@
         });
 
        $("#showArea").on("click", "[data-target = '#del']", function(){
-            var deleteId = $(this).parent().parent().attr("id")
+           let deleteId = $(this).parent().parent().attr("id");
            $("#deleteA").attr("deleteId", deleteId);
        });
         $("#deleteA").click(function(){
-            var deleteId = $(this).attr("deleteId");
+            let deleteId = $(this).attr("deleteId");
             mainAjax.deleteStdBillsLib(deleteId);
         });
 
        $("#showArea").on("click", "[data-target = '#edit']", function(){
-           var renameId = $(this).parent().parent().attr("id");
+           let renameId = $(this).parent().parent().attr("id");
            $("#renameA").attr("renameId", renameId);
 
        });
 
         $("#renameA").click(function(){
-            var newName = $("#renameText").val();
-            var renameId = $(this).attr("renameId");
+            let newName = $("#renameText").val();
+            let renameId = $(this).attr("renameId");
             if(newName){
                 mainAjax.renameStdBillsLib(renameId, newName);
                 $("#renameText").val("");
@@ -171,6 +171,7 @@
                 alert("请输入名称!");
             }
         });
+        //test es6
     });
 </script>
 

+ 71 - 7
web/maintain/bills_lib/html/neirong.html

@@ -11,7 +11,7 @@
     <link rel="stylesheet" href="/web/maintain/bills_lib/css/main.css">
     <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
     <!--spread-->
-    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013white.10.0.1.css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013lightGray.10.0.1.css">
     <!--zTree-->
     <link rel="stylesheet" href="/lib/ztree/css/zTreeStyle.css" type="text/css">
 </head>
@@ -166,6 +166,7 @@
     </div>
     <!-- JS. -->
     <script 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>
     <script src="/lib/jquery/jquery.min.js"></script>
     <script src="/lib/tether/tether.min.js"></script>
     <script src="/lib/bootstrap/bootstrap.min.js"></script>
@@ -177,11 +178,13 @@
     <script src="/web/maintain/bills_lib/scripts/bills_lib_setting.js"></script>
     <script src="/web/maintain/bills_lib/scripts/db_controller.js"></script>
     <SCRIPT type="text/javascript">
-        var billsLibId = getQueryString("billsLibId");
+        let billsLibId = getQueryString("billsLibId");
         tools.redirect(billsLibId, 'stdBillsmain');
-        var spreadAllJobs = new GC.Spread.Sheets.Workbook($('#spreadAllJobs')[0], {sheetCount: 1});
-        var orgJobData;
-        var maxJobNumer;
+        let spreadAllJobs = new GC.Spread.Sheets.Workbook($('#spreadAllJobs')[0], {sheetCount: 1});
+        let orgJobData;
+        let maxJobNumer;
+        let maxJobsNumber;
+        let sheetJobsDatas;
         $(document).ready(function(){
             $('#aStdBills').attr('href', function(){
                 return 'stdBills?billsLibId=' + billsLibId;
@@ -199,7 +202,7 @@
             TREE_SHEET_HELPER.loadSheetHeader(setting, spreadAllJobs.getActiveSheet());
             jobsAjax.getJobContent(billsLibId, function(datas){
                 spreadAllJobs.getActiveSheet().suspendPaint();
-                var len = datas.length;
+                let len = datas.length;
                 for(var i=0; i<len; i++){
                     setting.cols.forEach(function(col, colIdx){
                         spreadAllJobs.getActiveSheet().setTag(i, colIdx, datas[i].id, GC.Spread.Sheets.SheetArea.viewport);
@@ -212,15 +215,17 @@
                     });
                 }
                 spreadAllJobs.getActiveSheet().resumePaint();
-                var totalJobs = createObj.newJobs();
+                let totalJobs = createObj.newJobs();
                 totalJobs.loadJobs(null, datas);
                 tools.getBillsIds(function(ids){
                     myKey.delKey(spreadAllJobs, ids, totalJobs, setting, 'totalJobs');
                     bindSheet(totalJobs, spreadAllJobs.getActiveSheet(), setting);
+                    pasteJobs(spreadAllJobs.getActiveSheet(), totalJobs);
                 });
             });
         }
         function bindSheet(totalJobs, sheet, setting){
+            setSheet.setMaxRowCount(sheet, totalJobs.jobsArr);
             mainAjax.getMaxNumber(billsLibId, 'jobs', function(result){
                 if(result.length === 0){
                     maxJobsNumber = 0;
@@ -233,6 +238,65 @@
             });
         }
 
+        function pasteJobs(sheet, totalJobs){
+            sheetJobsDatas = tools.getsheetDatas(sheet, 'total');
+            sheet.bind(GC.Spread.Sheets.Events.ClipboardPasted, function(sender, args){
+                const colIdx = 1;
+                let orgRow = args.cellRange.row, orgCol = args.cellRange.col, rowCount = args.cellRange.rowCount, colCount = args.cellRange.colCount;
+                let maxRow = orgRow + rowCount - 1, maxCol = orgCol + colCount -1;
+                let pasteDatas = [], uncrossedDatas = [], crossedDatas = [];
+                for(let i = orgRow; i<= maxRow; i++){
+                    for(let j =0; j<=1; j++){
+                        let filed = j === 0 ? 'code' : 'content';
+                        if(sheet.getCell(i, j).value()){
+                            let unitData = {
+                                billsLibId: billsLibId,
+                                rowIdx: i,
+                                colIdx: j,
+                                field: filed,
+                                data: sheet.getCell(i, j).value(),
+                                type:  'Create'
+                            };
+                            pasteDatas.push(unitData);
+                        }
+                    }
+                }
+                for(let i=0; i< pasteDatas.length; i++){
+                    let crossedData;
+                    let flag = true;
+                    sheetJobsDatas.forEach(function(orgData){
+                        if(pasteDatas[i].rowIdx === orgData.rowIdx && pasteDatas[i].colIdx === orgData.colIdx){
+                            flag = false;
+                            crossedData = {
+                                billsLibId: billsLibId,
+                                rowIdx: pasteDatas[i].rowIdx,
+                                colIdx: pasteDatas[i].colIdx,
+                                field: pasteDatas[i].field,
+                                orgId: orgData.id,
+                                data: pasteDatas[i].data,
+                                type: 'Update'
+                            }
+                        }
+                    });
+                    if(flag){
+                        uncrossedDatas.push(pasteDatas[i]);
+                    }
+                    else{
+                        crossedDatas.push(crossedData);
+                    }
+                }
+                let encapDatas = tools.encapTotalJobsDatas(sheet, totalJobs, uncrossedDatas, crossedDatas);
+                if(encapDatas.updateDatas.length > 0 || encapDatas.createDatas.length > 0){
+                    jobsAjax.pasteJobs(encapDatas, function(datas){
+                        pasteController.pasteJobsFront(sheet, totalJobs,datas);
+                    });
+                }
+                else{
+                    tools.reshowData(sheet, totalJobs.jobsArr, totalJobsSetting, true);
+                }
+            });
+        }
+
 
   	</SCRIPT>
 </body>

+ 192 - 48
web/maintain/bills_lib/html/qingdan.html

@@ -10,7 +10,7 @@
     <link rel="stylesheet" href="/web/maintain/bills_lib/css/main.css">
     <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
     <!--spread-->
-    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013white.10.0.1.css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013lightGray.10.0.1.css">
 </head>
 
 <body>
@@ -211,6 +211,7 @@
     </div>
     <!-- JS. -->
     <script 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>
     <script src="/lib/jquery/jquery.min.js"></script>
     <script src="/lib/tether/tether.min.js"></script>
     <script src="/lib/bootstrap/bootstrap.min.js"></script>
@@ -223,21 +224,23 @@
     <script src="/public/web/tree_sheet/tree_sheet_helper.js"></script>
     <script src="/web/maintain/bills_lib/scripts/bills_lib_setting.js"></script>
     <script src="/web/maintain/bills_lib/scripts/bills_lib_tree.js"></script>
-    <script src="/test/tmp_data/bills_grid_setting.js"></script>
     <script src="/web/maintain/bills_lib/scripts/db_controller.js"></script>
     <script src="/web/maintain/bills_lib/scripts/tools.js"></script>
 </body>
 <script type="text/javascript">
     autoFlashHeight();
-    var maxJobsNumber;
-    var maxItemsNumber;
-    var orgJobData;
-    var orgItemData;
-    var billsTree = billsLibTree.createBillsTree();
-    var billsLibId = getQueryString("billsLibId");
+    let maxJobsNumber;
+    let maxItemsNumber;
+    let orgJobData;
+    let orgItemData;
+    let billsTree = billsLibTree.createBillsTree();
+    let billsLibId = getQueryString("billsLibId");
+    let sheetDatas;
+    let sheetItemsDatas;
+    let sheetBillsDatas;
     tools.redirect(billsLibId, 'stdBillsmain');
-    var jobsSpread = new GC.Spread.Sheets.Workbook($("#spreadJobs")[0], {sheetCount: 1});
-    var itemsSpread = new GC.Spread.Sheets.Workbook($("#spreadItems")[0], {sheetCount: 1});
+    let jobsSpread = new GC.Spread.Sheets.Workbook($("#spreadJobs")[0], {sheetCount: 1});
+    let itemsSpread = new GC.Spread.Sheets.Workbook($("#spreadItems")[0], {sheetCount: 1});
     $(document).ready(function(){
         $("#aStdJobs").attr('href', function(){
             return 'stdJobs?billsLibId=' + billsLibId;
@@ -254,7 +257,7 @@
     });
 
     function nodeOpration(controller, totalJobs, totalItems){
-        dbController.editData(controller, controller.sheet);
+        dbController.editData(controller);
         $('#insert').click(function(){
             dbController.insert(controller);
             tools.clearData(jobsSpread.getActiveSheet());
@@ -279,13 +282,16 @@
 
 
     function showBillsSheet(datas, jobsSheet, itemsSheet, setting) {
-        var billsSpread = new GC.Spread.Sheets.Workbook($('#spreadBills')[0], {sheetCount: 1});
+        let billsSpread = new GC.Spread.Sheets.Workbook($('#spreadBills')[0], {sheetCount: 1});
+        //
+        /*let billsSheet = billsSpread.getActiveSheet();
+        billsSheet.setFormatter(-1, 0, "@", GC.Spread.Sheets.SheetArea.viewport);*/
+        //
         setSheet.initSheet(billsSpread, setting);
+        //setSheet.formatter(billsSpread.getActiveSheet());
         myKey.delKey(billsSpread);
         billsTree.loadDatas(datas);
-        //粘贴事件
-        bindPasteBills(billsSpread.getActiveSheet(), setting);
-        var controller = TREE_SHEET_CONTROLLER.createNew(billsTree.tree, billsSpread.getActiveSheet(), setting);
+        let controller = TREE_SHEET_CONTROLLER.createNew(billsTree.tree, billsSpread.getActiveSheet(), setting);
         controller.showTreeData();
         //setTagId
         setTagID(controller, setting);
@@ -295,12 +301,17 @@
         //刷新节点可进行操作的按钮
         refreshBtn(controller);
         controller.setTreeSelected(controller.tree.findNode(controller.sheet.getTag(0, 0)));
+        //粘贴事件
+        bindPasteBills(controller, billsSpread.getActiveSheet(), setting);
         //补注内容改变
         rechargeChange(controller);
         //jobs
         jobOperation(controller, jobsSheet, function(totalJobs){
+            //------关联表粘贴复制
+            bindPasteRel(jobsSheet, controller, totalJobs, jobsSetting);
             //items
             itemOperation(controller, itemsSheet, function(totalItems){
+                bindPasteItemsRel(itemsSheet, controller, totalItems, itemsSetting);
                 //节点操作
                 nodeOpration(controller, totalJobs, totalItems);
             });
@@ -309,7 +320,7 @@
 
     function setTagID(controller, setting){
         if(controller.tree.items.length > 0){
-            var length = controller.tree.items.length;
+            let length = controller.tree.items.length;
             for(var i=0; i<length; i++){
                 setting.cols.forEach(function(col, colIdx){
                     if(controller.tree.items[i].data.ID){
@@ -322,11 +333,15 @@
 
     function refreshBtn(controller){
         controller.bind('refreshBaseActn', function (tree) {
-            var showButton = function (show, btn) {
+            let showButton = function (show, btn) {
                 if (show) {
-                    btn.show();
+                    //btn.show();
+                    btn.css("opacity", "");
+                    btn.removeClass("disabled");
                 } else {
-                    btn.hide();
+                    //btn.hide();
+                    btn.css("opacity", "0.2");
+                    btn.addClass("disabled");
                 }
             };
             showButton(tree.selected && tree.selected.canUpLevel(), $('#upLevel'));
@@ -339,7 +354,7 @@
 
     function rechargeChange(controller){
         $('#exampleTextarea').bind('change', function(){
-            var newData = $('#exampleTextarea').val();
+            let newData = $('#exampleTextarea').val();
             if(controller.tree.selected){
                 rechargeController.updateRechar(controller.tree.selected, newData);
             }
@@ -355,7 +370,7 @@
                 maxJobsNumber = result[0].code;
             }
             jobsAjax.getJobContent(billsLibId, function(datas){
-                var totalJobs = createObj.newJobs();
+                let totalJobs = createObj.newJobs();
                 totalJobs.loadJobs(controller.tree.items, datas);
                 initData(controller, jobsSheet, jobsSetting, 'jobs');
                 myKey.delKey(jobsSpread, controller, totalJobs, jobsSetting, 'jobs');
@@ -377,7 +392,7 @@
                 maxItemsNumber = result[0].code;
             }
             itemsAjax.getItemCharacter(billsLibId, function(datas){
-                var totalItems = createObj.newItems();
+                let totalItems = createObj.newItems();
                 totalItems.loadItems(controller.tree.items, datas);
                 initData(controller, itemsSheet, itemsSetting, 'items');
                 myKey.delKey(itemsSpread, controller, totalItems, itemsSetting, 'items');
@@ -393,10 +408,13 @@
     //初始焦点工作表和项目表绑定数据
     function initData(controller, sheet, setting, classify){
         if(controller.tree.selected){
-            var arr = controller.tree.selected[classify];
-            var recharge = controller.tree.selected.data.recharge;
+            let arr = controller.tree.selected[classify];
+            let recharge = controller.tree.selected.data.recharge;
+            setSheet.setMaxRowCount(sheet, arr);
+            let prefix = classify === 'jobs' ? 'job' : 'item';
             if(arr.length > 0){
-                tools.reshowData(sheet, arr, setting, true);
+                //tools.reshowData(sheet, arr, setting, true);//update--
+                tools.orderReshowData(sheet, arr, setting, prefix,true);
             }
             if(recharge){
                 $('#exampleTextarea').val(recharge);
@@ -411,18 +429,23 @@
                 $('#exampleTextarea').val(controller.tree.selected.data.recharge);
                 tools.clearData(sheet);
                 if(field === 'jobs'){
-                    var jobs = controller.tree.selected.jobs;
+                    let jobs = controller.tree.selected.jobs;
+                    setSheet.setMaxRowCount(sheet, jobs);
                     if(jobs.length > 0){
-                        tools.reshowData(sheet, jobs, setting, true);
+                     //   tools.reshowData(sheet, jobs, setting, false);
+                        tools.orderReshowData(sheet, jobs, setting, 'job', true);
                         orgJobData = sheet.getValue(0, 0);
                     }
+                    sheetDatas = tools.getsheetDatas(sheet, 'jobs');
                 }
                 if(field === 'items'){
-                    var items = controller.tree.selected.items;
+                    let items = controller.tree.selected.items;
+                    setSheet.setMaxRowCount(sheet, items);
                     if(items.length > 0){
-                        tools.reshowData(sheet, items, setting, true);
+                        tools.orderReshowData(sheet, items, setting, 'item', false);
                         orgItemData = sheet.getValue(0, 0);
                     }
+                    sheetItemsDatas = tools.getsheetDatas(sheet, 'items');
                 }
             }
             else {
@@ -432,45 +455,166 @@
         });
     }
 
-    function bindPasteBills(sheet, setting){
+    function bindPasteBills(controller, sheet, setting){
+        sheetBillsDatas = tools.getsheetDatas(sheet, 'bills', controller);
         sheet.bind(GC.Spread.Sheets.Events.ClipboardPasted, function(sender, args){
-            var datas = [], field;
-            var orgRow = args.cellRange.row, orgCol = args.cellRange.col, rowCount = args.cellRange.rowCount, colCount = args.cellRange.colCount;
-            var maxRow = orgRow + rowCount - 1, maxCol = orgCol + colCount -1;
-            for(var i=orgRow; i<= maxRow; i++){
-                var id =  sheet.getTag(i, 0, GC.Spread.Sheets.SheetArea.viewport);
-                if(id){
-                    var pasteJson = {billsLibId: billsLibId, ID: id, code: null, name: null, unit: null, ruleText: null};
-                    var colLen = sheet.getColumnCount(GC.Spread.Sheets.SheetArea.viewport);
-                    for(var j=0; j<colLen; j++){
+            let datas = [], field;
+            let orgRow = args.cellRange.row, orgCol = args.cellRange.col, rowCount = args.cellRange.rowCount, colCount = args.cellRange.colCount;
+            let maxRow = orgRow + rowCount - 1, maxCol = orgCol + colCount -1;
+            //let id =  controller.tree.selected.getID();
+            let markRow = orgRow, colLen = sheet.getColumnCount(GC.Spread.Sheets.SheetArea.viewport);
+            //test
+            let validDatas = tools.getValidDatas(sheet, setting, args);
+            for(let i=orgRow, j=0; i<= maxRow; i++, j++){
+                let id = sheet.getTag(i, 0);
+                if(id && j< validDatas.length){
+                    console.log(`id: ${id} row: ${i}`);
+                    for(let k=0; k<colLen; k++){
                         setting.cols.forEach(function(col, colIdx){
-                            if(colIdx === j){
+                            if(colIdx === k){
                                 field = col.data.field;
                             }
                         });
-                        pasteJson[field] = sheet.getValue(i, j);
+                        sheet.setValue(i, k, validDatas[j][field]);
                     }
-                    datas.push(pasteJson);
+                    validDatas[j].billsLibId = billsLibId;
+                    validDatas[j].ID = id;
+                    datas.push(validDatas[j]);
+
+                }
+                else if(i< controller.tree.items.length && j>= validDatas.length) {
+                    //reshow orgDatas
+                    console.log(`rowIdx: ${i}`)
+                    sheetBillsDatas.forEach(function(rowData){
+                        if(rowData.rowIdx === i){
+                            sheet.setValue(i, 0, rowData.code + '');
+                            sheet.setValue(i, 1, rowData.name);
+                            sheet.setValue(i, 2, rowData.unit + '');
+                            sheet.setValue(i, 3, rowData.ruleText);
+                        }
+                    });
                 }
                 else {
                     sheet.clear(i, 0, 1, sheet.getColumnCount(), GC.Spread.Sheets.SheetArea.viewport,GC.Spread.Sheets.StorageType.data);
                 }
             }
             billsAjax.pasteBills(datas);
+            sheetBillsDatas = tools.getsheetDatas(sheet, 'bills', controller);
         });
     }
-
-    function bindPasteRel(sheet, setting){
+    function bindPasteRel(sheet, controller, totalJobs, setting){
+        sheetDatas = tools.getsheetDatas(sheet, 'jobs');
         sheet.bind(GC.Spread.Sheets.Events.ClipboardPasted, function(sender, args){
-            var orgRow = args.cellRange.row, orgCol = args.cellRange.col, rowCount = args.cellRange.rowCount, colCount = args.cellRange.colCount;
-            var maxRow = orgRow + rowCount - 1, maxCol = orgCol + colCount -1;
+            sheet.setColumnCount(2, GC.Spread.Sheets.SheetArea.viewport);
+            if(controller.tree.selected){
+                let orgRow = args.cellRange.row, orgCol = args.cellRange.col, rowCount = args.cellRange.rowCount, colCount = args.cellRange.colCount;
+                let maxRow = orgRow + rowCount - 1, maxCol = orgCol + colCount -1;
+                let pasteArr = [];
+                let crossedDatas = [];
+                let uncrossedDatas = [];
+                const colIdx = 1;
+                for(let i=orgRow; i<=maxRow; i++){
+                    if(sheet.getCell(i, colIdx).value()){
+                        pasteArr.push(sheet.getCell(i, colIdx).value());
+                    }
+                }
+                let uniqPasteArr = tools.uniqArr(pasteArr);
+                for(let i =orgRow, j=0; i<=uniqPasteArr.length+orgRow-1; i++, j++ ){
+                    let flag = true;
+                    let crossedData;
+                    sheetDatas.forEach(function(rowData){
+                        if(rowData.rowIdx === i && rowData.data !== uniqPasteArr[j]){
+                            flag = false;
+                            let serialNo = tools.getObj(controller.tree.selected.jobs, rowData.id, 'job');
+                            crossedData = {
+                                orgId: rowData.id,
+                                newData: uniqPasteArr[j],
+                                serialNo: serialNo
+                            };
+                        }
+                    });
+                    if(flag){
+                        let serialNo = tools.getSerialNo(controller.tree.selected.jobs);
+                        uncrossedDatas.push({data: uniqPasteArr[j], serialNo: serialNo});
+                    }
+                    else {
+                        crossedDatas.push(crossedData);
+                    }
+                }
+                let pasteDatas = tools.encapData(uncrossedDatas, crossedDatas, controller, totalJobs);
+                if(pasteDatas.updateDatas.length > 0 || pasteDatas.createDatas.length > 0){
+                    billsAjax.pasteRel(pasteDatas.updateDatas, pasteDatas.createDatas, 'jobs', function(datas){
+                        pasteController.frontOperator(sheet, setting, controller, totalJobs, datas);
+                    });
+                }
+                else {
+                    tools.orderReshowData(sheet, controller.tree.selected.jobs, setting, 'job', true);
+                }
+            }
+            else {
+                tools.clearData(sheet);
+            }
+        });
+    }
+    function bindPasteItemsRel(sheet, controller, totalItems, setting){
+        sheetItemsDatas = tools.getsheetDatas(sheet, 'items');
+        sheet.bind(GC.Spread.Sheets.Events.ClipboardPasted, function(sender, args){
+            sheet.setColumnCount(2, GC.Spread.Sheets.SheetArea.viewport);
+            if(controller.tree.selected){
+                let orgRow = args.cellRange.row, orgCol = args.cellRange.col, rowCount = args.cellRange.rowCount, colCount = args.cellRange.colCount;
+                let maxRow = orgRow + rowCount - 1, maxCol = orgCol + colCount -1;
+                let pasteArr = [];
+                let crossedDatas = [];
+                let uncrossedDatas = [];
+                const colIdx = 1;
+                for(let i=orgRow; i<=maxRow; i++){
+                    if(sheet.getCell(i, colIdx).value()){
+                        pasteArr.push(sheet.getCell(i, colIdx).value());
+                    }
+                }
+                let uniqPasteArr = tools.uniqArr(pasteArr);
+                for(let i =orgRow, j=0; i<=uniqPasteArr.length+orgRow-1; i++, j++ ){
+                    let flag = true;
+                    let crossedData;
+                    sheetItemsDatas.forEach(function(rowData){
+                        if(rowData.rowIdx === i && rowData.data !== uniqPasteArr[j]){
+                            flag = false;
+                            let serialNo = tools.getObj(controller.tree.selected.items, rowData.id, 'item');
+                            crossedData = {
+                                orgId: rowData.id,
+                                newData: uniqPasteArr[j],
+                                serialNo: serialNo
+                            };
+                        }
+                    });
+                    if(flag){
+                        let serialNo = tools.getSerialNo(controller.tree.selected.items);
+                        uncrossedDatas.push({data: uniqPasteArr[j], serialNo: serialNo});
+                    }
+                    else {
+                        crossedDatas.push(crossedData);
+                    }
+                }
+                let pasteDatas = tools.encapItemsData(uncrossedDatas, crossedDatas, controller, totalItems);
+                if(pasteDatas.updateDatas.length > 0 || pasteDatas.createDatas.length > 0){
+                    billsAjax.pasteRel(pasteDatas.updateDatas, pasteDatas.createDatas, 'items', function(datas){
+                        pasteController.frontItemsRelOperator(sheet, setting, controller, totalItems, datas);
+                    });
+                }
+                else{
+                    tools.orderReshowData(sheet, controller.tree.selected.items, setting, 'item', true);
+                }
+            }
+            else {
+                tools.clearData(sheet);
+            }
         });
     }
 
 
     function buildJobs(jobsSpread, setting){
         setSheet.initSheet(jobsSpread, setting);
-        setSheet.setMaxRowCount(jobsSpread.getActiveSheet(), 10);
+       // setSheet.setMaxRowCount(jobsSpread.getActiveSheet(), 10);
         myKey.downKey(jobsSpread);
         myKey.enterKey(jobsSpread);
         TREE_SHEET_HELPER.loadSheetHeader(jobsSetting, jobsSpread.getActiveSheet());
@@ -478,7 +622,7 @@
 
     function buildItems(itemsSpread, setting){
         setSheet.initSheet(itemsSpread, setting);
-        setSheet.setMaxRowCount(itemsSpread.getActiveSheet(), 10);
+       // setSheet.setMaxRowCount(itemsSpread.getActiveSheet(), 10);
         myKey.downKey(itemsSpread);
         myKey.enterKey(itemsSpread);
         TREE_SHEET_HELPER.loadSheetHeader(itemsSetting, itemsSpread.getActiveSheet());

+ 140 - 16
web/maintain/bills_lib/html/tezheng.html

@@ -11,7 +11,7 @@
     <link rel="stylesheet" href="/web/maintain/bills_lib/css/main.css">
     <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
     <!--spread-->
-    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013white.10.0.1.css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013lightGray.10.0.1.css">
     <!--zTree-->
     <link rel="stylesheet" href="/lib/ztree/css/zTreeStyle.css" type="text/css">
 </head>
@@ -167,6 +167,7 @@
     </div>
     <!-- JS. -->
     <script 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>
     <script src="/lib/jquery/jquery.min.js"></script>
     <script src="/lib/tether/tether.min.js"></script>
     <script src="/lib/bootstrap/bootstrap.min.js"></script>
@@ -179,14 +180,16 @@
     <script src="/web/maintain/bills_lib/scripts/bills_lib_setting.js"></script>
     <script src="/web/maintain/bills_lib/scripts/db_controller.js"></script>
     <SCRIPT type="text/javascript">
-        var spread = new GC.Spread.Sheets.Workbook($('#spreadAllItems')[0], {sheetCount: 1});
-        var spreadVal = new GC.Spread.Sheets.Workbook($('#spreadEigenvalue')[0], {sheetCount: 1});
-        var billsLibId = getQueryString('billsLibId');
+        let spread = new GC.Spread.Sheets.Workbook($('#spreadAllItems')[0], {sheetCount: 1});
+        let spreadVal = new GC.Spread.Sheets.Workbook($('#spreadEigenvalue')[0], {sheetCount: 1});
+        let billsLibId = getQueryString('billsLibId');
         tools.redirect(billsLibId, 'stdBillsmain');
-        var selectedId;
-        var orgValue;
-        var orgItemData;
-        var maxItemsNumber;
+        let selectedId;
+        let orgValue;
+        let orgItemData;
+        let maxItemsNumber;
+        let totalItemsDatas;
+        let valueDatas;
   		$(document).ready(function(){
             $('#aStdBills').attr('href', function(){
                 return 'stdBills?billsLibId=' + billsLibId;
@@ -205,8 +208,7 @@
             myKey.enterKey(spread);
             TREE_SHEET_HELPER.loadSheetHeader(setting, spread.getActiveSheet());
             itemsAjax.getItemCharacter(billsLibId, function(datas){
-                spread.getActiveSheet().suspendPaint();
-                var len = datas.length;
+                let len = datas.length;
                 for(var i=0; i<len; i++){
                     if(datas[0].id){
                         selectedId = datas[0].id;
@@ -229,9 +231,9 @@
                     myKey.delKey(spread, ids, totalItems, totalItemsSetting, 'totalItems');
                     myKey.delKey(spreadVal, null, totalItems, eigenValueSetting, 'itemValue');
                     bindSheet(totalItems, spread.getActiveSheet(), spreadVal.getActiveSheet(), totalItemsSetting);
+                    pasteItems(spread.getActiveSheet(), totalItems);
+                    pasteValue(spreadVal.getActiveSheet(), totalItems);
                 });
-                //
-                spread.getActiveSheet().resumePaint();
             });
         }
 
@@ -245,6 +247,7 @@
         }
 
         function bindSheet(totalItems, itemSheet, valueSheet, setting){
+            setSheet.setMaxRowCount(itemSheet, totalItems.itemsArr);
             mainAjax.getMaxNumber(billsLibId, 'items', function(result){
                 if(result.length === 0){
                     maxItemsNumber = 0;
@@ -257,12 +260,15 @@
             });
             valueController.editData(totalItems, valueSheet, eigenValueSetting);
             itemSheet.bind(GC.Spread.Sheets.Events.SelectionChanged, function(sender, args){
-                var itemId = itemSheet.getTag(args.newSelections[0].row, args.newSelections[0].col, GC.Spread.Sheets.SheetArea.viewport);
+                let itemId = itemSheet.getTag(args.newSelections[0].row, args.newSelections[0].col, GC.Spread.Sheets.SheetArea.viewport);
                 if(itemId && args.oldSelections[0].row !== args.newSelections[0].row|| itemId && args.oldSelections[0].row === 0){
-                    var valueArr = valueController.getValues(totalItems, itemId);
+                    let valueArr = valueController.getValues(totalItems, itemId);
                     tools.clearData(valueSheet);
                     selectedId = itemId;
-                    tools.reshowValue(valueSheet, valueArr, eigenValueSetting, true);
+                    if(valueArr){
+                        setSheet.setMaxRowCount(valueSheet, valueArr);
+                        tools.reshowValue(valueSheet, valueArr, eigenValueSetting, true);
+                    }
                     orgValue = valueSheet.getValue(0, 0);
                 }
                 else {
@@ -273,13 +279,131 @@
 
         function initValue(sheet, totalItems, setting){
             if(selectedId){
-                var valueArr = valueController.getValues(totalItems, selectedId);
+                let valueArr = valueController.getValues(totalItems, selectedId);
                 if(valueArr.length > 0){
                     tools.reshowValue(sheet, valueArr, setting, true);
                 }
             }
         }
 
+        function pasteItems(sheet, totalItems){
+            totalItemsDatas = tools.getsheetDatas(sheet, 'total');
+            sheet.bind(GC.Spread.Sheets.Events.ClipboardPasted, function(sender, args){
+                const colIdx = 1;
+                let orgRow = args.cellRange.row, orgCol = args.cellRange.col, rowCount = args.cellRange.rowCount, colCount = args.cellRange.colCount;
+                let maxRow = orgRow + rowCount - 1, maxCol = orgCol + colCount -1;
+                let pasteDatas = [], uncrossedDatas = [], crossedDatas = [];
+                for(let i = orgRow; i<= maxRow; i++){
+                    for(let j =0; j<=1; j++){
+                        let filed = j === 0 ? 'code' : 'content';
+                        if(sheet.getCell(i, j).value()){
+                            let unitData = {
+                                billsLibId: billsLibId,
+                                rowIdx: i,
+                                colIdx: j,
+                                field: filed,
+                                data: sheet.getCell(i, j).value(),
+                                type:  'Create'
+                            };
+                            pasteDatas.push(unitData);
+                        }
+                    }
+                }
+                for(let i=0; i< pasteDatas.length; i++){
+                    let crossedData;
+                    let flag = true;
+                    totalItemsDatas.forEach(function(orgData){
+                        if(pasteDatas[i].rowIdx === orgData.rowIdx && pasteDatas[i].colIdx === orgData.colIdx){
+                            flag = false;
+                            crossedData = {
+                                billsLibId: billsLibId,
+                                rowIdx: pasteDatas[i].rowIdx,
+                                colIdx: pasteDatas[i].colIdx,
+                                field: pasteDatas[i].field,
+                                orgId: orgData.id,
+                                data: pasteDatas[i].data,
+                                type: 'Update'
+                            }
+                        }
+                    });
+                    if(flag){
+                        uncrossedDatas.push(pasteDatas[i]);
+                    }
+                    else{
+                        crossedDatas.push(crossedData);
+                    }
+                }
+                let encapDatas = tools.encapTotalItemsDatas(sheet, totalItems, uncrossedDatas, crossedDatas);
+                if(encapDatas.updateDatas.length > 0 || encapDatas.createDatas.length > 0){
+                    itemsAjax.pasteItems(encapDatas, function(datas){
+                        pasteController.pasteItemsFront(sheet, totalItems, datas);
+                    });
+                }
+                else{
+                    tools.reshowData(sheet, totalItems.itemsArr, totalItemsSetting, true);
+                }
+            });
+        }
+
+        function pasteValue(sheet, totalItems){
+            sheet.bind(GC.Spread.Sheets.Events.ClipboardPasted, function(sender, args){
+                valueDatas = tools.getsheetDatas(sheet, 'total');
+                const colIdx = 1;
+                let orgRow = args.cellRange.row, orgCol = args.cellRange.col, rowCount = args.cellRange.rowCount, colCount = args.cellRange.colCount;
+                let maxRow = orgRow + rowCount - 1, maxCol = orgCol + colCount -1;
+                let pasteDatas = [], uncrossedDatas = [], crossedDatas = [];
+                for(let i = orgRow; i<= maxRow; i++){
+                    for(let j =0; j<=1; j++){
+                        let filed = j === 0 ? 'code' : 'value';
+                        if(sheet.getCell(i, j).value()){
+                            let unitData = {
+                                billsLibId: billsLibId,
+                                rowIdx: i,
+                                colIdx: j,
+                                field: filed,
+                                data: sheet.getCell(i, j).value(),
+                                type:  'Create'
+                            };
+                            pasteDatas.push(unitData);
+                        }
+                    }
+                }
+                for(let i=0; i< pasteDatas.length; i++){
+                    let crossedData;
+                    let flag = true;
+                    valueDatas.forEach(function(orgData){
+                        if(pasteDatas[i].rowIdx === orgData.rowIdx && pasteDatas[i].colIdx === orgData.colIdx){
+                            flag = false;
+                            crossedData = {
+                                billsLibId: billsLibId,
+                                rowIdx: pasteDatas[i].rowIdx,
+                                colIdx: pasteDatas[i].colIdx,
+                                field: pasteDatas[i].field,
+                                orgId: orgData.id,
+                                data: pasteDatas[i].data,
+                                type: 'Update'
+                            }
+                        }
+                    });
+                    if(flag){
+                        uncrossedDatas.push(pasteDatas[i]);
+                    }
+                    else{
+                        crossedDatas.push(crossedData);
+                    }
+                }
+                let encapDatas = tools.encapValues(sheet, totalItems, uncrossedDatas, crossedDatas);
+                if(encapDatas.updateDatas.length > 0 || encapDatas.createDatas.length > 0){
+                    itemsAjax.pasteValues(encapDatas, function(datas){
+                        pasteController.pasteValueFront(sheet, totalItems, datas);
+                    });
+                }
+                else{
+                    tools.reshowValue(sheet, valuesArr, eigenValueSetting, true);
+                }
+            });
+        }
+
   	</SCRIPT>
 </body>
 <script type="text/javascript">

+ 161 - 36
web/maintain/bills_lib/scripts/bills_lib_ajax.js

@@ -111,6 +111,18 @@ var mainAjax = {
                 }
             }
         });
+    },
+    getCurrentUniqId: function (callback) {
+        $.ajax({
+            type: 'post',
+            url: 'stdBillsEditor/getCurrentUniqId',
+            dataType: 'json',
+            success: function(result){
+                if(!result.error && callback){
+                    callback(result.data);
+                }
+            }
+        });
     }
 }
 
@@ -144,11 +156,11 @@ var billsAjax = {
             }
         });
     },
-    createBills: function(billsLibId, newId, pid, nid, callback){
+    createBills: function(billsLibId, newId, pid, nid, updatePreData, callback){
         $.ajax({
             type: 'post',
             url: 'stdBillsEditor/createBills',
-            data: {data: JSON.stringify({billsLibId: billsLibId, newId: newId, ParentID: pid, NextSiblingID: nid})},
+            data: {data: JSON.stringify({billsLibId: billsLibId, newId: newId, ParentID: pid, NextSiblingID: nid, updatePreData: updatePreData})},
             dataType: 'json',
             success: function(result){
                 if(!result.error){
@@ -159,7 +171,19 @@ var billsAjax = {
             }
         });
     },
-
+    upMove: function(billsLibId, updateDatas, callback){
+        $.ajax({
+            type: 'post',
+            url: 'stdBillsEditor/upMove',
+            data: {data: JSON.stringify({billsLibId: billsLibId, updateDatas: updateDatas})},
+            dataType: 'json',
+            success: function(result){
+                if(!result.error && callback){
+                    callback();
+                }
+            }
+        });
+    },
     updatePNId: function(billsLibId, updateData, callback){
         $.ajax({
             type: 'post',
@@ -167,22 +191,24 @@ var billsAjax = {
             data: {data: JSON.stringify({billsLibId: billsLibId, updateData: updateData})},
             dataType: 'json',
             success: function(result){
-                if(!result.error){
-                    if(callback){
-                        callback();
-                    }
+                if(!result.error && callback){
+                    callback();
+                }
+                else {
+                    //提示窗口:更新失败
                 }
             }
         });
     },
-    deleteBills: function(billsLibId, deleteIds, callback){
+    deleteBills: function(billsLibId, deleteIds, updateNode, callback){
         $.ajax({
             type: 'post',
             url: 'stdBillsEditor/deleteBills',
-            data: {data: JSON.stringify({billsLibId: billsLibId, deleteIds: deleteIds})},
+            data: {data: JSON.stringify({billsLibId: billsLibId, deleteIds: deleteIds, updateNode: updateNode})},
             dataType: 'json',
             success: function(result){
                 if(!result.error){
+                    console.log(result.message);
                     if(callback){
                         callback();
                     }
@@ -223,18 +249,31 @@ var billsAjax = {
             }
         });
     },
-    updateRecharge: function(billsLibId, updateIds, data){
+    updateRecharge: function(billsLibId, updateId, data){
         $.ajax({
             type: 'post',
             url: 'stdBillsEditor/updateRecharge',
-            data: {data: JSON.stringify({billsLibId: billsLibId, updateIds: updateIds, data: data})},
+            data: {data: JSON.stringify({billsLibId: billsLibId, updateId: updateId, data: data})},
             dataType: 'json',
             success: function(result){
 
             }
         });
+    },
+    pasteRel: function (updateDatas, createDatas, field, callback) {
+        $.ajax({
+            type: 'post',
+            url: 'stdBillsEditor/pasteRel',
+            data: {data:JSON.stringify({updateDatas: updateDatas, createDatas: createDatas, field: field})},
+            dataType: 'json',
+            success: function(result){
+                if(!result.error && callback){
+                    callback(result.data);
+                }
+            }
+        });
     }
-}
+};
 
 var jobsAjax = {
     getJobContent: function(billsLidId, callback){
@@ -263,44 +302,82 @@ var jobsAjax = {
             }
         });
     },
-    createJobContent: function(billsLibId, field, data, serialNo, callback){
+    createJobContent: function(billsLibId, data, serialNo, callback){
         $.ajax({
             type: 'post',
             url: 'stdBillsEditor/createJobContent',
-            data: {data: JSON.stringify({billsLibId: billsLibId, field: field, data: data, serialNo: serialNo })},
+            data: {data: JSON.stringify({billsLibId: billsLibId, data: data, serialNo: serialNo})},
             dataType: 'json',
             success: function(result){
-                if(!result.error){
-                    if(callback){
-                        callback(result.data);
-                    }
+                if(!result.error && callback){
+                    callback(result.data);
                 }
             }
         });
     },
-    updateJobContent: function(id, field, data){
+    updateJobContent: function(billsLibId, id, field, data){
         $.ajax({
             type: 'post',
             url: 'stdBillsEditor/updateJobContent',
-            data: {data: JSON.stringify({updateId: id, field: field, data: data })},
+            data: {data: JSON.stringify({billsLibId: billsLibId, updateId: id, field: field, data: data })},
             dataType: 'json',
             success: function(result){
 
             }
         });
     },
-    deleteJobContent: function(ids){
+    deleteJobContent: function(billsLibId, ids){
         $.ajax({
             type: 'post',
             url: 'stdBillsEditor/deleteJobContent',
-            data: {data: JSON.stringify({ids: ids})},
+            data: {data: JSON.stringify({billsLibId: billsLibId, ids: ids})},
             dataType: 'json',
             success: function(result){
 
             }
         });
+    },
+    pasteJobs: function(pasteDatas, callback){
+        $.ajax({
+            type: 'post',
+            url: 'stdBillsEditor/pasteJobs',
+            data: {data: JSON.stringify({pasteDatas: pasteDatas})},
+            dataType: 'json',
+            success: function(result){
+                if(!result.error && callback){
+                    callback(result.data);
+                }
+            }
+
+        });
+    },
+    edCreateJob: function(billsLibId, billsId, data, code, serialNo, callback){
+        $.ajax({
+            type: 'post',
+            url: 'stdBillsEditor/edCreateJob',
+            data: {data: JSON.stringify({billsLibId: billsLibId, billsId:billsId, data: data, code: code, serialNo: serialNo})},
+            dataType: 'json',
+            success: function(result){
+                if(!result.error && callback){
+                    callback(result.data);
+                }
+            }
+        });
+    },
+    edUpdateJob: function(billsLibId, billsId, content, code, orgJobId, callback){
+        $.ajax({
+            type: 'post',
+            url: 'stdBillsEditor/edUpdateJob',
+            data: {data: JSON.stringify({billsLibId: billsLibId, billsId:billsId, content: content, code: code, orgJobId: orgJobId})},
+            dataType: 'json',
+            success: function(result){
+                if(!result.error && callback){
+                    callback(result.data);
+                }
+            }
+        });
     }
-}
+};
 
 var itemsAjax = {
     getItemCharacter: function(billsLibId, callback){
@@ -318,53 +395,101 @@ var itemsAjax = {
             }
         });
     },
-    createItemCharacter: function(billsLibId, field, data, serialNo, callback){
+    createItemCharacter: function(billsLibId,  data, serialNo, id){
         $.ajax({
             type: 'post',
             url: 'stdBillsEditor/createItemCharacter',
-            data: {data: JSON.stringify({billsLibId: billsLibId, field: field, data: data, serialNo: serialNo})},
+            data: {data: JSON.stringify({billsLibId: billsLibId, data: data, serialNo: serialNo, id: id})},
             dataType: 'json',
             success: function(result){
-                if(!result.error){
-                    if(callback){
-                        callback(result.data);
-                    }
-                }
             }
         });
     },
-    updateItemCharacter: function(id, field, data){
+    updateItemCharacter: function(billsLibId, id, field, data){
         $.ajax({
             type: 'post',
             url: 'stdBillsEditor/updateItemCharacter',
-            data: {data: JSON.stringify({updateId: id, field: field, data: data })},
+            data: {data: JSON.stringify({billsLibId: billsLibId, updateId: id, field: field, data: data })},
             dataType: 'json',
             success: function(result){
 
             }
         });
     },
-    updateValue: function(id, data, deleteCodes, type){
+    updateValue: function(billsLibId, id, data, deleteCodes, type){
         $.ajax({
             type: 'post',
             url: 'stdBillsEditor/updateValue',
-            data: {data: JSON.stringify({updateId: id, data: data, type: type, deleteCodes: deleteCodes})},
+            data: {data: JSON.stringify({billsLibId: billsLibId, updateId: id, data: data, type: type, deleteCodes: deleteCodes})},
             dataType: 'json',
             success: function(reslut){
 
             }
         });
     },
-    deleteItemCharacter: function(ids){
+    deleteItemCharacter: function(billsLibId, ids){
         $.ajax({
             type: 'post',
             url: 'stdBillsEditor/deleteItemCharacter',
-            data: {data: JSON.stringify({ids: ids})},
+            data: {data: JSON.stringify({billsLibId: billsLibId, ids: ids})},
             dataType: 'json',
             success: function(result){
 
             }
         });
+    },
+    pasteItems: function(pasteDatas, callback){
+        $.ajax({
+            type: 'post',
+            url: 'stdBillsEditor/pasteItems',
+            data: {data: JSON.stringify({pasteDatas: pasteDatas})},
+            dataType: 'json',
+            success: function(result){
+                if(!result.error && callback){
+                    callback(result.data);
+                }
+            }
+
+        });
+    },
+    pasteValues: function(pasteDatas, callback){
+        $.ajax({
+            type: 'post',
+            url: 'stdBillsEditor/pasteValues',
+            data: {data: JSON.stringify({pasteDatas: pasteDatas})},
+            dataType: 'json',
+            success: function(result){
+                if(!result.error && callback){
+                    callback(result.data);
+                }
+            }
+        });
+    },
+    edCreateItem: function(billsLibId, billsId, data, code, serialNo, callback){
+        $.ajax({
+            type: 'post',
+            url: 'stdBillsEditor/edCreateItem',
+            data: {data: JSON.stringify({billsLibId: billsLibId, billsId:billsId, data: data, code: code, serialNo: serialNo})},
+            dataType: 'json',
+            success: function(result){
+                if(!result.error && callback){
+                    callback(result.data);
+                }
+            }
+        });
+    },
+    edUpdateItem: function(billsLibId, billsId, content, code, orgItemId, callback){
+        $.ajax({
+            type: 'post',
+            url: 'stdBillsEditor/edUpdateItem',
+            data: {data: JSON.stringify({billsLibId: billsLibId, billsId:billsId, content: content, code: code, orgItemId: orgItemId})},
+            dataType: 'json',
+            success: function(result){
+                if(!result.error && callback){
+                    callback(result.data);
+                }
+            }
+        });
     }
 }
 

+ 40 - 40
web/maintain/bills_lib/scripts/bills_lib_setting.js

@@ -10,13 +10,13 @@ var billsLibSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: 'Arial'
             },
             data: {
                 field: 'code',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 160
         },
@@ -27,13 +27,13 @@ var billsLibSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: 'Arial'
             },
             data: {
                 field: 'name',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 300
         },
@@ -44,13 +44,13 @@ var billsLibSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: 'Arial'
             },
             data: {
                 field: 'unit',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 160
         },
@@ -61,19 +61,19 @@ var billsLibSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: ' Arial'
             },
             data: {
                 field: 'ruleText',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 420
         }
     ],
-    headRows: 2,
-    headRowHeight: [20, 30, 30],
+    headRows: 1,
+    headRowHeight: [47],
     emptyRows: 3,
     treeCol: 0
 };
@@ -87,13 +87,13 @@ var jobsSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: 'Arial'
             },
             data: {
                 field: 'code',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 100
         },
@@ -104,19 +104,19 @@ var jobsSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: 'Arial'
             },
             data: {
                 field: 'content',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 210
         },
     ],
-    headRows: 2,
-    headRowHeight: [20, 30, 30],
+    headRows: 1,
+    headRowHeight: [47],
     emptyRows: 3,
     treeCol: 0
 };
@@ -130,13 +130,13 @@ var itemsSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: 'Arial'
             },
             data: {
                 field: 'code',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 100
         },
@@ -147,19 +147,19 @@ var itemsSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: 'Arial'
             },
             data: {
                 field: 'content',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 210
         },
     ],
-    headRows: 2,
-    headRowHeight: [20, 30, 30],
+    headRows: 1,
+    headRowHeight: [47],
     emptyRows: 3,
     treeCol: 0
 };
@@ -173,13 +173,13 @@ var totalJobsSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: 'Arial'
             },
             data: {
                 field: 'code',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 200
         },
@@ -190,19 +190,19 @@ var totalJobsSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: 'Arial'
             },
             data: {
                 field: 'content',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 850
         },
     ],
-    headRows: 2,
-    headRowHeight: [20, 30, 30],
+    headRows: 1,
+    headRowHeight: [47],
     emptyRows: 3,
     treeCol: 0
 };
@@ -216,13 +216,13 @@ var totalItemsSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: 'Arial'
             },
             data: {
                 field: 'code',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 200
         },
@@ -233,19 +233,19 @@ var totalItemsSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: 'Arial'
             },
             data: {
                 field: 'content',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 850
         },
     ],
-    headRows: 2,
-    headRowHeight: [20, 30, 30],
+    headRows: 1,
+    headRowHeight: [47],
     emptyRows: 3,
     treeCol: 0
 };
@@ -259,13 +259,13 @@ var eigenValueSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: 'Arial'
             },
             data: {
                 field: 'code',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 200
         },
@@ -276,19 +276,19 @@ var eigenValueSetting = {
                 spanRows: [2],
                 vAlign: [1, 1],
                 hAlign: [1, 1],
-                font: '16px Arial'
+                font: 'Arial'
             },
             data: {
                 field: 'value',
                 vAlign: 1,
                 hAlign: 0,
-                font: '14px Arial'
+                font: 'Arial'
             },
             width: 480
         },
     ],
-    headRows: 2,
-    headRowHeight: [20, 30, 30],
+    headRows: 1,
+    headRowHeight: [47],
     emptyRows: 3,
     treeCol: 0
 }

File diff suppressed because it is too large
+ 1154 - 181
web/maintain/bills_lib/scripts/db_controller.js


+ 18 - 6
web/maintain/bills_lib/scripts/set_sheets.js

@@ -9,8 +9,10 @@ var setSheet = {
         spread.options.showVerticalScrollbar =false;
         spread.options.tabStripVisible = false;
         spread.options.scrollbarMaxAlign = true;
+        spread.options.allowExtendPasteRange = true;
+        spread.options.allowCopyPasteExcelStyle = false;
         sheet.showRowOutline(false);
-        sheet.defaults.rowHeight = 30;
+       // sheet.defaults.rowHeight = 30;
         setting.cols.forEach(function(col, colIdx){
             sheet.getRange(-1,colIdx,-1,1, GC.Spread.Sheets.SheetArea.viewport).hAlign(GC.Spread.Sheets.HorizontalAlign.left);
             sheet.getRange(-1,colIdx,-1,1, GC.Spread.Sheets.SheetArea.viewport).vAlign(GC.Spread.Sheets.VerticalAlign.center);
@@ -24,8 +26,19 @@ var setSheet = {
         sheet.setStyle(-1, colIdx, style);
         sheet.options.isProtected = true;
     },
-    setMaxRowCount: function(sheet, rowCount){
+    setMaxRowCount: function(sheet, arr){
+        let arrL = arr.length;
+        let rowCount = arrL + 10;
+        /*if(arrL <10){
+            rowCount = 10;
+        }
+        else {
+            rowCount = arrL + 3;
+        }*/
         sheet.setRowCount(rowCount, GC.Spread.Sheets.SheetArea.viewport);
+    },
+    formatter: function(sheet){
+        sheet.setFormatter(-1, 0, "@", GC.Spread.Sheets.SheetArea.viewport);
     }
 }
 
@@ -103,7 +116,6 @@ var myKey = {
             spread.commandManager().register('myDelete', function(){
                 spread.suspendEvent();
                 var ids = tools.delIds(sheet);
-                console.log(ids);
                 tools.deleteELes(controller.tree.selected[classify], ids, function(result){
                     //deleteFrontData
                     tools.reshowData(sheet, controller.tree.selected[classify], setting, true);
@@ -152,7 +164,7 @@ var myKey = {
                         totalJobs.jobsArr.splice(totalJobs.jobsArr.indexOf(job), 1);
                     });
                     tools.reshowData(sheet, totalJobs.jobsArr, setting, true);
-                    jobsAjax.deleteJobContent(ids);
+                    jobsAjax.deleteJobContent(billsLibId, ids);
                     billsAjax.updateBillsArr(billsLibId, billsIds, ids, null, 'deleteAll', 'jobs');
                 }
                 spread.resumeEvent();
@@ -172,7 +184,7 @@ var myKey = {
                         totalItems.itemsArr.splice(totalItems.itemsArr.indexOf(item), 1);
                     });
                     tools.reshowData(sheet, totalItems.itemsArr, setting, true);
-                    itemsAjax.deleteItemCharacter(ids);
+                    itemsAjax.deleteItemCharacter(billsLibId, ids);
                     billsAjax.updateBillsArr(billsLibId, billsIds, ids, null, 'deleteAll', 'items');
                     //reshowVal
                     if(totalItems.itemsArr.length > 0){
@@ -205,7 +217,7 @@ var myKey = {
                 });
                 tools.reshowValue(sheet, valsArr, setting, true);
                 //deleteDb
-                itemsAjax.updateValue(selectedId, null, ids, 'delete');
+                itemsAjax.updateValue(billsLibId, selectedId, null, ids, 'delete');
                 spread.resumeEvent();
             });
             spread.commandManager().setShortcutKey(null, GC.Spread.Commands.Key.del, false, false, false, false);

+ 1 - 1
web/maintain/ration_repository/dinge.html

@@ -47,7 +47,7 @@
                       <div class="tab-bar">
                           <a onclick="zTreeOprObj.addRootNode()" class="btn btn-secondary btn-sm">增加根节点</a>
                       </div>
-                    <div class="tab-content">
+                    <div class="tab-content" style="width: 100%; height: 100%; overflow: auto">
                       <ul id="rationChapterTree" class="ztree"></ul>
                     </div>
                   </div>

+ 4 - 4
web/maintain/ration_repository/js/coe.js

@@ -38,7 +38,7 @@ var coeList = {
     ],
     colDefContent: [
         {name: "coeType", displayName: "类型", size: 100, hAlign: "center"},
-        {name: "gljID", displayName: "工料机ID", size: 100, hAlign: "center",formatter: "00000000"},
+        {name: "gljCode", displayName: "工料机编号", size: 100, dataType: "String", formatter: "@", hAlign: "center"},
         {name: "operator", displayName: "操作符", size: 60, hAlign: "center"},
         {name: "amount", displayName: "数量", size: 80, hAlign: "right"}
     ],
@@ -51,7 +51,7 @@ var coeList = {
         me.detailSpread = sheetObj.create($('#contentSpread')[0], me.colDefContent, me.datas[0].coes);
 
         var coeType = new GC.Spread.Sheets.CellTypes.ComboBox();
-        coeType.items(["单个","全部","人工类","材料类","机械类"]);
+        coeType.items(["单个","定额","人工","材料","机械"]);
         me.detailSpread.getSheet(0).getRange(-1, 0, -1, 1).cellType(coeType);
 
         var operType = new GC.Spread.Sheets.CellTypes.ComboBox();
@@ -139,7 +139,7 @@ var coeList = {
             obj.ID = me.tempID;
             if (obj.name == undefined){obj.name = '';};     // 生成属性,令属性存储顺序一致
             if (obj.content == undefined){obj.content = '';};
-            obj.coes = [{coeType:"全部", operator:"*", amount: "0"}];
+            obj.coes = [{coeType:"定额", operator:"*", amount: "0"}];
             me.datas[row] = obj;
 
             me.save([obj],[],[]);
@@ -178,7 +178,7 @@ var coeList = {
             var curType = curDetailData.coeType;
             if (curType !== '单个'){
                 me.detailSpread.suspendPaint();
-                curDetailData.gljID = null;
+                curDetailData.gljCode = null;
                 me.detailSpread.resumePaint();
             };
 

+ 1 - 1
web/maintain/ration_repository/js/ration_glj.js

@@ -10,7 +10,7 @@ var rationGLJOprObj = {
             {headerName:"编码",headerWidth:120,dataCode:"code", dataType: "String", formatter: "@"},
             {headerName:"名称",headerWidth:400,dataCode:"name", dataType: "String"},
             {headerName:"单位",headerWidth:160,dataCode:"unit", dataType: "String"},
-            {headerName:"单位基价",headerWidth:160, dataCode:"basePrice", dataType: "Number", precision: 2},
+            {headerName:"基价单位",headerWidth:160, dataCode:"basePrice", dataType: "Number", formatter:"0.00",  precision: 2},
             {headerName:"定额消耗",headerWidth:160, dataCode:"consumeAmt", dataType: "Number", precision: 3},
             {headerName:"类型",headerWidth:160,dataCode:"gljDistType", dataType: "String"}
         ],

+ 23 - 5
web/maintain/report/css/main.css

@@ -213,6 +213,7 @@ body {
     }
 }
 .bottom-content {
+    height: 370px;
     overflow: hidden;
 }
 .bottom-content .tab-content .main-data-bottom{
@@ -269,10 +270,27 @@ body {
     max-height: 200px;
     overflow:auto;
 }
-.main-data-bottom,.main-data{
-    overflow: auto;
+.main-data-top,.main-data-bottom,.main-data,.main-data-h{
+  overflow: auto;
 }
-.main-data-top{
-    max-height: 300px;
-    overflow:auto;
+.modal-fixed-height {
+    height:400px;
+    overflow-y:auto;
+}
+.form-view {
+    border-left:1px solid #ccc;
+}
+.ztree {
+  border-style:solid; 
+  border-width:1px; 
+  border-color:#000;
+}
+.ztree-warp {
+  height:200px;
+  overflow: auto;
+}
+.sub-button{
+  position:sticky;
+  bottom:0;
+  left:0
 }

web/maintain/templates/css/main.css → web/maintain/report/css/templates/css/main.css


+ 4 - 4
web/maintain/templates/html/bills.html

@@ -6,7 +6,7 @@
     <meta http-equiv="x-ua-compatible" content="ie=edge">
     <title>模板清单-Smartcost</title>
     <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
-    <link rel="stylesheet" href="/web/maintain/templates/css/main.css">
+    <link rel="stylesheet" href="/web/maintain/report/css/templates/css/main.css">
     <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
     <!--SpreadJs-->
     <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013lightGray.10.0.1.css" type="text/css">
@@ -87,7 +87,7 @@
 <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="/web/maintain/templates/js/global.js"></script>
+<script src="/web/maintain/report/css/templates/js/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>
@@ -97,8 +97,8 @@
 <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_controller.js"></script>
 <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_helper.js"></script>
 <!-- service -->
-<script type="text/javascript" src="/web/maintain/templates/js/bills.js"></script>
-<script type="text/javascript" src="/web/maintain/templates/js/tp_bills_setting.js"></script>
+<script type="text/javascript" src="/web/maintain/report/css/templates/js/bills.js"></script>
+<script type="text/javascript" src="/web/maintain/report/css/templates/js/tp_bills_setting.js"></script>
 <script type="text/javascript" src="/public/web/common_ajax.js"></script>
 <script>
     autoFlashHeight();

web/maintain/templates/js/bills.js → web/maintain/report/css/templates/js/bills.js


web/maintain/templates/js/global.js → web/maintain/report/css/templates/js/global.js


web/maintain/templates/js/tp_bills_setting.js → web/maintain/report/css/templates/js/tp_bills_setting.js


+ 121 - 0
web/maintain/report/js/cfg_const.js

@@ -36,3 +36,124 @@ let setting = {
         onRename: zTreeOprObj.onRename
     }
 };
+
+let common_rpt_type_ids = {
+    flow: 4,
+    bill: 6,
+    cross: 5
+};
+
+let bandSetting = {
+    view: {
+        showIcon: true,
+        expandSpeed: "",
+        selectedMulti: false
+    },
+    edit: {
+        enable: true,
+        editNameSelectAll: true,
+        showRemoveBtn: false,
+        showRenameBtn: true,
+        //removeTitle: "删除节点",
+        renameTitle: "更改名称"
+    },
+    data: {
+        keep: {
+            parent:true,
+            leaf:true
+        },
+        key: {
+            children: 'band_s',
+            name: "Name"
+        },
+        simpleData: {
+            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: false,
+        removeTitle: "删除",
+        renameTitle: "更改名称",
+        drag: {
+            isCopy: false,
+            isMove: true
+        }
+    },
+    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,
+        beforeDrop: fieldMapTreeOprObj.onBeforeDrop
+    }
+};
+
+let selectableFieldSetting = {
+    view: {
+        showIcon: true,
+        expandSpeed: "",
+        selectedMulti: false
+        //,addDiyDom: selectableFiledTreeOprObj.addDiyDom
+    },
+    edit: {
+        enable: true,
+        editNameSelectAll: false,
+        showRemoveBtn: false,
+        showRenameBtn: false,
+        removeTitle: "删除",
+        renameTitle: "更改名称",
+        drag: {
+            isCopy: true,
+            isMove: false
+        }
+    },
+    data: {
+        keep: {
+            parent:true,
+            leaf:true
+        },
+        key: {
+            children: 'items',
+            name: "Name"
+        },
+        simpleData: {
+            enable: true
+        }
+    },
+    callback:{
+        onClick: selectableFiledTreeOprObj.onClick,
+        beforeDrag: selectableFiledTreeOprObj.onBeforeDrag,
+        beforeDrop: selectableFiledTreeOprObj.onBeforeDrop
+    }
+};

+ 2 - 6
web/maintain/report/js/global.js

@@ -5,12 +5,8 @@ function autoFlashHeight(){
     var toolsBar = $(".tools-bar").height();
     $(".content").height($(window).height()-headerHeight);
     $(".main-side").height($(window).height()-headerHeight-2);
-    $(".fluid-content").height($(window).height()-headerHeight-1);
-    $(".side-content").height($(window).height()-headerHeight );
-    $(".poj-list").height($(window).height()-headerHeight);
-    $(".form-list").height($(window).height()-headerHeight-50 );
-    $(".main-data-top").height($(window).height()-headerHeight-toolsBar-bottomContentHeight-2);
-    $(".main-data").height($(window).height()-headerHeight);
+    $(".main-data").height($(window).height()-headerHeight-toolsBar-1);
+    $(".main-data-h").height($(window).height()-headerHeight-1);
 };
 $(window).resize(autoFlashHeight);
 /*全局自适应高度结束*/

+ 1 - 1
web/maintain/report/js/jpc_output.js

@@ -1,5 +1,5 @@
 /** Created by Tony on 2016/12/2. */
-JpcCanvasOutput = {
+let JpcCanvasOutput = {
     offsetX: 10,
     offsetY: 10,
     cleanCanvas: function (canvas) {

+ 1 - 1
web/maintain/report/js/jpc_output_value_define.js

@@ -2,7 +2,7 @@
  * Created by Tony on 2017/1/4.
  */
 
-var JV = {
+let JV = {
     NODE_MAIN_INFO: "主信息",
     NODE_PAGE_INFO: "打印页面_信息",
     NODE_MARGINS: "页边距",

+ 248 - 0
web/maintain/report/js/rpt_tpl_band.js

@@ -0,0 +1,248 @@
+'use strict'
+
+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[JV.BAND_PROP_SUB_BANDS]) {
+                for (let band of parentBand[JV.BAND_PROP_SUB_BANDS]) {
+                    band.ID = startIdx;
+                    band.ParentID = parentBand.ID;
+                    startIdx++;
+                    private_setBandId(band);
+                }
+            }
+        }
+        for (let band of bandList) {
+            band.ID = startIdx;
+            band.ParentID = -1;
+            startIdx++;
+            private_setBandId(band);
+        }
+
+        return rst;
+    },
+    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>");
+    },
+    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];
+        let posIdx = JV.LAYOUT.indexOf(node[JV.BAND_PROP_ALIGNMENT])
+        switch(posIdx) {
+            case 0:
+            case 1:
+                rst[JV.BAND_PROP_HEIGHT] = node[JV.BAND_PROP_HEIGHT];
+                break;
+            case 2:
+            case 3:
+                rst[JV.BAND_PROP_WIDTH] = node[JV.BAND_PROP_WIDTH];
+                break;
+        }
+        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_MERGE_BORDER] != undefined) {
+            rst[JV.BAND_PROP_MERGE_BORDER] = node[JV.BAND_PROP_MERGE_BORDER];
+        } else {
+            rst[JV.BAND_PROP_MERGE_BORDER] = 'F';
+        }
+        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';
+        rst[JV.BAND_PROP_MERGE_BORDER] = 'F';
+        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;
+        //高与宽
+        me.setupWidthHeightByPosition(posIdx);
+        //频率
+        $("#pageFrequency").get(0).selectedIndex = JV.PAGE_STATUS.indexOf(treeNode[JV.BAND_PROP_DISPLAY_TYPE])
+        //
+        me.canTrickEvent = true;
+    },
+    setupWidthHeightByPosition: function (posIdx) {
+        let me = this, treeNode = me.currentNode;
+        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;
+        }
+    },
+    bandStyleChange: function (dom) {
+        let me = this;
+        if (me.currentNode) {
+            me.currentNode[JV.PROP_STYLE] = me.reportCfg.borderArr[dom.selectedIndex];
+        }
+    },
+    bandAlignmentChange: function (dom) {
+        let me = this;
+        if (me.currentNode) {
+            let posIdx = dom.selectedIndex;
+            me.currentNode[JV.BAND_PROP_ALIGNMENT] = JV.LAYOUT[posIdx];
+            me.setupWidthHeightByPosition(posIdx);
+        }
+    },
+    bandHeightWidthChange: function (dom) {
+        let me = this, treeNode = me.currentNode;
+        if (me.currentNode) {
+            let posIdx = $("#bandAlignment").get(0).selectedIndex;
+            switch(posIdx) {
+                case 0:
+                case 1:
+                    treeNode[JV.BAND_PROP_HEIGHT] = dom.value;
+                    break;
+                case 2:
+                case 3:
+                    treeNode[JV.BAND_PROP_WIDTH] = dom.value;
+                    break;
+            }
+        }
+    },
+    bandShowFrequencyChange: function (dom) {
+        let me = this;
+        if (me.currentNode) {
+            me.currentNode[JV.BAND_PROP_DISPLAY_TYPE] = JV.PAGE_STATUS[dom.selectedIndex];
+        }
+    },
+    bandBorderMergeChange: function (dom) {
+        let me = this;
+        if (me.currentNode) {
+            me.currentNode[JV.BAND_PROP_MERGE_BORDER] = dom.checked?'T':'F';
+        }
+    },
+    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;
+        }
+    }
+
+};

+ 31 - 0
web/maintain/report/js/rpt_tpl_calculation.js

@@ -0,0 +1,31 @@
+/**
+ * Created by Tony on 2017/7/7.
+ */
+
+let calculationTreeOprObj = {
+    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) {
+    },
+    onClick: function () {
+        //
+    },
+    onBeforeRemove: function(treeId, treeNode){
+    },
+    beforeRename: function(treeId, treeNode, newName, isCancel) {
+    },
+    onRemove: function () {
+        //
+    },
+    onRename: function () {
+        //
+    },
+    extractCalculation: function (rptTpl) {
+        //
+    }
+}

+ 31 - 0
web/maintain/report/js/rpt_tpl_field_cfg.js

@@ -0,0 +1,31 @@
+/**
+ * Created by Tony on 2017/7/7.
+ */
+
+let tabFieldCfgTreeOprObj = {
+    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) {
+    },
+    onClick: function () {
+        //
+    },
+    onBeforeRemove: function(treeId, treeNode){
+    },
+    beforeRename: function(treeId, treeNode, newName, isCancel) {
+    },
+    onRemove: function () {
+        //
+    },
+    onRename: function () {
+        //
+    },
+    extractTabFields: function (rptTpl) {
+        //
+    }
+}

+ 167 - 0
web/maintain/report/js/rpt_tpl_field_map.js

@@ -0,0 +1,167 @@
+'use strict'
+
+let fieldMapTreeOprObj = {
+    treeObj : null,
+    currentNode: null,
+    dataTypeDef: ['string', 'int32', 'int64', 'double', 'currency', 'date', 'image'],
+    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 (event,treeId,treeNode) {
+        let me = fieldMapTreeOprObj;
+        me.currentNode = treeNode;
+        //then refresh the field map tab properties
+        //数据类型
+        switch (me.dataTypeDef.indexOf(treeNode[JV.PROP_DATA_TYPE])) {
+            case 0:
+                $("#fieldDataTypeSelection").get(0).selectedIndex = 0;
+                break;
+            case 1:
+            case 2:
+            case 3:
+            case 4:
+                $("#fieldDataTypeSelection").get(0).selectedIndex = 1;
+                break;
+            case 5:
+                $("#fieldDataTypeSelection").get(0).selectedIndex = 2;
+                break;
+            case 6:
+                $("#fieldDataTypeSelection").get(0).selectedIndex = 3;
+                break;
+            default:
+                $("#fieldDataTypeSelection").get(0).selectedIndex = 0;
+                break;
+        }
+        //映射指标
+    },
+    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;
+    },
+    onBeforeDrop: function(treeId, treeNodes, targetNode, moveType){
+        let rst = true;
+        if (treeId === 'selectable_field_tree_reversed' || targetNode.level === 0 || moveType === 'inner') {
+            rst = false;
+        } else {
+            //
+        }
+        return rst;
+    },
+    onRemove: function () {
+        //
+    },
+    onRename: function () {
+        //
+    },
+    extractFieldMaps: function (rptTpl) {
+        let me = this;
+        for (let rootNode of me.treeObj.getNodes()) {
+            rptTpl[JV.NODE_FIELD_MAP][rootNode.Name] = [];
+            for (let mappingFieldNode of rootNode.items) {
+                rptTpl[JV.NODE_FIELD_MAP][rootNode.Name].push(me.createMapFieldByNode(mappingFieldNode));
+            }
+        }
+    },
+    createMapFieldByNode: function (node) {
+        let rst = {};
+        rst[JV.PROP_ID] = node[JV.PROP_ID];
+        rst[JV.PROP_NAME] = node[JV.PROP_NAME];
+        rst[JV.PROP_DATA_TYPE] = node[JV.PROP_DATA_TYPE];
+        rst.mapExpression = node.mapExpression;
+        rst[JV.PROP_ID] = node[JV.PROP_ID];
+        return rst;
+    }
+};
+
+let selectableFiledTreeOprObj = {
+    treeObj : null,
+    currentNode: null,
+    iniTree: function() {
+        let me = this, params = {};
+        params.userId = userID;
+        CommonAjax.postEx("report_tpl_api/getMappingFields", params, 20000, true, function(result){
+                let showRst = [];
+                for (let item of result) {
+                    if (item.items.length > 0) {
+                        showRst.push(item);
+                    }
+                }
+                me.treeObj = $.fn.zTree.init($("#selectable_field_tree_reversed"), selectableFieldSetting, showRst);
+                me.treeObj.expandAll(true);
+                showRst = null;
+            }, null, null
+        );
+    },
+    onClick: function (event,treeId,treeNode) {
+        let me = fieldMapTreeOprObj;
+        me.currentNode = treeNode;
+    },
+    onBeforeDrag: function (treeId, treeNodes) {
+        let rst = true;
+        for (let node of treeNodes) {
+            if (node.level === 0) {
+                rst = false;
+                break;
+            }
+        }
+        return rst;
+    },
+    onBeforeDrop: function(treeId, treeNodes, targetNode, moveType){
+        let rst = true;
+        if (treeId === 'field_map_tree_reversed') {
+            if ( (targetNode.level === 0 && moveType !== 'inner') || (targetNode.level > 0 && moveType === 'inner')) {
+                rst = false;
+            }
+        } else {
+            rst = false;
+        }
+        return rst;
+    },
+    addDiyDom: function (treeId, treeNode) {
+        if (treeNode.level > 0) {
+            let aObj = $("#" + treeNode.tId + "_a");
+            if ($("#diyBtn_"+treeNode.ID).length>0) return;
+            let editStr = "<span>&nbsp(" + treeNode.DataType + ")</span>";
+            aObj.append(editStr);
+            let btn = $("#diyBtn_"+treeNode.ID);
+            if (btn) btn.bind("click", function(){alert("diy Button for " + treeNode.name);});
+        }
+    }
+}

+ 66 - 0
web/maintain/report/js/rpt_tpl_helper.js

@@ -36,6 +36,72 @@ let tplHelper = {
         if (zTreeOprObj.currentNode && zTreeOprObj.currentNode.nodeType == RT.NodeType.TEMPLATE) {
             //
         }
+    },
+
+    refreshTplView: function (rptTpl) {
+        if (rptTpl) {
+            //1. 模板信息
+            $("#rptTplName")[0].value = rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MAIN_INFO_RPT_NAME];
+            $("#rptTplPageSize")[0].selectedIndex = JV.PAGES_SIZE_STR.indexOf(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE]);
+            if (rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_ORIENTATION] === JV.ORIENTATION_PORTRAIT ||
+                rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_ORIENTATION] === JV.ORIENTATION_PORTRAIT_CHN) {
+                $("#rptTplPageOrientation")[0].selectedIndex = 1;
+            } else {
+                $("#rptTplPageOrientation")[0].selectedIndex = 0;
+            }
+            if (rptTpl[JV.NODE_FLOW_INFO]) {
+                $("#multiColCnt")[0].style.display = "";
+            } else {
+                $("#multiColCnt")[0].style.display = "none";
+            }
+            $("#rptTplMarginLeft")[0].value = rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_LEFT];
+            $("#rptTplMarginRight")[0].value = rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_RIGHT];
+            $("#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. 模板布局
+            bandTreeOprObj.iniTree(rptTpl);
+            //3. 指标映射
+            fieldMapTreeOprObj.iniTree(rptTpl);
+            //4. 指标摆放
+            //5. 计算式
+        }
+    },
+
+    saveRptTpl: function () {
+        let me = this, params = null;
+        if (me.reCombineRptTpl()) {
+            let rptTpl = zTreeOprObj.currentNode.rptTpl;
+            params = {};
+            params.rptTpl = JSON.stringify(rptTpl);
+            CommonAjax.postEx("report_tpl_api/updateRptTpl", params, 20000, true, function(result){
+                    if (result) {
+                        alert('update succeeded!')
+                    } else {
+                        alert('update failed!')
+                    }
+                }, null, null
+            );
+        }
+    },
+
+    reCombineRptTpl: function () {
+        let rst = true;
+        if (zTreeOprObj.currentNode && zTreeOprObj.currentNode.nodeType == RT.NodeType.TEMPLATE && zTreeOprObj.currentNode.rptTpl != null) {
+            let rptTpl = zTreeOprObj.currentNode.rptTpl;
+            //1. 模板信息
+            zTreeOprObj.extractMainInfo(rptTpl);
+            //2. 模板布局
+            bandTreeOprObj.extractBands(rptTpl);
+            //3. 指标映射
+            fieldMapTreeOprObj.extractFieldMaps(rptTpl);
+            //4. 指标摆放
+            tabFieldCfgTreeOprObj.extractTabFields(rptTpl);
+            //5. 计算式
+            calculationTreeOprObj.extractCalculation(rptTpl);
+        } else {
+            rst = false;
+        }
+        return rst;
     }
 
 }

+ 121 - 13
web/maintain/report/js/rpt_tpl_main.js

@@ -2,8 +2,10 @@
 
 let rptTplObj = {
     iniPage: function() {
-        let me = this
         zTreeOprObj.getReportTemplateTree(RT.GrpType.CONSTRUCT);
+        bandTreeOprObj.getReportTplCfg();
+        selectableFiledTreeOprObj.iniTree();
+        preview_util.drawBorder($("#tplCanvas")[0]);
     }
 }
 
@@ -16,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() {
@@ -41,6 +43,40 @@ let zTreeOprObj = {
         }
         me.treeObj.refresh();
     },
+    moveUpNode: function() {
+        let me = this, nodes = [];
+        if (me.currentNode && me.currentNode.getPreNode()) {
+            let preNode = me.currentNode.getPreNode(), pre_preNode = preNode.getPreNode();
+            me.treeObj.moveNode(preNode, me.currentNode, "prev", true);
+            //then update the db
+            if (pre_preNode) {
+                pre_preNode.NextSiblingID = me.currentNode.ID;
+                nodes.push(me.createNodeFromZTreeNode(pre_preNode));
+            }
+            preNode.NextSiblingID = me.currentNode.NextSiblingID;
+            me.currentNode.NextSiblingID = preNode.ID;
+            nodes.push(me.createNodeFromZTreeNode(me.currentNode));
+            nodes.push(me.createNodeFromZTreeNode(preNode));
+            me.updateNodes(nodes);
+        }
+    },
+    moveDownNode: function() {
+        let me = this, nodes = [];
+        if (me.currentNode && me.currentNode.getNextNode()) {
+            let preNode = me.currentNode.getPreNode(), nextNode = me.currentNode.getNextNode();
+            me.treeObj.moveNode(nextNode, me.currentNode, "next", true);
+            //then update the db
+            if (preNode) {
+                preNode.NextSiblingID = nextNode.ID;
+                nodes.push(me.createNodeFromZTreeNode(preNode));
+            }
+            me.currentNode.NextSiblingID = nextNode.NextSiblingID;
+            nextNode.NextSiblingID = me.currentNode.ID;
+            nodes.push(me.createNodeFromZTreeNode(me.currentNode));
+            nodes.push(me.createNodeFromZTreeNode(nextNode));
+            me.updateNodes(nodes);
+        }
+    },
     addRootNode: function() {
         let me = this, rawNode = me.createIniRootNode(), lastNodeId = -1, lastNode = null;
         if (me.treeObj) {
@@ -75,12 +111,12 @@ let zTreeOprObj = {
             }
             let params = {};
             params.nodes = nodes;
-            CommonAjax.postEx("report_tpl_api/updateTptTplNodes", params, 5000, true, null, null, null);
+            CommonAjax.postEx("report_tpl_api/updateRptTplNodes", params, 5000, true, null, null, null);
         }
     },
     addTplNode: function (){
         let me = this;
-        if (me.currentNode) {
+        if (me.currentNode && me.currentNode.nodeType === RT.NodeType.NODE) {
             let rawNode = me.createIniRootNode(), lastNodeId = -1, lastNode = null;
             rawNode.nodeType = RT.NodeType.TEMPLATE;
             rawNode.ParentID = me.currentNode.ID;
@@ -109,11 +145,11 @@ let zTreeOprObj = {
             }
         }
     },
-    addNewNode: function(rawNode, lastNodeId, callback, failcallback) {
+    addNewNode: function(rawNode, lastNodeId, callback, failCallback) {
         let params = {};
         params.lastNodeId = lastNodeId;
         params.rawNodeData = rawNode;
-        CommonAjax.postEx("report_tpl_api/createTplTreeNode", params, 5000, true, callback, failcallback, null);
+        CommonAjax.postEx("report_tpl_api/createTplTreeNode", params, 5000, true, callback, failCallback, null);
     },
     createIniRootNode: function() {
         let rst = {
@@ -208,7 +244,7 @@ let zTreeOprObj = {
         params.nodeIds = nodeIds;
         params.preNodeId = preNodeId;
         params.preNodeNextId = treeNode.NextSiblingID;
-        CommonAjax.postEx("report_tpl_api/deleteTptTplNodes", params, 5000, false, function(data){
+        CommonAjax.postEx("report_tpl_api/deleteRptTplNodes", params, 5000, false, function(data){
             canRemove = true;
         }, null, null);
         return canRemove;
@@ -231,18 +267,90 @@ let zTreeOprObj = {
         let me = zTreeOprObj, nodes = [];
         nodes.push(me.createNodeFromZTreeNode(treeNode));
         me.updateNodes(nodes);
+        if (treeNode.nodeType == RT.NodeType.TEMPLATE && treeNode.refId >= 0) {
+            if (treeNode.rptTpl != null) {
+                treeNode.rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MAIN_INFO_RPT_NAME] = treeNode.name;
+                $("#rptTplName")[0].value = treeNode.rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MAIN_INFO_RPT_NAME];
+            } else {
+                me.onClick(e, treeId, treeNode);
+            }
+        }
     },
     onClick: function(event,treeId,treeNode) {
         let me = zTreeOprObj;
+        me.currentNode = treeNode;
+        bandTreeOprObj.currentNode = null;
         if (treeNode.nodeType == RT.NodeType.NODE) {
-            me.currentNode = treeNode;
             $("#rpt_tpl_display_label")[0].innerText = "...";
         } else if (treeNode.nodeType == RT.NodeType.TEMPLATE) {
-            me.currentNode = null;
-            $("#rpt_tpl_display_label")[0].innerText = treeNode.name;
+            let showText = treeNode.name, parentNode = treeNode.getParentNode();
+            while (parentNode !== null) {
+                showText = parentNode.name + ' > ' + showText;
+                parentNode = parentNode.getParentNode();
+            }
+            $("#rpt_tpl_display_label")[0].innerText = showText;
             if (treeNode.refId < 0) {
                 //创建新报表模板
+                $('#rptTypeSelectionModal').modal('show');
+            } else {
+                //显示报表模板
+                me.chkAndRreshRefTpl();
             }
         }
+    },
+    createNewTpl: function () {
+        let me = zTreeOprObj, params = {};
+        if (me.currentNode && me.currentNode.nodeType == RT.NodeType.TEMPLATE) {
+            params.treeNodeId = me.currentNode.ID;
+            let rptTypeId = common_rpt_type_ids.flow;
+            if ($("#crossTypeOpt")[0].checked) rptTypeId = common_rpt_type_ids.cross;
+            if ($("#billTypeOpt")[0].checked) rptTypeId = common_rpt_type_ids.bill;
+            params.rptDftTplId = rptTypeId
+            CommonAjax.postEx("report_tpl_api/createDftRptTpl", params, 20000, true, function(result){
+                    me.currentNode.rptTpl = result;
+                }, null, null
+            );
+        }
+    },
+    chkAndRreshRefTpl: function() {
+        let me = zTreeOprObj, params = {};
+        if (me.currentNode && me.currentNode.nodeType == RT.NodeType.TEMPLATE && me.currentNode.refId > 0) {
+            if (!(me.currentNode.rptTpl)) {
+                params.rptTplId = me.currentNode.refId;
+                CommonAjax.postEx("report_tpl_api/getRefRptTpl", params, 20000, true, function(result){
+                        me.currentNode.rptTpl = result;
+                        me.currentNode.rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MAIN_INFO_RPT_NAME] = me.currentNode.name;
+                        tplHelper.refreshTplView(me.currentNode.rptTpl);
+                    }, null, null
+                );
+            } else {
+                me.currentNode.rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MAIN_INFO_RPT_NAME] = me.currentNode.name;
+                tplHelper.refreshTplView(me.currentNode.rptTpl);
+            }
+        }
+    },
+    getRefTpl: function() {
+        let me = zTreeOprObj, rst = null;
+        if (me.currentNode && me.currentNode.nodeType == RT.NodeType.TEMPLATE && me.currentNode.refId > 0) {
+            rst = me.currentNode.rptTpl
+        }
+        return rst;
+    },
+    extractMainInfo: function (rptTpl) {
+        //模板信息
+        rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MAIN_INFO_RPT_NAME] = $("#rptTplName")[0].value;
+        rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = JV.PAGES_SIZE_STR[$("#rptTplPageSize")[0].selectedIndex];
+        if ($("#rptTplPageOrientation")[0].selectedIndex == 1) {
+            rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_ORIENTATION] = JV.ORIENTATION_PORTRAIT;
+        } else {
+            rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_ORIENTATION] = JV.ORIENTATION_LANDSCAPE;
+        }
+        if (rptTpl[JV.NODE_FLOW_INFO]) {
+            rptTpl[JV.NODE_FLOW_INFO][JV.PROP_MULTI_COLUMN] = parseInt($("#rptTplMultiCols")[0].value);
+        }
+        rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_LEFT] = $("#rptTplMarginLeft")[0].value;
+        rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_RIGHT] = $("#rptTplMarginRight")[0].value;
+        rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_TOP] = $("#rptTplMarginTop")[0].value;
+        rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_BOTTOM] = $("#rptTplMarginBottom")[0].value;
     }
-}
+};

+ 167 - 0
web/maintain/report/js/rpt_tpl_preview_util.js

@@ -0,0 +1,167 @@
+/**
+ * Created by Tony on 2017/7/3.
+ * 报表模板预览工具类
+ */
+
+let preview_util = {
+    offsetX: 0,
+    offsetY: 0,
+    clearCanvas: function (canvas) {
+        if (canvas) {
+            let ctx = canvas.getContext("2d");
+            ctx.save();
+            ctx.fillStyle="white";
+            ctx.clearRect(0,0, canvas.width, canvas.height);
+            ctx.restore();
+        }
+    },
+    drawBorder: function (canvas) {
+        let me = this;
+        if (canvas) {
+            let size = [];
+            size[0] = canvas.width - 1;
+            size[1] = canvas.height - 1;
+            let ctx = canvas.getContext("2d");
+            ctx.save();
+            ctx.beginPath();
+            ctx.translate(0.5,0.5);
+            ctx.lineWidth = 1;
+            ctx.moveTo(me.offsetX, me.offsetY);
+            ctx.lineTo(size[0] + me.offsetX, me.offsetY);
+            ctx.lineTo(size[0] + me.offsetX, size[1] + me.offsetY);
+            ctx.lineTo(me.offsetX, size[1] + me.offsetY);
+            ctx.lineTo(me.offsetX, me.offsetY);
+            ctx.stroke();
+            ctx.restore();
+            ctx.fillStyle="black";
+            ctx.fillRect(size[0] + me.offsetX,10 + me.offsetY,10,size[1]);
+            ctx.fillRect(10 + me.offsetX,size[1] + me.offsetY,size[0],10);
+        }
+    },
+    preview: function(canvas, rptTpl) {
+        let me = this, resolution= [96,96], size = null, shrinkFactor = 1;
+
+        if (!(rptTpl)) return;
+
+        me.clearCanvas(canvas);
+
+        let ctx = canvas.getContext("2d");
+        let pageSize = rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE];
+        let sizeIdx = JV.PAGES_SIZE_STR.indexOf(pageSize);
+        if (sizeIdx >= 0) {
+            size = JV.PAGES_SIZE[sizeIdx].concat([]);
+        } else {
+            size = JV.PAGES_SIZE[0].concat([]);
+        }
+        if (rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_ORIENTATION] === JV.ORIENTATION_LANDSCAPE || rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_ORIENTATION] === JV.ORIENTATION_LANDSCAPE_CHN) {
+            let ts = size[0];
+            size[0] = size[1];
+            size[1] = ts;
+        }
+        if (size[0] > size[1]) {
+            shrinkFactor = 1.0 * canvas.width / (size[0] * resolution[0]);
+        } else {
+            shrinkFactor = 1.0 * canvas.height / (size[1] * resolution[1]);
+        }
+
+        let private_translateUnit = function(unitStr) {
+            let me = this, rst = 1.0;
+            if (unitStr) {
+                if (JV.MEASUREMENT.PIXEL.indexOf(unitStr) >= 0) {
+                    rst = 1.0;
+                } else if (JV.MEASUREMENT.CM.indexOf(unitStr) >= 0) {
+                    rst = 1.0 * resolution[0] / 2.54;
+                } else if (JV.MEASUREMENT.INCH.indexOf(unitStr) >= 0) {
+                    rst = 1.0 * resolution[0];
+                }
+            }
+            return rst;
+        };
+
+        let private_getReportArea = function(rptTpl, unitFactor) {
+            let rst = [];
+            rst.push(unitFactor * rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_LEFT]);
+            rst.push(unitFactor * rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_TOP]);
+            rst.push(size[0] * resolution[0] - unitFactor * rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_RIGHT]);
+            rst.push(size[1] * resolution[0] - unitFactor * rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_BOTTOM]);
+            return rst;
+        };
+
+        let private_setupBandArea = function(band, parentArea) {
+            let rstArea = [].concat(parentArea);
+            switch (JV.LAYOUT.indexOf(band[JV.BAND_PROP_ALIGNMENT])) {
+                case JV.LAYOUT_TOP:
+                    if (band[JV.PROP_CALCULATION] == JV.CAL_TYPE_ABSTRACT) {
+                        rstArea[JV.IDX_BOTTOM] = rstArea[JV.IDX_TOP] + unitFactor * parseFloat(band[JV.BAND_PROP_HEIGHT]);
+                    } else {
+                        rstArea[JV.IDX_BOTTOM] = rstArea[JV.IDX_TOP] + (rstArea[JV.IDX_BOTTOM] - rstArea[JV.IDX_TOP]) * parseFloat(band[JV.BAND_PROP_HEIGHT]) / 100;
+                    }
+                    parentArea[JV.IDX_TOP] = rstArea[JV.IDX_BOTTOM];
+                    break;
+                case JV.LAYOUT_BOTTOM:
+                    if (band[JV.PROP_CALCULATION] == JV.CAL_TYPE_ABSTRACT) {
+                        rstArea[JV.IDX_TOP] = rstArea[JV.IDX_BOTTOM] - unitFactor * parseFloat(band[JV.BAND_PROP_HEIGHT]);
+                    } else {
+                        rstArea[JV.IDX_TOP] = rstArea[JV.IDX_BOTTOM] - (rstArea[JV.IDX_BOTTOM] - rstArea[JV.IDX_TOP]) * parseFloat(band[JV.BAND_PROP_HEIGHT]) / 100;
+                    }
+                    parentArea[JV.IDX_BOTTOM] = rstArea[JV.IDX_TOP];
+                    break;
+                case JV.LAYOUT_LEFT:
+                    if (band[JV.PROP_CALCULATION] == JV.CAL_TYPE_ABSTRACT) {
+                        rstArea[JV.IDX_RIGHT] = rstArea[JV.IDX_LEFT] + unitFactor * parseFloat(band[JV.BAND_PROP_WIDTH]);
+                    } else {
+                        rstArea[JV.IDX_RIGHT] = rstArea[JV.IDX_LEFT] + (rstArea[JV.IDX_RIGHT] - rstArea[JV.IDX_LEFT]) * parseFloat(band[JV.BAND_PROP_WIDTH]) / 100;
+                    }
+                    parentArea[JV.IDX_LEFT] = rstArea[JV.IDX_RIGHT];
+                    break;
+                case JV.LAYOUT_RIGHT:
+                    if (band[JV.PROP_CALCULATION] == JV.CAL_TYPE_ABSTRACT) {
+                        rstArea[JV.IDX_LEFT] = rstArea[JV.IDX_RIGHT] - unitFactor * parseFloat(band[JV.BAND_PROP_WIDTH]);
+                    } else {
+                        rstArea[JV.IDX_LEFT] = rstArea[JV.IDX_RIGHT] - (rstArea[JV.IDX_RIGHT] - rstArea[JV.IDX_LEFT]) * parseFloat(band[JV.BAND_PROP_WIDTH]) / 100;
+                    }
+                    parentArea[JV.IDX_RIGHT] = rstArea[JV.IDX_LEFT];
+                    break;
+            }
+            return rstArea;
+        };
+        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;
+            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);
+            ctx.lineTo((me.offsetX + myArea[JV.IDX_LEFT]) * shrinkFactor, (me.offsetY + myArea[JV.IDX_BOTTOM]) * shrinkFactor);
+            ctx.lineTo((me.offsetX + myArea[JV.IDX_LEFT]) * shrinkFactor, (me.offsetY + myArea[JV.IDX_TOP]) * shrinkFactor);
+            ctx.stroke();
+            ctx.restore();
+            //2. then draw sub bands border if have.
+            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, false, false);
+                }
+            }
+        };
+        let unitFactor = private_translateUnit(rptTpl[JV.NODE_MAIN_INFO][JV.PROP_UNITS]),
+            orgArea = private_getReportArea(rptTpl, unitFactor);
+        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);
+            //bandTreeOprObj.reportCfg.styles
+            private_showBand(band, area, false, false);
+        }
+        if (bandTreeOprObj.currentNode) {
+            //need to high-light the band?
+        }
+    }
+}

+ 26 - 32
web/maintain/report/rpt_test.html

@@ -17,9 +17,9 @@
             <td width="5"></td>
             <td>
                 <select name="select1" id="select_k1" onchange="ajaxCall()">
-                    <option value="SC;07_1">07-1表</option>
-                    <option value="SC;08_2">08-2表</option>
-                    <option value="MEASURE;M_ZB03_QDZF_09">计量-清单支付09表</option>
+                    <option value="2">07-1表</option>
+                    <option value="1">08-2表</option>
+                    <option value="3">计量-清单支付09表</option>
                 </select>
                 <select name="select2" id="select_k2" onchange="ajaxCall()">
                     <option value="A4">A4</option>
@@ -48,14 +48,12 @@
     }
 </style>
 <script>
-    var currentPage = 1;
-    var pageRst = null;
-    var currentRptTpl = null;
-    var maxPages = 20;
-    var defProperties = null;
-    var rpt_grp = null;
-    var rpt_id = null;
-    var rpt_size = null;
+    let currentPage = 1;
+    let pageRst = null;
+    let currentRptTpl = null;
+    let maxPages = 20;
+    let rpt_id = null;
+    let rpt_size = null;
 
     function printCurrentPage() {
         if (currentRptTpl) {
@@ -67,12 +65,12 @@
     }
 
     function getScreenDPI() {
-        var me = this, arrDPI = [];
+        let me = this, arrDPI = [];
         if (window.screen.deviceXDPI != undefined) {
             arrDPI.push(window.screen.deviceXDPI);
             arrDPI.push(window.screen.deviceYDPI);
         } else {
-            var tmpNode = document.createElement("DIV");
+            let tmpNode = document.createElement("DIV");
             tmpNode.style.cssText = "width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden";
             document.body.appendChild(tmpNode);
             arrDPI.push(parseInt(tmpNode.offsetWidth));
@@ -83,13 +81,11 @@
     }
 
     function setupReport() {
-        var rst = false;
-        var rpt = document.getElementById("select_k1");
-        var size = document.getElementById("select_k2");
+        let rst = false;
+        let rpt = document.getElementById("select_k1");
+        let size = document.getElementById("select_k2");
         if (rpt.selectedIndex >= 0 && size.selectedIndex >= 0) {
-            var strs = rpt.options[rpt.selectedIndex].value.split(';');
-            rpt_grp = strs[0];
-            rpt_id = strs[1];
+            rpt_id = rpt.options[rpt.selectedIndex].value;
             rpt_size = size.options[size.selectedIndex].value;
             rst = true;
         }
@@ -99,7 +95,7 @@
     function showPage(pageStep, cv) {
         if (currentPage + pageStep >= 1 && currentPage + pageStep <= maxPages) {
             currentPage = currentPage + pageStep;
-            var canvas = null;
+            let canvas = null;
             if (cv) {
                 canvas = cv;
             } else canvas = document.getElementById("myCanvas");
@@ -110,34 +106,32 @@
     }
 
     function getDummyExcel() {
-        var id = "dummy_request_id";
-        var p1 = "dummy_paramm_2";
-        var url =  "/report_api/getDummyExcel/" + id + "/" + p1;
+        let id = "dummy_request_id";
+        let p1 = "dummy_paramm_2";
+        let url =  "/report_api/getDummyExcel/" + id + "/" + p1;
         window.location = url;//这里不能使用get方法跳转,否则下载不成功
     }
 
     function getExcel() {
-        var rpt = document.getElementById("select_k1");
-        var size = document.getElementById("select_k2");
-        var rpt_name = rpt.options[rpt.selectedIndex].text;
+        let rpt = document.getElementById("select_k1");
+        let size = document.getElementById("select_k2");
+        let rpt_name = rpt.options[rpt.selectedIndex].text;
         if (rpt.selectedIndex >= 0 && size.selectedIndex >= 0) {
-            var strs = rpt.options[rpt.selectedIndex].value.split(';');
-            rpt_grp = strs[0];
-            rpt_id = strs[1];
+            rpt_id = rpt.options[rpt.selectedIndex].value;
             rpt_size = size.options[size.selectedIndex].value;
         }
-        var url =  "/report_api/getExcel/" + rpt_grp + "/" + rpt_id + "/" + rpt_size + "/" + rpt_name;
+        let url =  "/report_api/getExcel/" + rpt_id + "/" + rpt_size + "/" + rpt_name;
         window.location = url;//这里不能使用get方法跳转,否则下载不成功
     }
 
     function ajaxCall() {
         if (setupReport()) {
-            var canvas = document.getElementById("myCanvas");
+            let canvas = document.getElementById("myCanvas");
             canvas.style.cursor = "wait";
             $.ajax({
                 type:"POST",
                 url: 'report_api/getReport',
-                data: {"grp_id": rpt_grp, "tpl_id": rpt_id, "pageSize": rpt_size},
+                data: {"ID": rpt_id, "pageSize": rpt_size},
                 dataType: 'json',
                 cache: false,
                 timeout: 15000,

+ 307 - 100
web/maintain/report/rpt_tpl_main.html

@@ -20,124 +20,331 @@
 </head>
 
 <body>
-<div class="header">
-    <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 ">
-        <span class="header-logo px-2">Smartcost</span>
-        <div class="navbar-text"><a>报表模板库</a> > <a id="rpt_tpl_display_label">...</a></div>
-    </nav>
-    <nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0">
-        <ul class="nav nav-tabs" role="tablist">
-            <li class="nav-item">
-                <a class="nav-link px-3" href="#"><i class="fa fa-sign-out fa-flip-horizontal" aria-hidden="true"></i></a>
-            </li>
-            <li class="nav-item">
-                <a class="nav-link px-3" href="#"><i class="fa fa-sign-out" aria-hidden="true"></i></a>
-            </li>
-            <li class="nav-item">
-                <a class="nav-link active px-3" href="#">系统模板</a>
-            </li>
-        </ul>
-    </nav>
-</div>
-<div class="main">
-    <div class="content">
-        <div class="container-fluid">
-            <div class="row">
-                <div class="main-side col-lg-2 p-0">
-                    <div class="tab-bar">
-                        <a onclick="zTreeOprObj.addRootNode()" class="btn btn-secondary btn-sm">增加根节点</a>
-                        <a onclick="zTreeOprObj.addTplNode()" class="btn btn-secondary btn-sm">增加模板节点</a>
-                    </div>
-                    <div class="tab-content">
-                        <ul id="rptTplTree" class="ztree"></ul>
+    <div class="header">
+        <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 ">
+            <span class="header-logo px-2">Smartcost</span>
+            <div class="navbar-text"><a>报表模板库</a> > <a id="rpt_tpl_display_label">...</a></div>
+        </nav>
+        <nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0">
+            <ul class="nav nav-tabs" role="tablist">
+                <li class="nav-item">
+                    <a class="nav-link px-3" href="#"><i class="fa fa-sign-out fa-flip-horizontal" aria-hidden="true"></i></a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link px-3" href="#"><i class="fa fa-sign-out" aria-hidden="true"></i></a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link active px-3" href="#">系统模板</a>
+                </li>
+            </ul>
+        </nav>
+    </div>
+    <div class="main">
+        <div class="content">
+            <div class="container-fluid">
+                <div class="row">
+                    <div class="main-side col-lg-3 p-0">
+                        <div class="tab-bar">
+                            <a onclick="zTreeOprObj.addRootNode()" class="btn btn-secondary btn-sm fa fa-plus-square">根节点</a>
+                            <a onclick="zTreeOprObj.addTplNode()" class="btn btn-secondary btn-sm fa fa-plus-square">模板节点</a>
+                            <a onclick="zTreeOprObj.moveDownNode()" class="btn btn-sm" id="downMove"><i class="fa fa-arrow-down" aria-hidden="true"></i>下移</a>
+                            <a onclick="zTreeOprObj.moveUpNode()" class="btn btn-sm" id="upMove"><i class="fa fa-arrow-up" aria-hidden="true"></i>上移</a>
+                        </div>
+                        <div class="tab-content">
+                            <ul id="rptTplTree" class="ztree"></ul>
+                        </div>
                     </div>
-                </div>
-                <div class="main-content col-lg-10 p-0">
-                    <div class="container-fluid">
-                        <div class="row">
-                            <div class="main-side col-lg-5 p-0">
-                                <div class="main-data-top">
-                                    <!-- 右标签 -->
-                                    <ul class="nav nav-tabs tools-bar" role="tablist">
-                                        <li class="nav-item">
-                                            <a class="nav-link active" data-toggle="tab" href="#rpttplinfo" role="tab">模板信息</a>
-                                        </li>
-                                        <li class="nav-item">
-                                            <a class="nav-link" data-toggle="tab" href="#rpttpllayout" role="tab">模板布局</a>
-                                        </li>
-                                        <li class="nav-item">
-                                            <a class="nav-link" data-toggle="tab" href="#rpttplfieldmap" role="tab">指标映射</a>
-                                        </li>
-                                        <li class="nav-item">
-                                            <a class="nav-link" data-toggle="tab" href="#rpttplformula" role="tab">计算式</a>
-                                        </li>
-                                    </ul>
-                                    <div class="tab-content">
-                                        <div class="tab-pane active" id="rpttplinfo" role="tabpanel">
-                                            <div class="container-fluid">
-                                                <label class="form-check-label"><input class="form-check-input" name="optionsRadios" value="option1" checked="" type="radio"> 流水式表</label>
-                                                <label class="form-check-label"><input class="form-check-input" name="optionsRadios" value="option1" type="radio"> 账单式表</label>
-                                                <label class="form-check-label"><input class="form-check-input" name="optionsRadios" value="option1" type="radio"> 交叉表</label>
-                                                <label class="form-check-label">  </label>
-                                                <a onclick="alert('You are going to confirm the report template type!')" class="btn btn-secondary btn-sm">确认</a>
+                    <div class="main-content col-lg-9 p-0">
+                        <div class="container-fluid">
+                            <div class="row">
+                                <!-- 报表设置 -->
+                                <div class="col-lg-4 p-0">
+                                    <div class="main-data-top">
+                                        <ul class="nav nav-tabs tools-bar" role="tablist">
+                                            <li class="nav-item">
+                                                <a class="nav-link p-1 active" data-toggle="tab" href="#rpttplinfo" role="tab">模板信息</a>
+                                            </li>
+                                            <li class="nav-item">
+                                                <a class="nav-link p-1" data-toggle="tab" href="#rpttpllayout" role="tab">模板布局</a>
+                                            </li>
+                                            <li class="nav-item">
+                                                <a class="nav-link p-1" data-toggle="tab" href="#rpttplfieldmap" role="tab">指标映射</a>
+                                            </li>
+                                            <li class="nav-item">
+                                                <a class="nav-link p-1" data-toggle="tab" href="#rpttplfieldlocation" role="tab">指标摆放</a>
+                                            </li>
+                                            <li class="nav-item">
+                                                <a class="nav-link p-1" data-toggle="tab" href="#rpttplformula" role="tab">计算式</a>
+                                            </li>
+                                        </ul>
+                                        <div class="tab-content">
+                                            <!--模板信息-->
+                                            <div class="tab-pane active" id="rpttplinfo" role="tabpanel">
+                                                <div class="main-data">
+                                                    <div class="p-3">
+                                                        <div class="form-group">
+                                                            <label>报表名称</label>
+                                                            <input class="form-control" id="rptTplName" value="" disabled>
+                                                        </div>
+                                                        <div class="form-group">
+                                                            <label>页面</label>
+                                                            <div class="row">
+                                                                <div class="input-group col-6">
+                                                                    <div class="input-group-addon">纸张</div>
+                                                                    <select class="form-control input-sm" id="rptTplPageSize"><option>A3</option><option>A4</option></select>
+                                                                </div>
+                                                                <div class="input-group col-6">
+                                                                    <div class="input-group-addon">方向</div>
+                                                                    <select class="form-control input-sm" id="rptTplPageOrientation"><option>横向</option><option>竖向</option></select>
+                                                                </div>
+                                                            </div>
+                                                        </div>
+                                                        <div class="form-group row">
+                                                            <div class="input-group col-6">
+                                                                <div class="input-group-addon">单位</div>
+                                                                <select class="form-control input-sm" id="rptTplUnit"><option>厘米</option></select>
+                                                            </div>
+                                                        </div>
+                                                        <div class="form-group" id="multiColCnt">
+                                                            <label>显示调整</label>
+                                                            <div class="row">
+                                                                <div class="input-group col-6">
+                                                                    <div class="input-group-addon">分栏</div>
+                                                                    <select class="form-control input-sm" id="rptTplMultiCols"><option>1</option><option>2</option></select>
+                                                                </div>
+                                                                <div class="input-group col-6" style="display: none">
+                                                                    <div class="input-group-addon">缩放</div>
+                                                                    <input class="form-control input-sm" type="number" value="1" step="0.25">
+                                                                </div>
+                                                            </div>
+                                                        </div>
+                                                        <div class="form-group row" style="display: none">
+                                                            <div class="input-group col-6">
+                                                                <div class="input-group-addon">空行提上</div>
+                                                                <select class="form-control input-sm"><option>提上</option></select>
+                                                            </div>
+                                                            <div class="input-group col-6">
+                                                                <div class="input-group-addon">空行显示</div>
+                                                                <select class="form-control input-sm"><option>显示</option></select>
+                                                            </div>
+                                                        </div>
+                                                        <div class="form-group">
+                                                            <label>页边距</label>
+                                                            <div class="row">
+                                                                <div class="input-group col-6">
+                                                                    <div class="input-group-addon">左</div>
+                                                                    <input class="form-control input-sm" id="rptTplMarginLeft" type="number" value="0.8" step="0.1" min="0">
+                                                                </div>
+                                                                <div class="input-group col-6">
+                                                                    <div class="input-group-addon">右</div>
+                                                                    <input class="form-control input-sm" id="rptTplMarginRight" type="number" value="0.8" step="0.1" min="0">
+                                                                </div>
+                                                            </div>
+                                                        </div>
+                                                        <div class="form-group row">
+                                                            <div class="input-group col-6">
+                                                                <div class="input-group-addon">上</div>
+                                                                <input class="form-control input-sm" id="rptTplMarginTop" type="number" value="0.8" step="0.1" min="0">
+                                                            </div>
+                                                            <div class="input-group col-6">
+                                                                <div class="input-group-addon">下</div>
+                                                                <input class="form-control input-sm" id="rptTplMarginBottom" type="number" value="0.8" step="0.1" min="0">
+                                                            </div>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <!--模板布局-->
+                                            <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">
+                                                            <label>边框样式</label>
+                                                            <select class="form-control" id="borderStyles" onchange="bandTreeOprObj.bandStyleChange(this)"></select>
+                                                        </div>
+                                                        <div class="form-group">
+                                                            <label>位置</label>
+                                                            <select class="form-control" id="bandAlignment" onchange="bandTreeOprObj.bandAlignmentChange(this)"></select>
+                                                        </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 onchange="bandTreeOprObj.bandHeightWidthChange(this)">
+                                                            </div>
+                                                            <div class="form-group col-md-6">
+                                                                <label>宽度</label>
+                                                                <input class="form-control mr-2" id="bandWidth"  type="number" step="0.1" disabled onchange="bandTreeOprObj.bandHeightWidthChange(this)">
+                                                            </div>
+                                                        </div>
+
+                                                        <div class="form-group">
+                                                            <label>出现频率</label>
+                                                            <select class="form-control" id="pageFrequency" onchange="bandTreeOprObj.bandShowFrequencyChange(this)"></select>
+                                                        </div>
+                                                        <div class="form-group">
+                                                            <div class="form-check">
+                                                                <label class="form-check-label">
+                                                                    <input type="checkbox" class="form-check-input" id="mergeBandBorder" onchange="bandTreeOprObj.bandBorderMergeChange(this)">
+                                                                    边框合并
+                                                                </label>
+                                                            </div>
+                                                        </div>
+                                                    </div>
+                                                </div>
                                             </div>
-                                            <div class="container-fluid">
-                                                <div class="input-group">
-                                                    <div class="row">
-                                                        <div class="input-group-addon">报表名称</div>
-                                                        <input type="text" class="form-control" placeholder="报表名称">
+                                            <!--指标映射-->
+                                            <div class="tab-pane" id="rpttplfieldmap" role="tabpanel">
+                                                <div class="main-data">
+                                                    <div class="p-3">
+                                                        <label>报表映射指标</label>
+                                                        <div class="tab-content">
+                                                            <ul id="field_map_tree_reversed" class="ztree"></ul>
+                                                        </div>
+                                                        <p/>
+                                                        <div class="tab-content">
+                                                            <label>可映射指标</label>
+                                                            <div class="tab-content">
+                                                                <ul id="selectable_field_tree_reversed" class="ztree"></ul>
+                                                            </div>
+                                                        </div>
                                                     </div>
                                                 </div>
-                                                <div class="input-group">
-                                                    <div class="row">
-                                                        <div class="input-group-addon">度量单位</div>
-                                                        <select class="form-control input-sm">
-                                                            <option>厘米</option>
-                                                            <option>英寸</option>
-                                                            <option>像素</option>
-                                                        </select>
+                                            </div>
+                                            <!--指标摆放-->
+                                            <div class="tab-pane" id="rpttplfieldlocation" role="tabpanel">
+                                                <div class="main-data">
+                                                    <div class="p-3">
+                                                        <div class="ztree-warp">
+                                                            ztree 保留空间
+                                                        </div>
+                                                        <div class="form-group">
+                                                            <label>所属Band</label>
+                                                            <select class="form-control"><option> </option></select>
+                                                        </div>
+                                                        <div class="form-group">
+                                                            <label>显示行高度</label>
+                                                            <select class="form-control"><option> </option></select>
+                                                            <small class="form-text text-muted">用于 流水行/交叉行</small>
+                                                        </div>
+                                                        <div class="form-group">
+                                                            <label>显示列宽度</label>
+                                                            <select class="form-control"><option> </option></select>
+                                                            <small class="form-text text-muted">用于 交叉列</small>
+                                                        </div>
+                                                        <div class="ztree-warp">
+                                                            ztree 保留空间
+                                                        </div>
+                                                        <div class="form-group">
+                                                            <label>映射指标</label>
+                                                            <select class="form-control"><option> </option></select>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                            <!--计算式-->
+                                            <div class="tab-pane" id="rpttplformula" role="tabpanel">
+                                                <div class="main-data">
+                                                    <div class="p-3">
+                                                        计算式
                                                     </div>
                                                 </div>
                                             </div>
                                         </div>
                                     </div>
                                 </div>
-                            </div>
-                            <div class="main-content col-lg-6 p-0">
-                                <div class="bottom-content">
-                                    <!--
-                                    -->
-                                    <h5>报表预览</h5>
-                                    <canvas id="preview_cvs"></canvas>
+                                <!-- 报表预览 -->
+                                <div class="form-view col-lg-8 p-0">
+                                    <div class="main-data-h" style="position:relative">
+                                        <div class="sub-button p-2">
+                                            <button class="btn btn-primary" onclick="preview_util.preview($('#tplCanvas')[0], zTreeOprObj.getRefTpl()) ">预览</button>
+                                            <button class="btn btn-primary" onclick="tplHelper.saveRptTpl()">保存</button>
+                                            <button class="btn btn-secondary">保存并发布</button>
+                                            <button class="btn btn-danger">删除模板</button>
+                                        </div>
+                                        <div class="main-data">
+                                            <canvas id="tplCanvas" height="820" width="920"></canvas>
+                                        </div>
+                                    </div>
                                 </div>
                             </div>
                         </div>
                     </div>
-
                 </div>
             </div>
         </div>
     </div>
-</div>
-<!-- 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="/web/maintain/report/js/global.js"></script>
-<script src="/web/maintain/report/js/rpt_tpl_main.js"></script>
-<script src="/web/maintain/report/js/rpt_tpl_helper.js"></script>
-<script src="/web/maintain/report/js/cfg_const.js"></script>
-<!-- zTree -->
-<script type="text/javascript" src="/public/web/date_util.js"></script>
-<script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
-<script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>
-<script type="text/javascript" src="/lib/ztree/jquery.ztree.exedit.js"></script>
-<script type="text/javascript" src="/public/web/storageUtil.js"></script>
-<script type="text/javascript" src="/public/web/rpt_tpl_def.js"></script>
-<script type="text/javascript" src="/public/web/common_ajax.js"></script>
-<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>
+    <!--弹出新建模板-->
+    <div class="modal fade" id="rptTypeSelectionModal" data-backdrop="static">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">创建新模板</h5>
+                </div>
+                <div class="modal-body">
+                    <div class="form-group">
+                        <label>模板类型</label>
+                        <div class="row">
+                            <div class="form-check col-4">
+                                <label class="form-check-label">
+                                    <input class="form-check-input" type="radio" name="inlineRadioOptions" id="flowTypeOpt" value="option1" checked="true"> 流水式表
+                                </label>
+                            </div>
+                            <div class="form-check col-4">
+                                <label class="form-check-label">
+                                    <input class="form-check-input" type="radio" name="inlineRadioOptions" id="billTypeOpt" value="option2"> 账单式表
+                                </label>
+                            </div>
+                            <div class="form-check col-4">
+                                <label class="form-check-label">
+                                    <input class="form-check-input" type="radio" name="inlineRadioOptions" id="crossTypeOpt" value="option3"> 交叉表
+                                </label>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="modal-footer text-xs-center">
+                    <button class="btn btn-secondary" data-dismiss="modal">取消</button>
+                    <button onclick="zTreeOprObj.createNewTpl()" class="btn btn-primary" data-dismiss="modal">创建</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 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="/web/maintain/report/js/global.js"></script>
+    <script src="/web/maintain/report/js/rpt_tpl_main.js"></script>
+    <script src="/web/maintain/report/js/rpt_tpl_band.js"></script>
+    <script src="/web/maintain/report/js/rpt_tpl_field_map.js"></script>
+    <script src="/web/maintain/report/js/rpt_tpl_field_cfg.js"></script>
+    <script src="/web/maintain/report/js/rpt_tpl_calculation.js"></script>
+    <script src="/web/maintain/report/js/rpt_tpl_helper.js"></script>
+    <script src="/web/maintain/report/js/cfg_const.js"></script>
+    <script src="/web/maintain/report/js/rpt_tpl_preview_util.js"></script>
+    <!-- zTree -->
+    <script type="text/javascript" src="/public/web/date_util.js"></script>
+    <script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
+    <script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>
+    <script type="text/javascript" src="/lib/ztree/jquery.ztree.exedit.js"></script>
+    <script type="text/javascript" src="/public/web/storageUtil.js"></script>
+    <script type="text/javascript" src="/public/web/rpt_tpl_def.js"></script>
+    <script type="text/javascript" src="/public/web/common_ajax.js"></script>
+    <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();