浏览代码

Merge branch 'master' of http://192.168.1.12:3000/SmartCost/ConstructionCost

TonyKang 7 年之前
父节点
当前提交
edf679eae2
共有 42 个文件被更改,包括 5540 次插入1062 次删除
  1. 2 0
      Dockerfile
  2. 15 0
      Dockerfile_qa
  3. 9 17
      config/config.js
  4. 220 0
      config/redis.js
  5. 55 0
      modules/common/const/engineering.js
  6. 131 0
      modules/complementary_glj_lib/controllers/gljController.js
  7. 235 0
      modules/complementary_glj_lib/models/gljModel.js
  8. 60 0
      modules/complementary_glj_lib/models/schemas.js
  9. 29 0
      modules/complementary_glj_lib/routes/routes.js
  10. 13 7
      modules/fee_rates/facade/fee_rates_facade.js
  11. 1 0
      modules/main/models/proj_counter.js
  12. 11 10
      modules/pm/controllers/new_proj_controller.js
  13. 11 11
      modules/pm/models/project_model.js
  14. 75 0
      modules/pm/models/templates/bills_template_model.js
  15. 35 0
      modules/pm/models/templates/schemas/bills_template.js
  16. 17 3
      modules/pm/routes/pm_route.js
  17. 1 1
      modules/users/controllers/boot_controller.js
  18. 2 3
      modules/users/controllers/login_controller.js
  19. 1 1
      modules/users/controllers/user_controller.js
  20. 35 1
      modules/users/models/compilation_model.js
  21. 1 0
      modules/users/routes/login_route.js
  22. 2 1
      package.json
  23. 77 49
      public/calc_util.js
  24. 1 1
      public/models/delete_schema.js
  25. 10 0
      public/web/tree_sheet/tree_sheet_helper.js
  26. 2 2
      server.js
  27. 3 4
      test/tmp_data/test_ration_calc/ration_calc_base.js
  28. 321 0
      web/building_saas/complementary_glj_lib/html/tools-gongliaoji.html
  29. 296 0
      web/building_saas/complementary_glj_lib/js/components.js
  30. 1073 0
      web/building_saas/complementary_glj_lib/js/glj.js
  31. 497 0
      web/building_saas/complementary_glj_lib/js/gljComponent.js
  32. 388 0
      web/building_saas/complementary_glj_lib/js/sheetOpr.js
  33. 19 2
      web/building_saas/main/js/calc/calc_fees.js
  34. 8 7
      web/building_saas/main/js/models/calc_program.js
  35. 3 3
      web/building_saas/main/js/views/calc_program_manage.js
  36. 11 12
      web/building_saas/main/js/views/calc_program_view.js
  37. 1 1
      web/building_saas/main/js/views/main_tree_col.js
  38. 15 6
      web/building_saas/main/js/views/project_view.js
  39. 2 4
      web/building_saas/main/js/views/sub_view.js
  40. 488 451
      web/building_saas/pm/html/project-management.html
  41. 735 465
      web/building_saas/pm/js/pm_main.js
  42. 629 0
      web/building_saas/pm/js/pm_main_bak.js

+ 2 - 0
Dockerfile

@@ -8,6 +8,8 @@ RUN cnpm install
 
 
 EXPOSE 6060
 EXPOSE 6060
 
 
+ENV NODE_ENV=prod
+
 ENTRYPOINT babel-node server.js
 ENTRYPOINT babel-node server.js
 
 
 
 

+ 15 - 0
Dockerfile_qa

@@ -0,0 +1,15 @@
+FROM server:2.0
+
+COPY . ConstructionCost
+
+WORKDIR ConstructionCost
+
+RUN cnpm install
+
+EXPOSE 6060
+
+ENV NODE_ENV=qa
+
+ENTRYPOINT babel-node server.js
+
+

+ 9 - 17
config/config.js

@@ -1,22 +1,15 @@
 module.exports = {
 module.exports = {
-    current: {server: "192.168.1.184", port: "60666"},
+    current: {server: "192.168.1.184", port: "60666",redis:{server:'192.168.1.184',port:'6379',pwd:'smartCost'}},
     local: {server: "localhost", port: "27017"},
     local: {server: "localhost", port: "27017"},
     qa: {server: "192.168.1.184", port: "60666"},
     qa: {server: "192.168.1.184", port: "60666"},
     prod: {server: "", port: ""},
     prod: {server: "", port: ""},
-    setToLocalDb: function() {
-        var me = this;
-        me.current.server = me.local.server;
-        me.current.port = me.local.port;
-    },
-    setToQaDb: function() {
-        var me = this;
-        me.current.server = me.qa.server;
-        me.current.port = me.qa.port;
-    },
-    setToProdDb: function() {
-        var me = this;
-        me.current.server = me.prod.server;
-        me.current.port = me.prod.port;
+    redis_local:{server:'127.0.0.1',port:'6379',pwd:'smartCost'},
+    redis_qa:{server:'192.168.1.184',port:'6379',pwd:'smartCost'},
+    setupDb:function (env="local") {
+        let me = this;
+        me.current.server = me[env].server;
+        me.current.port = me[env].port;
+        me.current.redis=me["redis_"+env];
     },
     },
     options:{
     options:{
             "user": "",
             "user": "",
@@ -26,9 +19,8 @@ module.exports = {
             },
             },
             "server": {
             "server": {
                  "socketOptions": {
                  "socketOptions": {
-                "connectTimeoutMS": 10000
+                 "connectTimeoutMS": 10000
                 }
                 }
             }
             }
-
         }
         }
 }
 }

+ 220 - 0
config/redis.js

@@ -0,0 +1,220 @@
+/**
+ * Created by chen on 2017/8/21.
+ */
+
+let Redis = require('ioredis'),
+    config=require('./config'),
+    redisConfig = config.current.redis;
+    redis = new Redis({
+        port: redisConfig.port,          // Redis port
+        host: redisConfig.server,   // Redis host
+        family: 4,           // 4 (IPv4) or 6 (IPv6)
+        password:redisConfig.pwd,
+        db: 0
+    });
+let client={};
+
+redis.on('ready',function(res){
+    console.log('ready');
+});
+
+redis.on("error", function (err) {
+    console.log("Error " + err);
+});
+client.redis = redis;
+//redis.hmset('测试',{12525:55,'a':'aaaa',b:"bbbbb"});
+
+//var stream = redis.scanStream({  match: '测*'});
+
+/*redis.hmset('RATION',{12525:55,'a':'aaaa',b:"bbbbb"});
+
+redis.hgetall("RATION",function (err,result) {
+    console.log(result);
+})*/
+
+
+client.scan = function(options,callback){
+    var stream = null;
+    if(options){
+        stream = redis.scanStream(options);
+    }else {
+        stream = redis.scanStream();
+    }
+    var keys = [];
+    stream.on('data', function (resultKeys) {
+        // `resultKeys` is an array of strings representing key names
+        for (var i = 0; i < resultKeys.length; i++) {
+            keys.push(resultKeys[i]);
+        }
+    });
+    stream.on('end', function () {
+        console.log('done with the keys: ', keys);
+        callback(keys);
+    });
+}
+
+client.set = function(key, value, expire, callback){
+    return redis.set(key, value, function(err, result){
+        if (err) {
+            console.log(err);
+            callback(err,null);
+            return;
+        }
+        if (!isNaN(expire) && expire > 0) {
+            redis.expire(key, parseInt(expire));
+        }
+        if(callback){
+            callback(null,result);
+        }
+    })
+}
+
+
+client.get = function(key, callback){
+    return redis.get(key, function(err,result){
+        if (err) {
+            console.log(err);
+            callback(err,null);
+            return;
+        }
+        if(callback){
+            callback(null,result);
+        }
+    });
+}
+
+client.hmset = function(key, value, expire, callback){
+    return redis.hmset(key, value, function(err, result){
+        if (err) {
+            console.log(err);
+            callback(err,null);
+            return;
+        }
+        if (!isNaN(expire) && expire > 0) {
+            redis.expire(key, parseInt(expire));
+        }
+        if(callback){
+            callback(null,result);
+        }
+    })
+}
+
+client.hmget = function (key,fields,callback) {
+    return redis.hmget(key,fields,function(err,result){
+        if (err) {
+            console.log(err);
+            callback(err,null)
+            return;
+        }
+        if(callback){
+            callback(null,result);
+        }
+    })
+}
+
+client.hgetall = function (key,callback) {
+    return redis.hgetall(key,function (err,result) {
+        if (err) {
+            console.log(err);
+            callback(err,null)
+            return;
+        }
+        callback(null,result);
+    })
+}
+
+
+client.hscan = function (key,options) {
+    var stream = null;
+    if(options){
+        stream = redis.hscanStream(key,options);
+    }else {
+        stream = redis.hscanStream(key);
+    }
+    var fields = [];
+    stream.on('data', function (resultFields) {
+        // `resultKeys` is an array of strings representing key names
+        for (var i = 0; i < resultFields.length; i++) {
+            fields.push(resultFields[i]);
+        }
+    });
+    stream.on('end', function () {
+        console.log('done with the keys: ', fields);
+        callback(fields);
+    });
+}
+
+client.rpush = function(key,value,expire, callback){
+    return redis.rpush(key, value, function(err, result){
+        if (err) {
+            console.log(err);
+            callback(err,null);
+            return;
+        }
+        if (!isNaN(expire) && expire > 0) {
+            redis.expire(key, parseInt(expire));
+        }
+        if(callback){
+            callback(null,result);
+        }
+    })
+}
+
+client.lrange= function (key,start,end,callback) {
+   return redis.lrange(key,start,end,callback);//获取列表在给定范围上的所有值 array lrange('key', 0, -1) (返回所有值)
+}
+
+client.lindex =function (key,index,callback) {
+    return redis.lindex(key,index,callback);//获取列表在给定位置上的单个元素 lindex('key', 1)
+}
+
+client.lpop = function (key,callback) {
+    return redis.lpop(key,callback);//从列表左端弹出一个值,并返回被弹出的值lpop('key')
+}
+
+client.rpop = function (key,callback) {
+    return redis.rpop(key,callback);//从列表右端弹出一个值,并返回被弹出的值rpop('key')
+}
+
+client.ltrim = function (key,start,end,callback) {
+    return redis.ltrim(key,start,end,callback);//将列表按指定的index范围裁减 ltrim('key', 'start', 'end')
+}
+
+
+client.del = function (keys,callback) {
+    return redis.del(keys,callback);// 删除一个(或多个)keys return 被删除的keys的数量  del('key1'[, 'key2', ...])
+}
+
+client.exists = function (key,callback) {
+    return redis.exists(key,callback);// 查询一个key是否存在  1/0 exists('key')
+}
+
+client.multi = function () {
+    return redis.multi();//用于开启一个事务,它总是返回 OK 。
+}
+
+client.exec =function () {
+   return redis.exec();//执行所有事务块内的命令
+}
+
+client.application_init = function () {
+    redis.flushdb();//清空所有keys
+    // load datas -- to do
+    /*data=[{
+     method:'hmset',
+     key:'ration:25555',
+     value:{
+     name:'aaa',
+     quantily:255
+     },
+     expire:2000,//options
+     callback:function, //option
+     }]
+     for(let data of datas){
+     client[data.method](data.key,data.value,data.expire,data.callback);
+     }
+     */
+}
+
+
+module.exports = client

+ 55 - 0
modules/common/const/engineering.js

@@ -0,0 +1,55 @@
+/**
+ * 专业工程相关常量
+ *
+ * @author CaiAoLin
+ * @date 2017/8/7
+ * @version
+ */
+const engineering = {
+    // 建筑工程
+    ARCHITECTURE: 1,
+    // 装饰工程
+    DECORATE: 2,
+    // 仿古建筑工程
+    ANTIQUE_ARCHITECTURE: 3,
+    // 安装工程
+    BUILD_IN: 4,
+    // 市政土建工程
+    MUNICIPAL_CONSTRUCTION: 5,
+    // 市政安装工程
+    MUNICIPAL_BUILD_IN: 6,
+    // 人工土石方工程
+    ARTIFICIAL_EARTHWORK: 7,
+    // 机械土石方工程
+    MECHANICAL_EARTHWORK: 8,
+    // 炉窖砌筑工程
+    KILN_MASONRY: 9,
+    // 园林工程
+    GARDEN: 10,
+    // 绿化工程
+    PLANTING: 11,
+    // 单拆除工程
+    DISMANTLE: 12,
+    // 建筑修缮工程
+    BUILDING_REPAIR: 13,
+    // 安装修缮工程
+    BUILD_IN_REPAIR: 14
+};
+const engineeringList = [
+    {name: "建筑工程", value: engineering.ARCHITECTURE},
+    {name: "装饰工程", value: engineering.DECORATE},
+    {name: "仿古建筑工程", value: engineering.ANTIQUE_ARCHITECTURE},
+    {name: "安装工程", value: engineering.BUILD_IN},
+    {name: "市政土建工程", value: engineering.MUNICIPAL_CONSTRUCTION},
+    {name: "市政安装工程", value: engineering.MUNICIPAL_BUILD_IN},
+    {name: "人工土石方工程", value: engineering.ARTIFICIAL_EARTHWORK},
+    {name: "机械土石方工程", value: engineering.MECHANICAL_EARTHWORK},
+    {name: "炉窖砌筑工程", value: engineering.KILN_MASONRY},
+    {name: "园林工程", value: engineering.GARDEN},
+    {name: "绿化工程", value: engineering.PLANTING},
+    {name: "单拆除工程", value: engineering.DISMANTLE},
+    {name: "建筑修缮工程", value: engineering.BUILDING_REPAIR},
+    {name: "安装修缮工程", value: engineering.BUILD_IN_REPAIR},
+];
+
+export {engineering as default, engineeringList as List};

+ 131 - 0
modules/complementary_glj_lib/controllers/gljController.js

@@ -0,0 +1,131 @@
+/**
+ * Created by Zhong on 2017/8/22.
+ */
+import BaseController from "../../common/base/base_controller";
+import stdgljutil  from "../../../public/cache/std_glj_type_util";
+import GljDao from "../models/gljModel";
+
+let gljDao = new GljDao();
+let callback = function(req, res, err, message, data){
+    res.json({error: err, message: message, data: data});
+};
+
+class GljController extends BaseController{
+    redirectGlj(req, res){
+        let gljLibId;
+        if(typeof req.session.sessionCompilation.ration_valuation[0].glj_lib[0] !== 'undefined'){
+            gljLibId = req.session.sessionCompilation.ration_valuation[0].glj_lib[0].id;
+        }
+        else if(typeof req.session.sessionCompilation.bill_valuation[0].glj_lib[0] !== 'undefined'){
+            gljLibId = req.session.sessionCompilation.bill_valuation[0].glj_lib[0].id;
+        }
+        res.render('building_saas/complementary_glj_lib/html/tools-gongliaoji.html',{
+            userID: req.session.sessionUser.ssoId,
+            gljLibId: gljLibId,
+            compilationId: req.session.sessionCompilation._id
+        });
+    }
+    getGljDistType (req, res) {
+        let gljDistTypeCache = stdgljutil.getStdGljTypeCacheObj().toArray();
+        if(gljDistTypeCache.length >0 ){
+            callback(req, res, null, '', gljDistTypeCache);
+        }
+        else {
+            callback(req, res, 1, 'Error', null);
+        }
+    }
+    getGljTree(req,res){
+        let gljLibId = req.body.gljLibId;
+        gljDao.getGljTypes(gljLibId,function(err,data){
+            callback(req,res,err, 'Get Tree', data)
+        });
+    }
+   /* updateRationBasePrc(req, res){
+        let basePrcArr = JSON.parse(req.body.basePrcArr);
+        rationItemDao.updateRationBasePrc(basePrcArr, function (err, message) {
+            if(err){
+                callback(req, res, err, message, null);
+            }
+            else{
+                callback(req, res, err, message, null);
+            }
+        });
+    }*/
+
+   /* getRationGljIds(req, res){
+        let rationLibs = req.body.rationLibs;
+        gljDao.getRationGljIds(rationLibs, function (err, msg, data) {
+            callback(req, res, err, msg, data);
+        })
+    }*/
+    createNewGljTypeNode(req, res) {
+        let repId = req.body.repositoryId;
+        let lastNodeId = req.body.lastNodeId;
+        let lastOpr = req.body.lastOpr;
+        let nodeData = JSON.parse(req.body.rawNodeData);
+        gljDao.createNewNode(repId, lastOpr, lastNodeId, nodeData, function(err, msg, data){
+            callback(req,res,err,msg, data)
+        });
+    }
+    updateGljNodes(req, res) {
+        let nodes = JSON.parse(req.body.nodes);
+        let repId = req.body.repId,
+            lastOpr = req.body.lastOpr;
+        gljDao.updateNodes(repId, lastOpr, nodes, function(err,results){
+            callback(req,res, err, results)
+        });
+    }
+    deleteGljNodes(req, res) {
+        let nodes = JSON.parse(req.body.nodes);
+        let preNodeId = req.body.preNodeId;
+        let preNodeNextId = req.body.preNodeNextId;
+        let repId = req.body.repId, lastOpr = req.body.lastOpr;
+        gljDao.removeNodes(repId, lastOpr, nodes, preNodeId, preNodeNextId, function(err,results){
+            callback(req,res, err, results)
+        });
+    }
+    getGljItems(req, res) {
+        let stdGljLibId = req.body.stdGljLibId,
+            userId = req.body.userId,
+            compilationId = req.body.compilationId;
+            gljDao.getGljItems(stdGljLibId, userId, compilationId, function(err, data){
+                callback(req,res,err,'Get Items',data)
+            });
+    }
+   /* getGljItemsByIds(req, res) {
+        let gljIds = JSON.parse(req.body.gljIds);
+        gljDao.getGljItems(gljIds, function(err, data){
+            callback(req,res,err,'Get Items',data)
+        });
+    }
+    getGljItemsByCodes(req, res) {
+        let gljCodes = JSON.parse(req.body.gljCodes),
+            repId = req.body.repId;
+        gljDao.getGljItemsByCode(repId, gljCodes, function(err, data){
+            callback(req,res,err,'Get Items',data)
+        });
+    }*/
+    updateComponent(req, res){
+        let userId = req.body.userId;
+        let updateArr = JSON.parse(req.body.updateArr);
+        gljDao.updateComponent(userId, updateArr, function (err, message, rst) {
+            callback(req, res, err, message, rst);
+        })
+    }
+    mixUpdateGljItems(req, res){
+        let userId = req.body.userId,
+            compilationId = req.body.compilationId,
+            updateItems = JSON.parse(req.body.updateItems),
+            addItems = JSON.parse(req.body.addItems),
+            removeIds = JSON.parse(req.body.removeIds);
+        gljDao.mixUpdateGljItems(userId, compilationId, updateItems, addItems, removeIds, function(err, message, rst){
+            if (err) {
+                callback(req, res, err, message, null);
+            } else {
+                callback(req, res, err, message, rst);
+            }
+        });
+    }
+}
+
+export default GljController;

+ 235 - 0
modules/complementary_glj_lib/models/gljModel.js

@@ -0,0 +1,235 @@
+/**
+ * Created by Zhong on 2017/8/22.
+ */
+import {complementaryGljModel, stdGljModel, gljClassModel} from "./schemas";
+import counter from "../../../public/counter/counter";
+import async from "async";
+
+class GljDao {
+    getGljTypes (gljLibId, callback){
+        gljClassModel.find({"repositoryId": gljLibId, "$or": [{"isDeleted": null}, {"isDeleted": false} ]},function(err,data){
+            if(data.length) {
+                callback(false,data);
+            }
+            else  if(err) callback("获取工料机类型错误!",false);
+        })
+    }
+
+
+    getGljItemsByRep(repositoryId,callback){
+        gljModel.find({"repositoryId": repositoryId},function(err,data){
+            if(err) callback(true, "")
+            else callback(false,data);
+        })
+    }
+
+    getGljItemByType (repositoryId, type, callback){
+        gljModel.find({"repositoryId": repositoryId, "gljType": type},function(err,data){
+            if(err) callback(true, "")
+            else callback(false, data);
+        })
+    };
+
+    getGljItem (repositoryId, code, callback){
+        gljModel.find({"repositoryId": repositoryId, "code": code},function(err,data){
+            if(err) callback(true, "")
+            else callback(false, data);
+        })
+    };
+    //获得用户的补充工料机和用户当前所在编办的标准工料机
+    getGljItems (stdGljLibId, userId, compilationId, callback){
+        let rst = {stdGljs: [], complementaryGljs: []};
+        async.parallel([
+            function (cb) {
+                stdGljModel.find({repositoryId: stdGljLibId}, function (err, stdGljs) {
+                    if(err){
+                        cb(err);
+                    }
+                    else{
+                        rst.stdGljs = stdGljs;
+                        cb(null);
+                    }
+                });
+            },
+            function (cb) {
+                complementaryGljModel.find({userId: userId, compilationId: compilationId}, function (err, complementaryGljs) {
+                    if(err){
+                        cb(err);
+                    }
+                    else{
+                        rst.complementaryGljs = complementaryGljs;
+                        cb(null);
+                    }
+                });
+            }
+        ], function (err) {
+            if(err){
+                callback(true, null);
+            }
+            else{
+                callback(false, rst);
+            }
+        })
+
+    };
+
+    getGljItemsByCode (repositoryId, codes, callback){
+        gljModel.find({"repositoryId": repositoryId,"code": {"$in": codes}},function(err,data){
+            if(err) callback(true, "")
+            else callback(false, data);
+        })
+    };
+
+    updateComponent(userId, updateArr, callback){
+        let parallelFucs = [];
+        for(let i = 0; i < updateArr.length; i++){
+            parallelFucs.push((function(obj){
+                return function (cb) {
+                    if(typeof obj.component === 'undefined'){
+                        obj.component = [];
+                    }
+                    complementaryGljModel.update({userId: userId, ID: obj.ID}, obj, function (err, result) {
+                        if(err){
+                            cb(err);
+                        }
+                        else{
+                            cb(null, obj);
+                        }
+                    })
+                }
+            })(updateArr[i]));
+        }
+        async.parallel(parallelFucs, function (err, result) {
+            if(err){
+                callback(err, '更新组成物错误!', null);
+            }
+            else{
+                callback(null, '成功!', result);
+            }
+        });
+    }
+    //-oprtor
+    mixUpdateGljItems (userId, compilationId, updateItems, addItems, rIds, callback) {
+        if (updateItems.length == 0 && rIds.length == 0) {
+            GljDao.addGljItems(userId, compilationId, addItems, callback);
+        }
+        else if(rIds.length > 0 && updateItems.length > 0){
+            async.parallel([
+                function (cb) {
+                    GljDao.removeGljItems(rIds, cb);
+                },
+                function (cb) {
+                    GljDao.updateGljItems(userId, compilationId, updateItems, cb);
+                }
+            ], function (err) {
+                if(err){
+                    callback(true, "Fail to update and delete", false)
+                }
+                else{
+                    callback(false, "Save successfully", false);
+                }
+            })
+        }
+        else if (rIds.length > 0 && updateItems.length === 0) {
+            GljDao.removeGljItems(rIds, callback);
+        }
+        else if(updateItems.length > 0 || addItems.length > 0){
+            GljDao.updateGljItems(userId, compilationId, updateItems, function(err, results){
+                if (err) {
+                    callback(true, "Fail to update", false);
+                } else {
+                    if (addItems && addItems.length > 0) {
+                        GljDao.addGljItems(userId, compilationId, addItems, callback);
+                    } else {
+                        callback(false, "Save successfully", results);
+                    }
+                }
+            });
+        }
+    }
+
+    /*mixUpdateGljItems (repId, lastOpr, updateItems, addItems, rIds, callback) {
+     if (updateItems.length == 0 && rIds.length == 0) {
+     GljDao.addGljItems(repId, lastOpr, addItems, callback);
+     } else if (rIds.length > 0) {
+     GljDao.removeGljItems(repId, lastOpr, rIds, function(err, message, docs) {
+     });
+     }else{
+     GljDao.updateGljItems(repId, lastOpr, updateItems, function(err, results){
+     if (err) {
+     callback(true, "Fail to update", false);
+     } else {
+     if (addItems && addItems.length > 0) {
+     GljDao.addGljItems(repId, lastOpr, addItems, callback);
+     } else {
+     callback(false, "Save successfully", results);
+     }
+     }
+     });
+     }
+     };*/
+
+    static removeGljItems (rIds, callback) {
+        if (rIds && rIds.length > 0) {
+            complementaryGljModel.collection.remove({ID: {$in: rIds}}, null, function(err, docs){
+                if (err) {
+                    callback(true, "Fail to remove", false);
+                } else {
+                    callback(false, "Remove successfully", docs);
+                }
+            })
+        } else {
+            callback(false, "No records were deleted!", null);
+        }
+    }
+
+    static addGljItems (userId, compilationId, items, callback) {
+        if (items && items.length > 0) {
+            counter.counterDAO.getIDAfterCount(counter.moduleName.GLJ, items.length, function(err, result){
+                var maxId = result.value.sequence_value;
+                var arr = [];
+                for (var i = 0; i < items.length; i++) {
+                    var obj = new complementaryGljModel(items[i]);
+                    obj.ID = (maxId - (items.length - 1) + i);
+                    obj.userId = userId;
+                    obj.compilationId = compilationId;
+                    arr.push(obj);
+                }
+                complementaryGljModel.collection.insert(arr, null, function(err, docs){
+                    if (err) {
+                        callback(true, "Fail to add", false);
+                    } else {
+                        callback(false, "Add successfully", docs);
+                    }
+                });
+            });
+        } else {
+            callback(true, "No source", false);
+        }
+    }
+
+    static updateGljItems(userId, compilationId, items, callback) {
+        var functions = [];
+        for (var i=0; i < items.length; i++) {
+            functions.push((function(doc) {
+                return function(cb) {
+                    var filter = {};
+                    if (doc.ID) {
+                        filter.ID = doc.ID;
+                    } else {
+                        filter.userId = userId;
+                        filter.compilationId = compilationId;
+                        filter.code = doc.code;
+                    }
+                    complementaryGljModel.update(filter, doc, cb);
+                };
+            })(items[i]));
+        }
+        async.parallel(functions, function(err, results) {
+            callback(err, results);
+        });
+    }
+}
+
+export default GljDao;
+

+ 60 - 0
modules/complementary_glj_lib/models/schemas.js

@@ -0,0 +1,60 @@
+/**
+ * Created by Zhong on 2017/8/22.
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let gjlComponentSchema = mongoose.Schema(
+    {
+        ID: Number,
+        consumeAmt: Number
+    },
+    {_id: false},
+    {versionKey: false}
+);
+//补充工料机跟用户和编办绑定
+let complementaryGljSchema = new Schema({
+    userId: Number,
+    compilationId: String,
+    ID: Number,
+    code: String,
+    name: String,
+    specs: String,
+    unit: String,
+    basePrice: String,
+    gljClass: Number,
+    gljType: Number,
+    shortName: String,
+    component: [gjlComponentSchema]
+}, {versionKey: false});
+
+//标准工料机
+let stdGljSchema = new Schema({
+    deleted: Boolean,
+    repositoryId: Number,
+    ID: Number,
+    code: String,
+    name: String,
+    specs: String,
+    basePrice: Number,
+    gljClass: Number,
+    gljType: Number,
+    shortName: String,
+    component: [gjlComponentSchema]
+},{versionKey: false});
+
+//标准工料机分类树
+let gljClassSchema = mongoose.Schema({
+    repositoryId: Number,
+    ID: Number,
+    ParentID: Number,
+    NextSiblingID: Number,
+    Name: String,
+    deleted: Boolean
+}, {versionKey: false});
+
+let complementaryGljModel = mongoose.model('complementary_glj_lib', complementaryGljSchema, 'complementary_glj_lib');
+let stdGljModel = mongoose.model('std_glj_lib_gljList', stdGljSchema, 'std_glj_lib_gljList');
+let gljClassModel = mongoose.model('std_glj_lib_gljClass', gljClassSchema, 'std_glj_lib_gljClass');
+
+export {complementaryGljModel, stdGljModel, gljClassModel};

+ 29 - 0
modules/complementary_glj_lib/routes/routes.js

@@ -0,0 +1,29 @@
+/**
+ * Created by Zhong on 2017/8/22.
+ */
+
+import express from "express";
+import GljController from "../controllers/gljController"
+
+let router = express.Router();
+let gljController = new GljController();
+
+module.exports = function (app) {
+    app.get('/complementaryGlj', gljController.init, gljController.redirectGlj);
+
+   /* router.post("/updateRationBasePrc",gljController.init, gljController.updateRationBasePrc);//更新定额单价
+    router.post("/getRationGljIds", gljController.init, gljController.getRationGljIds);
+    router.post("/createNewGljTypeNode", gljController.init, gljController.createNewGljTypeNode);
+    router.post("/updateGljNodes", gljController.init, gljController.updateGljNodes);
+    router.post("/deleteGljNodes", gljController.init, gljController.deleteGljNodes);*/
+    router.post("/getGljDistType", gljController.init, gljController.getGljDistType);
+    router.post("/getGljTree", gljController.init, gljController.getGljTree);
+    router.post("/getGljItems", gljController.init, gljController.getGljItems);
+    router.post("/updateComponent", gljController.init, gljController.updateComponent);
+    router.post("/mixUpdateGljItems", gljController.init, gljController.mixUpdateGljItems);
+    //router.post("/getGljItemsByIds", gljController.init, gljController.getGljItemsByIds);
+    //router.post("/getGljItemsByCodes", gljController.init, gljController.getGljItemsByCodes);
+
+    app.use("/complementartGlj/api", router);
+
+};

+ 13 - 7
modules/fee_rates/facade/fee_rates_facade.js

@@ -184,13 +184,19 @@ async function getFeeRateData(projectID) {
     }
     }
     try {
     try {
         //
         //
-        let tem = await project_feerate_temp.findOne({projectID:projectID});//暂时取tem表的记录
-        let feeRateData = await feeRateFileModel.findOne({'ID':tem.feeRateFileID,deleteInfo:null});
-        let feeRate = await feeRateModel.findOne({ID:feeRateData.feeRateID});
-        feeRateData._doc.rates = feeRate.rates;
-        //
-        feeRateData._doc.usageProjects=getUsageProjects(feeRateData.ID);
-        result.datas = feeRateData;
+        let tem = await project_feerate_temp.findOne({projectID:projectID});//暂时取tem表的记录,写死为99
+        if (tem){
+            let feeRateData = await feeRateFileModel.findOne({'ID':tem.feeRateFileID,deleteInfo:null});
+            let feeRate = await feeRateModel.findOne({ID:feeRateData.feeRateID});
+            feeRateData._doc.rates = feeRate.rates;
+            //
+            feeRateData._doc.usageProjects=getUsageProjects(feeRateData.ID);
+            result.datas = feeRateData;
+        }else {
+            result.datas=[];
+        }
+
+
     }catch (err){
     }catch (err){
         console.log(err);
         console.log(err);
         result.err=err;
         result.err=err;

+ 1 - 0
modules/main/models/proj_counter.js

@@ -2,6 +2,7 @@
  * Created by Mai on 2017/6/13.
  * Created by Mai on 2017/6/13.
  */
  */
 
 
+let mongoose = require('mongoose');
 let baseModel = require('./base_model');
 let baseModel = require('./base_model');
 
 
 class projCounter extends baseModel {
 class projCounter extends baseModel {

+ 11 - 10
modules/pm/controllers/new_proj_controller.js

@@ -2,23 +2,24 @@
  * Created by Mai on 2017/4/24.
  * Created by Mai on 2017/4/24.
  */
  */
 
 
-let BillsTemplateData = require('../../templates/models/bills_template');
 let billsData = require('../../main/models/bills');
 let billsData = require('../../main/models/bills');
 let projCounter = require('../../main/models/proj_counter');
 let projCounter = require('../../main/models/proj_counter');
 let async = require('async');
 let async = require('async');
 
 
+import BillsTemplateModel from "../models/templates/bills_template_model";
+
 module.exports = {
 module.exports = {
-    copyTemplateData: function (tempType, newProjID, callback) {
+    copyTemplateData: async function (valuationId, newProjID, callback) {
         async.parallel([
         async.parallel([
-            function (cb) {
-                BillsTemplateData.getTemplate(tempType).then(function (templates) {
-                    let datas = [];
-                    templates.forEach(function (template) {
-                        template._doc.projectID = newProjID;
-                        datas.push(template._doc);
-                    })
-                    return billsData.insertData(datas, cb);
+            async function (cb) {
+                // 获取清单模板数据
+                let billsTemplateModel = new BillsTemplateModel();
+                let templateData = JSON.stringify(await billsTemplateModel.getTemplateDataForNewProj(valuationId));
+                let billsDatas = JSON.parse(templateData);
+                billsDatas.forEach(function (template) {
+                    template.projectID = newProjID;
                 });
                 });
+                billsData.insertData(billsDatas, callback);
             },
             },
             function (cb) {
             function (cb) {
                 projCounter.insertData({"projectID": newProjID}, cb);
                 projCounter.insertData({"projectID": newProjID}, cb);

+ 11 - 11
modules/pm/models/project_model.js

@@ -9,7 +9,9 @@ let copyProjController = require('../controllers/copy_proj_controller');
 let Projects = require("./project_schema");
 let Projects = require("./project_schema");
 let projectType = {
 let projectType = {
     folder: 'Folder',
     folder: 'Folder',
-    tender: 'Tender'
+    tender: 'Tender',
+    project: 'Project',
+    engineering: 'Engineering',
 };
 };
 
 
 let ProjectsDAO = function(){};
 let ProjectsDAO = function(){};
@@ -35,7 +37,7 @@ ProjectsDAO.prototype.getUserProject = function (userId, ProjId, callback) {
 }
 }
 
 
 ProjectsDAO.prototype.updateUserProjects = function(userId, datas, callback){
 ProjectsDAO.prototype.updateUserProjects = function(userId, datas, callback){
-    let data, project, updateLength = 0, hasError = false, deleteInfo = null, tempType = 1, i, newProject;
+    let data, project, updateLength = 0, hasError = false, deleteInfo = null, valuationId = "599256ba700b1b340c03805e", i, newProject;
     let updateAll = function (err) {
     let updateAll = function (err) {
             if (!err){
             if (!err){
                 updateLength += 1;
                 updateLength += 1;
@@ -44,6 +46,7 @@ ProjectsDAO.prototype.updateUserProjects = function(userId, datas, callback){
                 }
                 }
             } else {
             } else {
                 hasError = true;
                 hasError = true;
+                console.log(err);
                 callback(1, '提交数据出错.', null);
                 callback(1, '提交数据出错.', null);
             }
             }
         };
         };
@@ -54,13 +57,11 @@ ProjectsDAO.prototype.updateUserProjects = function(userId, datas, callback){
                 Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll)
                 Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll)
             } else if (data.updateType === 'new') {
             } else if (data.updateType === 'new') {
                 data.updateData['userID'] = userId;
                 data.updateData['userID'] = userId;
-                if (data.updateData.projType === projectType.folder) {
-                    data.updateData['createDateTime'] = new Date();
-                }
+                data.updateData['createDateTime'] = new Date();
                 newProject = new Projects(data.updateData);
                 newProject = new Projects(data.updateData);
                 newProject.save(function (err, result) {
                 newProject.save(function (err, result) {
                     if (!err && result._doc.projType === projectType.tender) {
                     if (!err && result._doc.projType === projectType.tender) {
-                        newProjController.copyTemplateData(tempType, newProject.ID, updateAll);
+                        newProjController.copyTemplateData(valuationId, newProject.ID, updateAll);
                     } else {
                     } else {
                         updateAll(err);
                         updateAll(err);
                     }
                     }
@@ -92,6 +93,7 @@ ProjectsDAO.prototype.copyUserProjects = function (userId, datas, callback) {
             callback(1, '提交数据出错.', null);
             callback(1, '提交数据出错.', null);
         }
         }
     };
     };
+    console.log(datas);
     if (datas) {
     if (datas) {
         for (i = 0; i < datas.length && !hasError; i++) {
         for (i = 0; i < datas.length && !hasError; i++) {
             data = datas[i];
             data = datas[i];
@@ -99,14 +101,12 @@ ProjectsDAO.prototype.copyUserProjects = function (userId, datas, callback) {
                 Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll)
                 Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll)
             } else if (data.updateType === 'copy') {
             } else if (data.updateType === 'copy') {
                 data.updateData['userID'] = userId;
                 data.updateData['userID'] = userId;
-                if (data.updateData.projType === 'Tender') {
-                    data.updateData['createDateTime'] = new Date();
-                };
-                newProject = new Projects(data.updateData);
+                data.updateData['createDateTime'] = new Date();
+                let newProject = new Projects(data.updateData);
                 newProject['srcProjectId'] = data.srcProjectId;
                 newProject['srcProjectId'] = data.srcProjectId;
                 newProject.save(function (err, result) {
                 newProject.save(function (err, result) {
                     if (!err && result._doc.projType === 'Tender') {
                     if (!err && result._doc.projType === 'Tender') {
-                        copyProjController.copyProjectData(this.newProject.srcProjectId, result._doc.ID, updateAll);
+                        copyProjController.copyProjectData(newProject.srcProjectId, result._doc.ID, updateAll);
                     } else {
                     } else {
                         updateAll(err);
                         updateAll(err);
                     }
                     }

+ 75 - 0
modules/pm/models/templates/bills_template_model.js

@@ -0,0 +1,75 @@
+/**
+ * Created by Mai on 2017/4/14.
+ * 清单模板,新建项目使用
+ */
+import BaseModel from "../../../common/base/base_model";
+import BillsTemplateSchema from "./schemas/bills_template";
+
+class BillsTemplateModel extends BaseModel {
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = BillsTemplateSchema;
+        parent.init();
+    }
+
+    /**
+     * 获取计价类别对应的清单模板
+     * @param valuationId
+     * @returns {*}
+     */
+    async getTemplateData (valuationId) {
+        // 筛选字段
+        let field = {_id: 1, valuationId: 1, ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1, flags: 1};
+        let data = await this.findDataByCondition({valuationId: valuationId}, field, false);
+
+        return data === null ? [] : data;
+    }
+
+    /**
+     * 新建项目时,获取计价类别对应的清单模板
+     * @param valuationId
+     * @returns {*}
+     */
+    async getTemplateDataForNewProj (valuationId) {
+        // 筛选字段
+        let field = {_id: 0, ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1, flags: 1};
+        let data = await this.findDataByCondition({valuationId: valuationId}, field, false);
+
+        return data === null ? [] : data;
+    }
+
+    async updateTemplate (valuationId, datas) {
+        try {
+            for (let data of datas) {
+                data.data.valuationId = valuationId;
+                let condition = {valuationId: valuationId, ID: data.data.ID}, result;
+                if (data.type === 'update') {
+                    result = await this.db.update(condition, data.data);
+                    if (result === undefined || result.ok ===undefined || !result.ok) {
+                        throw '更新数据错误';
+                    }
+                } else if (data.type === 'new') {
+                    result = await this.db.create(data.data);
+                    if (!result) {
+                        throw '新增数据错误';
+                    }
+                } else if (data.type === 'delete') {
+                    result = await this.db.delete(condition);
+                    if (result === undefined || result.ok ===undefined || !result.ok) {
+                        throw '删除数据错误';
+                    }
+                }
+            }
+            return true;
+        } catch (error) {
+            console.log(error);
+        }
+    }
+};
+
+export default BillsTemplateModel;

+ 35 - 0
modules/pm/models/templates/schemas/bills_template.js

@@ -0,0 +1,35 @@
+/**
+ * Created by Mai on 2017/8/17.
+ */
+import mongoose from "mongoose";
+let Schema = mongoose.Schema;
+
+let collectionName = 'temp_bills';
+
+// 标记字段
+let flagsSchema = new Schema({
+    fieldName: String,
+    flag: Number
+});
+let BillsTemplateSchema = {
+    // 树结构所需ID
+    ID: Number,
+    ParentID: Number,
+    NextSiblingID: Number,
+    // 编号
+    code: String,
+    // 名称
+    name: String,
+    // 单位
+    unit: String,
+    // 标记
+    flags:{
+        type: [flagsSchema],
+        default: []
+    },
+    // 所属计价ID
+    valuationId: String
+};
+
+let model = mongoose.model(collectionName, new Schema(BillsTemplateSchema, {versionKey: false, collection: collectionName}));
+export {model as default, collectionName as collectionName};

+ 17 - 3
modules/pm/routes/pm_route.js

@@ -5,13 +5,27 @@
 
 
 let express = require('express');
 let express = require('express');
 let pmController = require('./../controllers/pm_controller');
 let pmController = require('./../controllers/pm_controller');
+const engineering = require("../../common/const/engineering");
 
 
 module.exports = function (app) {
 module.exports = function (app) {
 
 
     app.get('/pm', function(req, res){
     app.get('/pm', function(req, res){
-        res.render('building_saas/pm/html/project-management.html',
-            {userAccount: req.session.userAccount,
-                userID: req.session.sessionUser.ssoId});
+        // 获取编办信息
+        let sessionCompilation = req.session.sessionCompilation;
+        // 清单计价
+        let billValuation = sessionCompilation.bill_valuation !== undefined ? sessionCompilation.bill_valuation : [];
+
+        // 定额计价
+        let rationValuation = sessionCompilation.ration_valuation !== undefined ? sessionCompilation.ration_valuation : [];
+        let renderData = {
+            userAccount: req.session.userAccount,
+            userID: req.session.sessionUser.ssoId,
+            compilationData: sessionCompilation,
+            billValuation: JSON.stringify(billValuation),
+            rationValuation: JSON.stringify(rationValuation),
+            engineeringList: JSON.stringify(engineering.List)
+        };
+        res.render('building_saas/pm/html/project-management.html', renderData);
     });
     });
 
 
     let pmRouter = express.Router();
     let pmRouter = express.Router();

+ 1 - 1
modules/users/controllers/boot_controller.js

@@ -27,7 +27,7 @@ class BootController extends BaseController {
         // 判断是否有存入编办信息
         // 判断是否有存入编办信息
         if (sessionCompilation === undefined && compilationId !== '') {
         if (sessionCompilation === undefined && compilationId !== '') {
             let compilationModel = new CompilationModel();
             let compilationModel = new CompilationModel();
-            let compilationData = await compilationModel.findDataByCondition({_id: compilationId});
+            let compilationData = await compilationModel.getCompilationById(compilationId);
 
 
             request.session.sessionCompilation = compilationData;
             request.session.sessionCompilation = compilationData;
         }
         }

+ 2 - 3
modules/users/controllers/login_controller.js

@@ -74,13 +74,12 @@ class LoginController {
 
 
             let compilationModel = new CompilationModel();
             let compilationModel = new CompilationModel();
             compilationList = preferenceSetting.login_ask === 1 ? await compilationModel.getList() : [];
             compilationList = preferenceSetting.login_ask === 1 ? await compilationModel.getList() : [];
-
             // 获取编办信息
             // 获取编办信息
             let sessionCompilation = request.session.sessionCompilation;
             let sessionCompilation = request.session.sessionCompilation;
-            if (preferenceSetting.login_ask === 0 && sessionCompilation === undefined &&
+            if (preferenceSetting.login_ask === 0 && !sessionCompilation &&
                 preferenceSetting.select_version !== '') {
                 preferenceSetting.select_version !== '') {
-                let compilationData = await compilationModel.findDataByCondition({_id: preferenceSetting.select_version});
 
 
+                let compilationData = await compilationModel.getCompilationById(preferenceSetting.select_version);
                 request.session.sessionCompilation = compilationData;
                 request.session.sessionCompilation = compilationData;
             }
             }
 
 

+ 1 - 1
modules/users/controllers/user_controller.js

@@ -175,7 +175,7 @@ class UserController extends BaseController {
             if (data.login_ask === 1) {
             if (data.login_ask === 1) {
                 // 查找对应编办
                 // 查找对应编办
                 let compilationModel = new CompilationModel();
                 let compilationModel = new CompilationModel();
-                let compilationData = await compilationModel.findDataByCondition({_id: selectVersion});
+                let compilationData = await compilationModel.getCompilationById(selectVersion);
 
 
                 request.session.sessionCompilation = compilationData;
                 request.session.sessionCompilation = compilationData;
             }
             }

+ 35 - 1
modules/users/models/compilation_model.js

@@ -29,11 +29,45 @@ class CompilationModel extends BaseModel {
     async getList() {
     async getList() {
         // 筛选字段
         // 筛选字段
         let field = {_id: 1, name: 1, is_release: 1};
         let field = {_id: 1, name: 1, is_release: 1};
-        let compilationData = await this.findDataByCondition({name: {$ne: ''}}, field, false);
+        let compilationData = await this.findDataByCondition({name: {$ne: ''}, is_release: true}, field, false);
 
 
         return compilationData === null ? [] : compilationData;
         return compilationData === null ? [] : compilationData;
     }
     }
 
 
+    /**
+     * 根据id获取可用的编办数据
+     *
+     * @param {String} id
+     * @return {Promise}
+     */
+    async getCompilationById(id) {
+        let condition = {_id: id, is_release: true};
+        let compilationData = await this.findDataByCondition(condition);
+        if (compilationData.bill_valuation === undefined) {
+            return compilationData;
+        }
+
+        if (compilationData.bill_valuation.length > 0) {
+            for (let index in compilationData.bill_valuation) {
+                if (compilationData.bill_valuation[index].enable) {
+                    continue;
+                }
+                delete compilationData.bill_valuation[index];
+            }
+        }
+
+        if (compilationData.ration_valuation.length > 0) {
+            for (let index in compilationData.ration_valuation) {
+                if (compilationData.ration_valuation[index].enable) {
+                    continue;
+                }
+                delete compilationData.ration_valuation[index];
+            }
+        }
+
+        return compilationData;
+    }
+
 }
 }
 
 
 export default CompilationModel;
 export default CompilationModel;

+ 1 - 0
modules/users/routes/login_route.js

@@ -21,6 +21,7 @@ module.exports = function (app) {
 
 
     router.get("/logout", function (req, res) {
     router.get("/logout", function (req, res) {
         delete req.session.sessionUser;
         delete req.session.sessionUser;
+        delete req.session.sessionCompilation;
         res.redirect("/");
         res.redirect("/");
     });
     });
     app.use('/',router)
     app.use('/',router)

+ 2 - 1
package.json

@@ -27,7 +27,8 @@
     "moment": "^2.18.1",
     "moment": "^2.18.1",
     "socket.io": "^2.0.3",
     "socket.io": "^2.0.3",
     "ua-parser-js": "^0.7.14",
     "ua-parser-js": "^0.7.14",
-    "uuid": "^3.1.0"
+    "uuid": "^3.1.0",
+    "ioredis":"^3.1.4"
   },
   },
   "scripts": {
   "scripts": {
     "start": "C:\\Users\\mai\\AppData\\Roaming\\npm\\babel-node.cmd server.js"
     "start": "C:\\Users\\mai\\AppData\\Roaming\\npm\\babel-node.cmd server.js"

+ 77 - 49
public/calc_util.js

@@ -1,20 +1,25 @@
 /**
 /**
  * Created by Tony on 2017/6/21.
  * Created by Tony on 2017/6/21.
  * Modified by CSL, 2017-08-01
  * Modified by CSL, 2017-08-01
+ * 引入多套计算程序、费率同步、人工系数同步、改进基数计算、费字段映射等。
  */
  */
 
 
 let executeObj = {
 let executeObj = {
     treeNode: null,
     treeNode: null,
+    template: null,
+    calcBase: null,
+
     at: function(ID) {
     at: function(ID) {
         let me = executeObj,
         let me = executeObj,
             rst = 0;
             rst = 0;
-        rst = me.treeNode.data.calcTemplate.compiledTemplate[ID].unitFee;
+        rst = me.template.compiledCalcItems[ID].unitFee;
         rst = parseFloat(rst);
         rst = parseFloat(rst);
         return rst;
         return rst;
     },
     },
     base: function(calcBaseName) {
     base: function(calcBaseName) {
         let me = executeObj, rst = 0,
         let me = executeObj, rst = 0,
-            base = getRationCalcBase(calcBaseName);
+            //base = getRationCalcBase(calcBaseName);
+            base = me.calcBase[calcBaseName];
 
 
         if (base != null) {
         if (base != null) {
             let price = 0, tmpSum = 0;
             let price = 0, tmpSum = 0;
@@ -32,23 +37,56 @@ let executeObj = {
         };
         };
         return rst;
         return rst;
     }
     }
-/*    factor: function(factorID) {
-        let me = executeObj;
-        let rst = 7.77;
-        return rst;
-    }*/
 };
 };
 
 
 class Calculation {
 class Calculation {
-/*    init(template, feeRates){
+    // 先编译公用的基础数据
+    compilePublics(feeRates, labourCoes, feeTypes, calcBases){
         let me = this;
         let me = this;
-        me.template = template;
-        me.feeRates = feeRates;
-        me.hasCompiled = false;
-    };*/
+        let private_compile_feeRateFile = function() {
+            if (feeRates) {
+                me.compiledFeeRates = {};
+                for (let rate of feeRates) {
+                    me.compiledFeeRates["feeRate_" + rate.ID] = rate;
+                }
+            }
+        };
+        let private_compile_labourCoeFile = function() {
+            if (labourCoes) {
+                me.compiledLabourCoes = {};
+                for (let coe of labourCoes) {
+                    me.compiledLabourCoes["LabourCoe_" + coe.ID] = coe;
+                }
+            }
+        };
+        let private_compile_feeType = function() {
+            if (feeTypes) {
+                me.compiledFeeTypes = {};
+                for (let ft of feeTypes) {
+                    me.compiledFeeTypes[ft.type] = ft.name;
+                    me.compiledFeeTypes[ft.name] = ft.type;    // 中文预编译,可靠性有待验证
+                }
+            }
+        };
+        let private_compile_calcBase = function() {
+            if (calcBases) {
+                me.compiledCalcBases = {};
+                for (let cb of calcBases) {
+                    me.compiledCalcBases[cb.dispName] = cb;         // 中文预编译,可靠性有待验证
+                }
+            }
+        };
 
 
-    compile(template, feeRates, labourCoes){
+        private_compile_feeRateFile();
+        private_compile_labourCoeFile();
+        private_compile_feeType();
+        private_compile_calcBase();
+        me.compiledTemplates = {};
+    };
+
+    compileTemplate(template){
         let me = this;
         let me = this;
+        me.compiledTemplates[template.ID] = template;
         template.hasCompiled = false;
         template.hasCompiled = false;
         template.errs = [];
         template.errs = [];
 
 
@@ -81,10 +119,10 @@ class Calculation {
             while (idx >= 0) {
             while (idx >= 0) {
                 let ID = private_extract_ID(item.expression, idx);
                 let ID = private_extract_ID(item.expression, idx);
                 if (ID.length > 0) {
                 if (ID.length > 0) {
-                    let subItem = template.compiledTemplate[ID];
+                    let subItem = template.compiledCalcItems[ID];
                     if (subItem) {
                     if (subItem) {
                         if (subItem.ID !== item.ID) {
                         if (subItem.ID !== item.ID) {
-                            private_parse_ref(subItem, template.compiledTemplate[ID + "_idx"]);
+                            private_parse_ref(subItem, template.compiledCalcItems[ID + "_idx"]);
                         } else {
                         } else {
                             template.errs.push("There exists the self refer ID: " + ID);
                             template.errs.push("There exists the self refer ID: " + ID);
                         }
                         }
@@ -109,44 +147,32 @@ class Calculation {
                 let item = template.calcItems[idx];
                 let item = template.calcItems[idx];
                 item.compiledExpr = item.expression.split('@(').join('$CE.at(');
                 item.compiledExpr = item.expression.split('@(').join('$CE.at(');
                 item.compiledExpr = item.compiledExpr.split('base(').join('$CE.base(');
                 item.compiledExpr = item.compiledExpr.split('base(').join('$CE.base(');
-                //item.compiledExpr = item.compiledExpr.split('rate(').join('$CE.rate(');
-                //item.compiledExpr = item.compiledExpr.split('factor(').join('$CE.factor(');
+
                 if (item.labourCoeID){
                 if (item.labourCoeID){
                     let lc = me.compiledLabourCoes["LabourCoe_" + item.labourCoeID].coe;
                     let lc = me.compiledLabourCoes["LabourCoe_" + item.labourCoeID].coe;
                     item.dispExpr = item.dispExpr.replace(/L/gi, lc.toString());
                     item.dispExpr = item.dispExpr.replace(/L/gi, lc.toString());
                     item.compiledExpr = item.compiledExpr.replace(/L/gi, lc.toString());
                     item.compiledExpr = item.compiledExpr.replace(/L/gi, lc.toString());
-                }
-            }
-        };
-        let private_compile_feeFile = function() {
-            if (feeRates) {
-                me.compiledFeeRate = {};
-                for (let rate of feeRates) {
-                    me.compiledFeeRate["feeRate_" + rate.ID] = rate;
-                }
-            }
-        };
-        let private_compile_labourCoeFile = function() {
-            if (labourCoes) {
-                me.compiledLabourCoes = {};
-                for (let coe of labourCoes) {
-                    me.compiledLabourCoes["LabourCoe_" + coe.ID] = coe;
-                }
+                };
+
+                if (item.feeRateID) {
+                    item.feeRate = me.compiledFeeRates["feeRate_" + item.feeRateID].rate;
+                };
+
+                // 字段名映射
+                item.displayFieldName = me.compiledFeeTypes[item.fieldName];
             }
             }
         };
         };
 
 
         if (template && template.calcItems && template.calcItems.length > 0) {
         if (template && template.calcItems && template.calcItems.length > 0) {
             template.compiledSeq = [];
             template.compiledSeq = [];
-            template.compiledTemplate = {};
-            //1. first round -> prepare
-            private_compile_feeFile();
-            private_compile_labourCoeFile();
+            template.compiledCalcItems = {};
+
             for (let i = 0; i < template.calcItems.length; i++) {
             for (let i = 0; i < template.calcItems.length; i++) {
                 let item = template.calcItems[i];
                 let item = template.calcItems[i];
-                template.compiledTemplate[item.ID] = item;
-                template.compiledTemplate[item.ID + "_idx"] = i;
+                template.compiledCalcItems[item.ID] = item;
+                template.compiledCalcItems[item.ID + "_idx"] = i;
             }
             }
-            //2. second round -> go!
+
             for (let i = 0; i < template.calcItems.length; i++) {
             for (let i = 0; i < template.calcItems.length; i++) {
                 private_setup_seq(template.calcItems[i], i);
                 private_setup_seq(template.calcItems[i], i);
             }
             }
@@ -156,16 +182,21 @@ class Calculation {
             } else {
             } else {
                 console.log('errors: ' + template.errs.toString());
                 console.log('errors: ' + template.errs.toString());
             }
             }
-        }
+        };
     };
     };
 
 
     calculate($treeNode){
     calculate($treeNode){
         let me = this;
         let me = this;
-        let template = $treeNode.data.calcTemplate;
+        let templateID = $treeNode.data.calcTemplateID;
+        if (!templateID) templateID = 1;
+        let template = me.compiledTemplates[templateID];
+        $treeNode.data.calcTemplate = template;
 
 
         if ($treeNode && template.hasCompiled) {
         if ($treeNode && template.hasCompiled) {
             let $CE = executeObj;
             let $CE = executeObj;
             $CE.treeNode = $treeNode;
             $CE.treeNode = $treeNode;
+            $CE.template = template;
+            $CE.calcBase = me.compiledCalcBases;
 
 
             if (!$treeNode.fees) {
             if (!$treeNode.fees) {
                 $treeNode.fees = [];
                 $treeNode.fees = [];
@@ -175,13 +206,10 @@ class Calculation {
             for (let idx of template.compiledSeq) {
             for (let idx of template.compiledSeq) {
                 let calcItem = template.calcItems[idx];
                 let calcItem = template.calcItems[idx];
 
 
-                let feeRate = 100;    // 100%
-                // 下面三项用于界面显示。
-                if (calcItem.feeRateID) {
-                    feeRate = me.compiledFeeRate["feeRate_" + calcItem.feeRateID].rate;
-                    calcItem.feeRate = feeRate;
-                };
+                let feeRate = calcItem.feeRate;
+                if (!feeRate) feeRate = 100;    // 100%
                 calcItem.unitFee = eval(calcItem.compiledExpr) * feeRate * 0.01;   // 如果eval()对清单树有影响,就换成小麦的Expression对象再试
                 calcItem.unitFee = eval(calcItem.compiledExpr) * feeRate * 0.01;   // 如果eval()对清单树有影响,就换成小麦的Expression对象再试
+
                 let quantity = $treeNode.data.quantity;
                 let quantity = $treeNode.data.quantity;
                 if (!quantity) quantity = 0;
                 if (!quantity) quantity = 0;
                 calcItem.totalFee = calcItem.unitFee * quantity;
                 calcItem.totalFee = calcItem.unitFee * quantity;

+ 1 - 1
public/models/delete_schema.js

@@ -5,7 +5,7 @@
 var mongoose = require("mongoose");
 var mongoose = require("mongoose");
 var Schema = mongoose.Schema;
 var Schema = mongoose.Schema;
 
 
-// ·ÑÓÃ×Ö¶Î
+
 var deleteSchema = new Schema({
 var deleteSchema = new Schema({
     deleted: Boolean,
     deleted: Boolean,
     deleteDateTime: Date,
     deleteDateTime: Date,

+ 10 - 0
public/web/tree_sheet/tree_sheet_helper.js

@@ -3,6 +3,16 @@
  */
  */
 
 
 var TREE_SHEET_HELPER = {
 var TREE_SHEET_HELPER = {
+    createNewSpread: function (obj) {
+        var spread = new GC.Spread.Sheets.Workbook(obj, {sheetCount: 1});
+        spread.options.tabStripVisible = false;
+        spread.options.scrollbarMaxAlign = true;
+        spread.options.cutCopyIndicatorVisible = false;
+        spread.options.allowCopyPasteExcelStyle = false;
+        spread.options.allowUserDragDrop = false;
+        spread.getActiveSheet().setRowCount(3);
+        return spread;
+    },
     getSheetCellStyle: function (setting) {
     getSheetCellStyle: function (setting) {
         var style = new GC.Spread.Sheets.Style();
         var style = new GC.Spread.Sheets.Style();
         //style.locked = setting.readOnly ? true : false;
         //style.locked = setting.readOnly ? true : false;

+ 2 - 2
server.js

@@ -3,8 +3,8 @@ let express = require('express');
 let config = require("./config/config.js");
 let config = require("./config/config.js");
 let fileUtils = require("./modules/common/fileUtils");
 let fileUtils = require("./modules/common/fileUtils");
 let dbm = require("./config/db/db_manager");
 let dbm = require("./config/db/db_manager");
-//config.setToLocalDb();
-config.setToQaDb();
+///config.setToLocalDb();
+config.setupDb(process.env.NODE_ENV);
 
 
 let path = require('path');
 let path = require('path');
 let session = require('express-session');
 let session = require('express-session');

+ 3 - 4
test/tmp_data/test_ration_calc/ration_calc_base.js

@@ -85,13 +85,12 @@ let rationCalcBase = [
     }
     }
 ];
 ];
 
 
+// 该方法暂时不用,已使用中文预编译的方式代替,但可靠性有待验证,若有问题再用回来。
 function getRationCalcBase(dispName){
 function getRationCalcBase(dispName){
-    let rst = null;
     for (let base of rationCalcBase) {
     for (let base of rationCalcBase) {
        if (base.dispName == dispName) {
        if (base.dispName == dispName) {
-           rst = base;
-           break;
+           return base;
        };
        };
     }
     }
-    return rst;
+    return null;
 };
 };

+ 321 - 0
web/building_saas/complementary_glj_lib/html/tools-gongliaoji.html

@@ -0,0 +1,321 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>工料机库编辑-Smartcost</title>
+    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css" type="text/css">
+    <link rel="stylesheet" href="/web/building_saas/css/main.css" type="text/css">
+    <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css" type="text/css">
+    <link rel="stylesheet" href="/lib/jquery-contextmenu/jquery.contextMenu.css" type="text/css">
+    <!--zTree-->
+  	<link rel="stylesheet" href="/lib/ztree/css/zTreeStyle.css" type="text/css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013lightGray.10.0.1.css" type="text/css">
+    <style type="text/css">
+        .modal-lg{max-width: 1000px}
+    </style>
+</head>
+<body>
+    <div class="header">
+        <!-- <div class="top-msg clearfix">
+            <div class="alert alert-warning mb-0 py-0" role="alert">
+                <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                  <span aria-hidden="true">&times;</span>
+                </button>
+                <strong>Warning!</strong> Better check yourself, you're not looking too good.
+            </div>
+        </div> -->
+        <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 justify-content-between">
+            <span class="header-logo px-2">Smartcost</span>
+            <div class="navbar-text"><a href="/pm">项目管理</a></div>
+            <div class="float-lg-right navbar-text pt-0">
+                <div class="dropdown d-inline-block">
+                    <button class="btn btn-link btn-sm dropdown-toggle" type="button" data-toggle="dropdown">陈特</button>
+                    <div class="dropdown-menu dropdown-menu-right">
+                        <a class="dropdown-item" href="user-info.html" target="_blank">账号资料</a>
+                        <a class="dropdown-item" href="user-buy.html" target="_blank">产品购买</a>
+                        <a class="dropdown-item" href="user-set.html" target="_blank">偏好设置</a>
+                    </div>
+                </div>
+                <span class="btn btn-link btn-sm new-msg">
+                  <i class="fa fa-envelope-o" aria-hidden="true"></i>&nbsp;2
+                </span>
+                <button class="btn btn-link btn-sm">注销</button>
+            </div>
+        </nav>
+        <nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0">
+            <ul class="nav navbar-nav px-1">
+                <li class="nav-item">
+                    <a class="nav-link" href="#" aria-expanded="false"><i class="fa fa-sliders"></i> 选项</a>
+                </li>
+                <li class="nav-item dropdown">
+                    <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-wrench"></i> 工具</a>
+                    <div class="dropdown-menu">
+                        <a class="dropdown-item" href="#">定额库编辑器</a>
+                        <a class="dropdown-item" href="/complementaryGlj">工料机库编辑器</a>
+                    </div>
+                </li>
+                <li class="nav-item dropdown">
+                    <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-question-circle-o"></i> 帮助</a>
+                    <div class="dropdown-menu">
+                        <a class="dropdown-item" href="#">帮助</a>
+                        <a class="dropdown-item" href="#">升级说明</a>
+                        <a class="dropdown-item" href="#">重庆市2008定额说明</a>
+                        <a class="dropdown-item" href="#">纵横官网</a>
+                        <a class="dropdown-item" href="#">动画教程</a>
+                        <a class="dropdown-item" href="#">联系客服</a>
+                        <a class="dropdown-item" href="#">关于</a>
+                    </div>
+                </li>
+                <li class="nav-item">
+                    <a href="javacript:void(0);" data-toggle="modal" data-target="#history" class="nav-link"><i class="fa fa-history"></i> 历史记录</a>
+                </li>
+            </ul>
+            <form class="form-inline">
+                <input class="form-control form-control-sm mr-1" type="text" placeholder="告诉我你想做什么">
+            </form>
+        </nav>
+    </div>
+    <div class="main">
+        <div class="main-nav">
+            <ul class="nav flex-column">
+              <li><a href="#">定额库编辑器</a></li>
+              <li><a href="/complementaryGlj" class="active">工料机库编辑器</a></li>
+            </ul>
+        </div>
+        <div class="content">
+            <div class="container-fluid">
+              <div class="row">
+                <div class="col-lg-2 p-0">
+                  <div class="print-list">
+                    <div class="form-list">
+                      <ul id="repositoryTree" class="ztree"></ul>
+                    </div>
+                  </div>
+                </div>
+                <div id="GLJListSheet" class="col-lg-7 p-0">
+
+                </div>
+                <div id="gljComponentSheet" class="col-lg-3 p-0">
+                </div>
+              </div>
+            </div>
+        </div>
+      </div>
+      <!--弹出组成物-->
+    <button id="componentBtn" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#component" style="display: none"></button>
+      <div class="modal fade" id="component" data-backdrop="static">
+          <div class="modal-dialog modal-lg" role="document" id="modalCon">
+              <div class="modal-content" >
+                  <div class="modal-header">
+                    <h5 class="modal-title">内容</h5>
+                      <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">&times;</span>
+                      </button>
+                  </div>
+                  <div class="modal-body">
+                    <div class="row">
+                      <div class="col-4">
+                        <div  class="modal-auto-height">
+                            <div class="print-list">
+                                <div class="form-list" id="componentTreeDiv">
+                                    <ul id="componentTree" class="ztree"></ul>
+                                </div>
+                            </div>
+                        </div>
+                      </div>
+                      <div class="col-8">
+                          <div class="row">
+                              <div class="modal-auto-height col-12" id="gljRadios">
+                                  <input type="radio" class="glj-radio" name="glj" value="allGljs">所有工料机&nbsp;&nbsp;
+                                  <input type="radio" class="glj-radio" name="glj" value="stdGljs">标准工料机&nbsp;&nbsp;
+                                  <input type="radio" class="glj-radio" name="glj" value="complementaryGljs">补充工料机&nbsp;&nbsp;
+                                  <input type="radio" class="glj-radio" name="glj" value="selectedGljs">已选工料机机&nbsp;&nbsp;
+                                 <!-- <div class="form-group"><input id="searchGlj" type="text" class="form-control-sm" placeholder="查询工料机"></div>-->
+                              </div>
+                              <div class="modal-auto-height col-12"  id="componentSheet">
+                               <!--   <table class="table table-sm table-bordered m-0">
+                                      <thead>
+                                      <tr><th></th><th>编码</th><th>名称</th><th>规格型号</th><th>计量单位</th><th>单价</th><th>类型</th></tr>
+                                      </thead>
+                                      <tbody>
+                                      <tr><td>1</td><td></td><td></td><td></td><td></td><td></td></tr>
+                                      <tr><td>2</td><td></td><td></td><td></td><td></td><td></td></tr>
+                                      <tr><td>3</td><td></td><td></td><td></td><td></td><td></td></tr>
+                                      <tr><td>4</td><td></td><td></td><td></td><td></td><td></td></tr>
+                                      </tbody>
+                                  </table>-->
+                              </div>
+                          </div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="modal-footer">
+                      <button type="button" id="componentsCacnel" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                      <a href="javascript:void(0);" id="componentsConf" class="btn btn-primary">确定</a>
+                  </div>
+              </div>
+          </div>
+      </div>
+    <!--弹出警告-->
+    <button id="gljAlertBtn" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#gljAlert" style="display: none"></button>
+    <button id="codeAlertBtn" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#codeAlert" style="display: none"></button>
+    <div class="modal fade" id="gljAlert" data-backdrop="static" style="display: none;" aria-hidden="true">
+        <input type="hidden" id="gdid" value="123">
+        <div class="modal-dialog" role="document" style="width: 1200px;">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">取消确认</h5>
+                    <button type="button" id="gljAleClose" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">×</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <h5 class="text-danger" id="alertGljTxt">编号和类型不可为空!是否取消操作?</h5>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" id="aleCanceBtn" data-dismiss="modal">取消</button>
+                    <a href="javascript: void(0);" id="aleConfBtn" class="btn btn-danger" data-dismiss="modal">确认</a>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="modal" id="codeAlert" data-backdrop="static" style="display: none;" aria-hidden="true">
+        <input type="hidden" id="codedid" value="123">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">警告</h5>
+                    <button type="button" id="codAleClose" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">×</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <h5 class="text-danger" id="alertText">输入的编号已存在,请重新输入!</h5>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-danger" id="codAleConfBtn" data-dismiss="modal">确认</button>
+                </div>
+            </div>
+        </div>
+    </div>
+    <!-- JS. -->
+    <script src="/lib/jquery/jquery.min.js"></script>
+    <script src="/lib/jquery-contextmenu/jquery.contextMenu.min.js"></script>
+    <script src="/lib/jquery-contextmenu/jquery.ui.position.js"></script>
+    <script src="/lib/tether/tether.min.js"></script>
+    <script src="/lib/bootstrap/bootstrap.min.js"></script>
+    <script src="/web/building_saas/js/global.js"></script>
+    <!-- zTree -->
+    <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 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/treeDataHelper.js"></script>
+    <script type="text/javascript" src="/public/web/QueryParam.js"></script>
+    <script type="text/javascript" src="/web/building_saas/complementary_glj_lib/js/glj.js"></script>
+    <script type="text/javascript" src="/web/building_saas/complementary_glj_lib/js/gljComponent.js"></script>
+    <script type="text/javascript" src="/web/building_saas/complementary_glj_lib/js/components.js"></script>
+    <script type="text/javascript" src="/public/web/ztree_common.js"></script>
+    <script type="text/javascript" src="/web/building_saas/complementary_glj_lib/js/sheetOpr.js"></script>
+    <script type="text/javascript" src="/public/web/storageUtil.js"></script>
+    <SCRIPT type="text/javascript">
+        let userId = "<%= userID%>";
+        let compilationId = "<%= compilationId%>";
+        let stdGljLibId = "<%= gljLibId%>";//用户当前编办下的标准工料机库ID,目前认为一个编办只有一个标准工料机库
+        let gljSetting = {
+            view: {
+                //addHoverDom: gljTypeTreeOprObj.addHoverDom,
+                //removeHoverDom: gljTypeTreeOprObj.removeHoverDom,
+                expandSpeed: "",
+                selectedMulti: false
+            },
+            edit: {
+                enable: false,
+                editNameSelectAll: true,
+                showRemoveBtn: true,
+                showRenameBtn: true,
+                removeTitle: "删除节点",
+                renameTitle: "更改名称"
+            },
+            data: {
+                keep: {
+                    parent:true,
+                    leaf:true
+                },
+                key: {
+                    children: "items",
+                    name: "Name"
+                },
+                simpleData: {
+                    enable: false,
+                    idKey: "ID",
+                    pIdKey: "ParentID",
+                    rootPId: -1
+                }
+            },
+            callback:{
+                onClick: gljTypeTreeOprObj.onClick
+            }
+        };
+        //组成物弹出窗口组成物分类树
+        let componentSetting = {
+            view: {
+                //addHoverDom: gljTypeTreeOprObj.addHoverDom,
+                //removeHoverDom: gljTypeTreeOprObj.removeHoverDom,
+                expandSpeed: "",
+                selectedMulti: false
+            },
+            edit: {
+                enable: false,
+                editNameSelectAll: true,
+                showRemoveBtn: true,
+                showRenameBtn: true,
+                removeTitle: "删除节点",
+                renameTitle: "更改名称"
+            },
+            data: {
+                keep: {
+                    parent:true,
+                    leaf:true
+                },
+                key: {
+                    children: "items",
+                    name: "Name"
+                },
+                simpleData: {
+                    enable: false,
+                    idKey: "ID",
+                    pIdKey: "ParentID",
+                    rootPId: -1
+                }
+            },
+            callback:{
+                onClick: componentTypeTreeOprObj.onClick
+            }
+        };
+        $(document).ready(function(){
+            //解决spreadjs sheet初始化没高度宽度
+            $('#modalCon').width($(window).width()*0.5);
+            $('#componentTreeDiv').height($(window).height() - 300);
+            $("#componentSheet").height($("#componentTreeDiv").height()-21.6);
+            $("#componentSheet").width($('#modalCon').width() * 0.63);
+            pageOprObj.initPage($("#GLJListSheet")[0], $('#gljComponentSheet')[0], $("#componentSheet")[0]);
+        });
+        //组成物弹出窗大小设置
+        $(window).resize(function () {
+            $('#modalCon').width($(window).width()*0.5);
+            $('#componentTreeDiv').height($(window).height() - 300);
+            $("#componentSheet").height($("#componentTreeDiv").height()-21.6);
+            $("#componentSheet").width($('#modalCon').width()* 0.63);
+        });
+  	</SCRIPT>
+</body>
+<script type="text/javascript">
+    autoFlashHeight();
+</script>
+
+</html>

+ 296 - 0
web/building_saas/complementary_glj_lib/js/components.js

@@ -0,0 +1,296 @@
+/**
+ * Created by Zhong on 2017/8/25.
+ */
+/*
+   弹出组成物窗口 组成物表
+ * */
+let componentOprObj = {
+    treeObj:null,
+    rootNode: null,//分类树根节点
+    radiosSelected: null,//allGljs, stdGljs, complementaryGljs
+    workBook: null,
+    selectedList: [],//选中的组成物
+    setting: {
+        owner: "components",
+        header: [
+            {headerName:"选择", headerWidth: 40, dataCode: "select", hAlign: "center", vAlign: "center"},
+            {headerName:"编码",headerWidth:80,dataCode:"code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
+            {headerName:"名称",headerWidth:120,dataCode:"name", dataType: "String", hAlign: "left", vAlign: "center"},
+            {headerName:"规格型号",headerWidth:80,dataCode:"specs", dataType: "String", hAlign: "center", vAlign: "center"},
+            {headerName:"计量单位",headerWidth:80,dataCode:"unit", dataType: "String", hAlign: "center", vAlign: "center"},
+            {headerName:"单价",headerWidth:80,dataCode:"basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center"},
+            {headerName:"类型",headerWidth:80,dataCode:"gljType", dataType: "String",  hAlign: "center", vAlign: "center"}
+        ],
+        view: {
+            lockedCells: [1, 2, 3]
+        }
+    },
+    buildSheet: function (container) {
+        let me = componentOprObj;
+        me.workBook = sheetOpr.buildSheet(container, me.setting, 30);
+        me.workBook.getSheet(0).setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader);
+        me.workBook.getSheet(0).setFormatter(-1, 1, "@", GC.Spread.Sheets.SheetArea.viewport);
+        me.workBook.getSheet(0).options.isProtected = true;
+        me.workBook.bind(GC.Spread.Sheets.Events.ButtonClicked, me.onButtonClicked);//复选框点击事件
+        //sheetOpr.cleanSheet(me.workBook.getSheet(0), me.setting, -1);
+        me.componentsBtnOpr($('#componentsConf'));
+        me.radiosChange();
+        //me.searchChange();
+    },
+    onButtonClicked: function (sender, args) {
+        let me = componentOprObj, re = repositoryGljObj;
+        let val = args.sheet.getValue(args.row, args.col);
+        let thisComponent = me.currentCache[args.row];
+        thisComponent.isChecked = val;
+        console.log(val);
+        if(args.sheet.isEditing()){
+            args.sheet.endEdit(true);
+        }
+        else{
+            //维护选中组成物列表
+            if(val === true){
+                //解决复选框编辑状态的暂时方法todo
+                let isExist = false;
+                for(let i = 0, len = me.selectedList.length; i < len; i++){
+                    if(me.selectedList[i].ID === thisComponent.ID){
+                        isExist = true;
+                        break;
+                    }
+                }
+                if(!isExist){
+                    me.selectedList.push(thisComponent);
+                }
+            }
+            else if(val === false){
+                for(let i = 0, len = me.selectedList.length; i < len; i++){
+                    if(me.selectedList[i].ID === thisComponent.ID){
+                        me.selectedList.splice(i, 1);
+                        break;
+                    }
+                }
+                if($("input[name='glj']:checked").val() === 'selectedGljs'){//radio为已选工料机时
+                    me.showGljList = [];
+                    me.setShowGljList(me.selectedList, false);
+                    re.sortGlj(me.showGljList);
+                    //重新显示
+                    me.showGljItems(me.showGljList, me.gljCurTypeId);
+                    if (re.parentNodeIds["_pNodeId_" + me.gljCurTypeId]) {//更新cache
+                        me.currentOprParent = 1;
+                        me.currentCache = me.getParentCache(re.parentNodeIds["_pNodeId_" + me.gljCurTypeId]);
+                    } else {
+                        me.currentCache = me.getCache();
+                    }
+                }
+            }
+        }
+    },
+    setShowGljList: function (gljList, clearChecked) {
+        //初始为所有工料机,机械类型可添加机械组成物,混凝土,砂浆、配合比可添加普通材料
+        let materialArr = [202, 203, 204];//混凝土、砂浆、配合比, 201普通材料
+        let that = repositoryGljObj, me = componentOprObj;
+            for(let i = 0; i < gljList.length; i++){
+                if(that.currentGlj.gljType === 3 && gljList[i].gljType === 302 ||
+                    materialArr.indexOf(that.currentGlj.gljType) !== -1 && gljList[i].gljType === 201){
+                    //去除与已添加的组成物重复的条目
+                    let isExist = false;
+                    for(let j = 0; j < that.currentComponent.length; j++){
+                        if(that.currentComponent[j].ID === gljList[i].ID){
+                            isExist = true;
+                            break;
+                        }
+                    }
+                    if(!isExist){
+                        if(clearChecked){
+                            gljList[i].isChecked = false;//切换的时候清空选择
+                        }
+                       /* if(isSelected){//已选择工料机显示
+                            if(gljList[i].isChecked === true){
+                                me.showGljList.push(gljList[i]);
+                            }
+                        }*/
+                   //     else{
+                            me.showGljList.push(gljList[i]);
+                      //  }
+                    }
+                }
+            }
+    },
+    //初始默认radio
+    initRadio: function () {
+        let that = repositoryGljObj, me = componentOprObj;
+        $('#searchGlj').val('');//恢复搜索文本
+        //初始化组成物列表
+        me.selectedList = [];
+        //默认radio所有工料机
+        if(typeof $("input[name='glj']:checked")[0] !== 'undefined'){
+            $("input[name='glj']:checked")[0].checked = false;
+        }
+        $("input[value = 'allGljs']")[0].checked = true;
+        me.radiosSelected = 'allGljs';
+        //初始为所有工料机,机械类型可添加机械组成物,混凝土,砂浆、配合比可添加普通材料
+        me.showGljList = [];
+        if(me.radiosSelected === 'allGljs'){
+            me.setShowGljList(that.stdGljList, true);
+            me.setShowGljList(that.complementaryGljList, true);
+            that.sortGlj(me.showGljList);
+        }
+    },
+    //监听radios选择事件
+    radiosChange: function () {
+        let me = componentOprObj, re = repositoryGljObj;
+        let materialArr = [202, 203, 204];//混凝土、砂浆、配合比, 201普通材料
+        $('.glj-radio').change(function () {
+            let val = $("input[name='glj']:checked").val();
+            me.radiosSelected = val;
+            //选择改变,数据重新筛选显示
+            //清空选中的组成物列表
+            //me.selectedList = [];
+            me.showGljList = [];
+            if(me.radiosSelected === 'allGljs'){
+                me.setShowGljList(re.stdGljList);
+                me.setShowGljList(re.complementaryGljList);
+            }
+            else if(me.radiosSelected === 'stdGljs'){
+               me.setShowGljList(re.stdGljList);
+            }
+            else if(me.radiosSelected === 'complementaryGljs'){
+                me.setShowGljList(re.complementaryGljList);
+            }
+            else if(me.radiosSelected === 'selectedGljs'){
+                /*me.setShowGljList(re.stdGljList, false, true);
+                me.setShowGljList(re.complementaryGljList, false, true);*/
+                me.setShowGljList(me.selectedList, false);
+            }
+            re.sortGlj(me.showGljList);
+            //重新显示
+            me.showGljItems(me.showGljList, me.gljCurTypeId);
+            //切换radio后更新cache
+            if (me.currentOprParent = 1) {
+                if(re.parentNodeIds["_pNodeId_" + me.gljCurTypeId]){
+                    me.currentCache = me.getParentCache(re.parentNodeIds["_pNodeId_" + me.gljCurTypeId]);
+                }
+                else{
+                    me.currentCache = [];
+                }
+            } else {
+                me.currentCache = me.getCache();
+            }
+        });
+    },
+    //实时模糊搜索
+    searchChange: function () {
+        let me = componentOprObj, re = repositoryGljObj;
+        let interval = null;
+        function search(){
+            console.log($('#searchGlj').val());
+        }
+        $('#searchGlj').focus(function () {
+            interval = setInterval(search, 500);
+        }).blur(function () {
+            clearInterval(interval);
+        });
+    },
+  /*  //切换分类树时,记住当前分类的选择, value = true、false、null
+    setComponentChecked: function (sheet) {
+        let me = componentOprObj;
+        for(let i = 0; i < sheet.getRowCount(); i ++){
+            if(sheet.getValue(i, 0) === true){//选择了
+                me.preCache[i].isChecked = true;
+            }
+            else if(sheet.getValue(i, 0) === false){//避免value为null
+                me.preCache[i].isChecked = false;
+            }
+        }
+    },*/
+    //获得选择的组成物
+    getComponents: function () {
+        let rst = [];
+        let me = componentOprObj;
+        for(let i = 0; i < me.showGljList.length; i++){
+
+        }
+    },
+    getParentCache: function (nodes) {
+        let me = componentOprObj, rst = [];
+        for(let i = 0; i < me.showGljList.length; i++){
+            if(nodes.indexOf(me.showGljList[i].gljClass) !== -1){
+                rst.push(me.showGljList[i]);
+            }
+        }
+        rst.sort(function (a, b) {
+            let rst = 0;
+            if(a.code > b.code) rst = 1;
+            else if(a.code < b.code)rst = -1;
+            return rst;
+        });
+        return rst;
+    },
+    getCache: function() {
+        let me = componentOprObj, rst = [];
+        for (let i = 0; i < me.showGljList.length; i++) {
+            if (me.showGljList[i].gljClass == me.gljCurTypeId) {
+                rst.push(me.showGljList[i]);
+            }
+        }
+        return rst;
+    },
+    showGljItems: function(data, type) {
+        let me = componentOprObj, re = repositoryGljObj;
+        if (me.workBook) {
+            let cacheSection = [];
+            let pArr = re.parentNodeIds["_pNodeId_" + type];
+            for (let i = 0; i < data.length; i++) {
+                if (pArr && pArr.indexOf(data[i].gljClass) >= 0) {
+                    cacheSection.push(data[i]);
+                } else if (type == data[i].gljClass) {
+                    cacheSection.push(data[i]);
+                }
+            }
+            sheetOpr.cleanSheet(me.workBook.getSheet(0), me.setting, -1);
+            sheetOpr.showData(me.workBook.getSheet(0), me.setting, cacheSection, re.distTypeTree);
+            cacheSection = null;
+        }
+    },
+    //组成物窗口按钮操作
+    componentsBtnOpr: function (conf) {//确定、取消、关闭按钮
+        let me = componentOprObj, that = gljComponentOprObj, re = repositoryGljObj;
+        conf.click(function () {
+           //添加选择添加的组成物
+            let updateArr = [];
+            if(me.selectedList.length > 0){
+                for(let i = 0, len = me.selectedList.length; i < len; i++){
+                    re.currentGlj.component.push({ID: me.selectedList[i].ID, consumeAmt: 0});
+                }
+                updateArr.push(re.currentGlj);
+                that.updateComponent(updateArr);
+            }
+
+        });
+    }
+};
+
+let componentTypeTreeOprObj = {
+    onClick: function(event,treeId,treeNode) {
+        let me = componentOprObj, re = repositoryGljObj, that = gljComponentOprObj, gljTypeId = treeNode.ID;
+        if(me.gljCurTypeId !== treeNode.ID){
+            me.gljCurTypeId = treeNode.ID;
+            if (re.parentNodeIds["_pNodeId_" + treeNode.ID]) {
+                me.currentOprParent = 1;
+                me.currentCache = me.getParentCache(re.parentNodeIds["_pNodeId_" + treeNode.ID]);
+            } else {
+                me.currentCache = me.getCache();
+            }
+            //切换分类树时,记住当前分类的选择
+            //me.setComponentChecked(me.workBook.getSheet(0));
+        }
+        me.showGljItems(me.showGljList, gljTypeId);
+        /*sheetOpr.cleanSheet(that.workBook.getSheet(0), that.setting, 5);
+         that.workBook.getSheet(0).getRange(-1, 0 , -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+         that.workBook.getSheet(0).getRange(-1, 4 , -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+         re.workBook.getSheet(0).getRange(-1, 6 , -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);*/
+        //that.workBook.getSheet(0).options.isProtected = true;
+
+        //sheetOpr.lockCodeCells(re.workBook.getSheet(0), re.currentCache.length);
+        //re.workBook.getSheet(0).setRowCount(re.currentCache.length);
+    }
+}

文件差异内容过多而无法显示
+ 1073 - 0
web/building_saas/complementary_glj_lib/js/glj.js


+ 497 - 0
web/building_saas/complementary_glj_lib/js/gljComponent.js

@@ -0,0 +1,497 @@
+/**
+ * Created by Zhong on 2017/8/15.
+ */
+
+let gljComponentOprObj = {
+    workBook: null,
+    setting: {
+        owner: "gljComponent",
+        header:[
+            {headerName:"编码",headerWidth:80,dataCode:"code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
+            {headerName:"名称",headerWidth:110,dataCode:"name", dataType: "String", hAlign: "left", vAlign: "center"},
+            {headerName:"计量单位",headerWidth:80,dataCode:"unit", dataType: "String", hAlign: "center", vAlign: "center"},
+            {headerName:"单价",headerWidth:80,dataCode:"basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center"},
+            {headerName:"消耗量",headerWidth:80,dataCode:"consumeAmt", dataType: "Number", formatter: "0.000", hAlign: "right", vAlign: "center"}
+        ],
+        view: {
+            lockedCells:[0, 1, 2, 3]
+        }
+    },
+    buildSheet: function(container) {
+        let me = gljComponentOprObj;
+        me.workBook = sheetOpr.buildSheet(container, me.setting, 30);
+        me.workBook.getSheet(0).setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader);
+        me.workBook.getSheet(0).setFormatter(-1, 0, "@", GC.Spread.Sheets.SheetArea.viewport);
+        me.workBook.getSheet(0).options.isProtected = true;
+        sheetOpr.cleanSheet(me.workBook.getSheet(0), me.setting, -1);
+
+        me.onContextmenuOpr();//右键菜单
+        me.gljComponentDelOpr();
+        me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.EditStarting, me.onCellEditStart);
+        me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.EditEnded, me.onCellEditEnd);
+        me.workBook.bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
+        me.workBook.bind(GC.Spread.Sheets.Events.ClipboardPasted, me.onClipboardPasted);
+        /*me.gljComponentDelOpr();
+        me.workBook.bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
+        me.workBook.bind(GC.Spread.Sheets.Events.ClipboardPasted, me.onClipboardPasted);
+        me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.EditStarting, me.onCellEditStart);
+        me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.EditEnded, me.onCellEditEnd);*/
+
+    },
+    getRowData: function (sheet, row, setting) {
+        let rst = {};
+        for(let i = 0; i < setting.header.length; i++){
+            rst[setting.header[i].dataCode] = sheet.getValue(row, i);
+        }
+        return rst;
+    },
+    getComponent: function (sheet, rowCount) {
+        let component = [];
+        for(let row = 0; row < rowCount; row++){
+            let obj = {};
+            obj.consumeAmt = sheet.getValue(row, 4);
+            obj.ID = sheet.getTag(row, 0);
+            component.push(obj);
+        }
+        return component;
+    },
+    onContextmenuOpr: function () {
+        let me = gljComponentOprObj, that = repositoryGljObj, co = componentOprObj;
+        $.contextMenu({
+            selector: '#gljComponentSheet',
+            build: function($triggerElement, e){
+                //控制允许右键菜单在哪个位置出现
+                let clientX = e.originalEvent.clientX,
+                    clientY = e.originalEvent.clientY;
+                let sheet = me.workBook.getSheet(0);
+                let offset = $("#gljComponentSheet").offset(),
+                    x = clientX - offset.left,
+                    y = clientY - offset.top;
+                let target = sheet.hitTest(x, y);
+                if(target.hitTestType === 3 && typeof target.row !== 'undefined' && typeof target.col !== 'undefined'){//在表格内
+                    sheet.setActiveCell(target.row, target.col);
+                    //控制按钮是否可用
+                    let insertDis = false,
+                        delDis = false;
+                    if(me.isLocked){
+                        insertDis = true;
+                        delDis = true;
+                    }
+                    if(typeof that.currentComponent !== 'undefined' && target.row >= that.currentComponent.length){//右键定位在有组成物的行,删除键才显示可用
+                        delDis = true;
+                    }
+                    return {
+                        callback: function(){},
+                        items: {
+                            "insert": {name: "插入", disabled: insertDis, callback: function (key, opt) {
+                                //默认radio所有工料机
+                                co.initRadio();
+                                co.gljCurTypeId = null;
+                                //默认点击树根节点
+                                if(co.rootNode){
+                                    co.treeObj.selectNode(co.rootNode);
+                                    componentTypeTreeOprObj.onClick(null, 'componentTree', co.rootNode);
+                                }
+                                //弹出窗口
+                                $('#componentBtn').click();
+                            }},
+                            "delete": {name: "删除", disabled: delDis, callback: function (key, opt) {
+                                //删除
+                                let deleteObj = that.currentComponent[target.row];
+                                let gljComponent = that.currentGlj.component;
+                                let updateArr = [];
+                                //更新当前工料机的组成物列表
+                                for(let i = 0, len = gljComponent.length; i < len; i++){
+                                    if(gljComponent[i].ID === deleteObj.ID){
+                                        gljComponent.splice(i, 1);
+                                        break;
+                                    }
+                                }
+                                //重新计算工料机
+                                let gljBasePrc = me.reCalGljBasePrc(that.getCurrentComponent(gljComponent));
+                                if(gljBasePrc !== that.currentGlj.basePrice){
+                                    that.currentGlj.basePrice = gljBasePrc;
+                                    that.reshowGljBasePrc(that.currentGlj);
+                                    //updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
+                                }
+                                updateArr.push(that.currentGlj);
+                                me.updateComponent(updateArr);
+                            }}
+                        }
+                    };
+                }
+                else{
+                    return false;
+                }
+            }
+        });
+    },
+    gljComponentDelOpr: function () {
+        let me = gljComponentOprObj, that = repositoryGljObj, updateArr = [], removeArr = [], isUpdate = false, updateBasePrc= [];
+        me.workBook.commandManager().register('gljComponentDel', function () {
+            let sels = me.workBook.getSheet(0).getSelections();
+            if(sels.length > 0 && that.currentComponent.length > 0){
+                let component = that.currentGlj.component;
+                for(let i = 0; i < sels.length > 0; i++){
+                    if(sels[i].colCount === me.setting.header.length){//可删除
+                        for(let j = 0; j < sels[i].rowCount; j++){
+                            if(sels[i].row + j < that.currentComponent.length){
+                                removeArr.push(that.currentComponent[sels[i].row + j].ID);
+
+                            }
+                        }
+                    }
+                    else if(sels[i].col === 0){
+                            //编码不可为空
+                            alert("编码不可为空!");
+
+                    }
+                    else if(sels[i].col === 4){//消耗量修改为0
+                        if(sels[i].row === -1){//全修改
+                           for(let j = 0; j < that.currentComponent.length; j++){
+                               isUpdate = true;
+                               that.currentComponent[j].consumeAmt = 0;
+                               for(let k = 0; k < component.length; k++){
+                                   if(component[k].ID === that.currentComponent[j].ID){
+                                       component[k].consumeAmt = 0;
+                                       break;
+                                   }
+                               }
+                           }
+                        }
+                        else{//部分修改
+                            for(let j = 0; j < sels[i].rowCount; j++){
+                                if(sels[i].row + j < that.currentComponent.length){
+                                    isUpdate = true;
+                                    that.currentComponent[sels[i].row + j].consumeAmt = 0;
+                                    for(let k = 0; k < component.length; k++){
+                                        if(component[k].ID === that.currentComponent[sels[i].row + j].ID){
+                                            component[k].consumeAmt = 0;
+                                            break;
+                                        }
+                                    }
+
+                                }
+                            }
+                        }
+                    }
+                }
+                if(removeArr.length > 0 || isUpdate){
+                    for(let i = 0; i < removeArr.length; i++){
+                        for(let j = 0; j < that.currentComponent.length; j++){
+                            if(that.currentComponent[j].ID === removeArr[i]){
+                                that.currentComponent.splice(j--, 1);
+                            }
+                        }
+                        for(let j = 0; j < component.length; j++){
+                            if(component[j].ID === removeArr[i]){
+                                component.splice(j--, 1);
+                            }
+                        }
+                    }
+                    //重新计算工料机
+                    let gljBasePrc = me.reCalGljBasePrc(that.currentComponent);
+                    if(gljBasePrc !== that.currentGlj.basePrice){
+                        that.currentGlj.basePrice = gljBasePrc;
+                        that.reshowGljBasePrc(that.currentGlj);
+                        updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
+                    }
+                    updateArr.push(that.currentGlj);
+                    me.updateComponent(updateArr);
+                    if(updateBasePrc.length > 0){
+                        that.updateRationBasePrcRq(updateBasePrc);
+                    }
+                }
+            }
+        });
+        me.workBook.commandManager().setShortcutKey(null, GC.Spread.Commands.Key.del, false, false, false, false);
+        //me.workBook.commandManager().setShortcutKey('gljComponentDel', GC.Spread.Commands.Key.del, false, false, false, false);
+    },
+    onCellEditStart: function(sender, args) {
+        let me = gljComponentOprObj, that = repositoryGljObj;
+        let rObj = me.getRowData(args.sheet, args.row, me.setting);
+        me.currentEditingComponent = rObj;
+    },
+    onCellEditEnd: function (sender, args) {
+        let me = gljComponentOprObj, that = repositoryGljObj, updateBasePrc = [];
+        let gljList = that.gljList, updateArr = [], materialComponent = [202, 203, 204], machineComponent = [302, 303];
+        // if(args.editingText !== me.currentEditingComponent.code){
+        //编码
+      /*  if(args.col === 0 && args.editingText && args.editingText.trim().length > 0 &&args.editingText !== me.currentEditingComponent.code){
+            let component = that.currentGlj.component, hasCode = false;
+            for(let i = 0; i < gljList.length; i++){
+                if(gljList[i].code === args.editingText){//有效的组成物
+                    hasCode = true;
+                    if((materialComponent.indexOf(that.currentGlj.gljType) !== -1 && gljList[i].gljType === 201)
+                        || (that.currentGlj.gljType === 301 && machineComponent.indexOf(gljList[i].gljType) !== -1 )){//普通材料
+                        //是否与原有组成物不同
+                        let isExist = false;
+                        for(let j = 0; j < component.length; j++){
+                            if(component[j].ID === gljList[i].ID){
+                                isExist = true;
+                                break;
+                            }
+                        }
+                        if(!isExist){
+                            let rObj = {};
+                            rObj.ID = gljList[i].ID;
+                            //rObj.basePrice = gljList[i].basePrice;
+                            if(typeof that.currentComponent[args.row] !== 'undefined'){
+                                rObj.consumeAmt = that.currentComponent[args.row].consumeAmt;
+                                let index;
+                                for(let j = 0; j < component.length; j++){
+                                    if(component[j].ID === that.currentComponent[args.row].ID){
+                                        index = j;
+                                        break;
+                                    }
+                                }
+                                component.splice(index, 1);
+                                component.splice(index, 0, rObj);
+                                //计算工料机单价
+                                let gljBasePrc = me.reCalGljBasePrc(that.getCurrentComponent(component));
+                                if(gljBasePrc !== that.currentGlj.basePrice){
+                                    that.currentGlj.basePrice = gljBasePrc;
+                                    that.reshowGljBasePrc(that.currentGlj);
+                                    //工料机单价改变,重算引用了该工料机的定额单价
+                                    updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
+                                }
+                                updateArr.push(that.currentGlj);
+                            }
+                            else{
+                                rObj.consumeAmt = 0;
+                                component.push(rObj);
+                                //计算工料机单价
+                                let gljBasePrc = me.reCalGljBasePrc(that.getCurrentComponent(component));
+                                if(gljBasePrc !== that.currentGlj.basePrice){
+                                    that.currentGlj.basePrice = gljBasePrc;
+                                    that.reshowGljBasePrc(that.currentGlj);
+                                    //工料机单价改变,重算引用了该工料机的定额单价
+                                    updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
+                                }
+                                updateArr.push(that.currentGlj);
+                            }
+                            break;
+                        }
+                        else{
+                            //已存在
+                            alert("已存在!");
+                            args.sheet.setValue(args.row, args.col, me.currentEditingComponent[me.setting.header[args.col].dataCode] ?
+                                me.currentEditingComponent[me.setting.header[args.col].dataCode]: '');
+                        }
+
+                    }
+                    else{
+                        if(materialComponent.indexOf(that.currentGlj.gljType) === 1){
+                            alert("该组成物只能是普通材料!");
+                        }
+                        else if(that.currentGlj.gljType === 301){
+                            alert("该组成物只能是机械组成物或机上人工!")
+                        }
+                        args.sheet.setValue(args.row, args.col, me.currentEditingComponent[me.setting.header[args.col].dataCode] ?
+                            me.currentEditingComponent[me.setting.header[args.col].dataCode]: '');
+                        //无效
+                    }
+                }
+            }
+            if(!hasCode){
+                alert("不存在此工料机,请先添加!");
+                args.sheet.setValue(args.row, args.col, me.currentEditingComponent[me.setting.header[args.col].dataCode] ?
+                    me.currentEditingComponent[me.setting.header[args.col].dataCode] : '');
+                //不存在
+            }
+        }*/
+         if(args.col === 4 && me.currentEditingComponent.code && args.editingText && args.editingText.trim().length > 0){//消耗量
+            let consumeAmt = parseFloat(args.editingText);
+            if(!isNaN(consumeAmt) && consumeAmt !== me.currentEditingComponent.consumeAmt){
+                let roundCons = me.round(consumeAmt, 3);
+                let component = that.currentGlj.component;
+                for(let i = 0; i < component.length; i++){
+                    if(component[i].ID === that.currentComponent[args.row].ID){
+                        component[i].consumeAmt = roundCons;
+                    }
+                }
+                that.currentComponent[args.row].consumeAmt = roundCons;
+                //计算工料机单价
+                let gljBasePrc = me.reCalGljBasePrc(that.currentComponent);
+                if(gljBasePrc !== that.currentGlj.basePrice){
+                    that.currentGlj.basePrice = gljBasePrc;
+                    that.reshowGljBasePrc(that.currentGlj);
+                    //工料机单价改变,重算引用了该工料机的定额单价
+                    //updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
+                }
+                updateArr.push(that.currentGlj);
+            }
+            else{
+                //只能输入数值
+                args.sheet.setValue(args.row, args.col, me.currentEditingComponent[me.setting.header[args.col].dataCode] ?
+                    me.currentEditingComponent[me.setting.header[args.col].dataCode]: 0);
+
+            }
+        }
+        else{
+            args.sheet.setValue(args.row, args.col, me.currentEditingComponent.consumeAmt);
+        }
+        if(updateArr.length > 0){
+            me.updateComponent(updateArr);
+            /*if(updateBasePrc.length > 0){
+                that.updateRationBasePrcRq(updateBasePrc)
+            }*/
+        }
+    },
+    onClipboardPasting: function (sender, info) {
+        let me = gljComponentOprObj;
+        let maxCol = info.cellRange.col + info.cellRange.colCount - 1;
+        //复制的列数超过正确的列数,不可复制
+        if(maxCol >= me.setting.header.length){
+            args.cancel = true;
+        }
+    },
+    onClipboardPasted: function (sender, info) {
+        let me = gljComponentOprObj, that = repositoryGljObj, updateArr = [] ,materialComponent = [202, 203, 204], machineComponent = [302, 303],
+            component = that.currentGlj.component, newComponent = [], concatComponent = [], isChange = false, updateBasePrc = [];
+        let items = sheetOpr.analyzePasteData(me.setting, info);
+        let gljCache = that.gljList;
+        //编码
+   /*     if(info.cellRange.col === 0){
+            for(let i = 0; i < items.length; i++){
+                for(let j = 0; j < gljCache.length; j++){
+                    if(items[i].code === gljCache[j].code){
+                        if((materialComponent.indexOf(that.currentGlj.gljType) !== -1 && gljCache[j].gljType === 201)
+                            || (that.currentGlj.gljType === 301 && machineComponent.indexOf(gljCache[j].gljType) !== -1 )){
+                            //是否与原有组成物不同
+                            let isExist = false;
+                            for(let k = 0; k < component.length; k++){
+                                if(component[k].ID === gljCache[j].ID){
+                                    isExist = true;
+                                    me.workBook.getSheet(0).setValue(info.cellRange.row + i, info.cellRange.col,
+                                        typeof that.currentComponent[info.cellRange.row + i] !== 'undefined'? that.currentComponent[info.cellRange.row + i].code : '');
+                                    break;
+                                }
+                            }
+                            if(!isExist){
+                                isChange = true;
+                                let obj = {};
+                                obj.ID = gljCache[j].ID;
+                                if(typeof that.currentComponent[info.cellRange.row + i] !== 'undefined'){//更新
+                                    obj.consumeAmt = that.currentComponent[info.cellRange.row + i].consumeAmt;
+                                    let index;
+                                    for(let k = 0; k < component.length; k++){
+                                        if(that.currentComponent[info.cellRange.row + i].ID === component[k].ID){
+                                            index = k;
+                                            break;
+                                        }
+                                    }
+                                    component.splice(index, 1);
+                                    component.splice(index, 0, obj);
+                                }
+                                else{//新增
+                                    obj.consumeAmt = 0;
+                                    component.push(obj);
+                                }
+                                break;
+                            }
+
+                        }
+                        else{
+                            me.workBook.getSheet(0).setValue(info.cellRange.row + i, info.cellRange.col,
+                            typeof that.currentComponent[info.cellRange.row + i] !== 'undefined'? that.currentComponent[info.cellRange.row + i].code : '');
+
+                        }
+
+                    }
+                    else{
+                        me.workBook.getSheet(0).setValue(info.cellRange.row + i, info.cellRange.col,
+                            typeof that.currentComponent[info.cellRange.row + i] !== 'undefined'? that.currentComponent[info.cellRange.row + i].code : '');
+                    }
+                }
+            }
+            if(isChange){
+                //计算工料机单价
+                let gljBasePrc = me.reCalGljBasePrc(that.getCurrentComponent(component));
+                if(gljBasePrc !== that.currentGlj.basePrice){
+                    that.currentGlj.basePrice = gljBasePrc;
+                    that.reshowGljBasePrc(that.currentGlj);
+                    updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
+                }
+                updateArr.push(that.currentGlj);
+            }
+        }*/
+        //消耗量
+         if(info.cellRange.col === 4){
+            let items = sheetOpr.analyzePasteData(me.setting, info);
+            let row = info.cellRange.row;
+            for(let i = 0; i < items.length; i++){
+                if(row + i < that.currentComponent.length){
+                    let currentObj = that.currentComponent[row + i];
+                    if(items[i].consumeAmt.trim().length > 0 && items[i].consumeAmt !== currentObj.consumeAmt){
+                        let roundCons = me.round(items[i].consumeAmt, 3);
+                        isChange = true;
+                        currentObj.consumeAmt = roundCons;
+                        for(let j = 0; j < component.length; j++){
+                            if(component[j].ID === currentObj.ID){
+                                component[j].consumeAmt = currentObj.consumeAmt;
+                                break;
+                            }
+                        }
+                    }
+                    else{
+                        me.workBook.getSheet(0).setValue(row + i, info.cellRange.col, currentObj.consumeAmt);
+                    }
+                }
+                else{
+                    me.workBook.getSheet(0).setValue(row + i, info.cellRange.col, '');
+                }
+            }
+            if(isChange){
+                //计算工料机单价
+                let gljBasePrc = me.reCalGljBasePrc(that.currentComponent);
+                if(gljBasePrc !== that.currentGlj.basePrice){
+                    that.currentGlj.basePrice = gljBasePrc;
+                    that.reshowGljBasePrc(that.currentGlj);
+                    //updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
+                }
+                updateArr.push(that.currentGlj);
+            }
+        }
+        if(updateArr.length > 0){
+            me.updateComponent(updateArr);
+           /* if(updateBasePrc.length > 0){
+                that.updateRationBasePrcRq(updateBasePrc);
+            }*/
+        }
+    },
+    updateComponent: function (updateArr) {
+        let me = gljComponentOprObj, that = repositoryGljObj;
+        $.ajax({
+            type: 'post',
+            url: 'complementartGlj/api/updateComponent',
+            data: {"userId": pageOprObj.userId, "updateArr": JSON.stringify(updateArr)},
+            dataType: 'json',
+            success: function (result) {
+                if(!result.error){
+                        that.currentComponent =  that.getCurrentComponent(result.data[0].component);
+                        sheetOpr.cleanSheet(me.workBook.getSheet(0), me.setting, -1);
+                        sheetOpr.showData(me.workBook.getSheet(0), me.setting, that.currentComponent);
+                }
+                else{
+                    sheetOpr.cleanSheet(me.workBook.getSheet(0), me.setting, -1);
+                }
+                $('#componentsCacnel').click();
+            }
+        })
+    },
+    round: function (v, e) {
+        let t=1;
+        for(;e>0;t*=10,e--);
+        for(;e<0;t/=10,e++);
+        return Math.round(v*t)/t;
+    },
+    reCalGljBasePrc: function (component) {
+        let me = gljComponentOprObj, gljBasePrc = 0;
+        for(let i = 0; i < component.length; i++){
+            let roundBasePrc = me.round(component[i].basePrice, 2);
+            gljBasePrc += me.round(roundBasePrc * component[i].consumeAmt, 2);
+        }
+        return gljBasePrc;
+    }
+};

+ 388 - 0
web/building_saas/complementary_glj_lib/js/sheetOpr.js

@@ -0,0 +1,388 @@
+/**
+ * Created by Zhong on 2017/8/24.
+ */
+let sheetOpr = {
+    createSpread: function(container, SheetCount){
+        var me = this;
+        var spreadBook = new GC.Spread.Sheets.Workbook(container, { sheetCount: SheetCount });
+        spreadBook.options.allowCopyPasteExcelStyle = false;
+        spreadBook.options.tabStripVisible = false;
+        spreadBook.options.showHorizontalScrollbar = false;
+        return spreadBook;
+    },
+
+    initSheet: function(sheet, setting, rowCount) {
+        var me = this;
+        var spreadNS = GC.Spread.Sheets;
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        sheet.setRowCount(1, spreadNS.SheetArea.colHeader);
+        sheet.setColumnCount(setting.header.length, spreadNS.SheetArea.viewport);
+        sheet.options.colHeaderAutoTextIndex = 1;
+        sheet.options.colHeaderAutoText = spreadNS.HeaderAutoText.numbers;
+        sheet.showRowOutline(false);
+        me.buildHeader(sheet, setting);
+        if (rowCount > 0) sheet.setRowCount(rowCount);
+        sheet.resumeEvent();
+        sheet.resumePaint();
+    },
+
+    buildSheet: function(container, setting, rowCount) {
+        var me = this;
+        var spreadBook = new GC.Spread.Sheets.Workbook(container, { sheetCount: 1 });
+        spreadBook.options.tabStripVisible = false;
+        spreadBook.options.showHorizontalScrollbar = false;
+        spreadBook.options.scrollbarMaxAlign = true;
+        spreadBook.options.allowCopyPasteExcelStyle = false;
+        spreadBook.options.allowExtendPasteRange = true;
+        var spreadNS = GC.Spread.Sheets;
+        var sheet = spreadBook.getSheet(0);
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        //Set rowHeader count and columnHeader count.
+        sheet.setRowCount(1, spreadNS.SheetArea.colHeader);
+        sheet.setColumnCount(setting.header.length, spreadNS.SheetArea.viewport);
+        sheet.options.colHeaderAutoTextIndex = 1;
+        sheet.options.colHeaderAutoText = spreadNS.HeaderAutoText.numbers;
+        sheet.showRowOutline(false);
+        //setup column header
+        me.buildHeader(sheet, setting);
+        //setup cells
+        if (rowCount > 0) sheet.setRowCount(rowCount);
+        sheet.resumeEvent();
+        sheet.resumePaint();
+        return spreadBook;
+    },
+    buildHeader: function(sheet, setting){
+        var me = this, ch = GC.Spread.Sheets.SheetArea.colHeader;
+        for (var i = 0; i < setting.header.length; i++) {
+            sheet.setValue(0, i, setting.header[i].headerName, ch);
+            sheet.setColumnWidth(i, setting.header[i].headerWidth?setting.header[i].headerWidth:100);
+        }
+    },
+    cleanSheet: function(sheet, setting, rowCount) {
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        sheet.clear(-1, 0, -1, setting.header.length, GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
+        if (rowCount > 0) sheet.setRowCount(rowCount);
+        sheet.clearSelection();
+        sheet.resumeEvent();
+        sheet.resumePaint();
+    },
+    setAreaAlign: function(area, hAlign, vAlign){
+        if (!(hAlign) || hAlign === "left") {
+            area.hAlign(GC.Spread.Sheets.HorizontalAlign.left);
+        } else if (hAlign === "right") {
+            area.hAlign(GC.Spread.Sheets.HorizontalAlign.right);
+        } else if (hAlign === "center") {
+            area.hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+        } else {
+            area.hAlign(GC.Spread.Sheets.HorizontalAlign.left);
+        }
+        if (!(vAlign) || vAlign === "center") {
+            area.vAlign(GC.Spread.Sheets.VerticalAlign.center);
+        } else if (vAlign === "top") {
+            area.vAlign(GC.Spread.Sheets.VerticalAlign.top);
+        } else if (vAlign === "bottom") {
+            area.vAlign(GC.Spread.Sheets.VerticalAlign.bottom);
+        } else {
+            area.vAlign(GC.Spread.Sheets.VerticalAlign.center);
+        }
+    },
+    showData: function(sheet, setting, data, distTypeTree) {
+        var me = this, ch = GC.Spread.Sheets.SheetArea.viewport;
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        let checkBoxType = new GC.Spread.Sheets.CellTypes.CheckBox();
+        if(typeof setting.owner !== 'undefined' && setting.owner === 'gljComponent'){
+            sheet.setRowCount(data.length + 5);
+        }
+        else{
+            sheet.setRowCount(typeof repositoryGljObj !== 'undefined' && repositoryGljObj.currentOprParent === 1 ? data.length : data.length + 10);
+        }
+        if(data.length === 0){
+            for(let i = 0; i < sheet.getRowCount(); i++){
+                sheet.getCell(i, 4, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+            }
+        }
+        for (var col = 0; col < setting.header.length; col++) {
+            var hAlign = "left", vAlign = "center";
+            if (setting.header[col].hAlign) {
+                hAlign = setting.header[col].hAlign;
+            } else if (setting.header[col].dataType !== "String"){
+                hAlign = "right";
+            }
+            vAlign = setting.header[col].vAlign?setting.header[col].vAlign:vAlign;
+            me.setAreaAlign(sheet.getRange(-1, col, -1, 1), hAlign, vAlign);
+            if (setting.header[col].formatter) {
+                sheet.setFormatter(-1, col, setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
+            }
+            for (var row = 0; row < data.length; row++) {
+                //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
+                if(setting.header[col].dataCode === 'gljType' && data[row].gljType){
+                    if(typeof repositoryGljObj !== 'undefined' && typeof repositoryGljObj.allowComponent !== 'undefined' && repositoryGljObj.allowComponent.indexOf(data[row].gljType) !== -1){
+                        sheet.getCell(row, 4, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+                    }
+                    else if(typeof repositoryGljObj !== 'undefined' && typeof repositoryGljObj.allowComponent !== 'undefined' && repositoryGljObj.allowComponent.indexOf(data[row].gljType) === -1){
+                        sheet.getCell(row, 4, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+                    }
+                    let distTypeVal =  distTypeTree.distTypes[distTypeTree.prefix + data[row].gljType].data.fullName;
+                    sheet.setValue(row, col, distTypeVal, ch);
+                }
+                else {
+                    sheet.setValue(row, col, data[row][setting.header[col].dataCode], ch);
+                    sheet.setTag(row, 0, data[row].ID, ch);
+                    if(typeof setting.owner === 'undefined'){
+                        sheet.getCell(row, 0, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+                    }
+                }
+                //复选框
+                if(setting.header[col].dataCode === 'isComplementary'){
+                    sheet.setCellType(row, col, checkBoxType);
+                    sheet.getCell(row, col).value(1);
+                }
+                //新增组成物表,选择复选框
+                if(setting.header[col].dataCode === 'select'){
+                    sheet.setCellType(row, col, checkBoxType)
+                    sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+                    if(data[row].isChecked === true){
+                        sheet.getCell(row, col).value(1);
+                    }
+                }
+            }
+            for(let i = data.length; i < sheet.getRowCount(); i++){
+                sheet.setCellType(i, 6, null);
+                sheet.getCell(i, 4, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+            }
+        }
+        sheet.resumeEvent();
+        sheet.resumePaint();
+        //me.shieldAllCells(sheet);
+    },
+    analyzePasteData: function(setting, pastedInfo) {
+        var rst = [], propId = pastedInfo.cellRange.col, preStrIdx = 0, itemObj = {};
+        for (var i = 0; i < pastedInfo.pasteData.text.length; i++) {
+            if (pastedInfo.pasteData.text[i] === "\n") {
+                propId = pastedInfo.cellRange.col;
+                preStrIdx = i + 1;
+                rst.push(itemObj);
+                if (i < pastedInfo.pasteData.text.length - 1) {
+                    itemObj = {};
+                }
+            } else if (pastedInfo.pasteData.text[i] === "\t" || pastedInfo.pasteData.text[i] === "\r") {
+                itemObj[setting.header[propId].dataCode] = pastedInfo.pasteData.text.slice(preStrIdx, i);
+                propId++;
+                preStrIdx = i + 1;
+                //if the last copied-cell were empty, should check whether the end of text
+                if (i == pastedInfo.pasteData.text.length - 1) {
+                    itemObj[setting.header[propId].dataCode] = pastedInfo.pasteData.text.slice(preStrIdx);
+                    rst.push(itemObj);
+                }
+            } else if (i == pastedInfo.pasteData.text.length - 1) {
+                itemObj[setting.header[propId].dataCode] = pastedInfo.pasteData.text.slice(preStrIdx);
+                rst.push(itemObj);
+            }
+        }
+        return rst;
+    },
+    combineRowData: function(sheet, setting, row, repositoryGljObj) {
+        let me = this;
+        var rst = {};
+        let comboBoxCellType = sheet.getCellType(row, 5);
+        let items = comboBoxCellType.items();
+        for (var col = 0; col < setting.header.length; col++) {
+            if(setting.header[col].dataCode === 'gljType'){
+                items.forEach(function(item){
+                    if(sheet.getValue(row, col) === item.text){
+                        rst[setting.header[col].dataCode] = item.value;
+                        if(repositoryGljObj){
+                            rst.shortName = repositoryGljObj.distTypeTree.distTypes[repositoryGljObj.distTypeTree.prefix + item.value].data.shortName;
+                        }
+                    }
+                });
+            }
+            else if (setting.header[col].dataCode === 'code'){
+                if(repositoryGljObj){
+                    let stdGljList = repositoryGljObj.stdGljList,
+                        complementaryGljList = repositoryGljObj.complementaryGljList,
+                        orgCode = repositoryGljObj.orgCode,
+                        isExist = false;
+                    for(let i=0; i< stdGljList.length; i++){
+                        if(stdGljList[i].code == sheet.getValue(row, col) && sheet.getValue(row, col)!== orgCode){
+                            me.lockAllCells(sheet);
+                            $('#alertText').text("输入的编号已存在,请重新输入!");
+                            $('#codeAlertBtn').click();
+                            $('#codAleConfBtn').click(function () {
+                                // me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
+                                me.unLockAllCells(sheet);
+                                me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
+                                //sheet.setText(row, 0, '');
+                                sheet.getCell(row, 0).formatter("@");
+                                sheet.getCell(row, 0).text("");
+                                sheet.setActiveCell(row, 0);
+                            });
+                            $('#codAleClose').click(function () {
+                                //me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
+                                me.unLockAllCells(sheet);
+                                me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
+                                //sheet.setText(row, 0, '');
+                                sheet.getCell(row, 0).formatter("@");
+                                sheet.getCell(row, 0).text("");
+                                sheet.setActiveCell(row, 0);
+                            });
+                            // sheet.setValue(row, col, orgCode);
+                            isExist = true
+                            break;
+                        }
+                    }
+                    if(!isExist){
+                        for(let i=0; i< complementaryGljList.length; i++){
+                            if(complementaryGljList[i].code == sheet.getValue(row, col) && sheet.getValue(row, col)!== orgCode){
+                                me.lockAllCells(sheet);
+                                $('#alertText').text("输入的编号已存在,请重新输入!");
+                                $('#codeAlertBtn').click();
+                                $('#codAleConfBtn').click(function () {
+                                    // me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
+                                    me.unLockAllCells(sheet);
+                                    me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
+                                    //sheet.setText(row, 0, '');
+                                    sheet.getCell(row, 0).formatter("@");
+                                    sheet.getCell(row, 0).text("");
+                                    sheet.setActiveCell(row, 0);
+                                });
+                                $('#codAleClose').click(function () {
+                                    //me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
+                                    me.unLockAllCells(sheet);
+                                    me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
+                                    //sheet.setText(row, 0, '');
+                                    sheet.getCell(row, 0).formatter("@");
+                                    sheet.getCell(row, 0).text("");
+                                    sheet.setActiveCell(row, 0);
+                                });
+                                // sheet.setValue(row, col, orgCode);
+                                isExist = true
+                                break;
+                            }
+                        }
+                    }
+                    if(!isExist){
+                        rst[setting.header[col].dataCode] = sheet.getValue(row, col);
+                    }
+                }
+                else{
+                    rst[setting.header[col].dataCode] = sheet.getValue(row, col);
+                }
+            }
+            else{
+                rst[setting.header[col].dataCode] = sheet.getValue(row, col);
+            }
+        }
+        return rst;
+    },
+    combineRationRowData: function(sheet, setting, row) {
+        var rst = {};
+        for (var col = 0; col < setting.header.length; col++) {
+            rst[setting.header[col].dataCode] = sheet.getValue(row, col);
+        }
+        return rst;
+    },
+    shieldAllCells: function(sheet) {
+        sheet.options.isProtected = true;
+    },
+    unShieldAllCells: function(sheet) {
+        sheet.options.isProtected = false;
+    },
+    reLockSomeCodes: function (sheet, beginRow, endRow) {
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        let defaultStyle = new GC.Spread.Sheets.Style();
+        defaultStyle.locked = false;
+        sheet.setDefaultStyle(defaultStyle, GC.Spread.Sheets.SheetArea.viewport);
+        let unLockStyle = new GC.Spread.Sheets.Style();
+        unLockStyle.locked = false;
+        let lockStyle = new GC.Spread.Sheets.Style();
+        lockStyle.locked = true;
+        for(let row = beginRow; row < endRow; row++){
+            sheet.setStyle(row, 0, lockStyle);
+        }
+        for(let row = endRow; row < sheet.getRowCount(); row++){
+            sheet.setStyle(row, 0, unLockStyle);
+        }
+        sheet.options.isProtected = true;
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+    unLockAllCells: function (sheet) {
+        let defaultStyle = new GC.Spread.Sheets.Style();
+        defaultStyle.locked = false;
+        sheet.setDefaultStyle(defaultStyle, GC.Spread.Sheets.SheetArea.viewport);
+        sheet.setStyle(-1, 0, defaultStyle);
+        sheet.options.isProtected = false;
+    },
+    lockAllCells: function (sheet) {
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        let defaultStyle = new GC.Spread.Sheets.Style();
+        defaultStyle.locked = true;
+        sheet.setDefaultStyle(defaultStyle, GC.Spread.Sheets.SheetArea.viewport);
+        for(let i = 0; i < sheet.getRowCount(); i++){
+            sheet.setStyle(i, 0, defaultStyle);
+        }
+        sheet.options.isProtected = true;
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+    lockSomeCodes: function (sheet, beginRow, endRow) {
+        let defaultStyle = new GC.Spread.Sheets.Style();
+        defaultStyle.locked = false;
+        sheet.setDefaultStyle(defaultStyle, GC.Spread.Sheets.SheetArea.viewport);
+        let style = new  GC.Spread.Sheets.Style();
+        style.locked = true;
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        for(let i = beginRow; i < endRow; i++){
+            sheet.setStyle(i, 0, style);
+        }
+        sheet.options.isProtected = true;
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+    lockCodeCells: function (sheet, rowCount) {
+        let sheetRowCount = sheet.getRowCount();
+        let defaultStyle = new GC.Spread.Sheets.Style();
+        defaultStyle.locked = false;
+        sheet.setDefaultStyle(defaultStyle, GC.Spread.Sheets.SheetArea.viewport);
+        let style = new GC.Spread.Sheets.Style();
+        style.locked = true;
+        sheet.setStyle(-1, 0, style);
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        for(let i =rowCount; i<sheetRowCount; i++){
+            sheet.setStyle(i, -1, style);
+        }
+        sheet.options.isProtected = true;
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+    lockCells: function(sheet, setting){
+        if (setting && setting.view.lockColumns && setting.view.lockColumns.length > 0) {
+            sheet.options.isProtected = true;
+            sheet.getRange(-1, 0, -1, setting.header.length, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+            for (var i = 0; i < setting.view.lockColumns.length; i++) {
+                sheet.getRange(-1,setting.view.lockColumns[i] , -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+            }
+        }
+    },
+    chkIfEmpty: function(rObj, setting) {
+        var rst = true;
+        if (rObj) {
+            for (var i = 0; i < setting.header.length; i++) {
+                if (rObj[setting.header[i].dataCode]) {
+                    rst = false;
+                    break;
+                }
+            }
+        }
+        return rst;
+    }
+}

+ 19 - 2
web/building_saas/main/js/calc/calc_fees.js

@@ -4,11 +4,11 @@
 
 
 let feeType = [
 let feeType = [
     {type: 'common', name: '工程造价'},
     {type: 'common', name: '工程造价'},
-    {type: 'labour', name: '人工费'},
+    {type: 'baseLabour', name: '基价人工费'},
     {type: 'material', name: '材料费'},
     {type: 'material', name: '材料费'},
     {type: 'machine', name: '机械费'},
     {type: 'machine', name: '机械费'},
     {type: 'rationDirect', name: '定额直接费'},
     {type: 'rationDirect', name: '定额直接费'},
-    {type: 'management', name: '企业管理'},
+    {type: 'manageFee', name: '企业管理费'},
     {type: 'profit', name: '利润'},
     {type: 'profit', name: '利润'},
     {type: 'risk', name: '风险费'},
     {type: 'risk', name: '风险费'},
     // 模拟用户新增
     // 模拟用户新增
@@ -89,5 +89,22 @@ let calcFees = {
                 };
                 };
             }
             }
         }
         }
+    },
+    // CSL,2017.08.28
+    feeTypeToName: function (type) {
+        for (let ft of feeType) {
+            if (ft.type === type) {
+                return ft.name;
+            };
+        };
+    },
+
+    feeNameToType: function (name) {
+        for (let ft of feeType) {
+            if (ft.name === name) {
+                return ft.type;
+            };
+        };
+        return '';
     }
     }
 }
 }

+ 8 - 7
web/building_saas/main/js/models/calc_program.js

@@ -207,7 +207,7 @@ let calcTemplates = [
             {
             {
                 ID: "1",
                 ID: "1",
                 code: "1",
                 code: "1",
-                name: "基价直接工程费2",
+                name: "基价直接工程费",
                 fieldName: "baseDirect",
                 fieldName: "baseDirect",
                 dispExpr: "F2+F5+F6+F10",
                 dispExpr: "F2+F5+F6+F10",
                 expression: "@('2') + @('5') + @('6') + @('10')",
                 expression: "@('2') + @('5') + @('6') + @('10')",
@@ -401,7 +401,7 @@ let calcTemplates = [
             {
             {
                 ID: "1",
                 ID: "1",
                 code: "1",
                 code: "1",
-                name: "基价直接工程费3",
+                name: "基价直接工程费",
                 fieldName: "baseDirect",
                 fieldName: "baseDirect",
                 dispExpr: "F2+F5+F6+F10",
                 dispExpr: "F2+F5+F6+F10",
                 expression: "@('2') + @('5') + @('6') + @('10')",
                 expression: "@('2') + @('5') + @('6') + @('10')",
@@ -3599,18 +3599,19 @@ class CalcProgram {
     };
     };
 
 
     compileAllTemps(){
     compileAllTemps(){
-       for (let calcTemplate of calcTemplates){
-           this.calc.compile(calcTemplate, calcFeeRates, calcLabourCoes);
-       };
+        this.calc.compilePublics(calcFeeRates, calcLabourCoes, feeType, rationCalcBase);
+        for (let calcTemplate of calcTemplates){
+            this.calc.compileTemplate(calcTemplate);
+        };
     };
     };
 
 
     compile(calcTemplate){
     compile(calcTemplate){
-       this.calc.compile(calcTemplate, calcFeeRates, calcLabourCoes);
+        //this.calc.compilePublics(calcFeeRates, calcLabourCoes, feeType, rationCalcBase);
+        this.calc.compileTemplate(calcTemplate);
     };
     };
 
 
     calculate(treeNode){
     calculate(treeNode){
         treeNode.data.gljList = this.project.ration_glj.getGljArrByRation(treeNode.data.ID);
         treeNode.data.gljList = this.project.ration_glj.getGljArrByRation(treeNode.data.ID);
-        treeNode.data.calcTemplate = calcTemplates[0];  // AAAAAA = getCalcTemplate($RATION.calcTemplateID);
         this.calc.calculate(treeNode);
         this.calc.calculate(treeNode);
     };
     };
 }
 }

+ 3 - 3
web/building_saas/main/js/views/calc_program_manage.js

@@ -26,7 +26,7 @@ let rationPM = {
             {headerName:"计算基数",headerWidth:180,dataCode:"dispExpr", dataType: "String"},
             {headerName:"计算基数",headerWidth:180,dataCode:"dispExpr", dataType: "String"},
             {headerName:"基数说明",headerWidth:300,dataCode:"statement", dataType: "String"},
             {headerName:"基数说明",headerWidth:300,dataCode:"statement", dataType: "String"},
             {headerName:"费率",headerWidth:80,dataCode:"feeRate", dataType: "Number"},
             {headerName:"费率",headerWidth:80,dataCode:"feeRate", dataType: "Number"},
-            {headerName:"字段名称",headerWidth:180,dataCode:"fieldName", dataType: "String"},
+            {headerName:"字段名称",headerWidth:100,dataCode:"displayFieldName", dataType: "String", hAlign: "center"},
             {headerName:"备注",headerWidth:100,dataCode:"memo", dataType: "String"}
             {headerName:"备注",headerWidth:100,dataCode:"memo", dataType: "String"}
         ],
         ],
         view:{
         view:{
@@ -38,8 +38,8 @@ let rationPM = {
     buildSheet: function (){
     buildSheet: function (){
         let me = this;
         let me = this;
         me.datas = calcTemplates;
         me.datas = calcTemplates;
-        me.mainSpread = sheetCommonObj.buildSheet($('#mainSpread')[0], me.mainSetting, 16);
-        me.detailSpread = sheetCommonObj.buildSheet($('#detailSpread')[0], me.detailSetting, 18);
+        me.mainSpread = sheetCommonObj.buildSheet($('#mainSpread')[0], me.mainSetting, me.datas.length);
+        me.detailSpread = sheetCommonObj.buildSheet($('#detailSpread')[0], me.detailSetting, me.datas[0].calcItems.length);
 
 
         //var coeType = new GC.Spread.Sheets.CellTypes.ComboBox();
         //var coeType = new GC.Spread.Sheets.CellTypes.ComboBox();
         //coeType.items(["单个","定额","人工","材料","机械"]);
         //coeType.items(["单个","定额","人工","材料","机械"]);

+ 11 - 12
web/building_saas/main/js/views/calc_program_view.js

@@ -229,29 +229,28 @@ let calcProgramObj = {
     initSheet: function (sheet) {
     initSheet: function (sheet) {
         var me = this;
         var me = this;
         me.sheet = sheet;
         me.sheet = sheet;
-        sheetCommonObj.initSheet(me.sheet, me.setting, 20);
+        sheetCommonObj.initSheet(me.sheet, me.setting, 1);
     },
     },
 
 
     showData: function (treeNode) {
     showData: function (treeNode) {
         var me = this;
         var me = this;
         me.treeNode = treeNode;
         me.treeNode = treeNode;
-        projectObj.project.calcProgram.calculate(treeNode);
-        me.datas = me.treeNode.data.calcTemplate.calcItems;
-        //me.sheet.setRowCount(me.datas.length);
-        sheetCommonObj.initSheet(me.sheet, me.setting, me.datas.length);
-        sheetCommonObj.showData(me.sheet, me.setting, me.datas);
+        if (treeNode.sourceType === projectObj.project.Ration.getSourceType()) {
+            projectObj.project.calcProgram.calculate(treeNode);
+            me.datas = me.treeNode.data.calcTemplate.calcItems;
+            sheetCommonObj.initSheet(me.sheet, me.setting, me.datas.length);
+            sheetCommonObj.showData(me.sheet, me.setting, me.datas);
+        }
+        else if (treeNode.sourceType === projectObj.project.Bills.getSourceType()) {
+            SheetDataHelper.loadSheetHeader(calcProgramSetting, me.sheet);
+            SheetDataHelper.loadSheetData(calcProgramSetting, me.sheet, baseCalcField);
+        }
     },
     },
 
 
     clearData: function (){
     clearData: function (){
         var me = this;
         var me = this;
         me.treeNode = null;
         me.treeNode = null;
         sheetCommonObj.cleanSheet(me.sheet, me.setting, -1);
         sheetCommonObj.cleanSheet(me.sheet, me.setting, -1);
-    },
-
-    showBillsCalcProgram: function (node, calcProgram) {
-        var me = this;
-        SheetDataHelper.loadSheetHeader(calcProgramSetting, me.sheet);
-        SheetDataHelper.loadSheetData(calcProgramSetting, me.sheet, calcProgram);
     }
     }
 };
 };
 
 

+ 1 - 1
web/building_saas/main/js/views/main_tree_col.js

@@ -77,4 +77,4 @@ let MainTreeCol = {
                 return '0.##';
                 return '0.##';
         }
         }
     }
     }
-}
+};

+ 15 - 6
web/building_saas/main/js/views/project_view.js

@@ -132,11 +132,22 @@ var projectObj = {
                             return false;
                             return false;
                         }
                         }
                     };
                     };
+                    let canDelete = function (node) {
+                        if (selected) {
+                            if (selected.sourceType === that.project.Bills.getSourceType()) {
+                                return !(selected.data.flagsIndex && selected.data.flagsIndex.fixed && selected.data.flagsIndex.fixed.flag > 0);
+                            } else {
+                                return true;
+                            }
+                        } else {
+                            return false;
+                        }
+                    };
                     setButtonValid(canUpLevel(selected), $('#upLevel'));
                     setButtonValid(canUpLevel(selected), $('#upLevel'));
                     setButtonValid(canDownLevel(selected), $('#downLevel'));
                     setButtonValid(canDownLevel(selected), $('#downLevel'));
                     setButtonValid(selected && (selected.depth() > 0) && selected.canUpMove(), $('#upMove'));
                     setButtonValid(selected && (selected.depth() > 0) && selected.canUpMove(), $('#upMove'));
                     setButtonValid(selected && (selected.depth() > 0) && selected.canDownMove(), $('#downMove'));
                     setButtonValid(selected && (selected.depth() > 0) && selected.canDownMove(), $('#downMove'));
-                    setButtonValid(selected, $('#delete'));
+                    setButtonValid(canDelete(selected), $('#delete'));
                 });
                 });
 
 
               /*  if(!projectObj.gljSpreed){
               /*  if(!projectObj.gljSpreed){
@@ -150,14 +161,12 @@ var projectObj = {
 
 
                     // CSL.2017.07.25
                     // CSL.2017.07.25
                     if (SubActiveSheetNameIs('JSCX')) {
                     if (SubActiveSheetNameIs('JSCX')) {
-                        if (node.sourceType === that.project.Bills.getSourceType()) {
-                            calcProgramObj.showBillsCalcProgram(node.source, baseCalcField);
-                        } else if (node.sourceType=== that.project.Ration.getSourceType()) {
+                        if (node.sourceType === that.project.Bills.getSourceType() || node.sourceType === that.project.Ration.getSourceType()) {
                             calcProgramObj.showData(node);
                             calcProgramObj.showData(node);
                         } else {
                         } else {
                             calcProgramObj.clearData();
                             calcProgramObj.clearData();
-                        }
-                    }
+                        };
+                    };
                 });
                 });
 
 
                 that.mainSpread.bind(GC.Spread.Sheets.Events.EditEnded, that.mainSpreadEditEnded);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.EditEnded, that.mainSpreadEditEnded);

+ 2 - 4
web/building_saas/main/js/views/sub_view.js

@@ -61,13 +61,11 @@ $("#linkJSCX").click(function(){        // 计算程序
     calcProgramObj.initSheet(subSpread.getSheet(4));
     calcProgramObj.initSheet(subSpread.getSheet(4));
     let sel = projectObj.mainController.tree.selected;
     let sel = projectObj.mainController.tree.selected;
 
 
-    if (sel.sourceType === projectObj.project.Bills.getSourceType()) {
-        calcProgramObj.showBillsCalcProgram(sel.source, baseCalcField);
-    } else if (sel.sourceType=== projectObj.project.Ration.getSourceType()) {
+    if (sel.sourceType === projectObj.project.Bills.getSourceType() || sel.sourceType === projectObj.project.Ration.getSourceType()) {
         calcProgramObj.showData(sel);
         calcProgramObj.showData(sel);
     } else {
     } else {
         calcProgramObj.clearData();
         calcProgramObj.clearData();
-    }
+    };
 });
 });
 
 
 $("#linkFXSM").click(function(){
 $("#linkFXSM").click(function(){

文件差异内容过多而无法显示
+ 488 - 451
web/building_saas/pm/html/project-management.html


文件差异内容过多而无法显示
+ 735 - 465
web/building_saas/pm/js/pm_main.js


+ 629 - 0
web/building_saas/pm/js/pm_main_bak.js

@@ -0,0 +1,629 @@
+/**
+ * Created by Mai on 2017/2/24.
+ */
+
+var Tree = null, movetoZTree = null, copytoZTree = null;
+var ProjTreeSetting = {
+    tree: {
+        id: 'ID',
+        pid: 'ParentID',
+        nid: 'NextSiblingID',
+        btnColumn: 1,
+        nullId: -1
+    },
+    columns: [
+        {
+            head: '',
+            data: '',
+            width: '40',
+            event: {}
+        },
+        {
+            head: '工程列表',
+            data: 'name',
+            width: '78%',
+            event: {
+                getText: function (html, node, text) {
+                    html.push((node && node.data && node.data.projType === 'Folder') ? '&nbsp;' : '');
+                    html.push('<a ');
+                    if (node && node.data && node.data.projType === 'Tender') {
+                        //html.push('href="/main?project=', node.id(), '"');
+                        html.push('href="javacript:void(0);"');
+                    }
+                    html.push('>', text, '<a>');
+                },
+                getIcon: function (html, node) {
+                    if (node.data.projType === 'Folder') {
+                        html.push('<i class ="tree-icon fa fa-folder-open-o"></i>');
+                    } else {
+                        html.push('<span class="poj-icon">└</span>');
+                    }
+                },
+                tdBindEvent: function (td, node) {
+                    if (node.data.projType === 'Tender') {
+                        $('a:eq(1)', td).bind('click', function () {
+                            BeforeOpenProject(node.id(), {'fullFolder': GetFullFolder(node.parent)}, function () {
+                                window.location.href = '/main?project=' + node.id();
+                            });
+                            return false;
+                        });
+                    }
+                }
+            }
+        },
+        {
+            head: '最近使用',
+            data: 'lastDateTime',
+            width: '10%',
+            event: {
+                getText: function (html, node, text) {
+                    if (node.data.projType === 'Tender') {
+                        html.push(text ? new Date(text).Format('yyyy-MM-dd') : '');
+                    }
+                }
+            }
+        },
+        {
+            head: '创建日期',
+            data: 'createDateTime',
+            width: '10%',
+            event: {
+                getText: function (html, node, text) {
+                    if (node.data.projType === 'Tender') {
+                        html.push(text ? new Date(text).Format('yyyy-MM-dd') : '');
+                    }
+                }
+            }
+        }
+    ],
+    viewEvent: {
+        beforeSelect: function (node) {
+            if (node && node.row) {
+                $('td:eq(0)', node.row).children().remove();
+            }
+        },
+        onSelectNode: function (node) {
+            // 新建文件夹 是否可见
+            if (node.data.projType === 'Tender') {
+                $('#addFolderBtn').hide();
+            } else {
+                $('#addFolderBtn').show();
+            }
+            // 重命名可见
+            $('#renameBtn').show();
+            // 删除可见
+            $('#delBtn').show();
+            // 移动到、复制到、共享、协同 是否可见
+            if (node.data.projType === 'Tender') {
+                $('#movetoBtn').show();
+                $('#copytoBtn').show();
+                $('#shareBtn').show();
+                $('#cooperateBtn').show();
+            } else {
+                $('#movetoBtn').hide();
+                $('#copytoBtn').hide();
+                $('#shareBtn').hide();
+                $('#cooperateBtn').hide();
+            }
+            $('td:eq(0)', node.row).append($('<i class="fa fa-sort" data-toggle="tooltip" data-placement="top" title="长安拖动"></i>'));
+        }
+    }
+}
+// 从服务器拉取数据
+var LoadProjTree = function () {
+    var table = $('#ProjTree');
+    $('thead', table).remove();
+    $('tbody', table).remove();
+    GetAllProjectData(function (data) {
+        Tree = $.fn.treeTable.init(table, ProjTreeSetting, data);
+    });
+};
+
+var GetNeedUpdatePreNode = function (parent, next) {
+    if (next) {
+        return next.preSibling();
+    } else if (parent) {
+        return parent.firstChild();
+    } else {
+        return null;
+    }
+    /*if (parent && parent.id() !== -1) {
+        if (next && next.preSibling()) {
+            return next.preSibling();
+        } else {
+            return parent.lastChild();
+        }
+    } else {
+        return null;
+    }*/
+};
+var GetPreNodeUpdateData = function (pre, nid) {
+    var data = {};
+    data['updateType'] = 'update';
+    data['updateData'] = {};
+    data.updateData[Tree.setting.tree.id] = pre.id();
+    data.updateData[Tree.setting.tree.id] = nid;
+    return data;
+}
+// 获取新建项目数据
+var GetAddProjUpdateData = function (parent, next, name, newId) {
+    var datas = [], updateData, pre;
+    updateData = {};
+    updateData['updateType'] = 'new';
+    updateData['updateData'] = {};
+    updateData['updateData'][Tree.setting.tree.id] = newId;
+    updateData['updateData'][Tree.setting.tree.pid] = parent ? parent.id() : -1;
+    updateData['updateData'][Tree.setting.tree.nid] = next ? next.id() : -1;
+    updateData['updateData']['name'] = name;
+    updateData['updateData']['projType'] = 'Tender';
+    datas.push(updateData);
+    return datas;
+};
+var GetAddFolderProjUpdateData = function (parent, next, folderName1, folderName2, name, newId) {
+    var datas = [], updateData, folderData1, folderData2, pre;
+    var addUpdateData = function (parentId, nextId, name, projType) {
+        var data = {};
+        data['updateType'] = 'new';
+        data['updateData'] = {};
+        data['updateData'][Tree.setting.tree.id] = newId;
+        data['updateData'][Tree.setting.tree.pid] = parentId;
+        data['updateData'][Tree.setting.tree.nid] = nextId;
+        data['updateData']['name'] = name;
+        data['updateData']['projType'] = projType;
+        newId += 1;
+        datas.push(data);
+        return data;
+    }
+    folderData1 = addUpdateData(parent.id(), next ? next.id() : -1, folderName1, 'Folder');
+    folderData2 = addUpdateData(folderData1.updateData[Tree.setting.tree.id], -1, folderName2, 'Folder');
+    addUpdateData(folderData2.updateData[Tree.setting.tree.id], -1, name, 'Tender');
+    return datas;
+};
+// 获取新建文件夹数据
+var GetAddForlderUpdateData = function (parent, next, folderName, newId) {
+    var datas = [], updateData, pre;
+    updateData = {};
+    updateData['updateType'] = 'new';
+    updateData['updateData'] = {};
+    updateData['updateData'][Tree.setting.tree.id] = newId;
+    updateData['updateData'][Tree.setting.tree.pid] = parent ? parent.id() : -1;
+    updateData['updateData'][Tree.setting.tree.nid] = next ? next.id() : -1;
+    updateData['updateData']['name'] = folderName;
+    updateData['updateData']['projType'] = 'Folder';
+    datas.push(updateData);
+
+    pre = GetNeedUpdatePreNode(parent, next);
+    if (pre) {
+        datas.push(GetPreNodeUpdateData(pre, newId));
+    }
+    return datas;
+};
+
+var GetNextChangeUpdateData = function (datas, node, next) {
+    var data = null;
+    if (node && node.id() !== -1) {
+        data = {};
+        data['updateType'] = 'update';
+        data['updateData'] = {};
+        data['updateData'][Tree.setting.tree.id] = node.id();
+        data['updateData'][Tree.setting.tree.nid] = next ? next.id() : -1;
+        datas.push(data);
+    }
+    return data;
+}
+var GetFullFolder = function (node) {
+    var fullFolder = [],
+        cur = node;
+    while (cur && cur.data) {
+        fullFolder.unshift(cur.data.name);
+        cur = cur.parent;
+    }
+    return fullFolder;
+}
+var GetDeleteUpdateData = function (node) {
+    var datas = [], updateData,
+        pre = node.preSibling(),
+        deleteNodeData = function (node) {
+            var data = {};
+            data['updateType'] = 'delete';
+            data['updateData'] = {};
+            data['updateData'][Tree.setting.tree.id] = node.id();
+            if (node.data.projType === 'Tender') {
+                data['updateData']['FullFolder'] = GetFullFolder(node.parent);
+            }
+            return data;
+        },
+        addDeleteChildren = function (children) {
+            children.forEach(function(child){
+                datas.push(deleteNodeData(child));
+                addDeleteChildren(child.children);
+            });
+        };
+    if (pre && pre.id() !== -1) {
+        updateData = {};
+        updateData['updateType'] = 'update';
+        updateData['updateData'] = {};
+        updateData['updateData'][Tree.setting.tree.id] = pre.id();
+        updateData['updateData'][Tree.setting.tree.nid] = node ? node.nid() : -1;
+        datas.push(updateData);
+    }
+    datas.push(deleteNodeData(node));
+    addDeleteChildren(node.children);
+    return datas;
+};
+
+var GetMoveUpdateData = function (node, parent, next) {
+    var datas = [], updateData;
+    updateData = GetNextChangeUpdateData(datas, node.preSibling(), node.nextSibling);
+    if (next) {
+        updateData = GetNextChangeUpdateData(datas, next.preSibling(), node);
+    }
+    updateData = {};
+    updateData['updateType'] = 'update';
+    updateData['updateData'] = {};
+    updateData['updateData'][Tree.setting.tree.id] = node.id();
+    updateData['updateData'][Tree.setting.tree.pid] = parent ? parent.id() : -1;
+    updateData['updateData'][Tree.setting.tree.nid] = next ? next.id() : -1;
+    datas.push(updateData);
+    return datas;
+};
+
+var GetCopyUpdateData = function (node, parent, next, newId){
+    var datas = [], updateData, pre;
+    updateData = {};
+    updateData['updateType'] = 'copy';
+    updateData['srcProjectId'] = node.id();
+    updateData['updateData'] = {};
+    updateData['updateData'][Tree.setting.tree.id] = newId + 1;
+    updateData['updateData'][Tree.setting.tree.pid] = parent ? parent.id() : -1;
+    updateData['updateData'][Tree.setting.tree.nid] = next ? next.id() : -1;
+    updateData['updateData']['name'] = node.data.name;
+    updateData['updateData']['projType'] = node.data.projType;
+    datas.push(updateData);
+
+    pre = GetNeedUpdatePreNode(parent, next);
+    if (pre) {
+        updateData = {};
+        updateData['updateType'] = 'update';
+        updateData['updateData'] = {};
+        updateData['updateData'][Tree.setting.tree.id] = pre.id();
+        updateData['updateData'][Tree.setting.tree.nid] = node.tree.maxNodeId() + 1;
+        datas.push(updateData);
+    }
+    return datas;
+}
+
+var ConvertTreeToZtree = function (Tree, zTreeObj, filterNode) {
+    var setting = {
+            data: {
+                simpleData: {
+                    enable:true,
+                    idKey: "id",
+                    pIdKey: "pId",
+                    rootPId: "-1"
+                }
+            }},
+        zTreeData = [],
+        exportNodesData = function (nodes) {
+            nodes.forEach(function (node) {
+                if (node !== filterNode) {
+                    var data = {};
+                    data['id'] = node.data[Tree.setting.tree.id];
+                    data['pId'] = node.pid();
+                    data['name'] = node.data['name'];
+                    data['isParent'] = node.data.projType === 'Folder';//(node.data.projType === 'Folder' && node.children.length === 0);
+                    data['open'] = node.data.projType === 'Folder';//node.children.length !== 0;
+                    zTreeData.push(data);
+                    exportNodesData(node.children);
+                }
+            })
+        };
+    exportNodesData(Tree._root.children);
+    return $.fn.zTree.init(zTreeObj, setting, zTreeData);
+};
+var GetTargetTreeNode = function (zTreeObj) {
+    var ztree_selected;
+    if (zTreeObj && Tree) {
+        ztree_selected = zTreeObj.getSelectedNodes().length === 0 ? null : zTreeObj.getSelectedNodes()[0];
+        return ztree_selected ? Tree.findNode(ztree_selected.id) : null;
+    } else {
+        return null;
+    }
+};
+
+var AddFolderChildValid = function (node) {
+    if (node.data.projType === 'Folder') {
+        if (node.children.length === 0) {
+            return true;
+        } else {
+            return (node.firstChild().data.projType === 'Folder');
+        }
+    } else {
+        return false;
+    }
+};
+var AddTenderChildValid = function (node) {
+    if (node.data.projType === 'Folder') {
+        if (node.children.length === 0) {
+            return true;
+        } else {
+            return (node.firstChild().data.projType === 'Tender');
+        }
+    } else {
+        return false;
+    }
+};
+
+LoadProjTree();
+$('#movetoBtn').hide();
+$('#copytoBtn').hide();
+$('#shareBtn').hide();
+$('#cooperateBtn').hide();
+
+// 新建文件夹
+$('#addFolderBtn').click(function () {
+    if (Tree) {
+        $('#addFolder').modal('show');
+    }
+});
+$('#addFolderOk').click(function () {
+    var form = $('#addFolder');
+    var name = $('#folder-name-input').val();
+    var parent, next;
+    if (name) {
+        if (Tree.selected()) {
+            if (Tree.selected().children.length === 0 || Tree.selected().firstChild().data.projType === 'Folder') {
+                parent = Tree.selected();
+                next = Tree.selected().firstChild();
+            } else {
+                parent = Tree.selected().parent;
+                next = Tree.selected().nextSibling;
+            }
+        } else {
+            parent = Tree._root;
+            next = Tree.firstNode();
+        }
+
+        CommonAjax.post('/pm/api/getNewProjectID', {count: 1}, function (IDs) {
+            var updateData = GetAddForlderUpdateData(parent, next, name, IDs.lowID);
+            Tree.maxNodeId(IDs.lowID - 1);
+            UpdateProjectData(updateData, function(datas){
+                datas.forEach(function (data) {
+                    if (data.updateType === 'new') {
+                        Tree.addNodeData(data.updateData, parent, next);
+                    }
+                });
+                form.modal('hide');
+            });
+        });
+    }
+});
+
+// 新建工程
+var AddProj = function () {
+    var name = $('#tenderName').val();
+    if (name !== '') {
+        // if (Tree.selected()){
+        //     if (Tree.selected().data.projType === 'Tender') {
+        //         parent = Tree.selected().parent;
+        //         next = Tree.selected().next;
+        //     } else {
+        //         if (Tree.selected().firstNode.data.projType === 'Tender') {
+        //             parent = Tree.selected();
+        //             next = Tree.selected().firstNode();
+        //         } else {
+        //             return;
+        //         }
+        //     }
+        // } else {
+        //     parent = Tree._root();
+        //     next = Tree.firstNode();
+        // }
+        CommonAjax.post('/pm/api/getNewProjectID', {count: 1}, function (IDs) {
+            var updateData = GetAddProjUpdateData(Tree._root, Tree.firstNode(), name, IDs.lowID);
+            Tree.maxNodeId(IDs.lowID - 1);
+            UpdateProjectData(updateData, function (datas) {
+                datas.forEach(function (data) {
+                    var parent, next;
+                    if (data.updateType === 'new') {
+                        parent = data.updateData.parentId === -1 ?  Tree._root : Tree.findNode(data.updateData.parentId);
+                        next = data.updateData.nextId === -1 ? null : Tree.findNode(data.updateData.nextId);
+                        Tree.addNodeData(data.updateData, parent, next);
+                    }
+                });
+                $('#addProj').modal('hide');
+            });
+        });
+    }
+}
+var AddFolderProj = function () {
+    var nameB = $('#buildName').val(), nameX = $('#xiangName').val(), name = $('#tenderName').val();
+    if (nameB !== '' && nameX !== '' && name !== '') {
+        CommonAjax.post('/pm/api/getNewProjectID', {count: 3}, function (IDs) {
+            var updateData = GetAddFolderProjUpdateData(Tree._root, Tree.firstNode(), nameB, nameX, name, IDs.lowID);
+            Tree.maxNodeId(IDs.lowID - 1);
+            UpdateProjectData(updateData, function (datas) {
+                datas.forEach(function (data) {
+                    var parent, next;
+                    if (data.updateType === 'new') {
+                        parent = data.updateData[Tree.setting.tree.pid] === -1 ?  Tree._root : Tree.findNode(data.updateData[Tree.setting.tree.pid]);
+                        next = data.updateData[Tree.setting.tree.nid] === -1 ? null : Tree.findNode(data.updateData[Tree.setting.tree.nid]);
+                        Tree.addNodeData(data.updateData, parent, next);
+                    }
+                });
+                $('#addProj').modal('hide');
+            });
+        });
+    }
+}
+$('#addProjBtn').click(function () {
+    if (Tree) {
+        $('#addProj').modal('show');
+    }
+});
+$('#addProjOk').click(function () {
+    var hasFolder = $('#isAddFolder>input').is(':checked');
+    if (hasFolder) {
+        AddFolderProj();
+    } else {
+        AddProj();
+    }
+});
+$('#isAddFolder').change(function () {
+    if ($('input',this).is(':checked')) {
+        $('#moreinfo').collapse('show');
+    } else {
+        $('#moreinfo').collapse('hide');
+    }
+});
+
+// 重命名
+$('#renameBtn').click(function() {
+    if (Tree && Tree.selected()) {
+        $('#rename').modal('show');
+    }
+})
+$('#rename').on('show.bs.modal', function () {
+    $('#newName').attr('placeholder', Tree.selected().data.name);
+});
+$('#renameOk').click(function () {
+    var select = Tree.selected(),
+        newName = $('#newName').val(),
+        form = $('#rename');
+    if (select && newName !== select.data.name) {
+        RenameProject(select.id(), newName, function () {
+            form.modal('hide');
+            select.data.name = newName;
+            Tree.refreshNodesDom([select]);
+        });
+    } else {
+        form.modal('hide');
+    }
+});
+
+// 删除
+$('#delBtn').click(function() {
+    if (Tree && Tree.selected()) {
+        $('#del').modal('show');
+    }
+});
+$('#del').on('show.bs.modal', function() {
+    var hasTenderChild = function (children) {
+        var i;
+        for (i = 0; i < children.length; i++) {
+            if (children[i].children.length === 0) {
+                if (children[i].data.projType === 'Tender') {
+                    return true;
+                }
+            } else if (hasTenderChild(children[i].children)) {
+                return true;
+            }
+        }
+        return false;
+    };
+    if (Tree.selected().children.length == 0) {
+        $('#tenderHint').show();
+        $('#tenderHint').text('删除 "' + Tree.selected().data.name +'" ?');
+        $('#folderHint').hide();
+    } else {
+        $('#tenderHint').hide();
+        $('#folderHint').show();
+        $('#folderHint').text('删除 "'+ Tree.selected().data.name +'" 以及它包含的子项?');
+    }
+    if (hasTenderChild([Tree.selected()])) {
+        $('#restoreHint').show();
+    } else {
+        $('#restoreHint').hide();
+    }
+});
+$('#deleteProjOk').click(function () {
+    var updateData, form = $('#del');
+    if (Tree) {
+        updateData = GetDeleteUpdateData(Tree.selected());
+        UpdateProjectData(updateData, function () {
+            form.modal('hide');
+            Tree.removeNode(Tree.selected());
+        });
+    }
+});
+
+// 移动至
+$('#movetoBtn').click(function () {
+    if (Tree && Tree.selected()) {
+        $('#moveto').modal('show');
+    }
+});
+$('#moveto').on('show.bs.modal', function () {
+    movetoZTree = ConvertTreeToZtree(Tree, $('#treeDemo'), Tree.selected());
+});
+$('#movetoOk').click(function () {
+    var updateData, form = $('#moveto'),
+        target = GetTargetTreeNode($.fn.zTree.getZTreeObj('treeDemo')),
+        parent, next, cur = Tree.selected();
+    if (target) {
+        if (target.data.projType === 'Tender') {
+            parent = target.parent;
+            next = target.nextSibling;
+        } else {
+            parent = target;
+            next = target.firstChild();
+        }
+
+        if (parent !== cur.parent || (next !== cur && next !== cur.nextSibling)){
+            updateData = GetMoveUpdateData(Tree.selected(), parent, next);
+            UpdateProjectData(updateData, function (data) {
+                form.modal('hide');
+                Tree.move(Tree.selected(), parent, next);
+            });
+        } else {
+            form.modal('hide');
+        }
+    } else {
+        form.modal('hide');
+    }
+})
+
+// 复制到
+$('#copytoBtn').click(function () {
+    if (Tree && Tree.selected()) {
+        $('#copyto').modal('show');
+    }
+});
+$('#copyto').on('show.bs.modal', function () {
+    copytoZTree = ConvertTreeToZtree(Tree, $('#treeDemo2'));
+});
+$('#copytoOk').click(function() {
+    var form = $('#copyto'),
+        target = GetTargetTreeNode($.fn.zTree.getZTreeObj('treeDemo2')),
+        parent, next, cur = Tree.selected();
+    if (target && (target.data.projType === 'Tender' || target.children.length === 0 || target.firstChild().data.projType === 'Tender')) {
+        if (target.data.projType === 'Tender') {
+            parent = target.parent;
+            next = target.nextSibling;
+        } else {
+            parent = target;
+            next = target.firstChild();
+        }
+
+        if (parent !== cur.parent || (next !== cur && next !== cur.nextSibling)){
+            CommonAjax.post('/pm/api/getNewProjectID', {count: 1}, function (IDs) {
+                var updateData = GetCopyUpdateData(cur, parent, next, IDs.lowID);
+                Tree.maxNodeId(IDs.lowID - 1);
+                CommonAjax.post('/pm/api/copyProjects', {updateData: updateData}, function (data) {
+                    form.modal('hide');
+                    data.forEach(function (nodeData) {
+                        if (nodeData.updateType === 'copy') {
+                            Tree.addNodeData(nodeData.updateData, parent, next);
+                        }
+                    });
+                }, function () {
+                    form.modal('hide');
+                });
+            });
+        } else {
+            form.modal('hide');
+        }
+    } else {
+        form.modal('hide');
+    }
+});