瀏覽代碼

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

zhangweicheng 7 年之前
父節點
當前提交
ad52afccc1

+ 2 - 0
config/gulpConfig.js

@@ -56,6 +56,7 @@ module.exports = {
         'public/web/uuid.js',
         'public/web/sheet/sheet_common.js',
         'web/building_saas/main/js/models/calc_program.js',
+        'web/building_saas/main/js/models/calc_base.js',
         'web/building_saas/main/js/views/calc_program_manage.js',
         'public/web/common_ajax.js',
         'public/web/url_util.js',
@@ -118,6 +119,7 @@ module.exports = {
         'web/building_saas/main/js/views/sub_view.js',
         'web/building_saas/main/js/views/fee_rate_view.js',
         'web/building_saas/main/js/views/sub_fee_rate_views.js',
+        'web/building_saas/main/js/views/calc_base_view.js',
         'web/building_saas/main/js/views/project_property_labour_coe_view.js'
     ]
 }

+ 5 - 1
modules/main/facade/calc_program_facade.js

@@ -85,7 +85,11 @@ function getData(projectID, callback) {
 
 // 统一的 save() 方法供project调用
 function save (user_id, datas, callback) {
-    projectCalcProgramsModel.update({"projectID": 553}, {"libName":"goo—test"}, callback(null, {data: 'test'}));
+    let returnData ={
+        moduleName:'calc_program',
+        data:{}
+    };
+    projectCalcProgramsModel.update({"projectID": 553}, {"libName":"goo—test"}, callback(null, returnData));
 }
 
 function saveCalcItem(dataObj, callback) {

+ 7 - 1
modules/main/models/bills.js

@@ -105,7 +105,13 @@ class billsModel extends baseModel {
             functions.push(saveOne(data));
             quantity_detial.quantityEditChecking(data,'bills',functions);
         }
-        async.parallel(functions, callback);
+        async.parallel(functions, function(err,result){
+            let returnData = {
+                moduleName:'bills',
+                data:{}
+            };
+            callback(err, returnData);
+        });
     };
 
     getItemTemplate (callback) {

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

@@ -63,7 +63,7 @@ class LoginController {
             request.session.sessionUser = sessionUser;
             // 记录用户数据到数据库
             let result = await userModel.markUser(sessionUser, request);
-            console.log(request.session);
+
             // 获取偏好设置
             let settingModel = new SettingModel();
             preferenceSetting = await settingModel.getPreferenceSetting(request.session.sessionUser.id);
@@ -88,7 +88,14 @@ class LoginController {
             console.log(error);
             return response.json({error: 1, msg: error});
         }
-        response.json({error: 0, msg: '', login_ask: preferenceSetting.login_ask, compilation_list: JSON.stringify(compilationList)});
+        console.log(request.session.lastPage);
+        response.json({
+            error: 0,
+            msg: '',
+            login_ask: preferenceSetting.login_ask,
+            compilation_list: JSON.stringify(compilationList),
+            last_page: request.session.lastPage
+        });
     }
 
 }

+ 4 - 5
server.js

@@ -52,7 +52,7 @@ app.use(bodyParser.json({limit: '3mb'}));
 app.use(session({
     name: 'usersSession',
     secret: 'session users secret',
-    cookie: {maxAge: 1000*60*30},
+    cookie: {maxAge: 1000*60*60},
     resave: false,
     rolling: true,
     saveUninitialized: true
@@ -66,9 +66,7 @@ app.use(session({
 // 登录状态全局判断
 app.use(function (req, res, next) {
     let url = req.originalUrl;
-    // @todo 上一个页面跳转
-    let referer = '';
-    if (/^\/login/.test(url)) {
+    if (/^\/login/.test(url) || /\.map|\.ico$/.test(url)) {
         // 如果是登录页面则忽略判断数据
         next();
     } else {
@@ -78,9 +76,10 @@ app.use(function (req, res, next) {
             if (!sessionUser) {
                 throw 'session error';
             }
-
             res.locals.sessionUser = sessionUser;
         } catch (error) {
+            // 最后一个页面存入session
+            req.session.lastPage = url;
             return res.redirect('/login');
         }
 

+ 2 - 2
test/tmp_data/bills_grid_setting.js

@@ -405,10 +405,10 @@ var BillsGridSetting ={
                 ]
             },
             "data":{
-                "field":"",
+                "field":"calcBase",
                 "vAlign":1,
                 "hAlign":0,
-                "font":"Arial"
+                "font":"Arial",
             }
         },
         {

+ 11 - 10
web/building_saas/main/html/main.html

@@ -605,24 +605,22 @@
                 </div>
                 <div class="modal-body">
                     <div class="form-group">
-                        <input class="form-control" value="分部分项工程费+100">
+                        <input class="form-control" id="calcBaseExp" value="">
                         <p class="form-text">
-                            <button class="btn btn-secondary btn-sm">+</button>
-                            <button class="btn btn-secondary btn-sm">-</button>
-                            <button class="btn btn-secondary btn-sm">*</button>
-                            <button class="btn btn-secondary btn-sm">/</button>
-                            <button class="btn btn-secondary btn-sm">(</button>
-                            <button class="btn btn-secondary btn-sm">)</button>
+                            <button class="btn btn-secondary btn-sm" id="addOpr">+</button>
+                            <button class="btn btn-secondary btn-sm" id="subOpr">-</button>
+                            <button class="btn btn-secondary btn-sm" id="mulOpr">*</button>
+                            <button class="btn btn-secondary btn-sm" id="divOpr">/</button>
+                            <button class="btn btn-secondary btn-sm" id="leftOpr">(</button>
+                            <button class="btn btn-secondary btn-sm" id="rightOpr">)</button>
                         </p>
                     </div>
                     <div class=" modal-auto-height" style="overflow: hidden" id="billsBaseSpread">
-                        <p></p>
-                        <p></p>
                     </div>
                 </div>
                 <div class="modal-footer">
                     <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                    <a href="" class="btn btn-primary">确定</a>
+                    <a href="javascript:void(0);" class="btn btn-primary" id="calcBaseConf">确定</a>
                 </div>
             </div>
         </div>
@@ -698,8 +696,10 @@
         <!--<script type="text/javascript" src="/web/building_saas/main/js/models/volume_price.js"></script>-->
         <script type="text/javascript" src="/web/building_saas/main/js/models/labour_coe.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/models/calc_program.js"></script>
+        <script type="text/javascript" src="/web/building_saas/main/js/models/calc_base.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/calc_program_manage.js"></script>
 
+
         <script type="text/javascript" src="/public/web/id_tree.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/models/cache_tree.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/calc/calc_fees.js"></script>
@@ -744,6 +744,7 @@
         <script type="text/javascript" src="/web/building_saas/main/js/views/sub_view.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/fee_rate_view.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/sub_fee_rate_views.js"></script>
+        <script type="text/javascript" src="/web/building_saas/main/js/views/calc_base_view.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/project_property_labour_coe_view.js"></script>
         <!-- endinject -->
 

+ 1 - 0
web/building_saas/main/js/models/bills.js

@@ -122,6 +122,7 @@ var Bills = {
             if(data.quantityRefresh){
                 this.refreshDatas(data,'quantity');
             }
+            $.bootstrapLoading.end();
         };
 
         bills.prototype.refreshDatas = function(data,fieldName){

+ 452 - 0
web/building_saas/main/js/models/calc_base.js

@@ -0,0 +1,452 @@
+/**
+ * Created by Zhong on 2017/11/28.
+ */
+//清单固定行
+const fixedFlag = {
+    // 分部分项工程
+    SUB_ENGINERRING: 1,
+    // 措施项目
+    MEASURE: 2,
+    // 施工技术措施项目
+    CONSTRUCTION_TECH: 3,
+    // 安全文明施工按实计算费用
+    SAFETY_CONSTRUCTION_ACTUAL: 4,
+    // 施工组织措施专项费用
+    CONSTRUCTION_ORGANIZATION: 5,
+    // 安全文明施工专项费用
+    SAFETY_CONSTRUCTION: 6,
+    // 其他项目
+    OTHER: 7,
+    // 暂列金额
+    PROVISIONAL: 8,
+    // 暂估价
+    ESTIMATE: 9,
+    // 材料(工程设备)暂估价
+    MATERIAL_PROVISIONAL: 10,
+    // 专业工程暂估价
+    ENGINEERING_ESITIMATE: 11,
+    // 计日工
+    DAYWORK: 12,
+    // 总承包服务费
+    TURN_KEY_CONTRACT: 13,
+    // 索赔与现场签证
+    CLAIM_VISA: 14,
+    // 规费
+    CHARGE: 15,
+    // 社会保险费及住房公积金 Social insurance fee and housing accumulation fund
+    SOCIAL_INSURANCE_HOUSING_FUND: 16,
+    // 工程排污费 charges for disposing pollutants
+    POLLUTANTS: 17,
+    // 税金
+    TAX: 18
+};
+
+let cbTools = {
+    isDef: function (v) {
+        return v !== undefined && v !== null;
+    },
+    isUnDef: function (v) {
+        return v === undefined || v === null;
+    },
+    isNum: function (v) {
+        return this.isDef(v) && !isNaN(v) && v !== Infinity;
+    },
+    returnV: function (v, r) {
+        if(this.isDef(v)){
+            return v;
+        }
+        return r;
+    },
+    findBill: function (fixedFlag) {
+        let bills = projectObj.project.Bills.datas;
+        for(let i = 0, len = bills.length; i < len; i++){
+            if(bills[i].flagsIndex.flag === fixedFlag){
+                return bills[i];
+            }
+        }
+    },
+    //需要用到计算基数的时候,先找出所有的固定清单,避免每个基数都要去遍历寻找清单
+    setFixedBills: function (project, billsObj, fixedFlag) {
+        let bills = project.Bills.datas;
+        for(let i = 0, len = bills.length; i < len; i++){
+            if(this.isDef(bills[i].flagsIndex.fixed)){
+                for(let flag in fixedFlag){
+                    if(fixedFlag[flag] === bills[i].flagsIndex.fixed.flag){
+                        billsObj[fixedFlag[flag]] = bills[i];
+                    }
+                }
+            }
+        }
+    },
+    //生成清单基数计算分类模板
+    setBaseFigureClass: function (baseFigures, mapObj) {
+        mapObj['CONSTRUCTION_ORGANIZATION'] = Object.create(null);
+        mapObj['OTHER'] = Object.create(null);
+        mapObj['CHARGE'] = Object.create(null);
+        mapObj['TAX'] = Object.create(null);
+        mapObj['OTHERS'] = Object.create(null);
+        let filter = ['CSXMF', 'ZZCSXMF', 'ZZCSXMDEJJZJGCF', 'ZZCSXMDEJJRGF', 'ZZCSXMDEJJCLF', 'ZZCSXMDEJJJXF', 'QTXMF', 'GF', 'SJ'];
+        for(let figure in baseFigures){
+            if(filter.indexOf(baseFigures[figure]) === -1){
+                mapObj['CONSTRUCTION_ORGANIZATION'][figure] = baseFigures[figure];
+            }
+            if(baseFigures[figure] !== 'QTXMF'){
+                mapObj['OTHER'][figure] = baseFigures[figure];
+            }
+            if(baseFigures[figure] !== 'GF'){
+                mapObj['CHARGE'][figure] = baseFigures[figure];
+            }
+            if(baseFigures[figure] !== 'SJ'){
+                mapObj['TAX'][figure] = baseFigures[figure];
+            }
+            mapObj['OTHERS'][figure] = baseFigures[figure];
+        }
+    }
+};
+
+let baseFigureTemplate = {
+    'FBFXGCF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.common.totalFee || 0;
+    },
+    'FBFXDEJJRGF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.labour.totalFee || 0;
+    },
+    'FBFXDEJJCLF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.material.totalFee || 0;
+    },
+    'FBFXDEJJJXF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.machine.totalFee || 0;
+    },
+    'FBFXTZRGF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.adjustLabour.totalFee || 0;
+    },
+    'FBFXTZJSRGF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.adjustMachineLabour.totalFee || 0;
+    },
+    'FBFXZCF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.mainMaterial.totalFee || 0;
+    },
+    'FBFXSBF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.mainMaterial.totalFee || 0;
+    },
+    'FBFXWJJCLF': function () {
+        return 0;
+    },
+    'FBFXRGGR': function () {
+        return 0;
+    },
+    'FBFXGCLQDJJZJGCF': function () {
+        return this['FBFXDEJJRGF']() + this['FBFXDEJJCLF']() + this['FBFXDEJJJXF']();
+    },
+    'CSXMF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.MEASURE];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.common.totalFee || 0;
+    },
+    'ZZCSXMF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.common.totalFee || 0;
+    },
+    'ZZCSXMDEJJZJGCF': function () {
+        return this['ZZCSXMDEJJRGF']() + this['ZZCSXMDEJJCLF']() + this['ZZCSXMDEJJJXF']()
+    },
+    'ZZCSXMDEJJRGF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.labour.totalFee || 0;
+    },
+    'ZZCSXMDEJJCLF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.material.totalFee || 0;
+    },
+    'ZZCSXMDEJJJXF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.machine.totalFee || 0;
+    },
+    'JSCSXMF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.common.totalFee || 0;
+    },
+    'JSCSXMDEJJRGF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.labour.totalFee || 0;
+    },
+    'JSCSXMDEJJCLF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.material.totalFee || 0;
+    },
+    'JSCSXMDEJJJXF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.machine.totalFee || 0;
+    },
+    'JSCSXMTZRGF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.adjustLabour.totalFee || 0;
+    },
+    'JSCSXMTZJSRGF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.adjustMachineLabour.totalFee || 0;
+    },
+    'JSCSXMZCF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.mainMaterial.totalFee || 0;
+    },
+    'JSCSXMSBF': function () {
+        return 0;
+    },
+    'JSCSXMWJJCLF': function () {
+        return 0;
+    },
+    'JSCSXMRGGR': function () {
+        return 0;
+    },
+    'JSCSXMQDDEJJZJGCF': function () {
+        return this['JSCSXMDEJJRGF']() + this['JSCSXMDEJJCLF']() + this['JSCSXMDEJJJXF']();
+    },
+    'QTXMF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.OTHER];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.common.totalFee || 0;
+    },
+    'GF': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.CHARGE];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.common.totalFee || 0;
+    },
+    'SJ': function () {
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.TAX];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return bill.feesIndex.common.totalFee || 0;
+    }
+};
+
+let baseFigureMap = {
+    '分部分项工程费': 'FBFXGCF',
+    '分部分项定额基价人工费': 'FBFXDEJJRGF',
+    '分部分项定额基价材料费': 'FBFXDEJJCLF',
+    '分部分项定额基价机械费': 'FBFXDEJJJXF',
+    '分部分项调整人工费': 'FBFXTZRGF',
+    '分部分项调整机上人工费': 'FBFXTZJSRGF',
+    '分部分项主材费': 'FBFXZCF',
+    '分部分项设备费': 'FBFXSBF',
+    '分部分项未计价材料费': 'FBFXWJJCLF',
+    '分部分项人工工日': 'FBFXRGGR',
+    '分部分项工程量清单中的基价直接工程费': 'FBFXGCLQDJJZJGCF',
+    '措施项目费': 'CSXMF',
+    '组织措施项目费': 'ZZCSXMF',
+    '组织措施项目定额基价直接工程费': 'ZZCSXMDEJJZJGCF',
+    '组织措施项目定额基价人工费': 'ZZCSXMDEJJRGF',
+    '组织措施项目定额基价材料费': 'ZZCSXMDEJJCLF',
+    '组织措施项目定额基价机械费': 'ZZCSXMDEJJJXF',
+    '技术措施项目费': 'JSCSXMF',
+    '技术措施项目定额基价人工费': 'JSCSXMDEJJRGF',
+    '技术措施项目定额基价材料费': 'JSCSXMDEJJCLF',
+    '技术措施项目定额基价机械费': 'JSCSXMDEJJJXF',
+    '技术措施项目调整人工费': 'JSCSXMTZRGF',
+    '技术措施项目调整机上人工费': 'JSCSXMTZJSRGF',
+    '技术措施项目主材费': 'JSCSXMZCF',
+    '技术措施项目设备费': 'JSCSXMSBF',
+    '技术措施项目未计价材料费': 'JSCSXMWJJCLF',
+    '技术措施项目人工工日': 'JSCSXMRGGR',
+    '技术措施项目清单中的定额基价直接工程费': 'JSCSXMQDDEJJZJGCF',
+    '其他项目费': 'QTXMF',
+    '规费': 'GF',
+    '税金': 'SJ'
+};
+
+//输入式分析器
+let cbAnalyzer = {
+    standar: function (exp) {
+        //去空格
+        exp = exp.replace(/\s/g, '');
+        //( to (
+        exp = exp.replace(/(/g, '(');
+        //)to )
+        exp = exp.replace(/)/g, ')');
+        return exp;
+    },
+    //输入合法性
+    inputLegal: function (exp) {
+        let ilegalRex = /[^0-9,\u4e00-\u9fa5,\+,\-,\/,\*,\(,\),.]/g;
+        return !ilegalRex.test(exp);
+    },
+    //基数合法性、存在性
+    baseLegal: function (baseFigures, exp) {
+        let expFigures = cbParser.getFigure(exp);
+        for(let i = 0, len = expFigures.length; i < len; i++){
+            if(cbTools.isUnDef(baseFigures[expFigures[i]])){
+                return false;
+            }
+        }
+        return true;
+    },
+    //四则运算合法性,前端控制不允许重复出现运算符,这里主要判断()的使用问题,这里再判断一次
+    arithmeticLeagl: function (exp) {
+        let ilegalRex = /[\+,\-,\*,\/]{2}/g;
+        return !ilegalRex.test(exp);
+    },
+    //
+    legalExp: function (exp) {
+        exp = this.standar(exp);
+        if(this.inputLegal(exp)){
+            if(this.baseLegal(calcBase.baseFigures, exp)){
+                if(this.arithmeticLeagl(exp)){
+                    return exp;
+                }
+            }
+            return null;
+        }
+        return null;
+    },
+
+    isCN: function(v){
+        let regex = /[\u4e00-\u9fa5]/g;
+        return (regex.test(v));
+    }
+};
+
+//输入式转换器
+let cbParser = {
+    //获取表达式中的基数
+    getFigure: function(expr){
+        let rst = [];
+        let cnRex = /[^\u4e00-\u9fa5]/;
+        let temp = expr.split(cnRex);
+        for(let i = 0, len = temp.length; i < len; i++){
+            if(temp[i] !== '' && rst.indexOf(temp[i]) === -1){
+                rst.push(temp[i]);
+            }
+        }
+        return rst;
+    },
+
+    //将表达式转换为可编译的表达式
+    toCompileExpr: function(v){
+        let strs = this.getFigure(v);
+        let exps = [];
+        for(let i = 0, len = strs.length; i < len; i++){
+            let exp = Object.create(null);
+            exp.orgExp = strs[i];
+            exps.push(exp);
+        }
+        for(let i = 0, len = exps.length;i < len; i++){
+            exps[i].compileExp = '$CBC.base(\'' + exps[i].orgExp;
+            exps[i].compileExp = exps[i].compileExp + '\')';
+            v = v.replace(new RegExp(exps[i].orgExp,"g"), exps[i].compileExp);
+        }
+        return v;
+    }
+};
+
+let cbCalctor = {
+    //计算基数
+    base: function (figure) {
+        return baseFigureTemplate[calcBase.baseFigures[figure]]();
+    },
+    //计算
+    exec: function () {
+
+    }
+};
+
+let calcBase = {
+    //清单固定行
+    fixedFlag: null,
+    fixedBills: Object.create(null),
+    //清单基数
+    baseFigures: Object.create(null),
+    //清单可选基数映射,分两类:组织措施项目:排除父项和计算的父项; 其他项目、规费、税金、工程造价,及新增部分:显示所有计算基数
+    baseFigureClass: Object.create(null),
+    //初始化
+    init: function (project) {
+        let me = this;
+        me.project = project;
+        me.fixedFlag = fixedFlag;
+        cbTools.setFixedBills(project, me.fixedBills, me.fixedFlag);
+        me.baseFigures = baseFigureMap;
+        //me.baseFigures.fixedBills = me.fixedBills;
+        cbTools.setBaseFigureClass(me.baseFigures, me.baseFigureClass);
+    },
+    getBase: function (figure) {
+       return  cbCalctor.base(figure);
+
+    },
+    calculate: function (node) {
+        let me = calcBase,
+            $CBA = cbAnalyzer,
+            $CBP = cbParser,
+            $CBC = cbCalctor;
+        try {
+            //分析输入式合法性
+            let exp = $CBA.legalExp(node.data.userCalcBase);
+            if(!exp){
+                throw '表达式不正确';
+            }
+            //输入式转换表达式
+            let compileExp = $CBP.toCompileExpr(exp);
+
+            //计算
+            let calcBaseValue = eval(compileExp);
+            if(!cbTools.isNum(calcBaseValue)){
+                throw '表达式不正确';
+            }
+            //存储
+            node.data.calcBase = exp;
+            node.data.calcBaseValue = parseFloat(calcBaseValue).toDecimal(decimalObj.decimal('totalPrice', node));
+            me.project.calcProgram.calculate(node);
+            me.project.calcProgram.saveNode(node);
+        }
+        catch (err){
+            alert('表达式不正确');
+        }
+    },
+};

+ 4 - 4
web/building_saas/main/js/models/calc_program.js

@@ -411,7 +411,7 @@ class CalcProgram {
 
     doAfterUpdate (err, data) {
         if(!err){
-            // do
+            $.bootstrapLoading.end();
         }
     };
 
@@ -754,7 +754,7 @@ class CalcProgram {
             treeNode.data.feesIndex.common.totalFee = tf.toDecimal(decimalObj.bills.totalPrice);
             treeNode.data.feesIndex.common.tenderUnitFee = tuf.toDecimal(decimalObj.bills.unitPrice);
             treeNode.data.feesIndex.common.tenderTotalFee = ttf.toDecimal(decimalObj.bills.totalPrice);
-            treeNode.changed=true;
+            treeNode.changed = true;
             treeNode.data.calcTemplate = {"calcItems": []};
         }
         // 叶子清单的计算基数计算
@@ -764,7 +764,7 @@ class CalcProgram {
 
             let f = treeNode.data.feeRate ? treeNode.data.feeRate : 100;
             let q = treeNode.data.quantity ? treeNode.data.quantity : 0;
-            let b = treeNode.data.calcBase;
+            let b = treeNode.data.calcBaseValue;
             let uf = (b * f * q / 100).toDecimal(decimalObj.bills.unitPrice);
             let tuf = uf;
             let tf = (me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationPrice) ? (b * f / 100).toDecimal(decimalObj.bills.totalPrice) : (uf * q).toDecimal(decimalObj.bills.totalPrice);
@@ -777,7 +777,7 @@ class CalcProgram {
             treeNode.data.feesIndex.common.totalFee = tf;
             treeNode.data.feesIndex.common.tenderUnitFee = tuf;
             treeNode.data.feesIndex.common.tenderTotalFee = ttf;
-            treeNode.changed=true;
+            treeNode.changed = true;
             treeNode.data.calcTemplate = {"calcItems": []};
         }
         // 定额或清单自己的计算程序计算

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

@@ -86,6 +86,7 @@ var PROJECT = {
             this.composition.loadData();
             this.labourCoe = new LabourCoe(this);
             this.calcProgram = new CalcProgram(this);
+            this.calcBase = calcBase;
 
             // this.masterField = {ration: 'billsItemID', volumePrice: 'billsItemID'};
             this.masterField = {ration: 'billsItemID'};

+ 323 - 0
web/building_saas/main/js/views/calc_base_view.js

@@ -0,0 +1,323 @@
+/**
+ * Created by Zhong on 2017/12/1.
+ */
+/*
+* 清单计算基数
+* */
+let calcBaseView = {
+    //可用计算基数的清单固定列映射(与fixedFlag)
+    inputExpr: $('#calcBaseExp'),
+    confirmBtn: $('#calcBaseConf'),
+    noBaseBills: [1, 3],
+    editingCell: null,
+    workBook: null,
+    setting:{
+        header: [
+            {name: '计算基础名称', dataCode: 'base', width: 280, vAlign: 'center', hAlign: 'left'},
+            {name: '金额', dataCode: 'price', width: 120, vAlign: 'center', hAlign: 'left'}
+        ],
+        options: {
+            tabStripVisible:  false,
+            allowCopyPasteExcelStyle : false,
+            allowExtendPasteRange: false,
+            allowUserDragDrop : false,
+            allowUserDragFill: false,
+            scrollbarMaxAlign : true
+        },
+        dateRows: [],
+        locked: {
+            rows: [],
+            cols: [0, 1]
+        }
+    },
+
+    renderSheetFuc: function (sheet, fuc) {
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        fuc();
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+
+    setOptions: function (workbook, opts) {
+        for(let opt in opts){
+            workbook.options[opt] = opts[opt];
+        }
+    },
+
+    buildHeader: function (sheet, headers) {
+        let me = calcBaseView;
+        let fuc = function () {
+            sheet.options.clipBoardOptions = GC.Spread.Sheets.ClipboardPasteOptions.values;
+            sheet.options.isProtected = true;
+            sheet.setColumnCount(headers.length);
+            sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
+            for(let i = 0, len = headers.length; i < len; i++){
+                sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
+                sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
+            }
+        };
+        me.renderSheetFuc(sheet, fuc);
+    },
+
+    buildSheet: function () {
+        if(!this.workBook){
+            this.workBook = new GC.Spread.Sheets.Workbook($('#billsBaseSpread')[0], {sheetCount: 1});
+            this.setOptions(this.workBook, this.setting.options);
+            this.buildHeader(this.workBook.getActiveSheet(), this.setting.header);
+            this.bindEvent(this.workBook);
+        }
+    },
+
+    bindEvent: function (workBook) {
+        const _events = GC.Spread.Sheets.Events;
+        let sheet = workBook.getActiveSheet();
+        sheet.bind(_events.CellDoubleClick, this.onCellDoubleClick);
+    },
+
+    showData(datas){
+        let me = calcBaseView;
+        let sheet = this.workBook.getActiveSheet();
+        let cols = this.setting.header;
+        let fuc = function () {
+            sheet.setRowCount(datas.length);
+            sheet.setFormatter(-1, 1, '@');
+            for(let col = 0, cLen = cols.length; col < cLen; col++){
+                sheet.getRange(-1, col, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[cols[col]['hAlign']]);
+                sheet.getRange(-1, col, -1, 1).hAlign(GC.Spread.Sheets.VerticalAlign[cols[col]['vAlign']]);
+                for(let row = 0, rLen = datas.length; row < rLen; row++){
+                    sheet.setValue(row, col, datas[row][cols[col]['dataCode']]);
+                }
+            }
+        };
+        this.renderSheetFuc(sheet, fuc);
+    },
+
+    onCellDoubleClick: function (sender, args) {
+        let me = calcBaseView;
+        if(args.col === 0){
+            let baseFigure = args.sheet.getValue(args.row, args.col);
+            if(baseFigure.trim() !== ''){
+                //在光标后面插入
+                let insertStr = me.insertStr(baseFigure);
+                me.inputExpr.val(insertStr);
+            }
+        }
+        me.inputExpr.focus();
+    },
+    isDef: function (v) {
+        return v !== undefined && v !== null;
+    },
+    isFlag: function (v) {
+        return this.isDef(v.flagsIndex) && this.isDef(v.flagsIndex.fixed);
+    },
+    ifEdit: function () {
+        var selected = projectObj.project.mainTree.selected;
+        return MainTreeCol.readOnly.forCalcBase(selected)?false:true;
+    },
+    canBase: function (node) {
+        return node.sourceType === projectObj.project.Bills.getSourceType() && node.children.length === 0;
+    },
+    //根据节点获取可用计算基数
+    getFigure: function (node) {
+        let calcBase = projectObj.project.calcBase;
+        let parent = node.parent;
+        if(this.isFlag(node.data) && (node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.SUB_ENGINERRING
+            || node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CONSTRUCTION_TECH)){
+            return null;
+        }
+        else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION){
+            return calcBase.baseFigureClass.CONSTRUCTION_ORGANIZATION;
+        }
+        else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.OTHER){
+            return calcBase.baseFigureClass.OTHER;
+        }
+        else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CHARGE){
+            return calcBase.baseFigureClass.CHARGE;
+        }
+        else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.TAX){
+            return calcBase.baseFigureClass.TAX;
+        }
+        else {
+            if(!parent){
+                return calcBase.baseFigureClass.OTHERS;
+            }
+            else {
+                return this.getFigure(parent);
+            }
+        }
+    },
+    //计算基数转换为显示数据Obj to Array
+    toViewData: function (obj) {
+        let rst = [];
+        for(let figure in obj){
+            let figureObj = Object.create(null);
+            figureObj.base = figure;
+            figureObj.price = projectObj.project.calcBase.getBase(figure);
+            rst.push(figureObj);
+        }
+        return rst;
+    },
+
+    initCalctor: function (node) {
+        let me = calcBaseView;
+        me.buildSheet();
+        let baseObj = me.getFigure(node);
+        me.showData(me.toViewData(baseObj));
+
+    },
+
+    getInputExpr: function () {
+        return this.inputExpr.val();
+    },
+
+    //四则运算符控制,不可连续出现: ++ +*...
+    arithmeticLeagl: function (v) {
+        let rex = /[\+,\-,\*,\/]{2}/g;
+        return !rex.test(v);
+    },
+
+    //运算符点击显示到运算窗口
+    clickOpr: function (operators) {
+        let me = calcBaseView;
+        for(let i = 0, len = operators.length; i < len; i++){
+            operators[i].bind('click', function () {
+                let v = $(this)[0].textContent;
+                let insertStr = me.insertStr(v);
+                if(me.arithmeticLeagl(insertStr)){
+                    me.inputExpr.val(insertStr);
+                }
+                me.inputExpr.focus();
+            });
+        }
+    },
+
+    //光标处插入(替换选中)
+    insertStr: function (v) {
+        let me = calcBaseView;
+        //在光标后面插入
+        let exp = me.getInputExpr();
+        let startIdx = me.inputExpr[0].selectionStart;
+        let endIdx = me.inputExpr[0].selectionEnd;
+        let startStr = exp.substring(0, startIdx);
+        let endStr = exp.substring(endIdx, exp.length);
+        return startStr + v + endStr;
+    },
+
+    //输入窗口控制
+    inputControl: function () {
+        let me = calcBaseView;
+        me.inputExpr.keydown(function (e) {
+            if(!me.arithmeticLeagl(me.inputExpr.val() + e.key)){
+                return false;
+            }
+        });
+    },
+
+    //确认按钮
+    calcBaseConf: function () {
+        let me = calcBaseView;
+        me.confirmBtn.bind('click', function () {
+            let selected = projectObj.project.mainTree.selected;
+            selected.data.userCalcBase = me.getInputExpr();
+            projectObj.project.calcBase.calculate(selected);
+        });
+    },
+
+    getCalcBaseCellType:function () {
+        var ns = GC.Spread.Sheets;
+        function CalcBaseCellType() {
+            var init=false;
+        }
+        CalcBaseCellType.prototype = new ns.CellTypes.Text();
+        CalcBaseCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
+            if(value!=null){
+                // ctx.fillText(value,x+3+ctx.measureText(value).width,y+h-3);
+                ctx.fillText(value,x+w,y+h-3);
+            }
+            if(calcBaseView.editingCell){
+                if(calcBaseView.editingCell.row==options.row&&calcBaseView.editingCell.col==options.col){
+                    var image = document.getElementById('f_btn'),imageMagin = 3;
+                    var imageHeight = h-2*imageMagin;
+                    var imageWidth = w*2/7;
+                    var imageX = x + w - imageWidth- imageMagin, imageY = y + h / 2 - imageHeight / 2;
+                    ctx.save();
+                    ctx.drawImage(image, imageX, imageY,imageWidth,imageHeight);
+                    ctx.beginPath();
+                    ctx.arc(imageX+imageWidth/2,imageY+imageHeight/2,1,0,360,false);
+                    ctx.arc(imageX+imageWidth/2-4,imageY+imageHeight/2,1,0,360,false);
+                    ctx.arc(imageX+imageWidth/2+4,imageY+imageHeight/2,1,0,360,false);
+                    ctx.fillStyle="black";//填充颜色,默认是黑色
+                    ctx.fill();//画实心圆
+                    ctx.closePath();
+                    ctx.restore();
+                }
+            }
+        };
+        CalcBaseCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
+            return {
+                x: x,
+                y: y,
+                row: context.row,
+                col: context.col,
+                cellStyle: cellStyle,
+                cellRect: cellRect,
+                sheetArea: context.sheetArea
+            };
+        };
+        CalcBaseCellType.prototype.processMouseDown = function (hitinfo) {
+            let me=calcBaseView;
+            if(me.editingCell==null){
+                var showSelectBtn = true;
+                if(hitinfo.sheet.name()!='calc_detail'){
+                    showSelectBtn=me.ifEdit();
+                }
+                if(showSelectBtn){
+                    me.editingCell={
+                        row:hitinfo.row,
+                        col:hitinfo.col
+                    }
+                    hitinfo.sheet.invalidateLayout();
+                    hitinfo.sheet.repaint();
+                }
+            }else if(hitinfo.row==me.editingCell.row){
+                var offset=hitinfo.cellRect.x+hitinfo.cellRect.width-6;
+                var imageMagin=3;
+                var imageHeight = hitinfo.cellRect.height-2*imageMagin;
+                var imageWidth = hitinfo.cellRect.width*2/7;
+                if(hitinfo.x<offset&&hitinfo.x>offset-imageWidth){
+                    $('#qd-jsjs').modal({show: true});
+                }
+            }
+        };
+        CalcBaseCellType.prototype.processMouseLeave = function (hitinfo) {
+            calcBaseView.editingCell=null;
+            hitinfo.sheet.invalidateLayout();
+            hitinfo.sheet.repaint();
+        }
+        return new CalcBaseCellType();
+    },
+};
+
+$(document).ready(function () {
+   $('#qd-jsjs').on('shown.bs.modal', function () {
+       calcBaseView.initCalctor(projectObj.project.mainTree.selected);
+       calcBaseView.workBook.refresh();
+   });
+
+    $('#qd-jsjs').on('hidden.bs.modal', function () {
+        //清空输入框
+        calcBaseView.inputExpr.val('');
+        calcBaseView.workBook.destroy();
+        calcBaseView.workBook = null;
+    });
+
+    //bind operator click function
+    calcBaseView.clickOpr([$('#addOpr'), $('#subOpr'), $('#mulOpr'), $('#divOpr'), $('#leftOpr'), $('#rightOpr')]);
+
+    //bind input control
+    calcBaseView.inputControl();
+
+    //confirmBtn
+    calcBaseView.calcBaseConf();
+});

+ 32 - 3
web/building_saas/main/js/views/main_tree_col.js

@@ -41,11 +41,36 @@ let MainTreeCol = {
             ) return false
             else return true;
         },
+
         commonUnitFee: function(node){
             return !projectObj.project.calcProgram.isNullBill(node);
         },
-
-        bills: function (node) {
+        //根据节点、父节点类型判断是否可用计算基数
+        calcBaseType: function (node) {
+            function isDef (v) {
+                return v !== undefined && v !== null;
+            }
+            function isFlag (v) {
+                return this.isDef(v.flagsIndex) && this.isDef(v.flagsIndex.fixed);
+            }
+            let calcBase = projectObj.project.calcBase;
+            let parent = node.parent;
+            if(isFlag(node.data) && (node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.SUB_ENGINERRING
+                || node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CONSTRUCTION_TECH)){
+                return true;
+            }
+            else if(isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION){
+                return false;
+            }
+            else {
+                if(!parent){
+                    return false;
+                }
+                else {
+                    return this.calcBaseType(parent);
+                }
+            }
+        },        bills: function (node) {
             return node.sourceType === projectObj.project.Bills.getSourceType();
         },
         ration: function (node) {
@@ -71,7 +96,7 @@ let MainTreeCol = {
         },
         forCalcBase: function (node) {
             // to do according to billsParentType
-            return MainTreeCol.readOnly.billsParent(node) || MainTreeCol.readOnly.non_bills(node)||MainTreeCol.readOnly.leafBillsWithDetail(node);
+            return MainTreeCol.readOnly.billsParent(node) || MainTreeCol.readOnly.non_bills(node)||MainTreeCol.readOnly.leafBillsWithDetail(node) ||MainTreeCol.readOnly.calcBaseType(node);
         },
         forUnitFee: function (node) {
             return MainTreeCol.readOnly.ration(node) || MainTreeCol.readOnly.billsParent(node) || MainTreeCol.readOnly.leafBillsWithDetail(node);
@@ -99,6 +124,10 @@ let MainTreeCol = {
             return feeRateObject.getFeeRateEditCellType();
         },
 
+        calcBase: function () {
+            return calcBaseView.getCalcBaseCellType();
+        },
+
         // CSL, 2017-11-28
         calcProgramName: function (node) {
             if (

+ 4 - 3
web/building_saas/main/js/views/project_property_decimal_view.js

@@ -31,14 +31,14 @@ decimalObj.decimal = function (field, node) {
                     return billsQuanDecimal.decimal(node.data.unit);
                 }
                 else {
-                    returnV(this['bills'][field], this.process);
+                    return returnV(this['bills'][field], this.process);
                 }
             }
             else if(node.sourceType === projectObj.project.Ration.getSourceType()){
-                returnV(this['ration'][field], this.process);
+                return returnV(this['ration'][field], this.process);
             }
             else if(node.sourceType === projectObj.project.GLJ.getSourceType()){
-                returnV(this['glj'][field], this.process);
+                return returnV(this['glj'][field], this.process);
             }
         }
     }
@@ -47,6 +47,7 @@ decimalObj.decimal = function (field, node) {
 
 function returnV(v, r){
     if(isDef(v)){
+        console.log(v);
         return v;
     }
     return r;

+ 2 - 0
web/building_saas/main/js/views/project_view.js

@@ -322,6 +322,7 @@ var projectObj = {
         }
     },
     mainSpreadEditEnded: function (sender, info) {
+        $.bootstrapLoading.start();
         let project = projectObj.project;
         let node = project.mainTree.items[info.row];
         let colSetting = projectObj.mainController.setting.cols[info.col];
@@ -362,6 +363,7 @@ var projectObj = {
             console.log(projectInfoObj);
             if (!err) {
                 that.project.calcProgram.compileAllTemps();
+                that.project.calcBase.init(that.project);
                 that.project.calcFields = JSON.parse(JSON.stringify(feeType));
                 that.project.initCalcFields();
                 let str = JSON.stringify(that.project.projSetting.main_tree_col);

+ 4 - 2
web/users/js/login.js

@@ -21,13 +21,15 @@ $(document).ready(function () {
             data: {"account": account, "pw": pw},
             success: function (response) {
                 if (response.error === 0) {
+                    const url = response.last_page !== null && response.last_page !== '' ?
+                        response.last_page : '/pm';
                     if (response.login_ask === 0) {
-                        location.href = '/pm';
+                        location.href = url;
                     } else {
                         response.compilation_list = response.compilation_list === undefined || response.compilation_list === '' ?
                             null : JSON.parse(response.compilation_list);
                         if (response.compilation_list === null || response.compilation_list.length <= 0) {
-                            location.href = '/pm';
+                            location.href = url;
                             return false;
                         }
                         setVersion(response.compilation_list);