Browse Source

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

Conflicts:
	web/building_saas/main/js/views/main_tree_col.js
zhongzewei 7 năm trước cách đây
mục cha
commit
0b2e98bdf1

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 6 - 5
lib/bootstrap/bootstrap.min.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 2 - 2
lib/bootstrap/css/bootstrap.min.css


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

+ 1 - 2
modules/main/models/schemas/proj_setting.js

@@ -7,7 +7,7 @@ let Schema = mongoose.Schema;
 let collectionName = 'proj_setting';
 let settingConst = {
     billsCalcMode: {
-        rationContent: 0, rationPrice: 1, rationPriceConverse: 2, billsPrice: 3
+        rationContent: 0, rationPriceConverse: 1, rationPrice: 2, billsPrice: 3
     },
     zanguCalcMode: {
         common: 0, gatherMaterial: 1
@@ -26,7 +26,6 @@ let projSettingSchema = {
     billsCalcMode: {
         type: Number,
         default: settingConst.billsCalcMode.rationContent
-        // rationContent = 0, rationPrice = 1, rationPriceConverse = 2, billsPrice = 3
     },
     zanguCalcMode: {
         type: Number,

+ 4 - 4
modules/ration_glj/facade/ration_glj_facade.js

@@ -92,10 +92,10 @@ function combineQuantity(results,rations) {
         }
         resultList.push(tmp);
       /*  if(resultMap.hasOwnProperty(data.projectGLJID)){
-            resultMap[data.projectGLJID] += data.quantity;
-        }else {
-            resultMap[data.projectGLJID] = data.quantity;
-        }*/
+         resultMap[data.projectGLJID] += data.quantity;
+         }else {
+         resultMap[data.projectGLJID] = data.quantity;
+         }*/
     });
 
  /*   var resultList =[];

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

+ 5 - 0
public/web/common_util.js

@@ -13,3 +13,8 @@ String.prototype.hasSubStr = function (str) {
     return this.toLowerCase().indexOf(str.toLowerCase()) > -1;
 };
 
+// 树结点计算时,取费会出现值为NaN的情况,导致往父节点汇总(递归相加)会出现错误。
+function parseFloatPlus(value){
+    let rst = parseFloat(value);
+    return  isNaN(rst) ? 0 : rst;
+};

+ 4 - 1
public/web/sheet/sheet_common.js

@@ -98,7 +98,7 @@ var sheetCommonObj = {
 
         sheet.clear(0, 0, sheet.getRowCount(), sheet.getColumnCount(), GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
         if(sheet.getRowCount()<data.length){
-            sheet.setRowCount(data.length);
+            data.length<30?  sheet.setRowCount(30):sheet.setRowCount(data.length);
         }
         for (var col = 0; col < setting.header.length; col++) {
             var hAlign = "left", vAlign = "center";
@@ -126,6 +126,9 @@ var sheetCommonObj = {
                 //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
                 var val = data[row][setting.header[col].dataCode];
                 if(val&&setting.header[col].dataType === "Number"){
+                    if(setting.header[col].hasOwnProperty('tofix')){
+                        val =scMathUtil.roundToString(val,setting.header[col].tofix);
+                    }
                     if(setting.header[col].hasOwnProperty('decimalField')){
                         var decimal = getDecimal(setting.header[col].decimalField);
                         val =scMathUtil.roundToString(val,decimal);

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

+ 48 - 48
web/building_saas/css/main.css

@@ -8,10 +8,10 @@ body {
     font-size: 0.9rem
 }
 .btn.disabled, .btn:disabled {
-    color:#999
+  color:#999
 }
 .btn-link:focus, .btn-link:hover{
-    text-decoration: none
+  text-decoration: none
 }
 /*自定义css*/
 .header {
@@ -28,10 +28,10 @@ body {
     line-height: inherit
 }
 .top-msg{
-    position: fixed;
-    top:0;
-    width:100%;
-    z-index: 999
+  position: fixed;
+  top:0;
+  width:100%;
+  z-index: 999
 }
 .in-1{padding-left:0px!important}
 .in-2{padding-left:21px!important}
@@ -70,7 +70,7 @@ body {
     color: #333
 }
 .main-nav .nav-tabs{
-    border-bottom: none
+  border-bottom: none
 }
 .content {
     border-left: 1px solid #ccc;
@@ -78,7 +78,7 @@ body {
     background: #fff
 }
 .toolsbar,.toolsbar-f {
-    border-bottom: 1px solid #ccc
+  border-bottom: 1px solid #ccc
 }
 .tools-btn {
     height: 30px;
@@ -92,23 +92,23 @@ body {
     overflow-y: hidden;
 }
 .main-data-top,.main-data-full{
-    overflow: hidden;
-    width:100%
+  overflow: hidden;
+  width:100%
 }
 .main-content.col-lg-8{
-    width:66.666667%
+  width:66.666667%
 }
 .main-content.col-lg-12{
-    width:100%
+  width:100%
 }
 .main-side.col-lg-4{
-    width: 33.333333%;
+  width: 33.333333%;
 }
 .main-side.col-lg-0{
-    width:0%;
+  width:0%;
 }
 .sidebar-bottom,.sidebar-bottom .col-lg-6,.sidebar-bottom .col-lg-12 {
-    height:300px
+  height:300px
 }
 .top-content, .fluid-content {
     overflow: auto;
@@ -124,7 +124,7 @@ body {
     padding: 0.2em 0.5em
 }
 .side-tabs .nav-tabs .nav-item {
-    z-index: 999
+  z-index: 999
 }
 .side-tabs .nav-tabs {
     border-bottom: none;
@@ -251,69 +251,69 @@ body {
     overflow: auto;
 }
 .poj-list span.poj-icon {
-    padding-right:7px;
-    color:#ccc
+  padding-right:7px;
+  color:#ccc
 }
 .poj-list a.tree-open,.poj-list a.tree-close{
-    width:15px;
-    display: inline-block;
+  width:15px;
+  display: inline-block;
 }
 .print-toolsbar{
-    padding:5px
+  padding:5px
 }
 .print-toolsbar .panel {
-    display:inline-block;
-    vertical-align:top;
-    background:#f7f7f9
+  display:inline-block;
+  vertical-align:top;
+  background:#f7f7f9
 }
 .print-toolsbar .panel .panel-foot{
-    text-align: center;
-    font-size: 12px
+  text-align: center;
+  font-size: 12px
 }
 .print-list {
-    border-right:1px solid #ccc
+  border-right:1px solid #ccc
 }
 .print-list .form-list {
-    overflow: auto
+  overflow: auto
 }
 .print-list .list-tools{
-    height:50px;
-    padding:10px 0;
-    border-bottom:1px solid #f2f2f2
+  height:50px;
+  padding:10px 0;
+  border-bottom:1px solid #f2f2f2
 }
 .pageContainer {
-    background: #ededed;
-    text-align: center
+  background: #ededed;
+  text-align: center
 }
 .pageContainer .page{
-    border:9px solid transparent;
-    display: inline-block;
+  border:9px solid transparent;
+  display: inline-block;
 }
 .pageContainer .page img{
-    width:inherit;
-    height: inherit;
+  width:inherit;
+  height: inherit;
 }
 .modal-auto-height {
-    height: 400px;
-    overflow-y: auto;
+  height: 400px;
+  overflow-y: auto;
 }
 .modal-fixed-height {
-    height: 400px;
-    overflow-y: hidden;
+  height: 400px;
+  overflow-y: hidden;
 }
 .sidebar-tools-bar {
-    background:#fff
+  background:#fff
 }
 .side-search-box{
-    background:#fff;
-    border-bottom:1px solid #ddd
+  background:#fff;
+  border-bottom:1px solid #ddd
 }
 .navbar-crumb span{
-    max-width: 200px
+  max-width: 200px
 }
 .dropdown-item{
-    color:#007bff
+  color:#007bff
 }
 .dropdown-item.disabled, .dropdown-item:disabled{
-    pointer-events:none
-}
+  pointer-events:none
+}

+ 4 - 1
web/building_saas/glj/html/glj_index.html

@@ -12,7 +12,7 @@
 </div>
 <div class="container-fluid">
     <div class="row">
-        <div class="col-lg-12 p-0">
+        <div class="col-lg-12 p-0" id="glj-main">
             <div class="top-content">
                 <div class="main-data-top" id="project-glj">
                     <p style="text-align: center; margin-top: 30px;">正在加载数据</p>
@@ -29,6 +29,9 @@
                     <li class="nav-item">
                         <a class="nav-link" data-toggle="tab" data-name="machine" href="#jx" role="tab">机械单价</a>
                     </li>
+                    <li class="nav-item ml-auto mr-4">
+                        <a class="nav-link text-muted position-absolute resize" data-toggle="tooltip" data-placement="bottom" title="按住,上下拖动调整高度"><i class="fa fa-arrows-v"></i></a>
+                    </li>
                 </ul>
                 <!-- Tab panes -->
                 <div class="tab-content">

+ 8 - 0
web/building_saas/glj/js/project_glj.js

@@ -32,6 +32,10 @@ $(document).ready(function () {
         init();
     });
 
+    slideResize($("#glj-main"), function() {
+        projectGLJSpread.sheetObj.spread.refresh();
+    });
+
     // 单价文件切换弹框
     $('#change-dj').on('shown.bs.modal', function () {
         // 获取当前建设项数据
@@ -285,6 +289,10 @@ function spreadInit() {
             projectGLJSheet.filterData('unit_price.type', []);
         }
     });
+
+    loadSize("glj-main", function() {
+        projectGLJSpread.sheetObj.spread.refresh();
+    });
 }
 
 /**

+ 15 - 13
web/building_saas/js/global.js

@@ -17,17 +17,18 @@ function autoFlashHeight(){
     $(".poj-list").height($(window).height()-headerHeight-toolsbarHeight);
     $(".form-view").height($(window).height()-headerHeight-ftoolsbarHeight);
     $(".form-list").height($(window).height()-headerHeight-50 );
+
 };
 $(window).resize(autoFlashHeight);
 /*全局自适应高度结束*/
-$(function(){
-/*侧滑*/
-$(".open-sidebar").click(function(){
-    $(".slide-sidebar").animate({width:"800"}).addClass("open");
-});
-$("body").click(function(event){
+$(function () {
+    /*侧滑*/
+    $(".open-sidebar").click(function () {
+        $(".slide-sidebar").animate({width: "800"}).addClass("open");
+    });
+    $("body").click(function (event) {
         var e = event || window.event; //浏览器兼容性
-        if(!$(event.target).is('a')) {
+        if (!$(event.target).is('a')) {
             var elem = event.target || e.srcElement;
             while (elem) { //循环判断至跟节点,防止点击的是div子元素
                 if (elem.className == "open-sidebar" || elem.className == 'slide-sidebar open') {
@@ -35,13 +36,14 @@ $("body").click(function(event){
                 }
                 elem = elem.parentNode;
             }
-            $(".slide-sidebar").animate({width:"0"}).removeClass("open")// 关闭处理
+            $(".slide-sidebar").animate({width: "0"}).removeClass("open")// 关闭处理
         }
 
     });
-/*侧滑*/
-/*工具提示*/
-$(function () {
-  $('[data-toggle="tooltip"]').tooltip()
-});
+    /*侧滑*/
+    /*工具提示*/
+    $(function () {
+        $('[data-toggle="tooltip"]').tooltip();
+    });
+
 });

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

@@ -80,7 +80,7 @@
               </div>
               <div class="container-fluid">
                   <div class="row">
-                      <div class="main-content col-lg-12 p-0">
+                      <div class="main-content col-lg-12 p-0" id="main">
                           <div class="top-content">
                               <div class="main-data-top" id="billsSpread"></div>
                           </div>
@@ -107,6 +107,9 @@
                                   <li class="nav-item">
                                       <a class="nav-link" id="linkTZJNR" data-toggle="tab" href="#subSpread" role="tab">特征及内容</a>
                                   </li>
+                                  <li class="nav-item ml-auto mr-4">
+                                      <a class="nav-link text-muted position-absolute resize" data-toggle="tooltip" data-placement="bottom" title="按住,上下拖动调整高度"><i class="fa fa-arrows-v"></i></a>
+                                  </li>
                               </ul>
                               <!-- Tab panes -->
                               <div class="tab-content" id="tabCon">
@@ -266,13 +269,13 @@
                                             </div>
                                             <div class="form-check">
                                                 <label class="form-check-label">
-                                                    <input class="form-check-input" name="calcFlag" id="rationPrice" value="1" type="radio">
+                                                    <input class="form-check-input" name="calcFlag" id="rationPriceConverse" value="1" type="radio">
                                                     子目单价取费(反算):清单综合合价=清单综合单价*清单工程量
                                                 </label>
                                             </div>
                                             <div class="form-check">
                                                 <label class="form-check-label">
-                                                    <input class="form-check-input" name="calcFlag" id="rationPriceConverse" value="2" type="radio">
+                                                    <input class="form-check-input" name="calcFlag" id="rationPrice" value="2" type="radio">
                                                     子目单价取费(正算):清单综合合价=∑子目综合合价
                                                 </label>
                                             </div>
@@ -633,12 +636,6 @@
 
         <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
 
-
-        <!-- JS. -->
-        <script src="/lib/popper/popper.min.js"></script>
-        <script src="/lib/bootstrap/bootstrap.min.js"></script>
-        <script src="/web/building_saas/js/global.js"></script>
-
         <!--expression calculate-->
         <script src="/lib/JSExpressionEval_src/Date.js"></script>
         <script src="/lib/JSExpressionEval_src/Stack.js"></script>
@@ -655,6 +652,11 @@
         <script type="text/javascript" src="/public/web/url_util.js"></script>
         <script type="text/javascript" src="/public/web/number_util.js"></script>
         <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
+
+        <!-- JS. -->
+        <script src="/lib/popper/popper.min.js"></script>
+        <script src="/lib/bootstrap/bootstrap.min.js"></script>
+        <script src="/web/building_saas/js/global.js"></script>
         <!--报表 zTree -->
 
         <!-- SpreadJs -->

+ 1 - 1
web/building_saas/main/js/controllers/project_controller.js

@@ -63,7 +63,7 @@ ProjectController = {
                     newSource = project.Ration.insertStdRation(selected.source.getID(), null, std);
                     project.ration_glj.addRationGLJ(newSource,std);
                 } else {
-                    newSource = project.Ration.insertRation(selected.source.getID());
+                    newSource = project.Ration.insertRation(selected.source.getID(),null, rationType);
                 }
 
                 newNode = project.mainTree.insert(selected.getID(), selected.tree.rootID());

+ 99 - 1
web/building_saas/main/js/main.js

@@ -19,4 +19,102 @@ $(function () {
         // do something
     });
 
-});
+    // 读取本地存储的高度
+    loadSize("main", function() {
+        refreshSubSpread();
+    });
+
+    slideResize($("#main"), function() {
+        projectObj.mainSpread.refresh();
+        refreshSubSpread();
+    });
+});
+
+/**
+ * 拖动更改div大小
+ *
+ * @param {Object} rootElement - 最顶层div
+ * @param {function} callback - 成功后执行
+ * @return {void}
+ */
+function slideResize(rootElement, callback) {
+    let startY = 0;
+    let drag = false;
+    const element = rootElement.find('.resize');
+    const topContentEle = rootElement.find(".top-content");
+    const bottomContentEle = rootElement.find(".bottom-content");
+    let topContentHeight = 0;
+    let bottomContentHeight = 0;
+    let navHeight = 0;
+    let topChangeHeight = 0;
+    let bottomChangeHeight = 0;
+
+    // 鼠标点下时
+    element.mousedown(function(e) {
+        drag = true;
+        startY = e.clientY;
+        // 获取上部分的高度
+        topContentHeight = topContentEle.height();
+        // 获取下部分的高度
+        bottomContentHeight = bottomContentEle.height();
+        // nav高度部分
+        navHeight = bottomContentEle.children('ul.nav').height();
+        element.tooltip('hide');
+    });
+
+    // 鼠标移动
+    $("body").mousemove(function(e) {
+        if (drag) {
+            let moveHeight = e.clientY - startY;
+            // 判断拖动范围不能超出
+            topChangeHeight = topContentHeight + moveHeight;
+            topChangeHeight = topChangeHeight < 170 ? 170 : topChangeHeight;
+            topChangeHeight = topChangeHeight > 700 ? 700 : topChangeHeight;
+            topContentEle.children(".main-data-top").height(topChangeHeight);
+
+            bottomChangeHeight = bottomContentHeight - moveHeight;
+            bottomChangeHeight = bottomChangeHeight < 170 ? 170 : bottomChangeHeight;
+            bottomChangeHeight = bottomChangeHeight > 700 ? 700 : bottomChangeHeight;
+            bottomContentEle.children().find(".main-data-bottom").height(bottomChangeHeight - navHeight);
+        }
+    });
+
+    // 鼠标弹起
+    $("body").mouseup(function(e) {
+        if (drag) {
+            callback();
+            drag = false;
+            // 存入本地缓存
+            const storage = window.localStorage;
+            if (storage) {
+                const id = rootElement.attr('id');
+                storage.setItem('topHeight:' + id, topChangeHeight);
+                storage.setItem('bottomHeight:' + id, bottomChangeHeight);
+            }
+        }
+    });
+}
+
+/**
+ * 读取设置的高度
+ *
+ * @param {String} tag - 顶层div的id
+ * @param {function} callback - 回调函数
+ * @return {void}
+ */
+function loadSize(tag, callback) {
+    const storage = window.localStorage;
+    if (!storage || tag === '') {
+        return;
+    }
+    const topHeight = storage.getItem('topHeight:' + tag);
+    const bottomHeight = storage.getItem('bottomHeight:' + tag);
+    if (topHeight === null || bottomHeight === null) {
+        return;
+    }
+    const navHeight = $("#"+ tag +" .bottom-content").children('ul.nav').height();
+    $("#"+ tag +" .main-data-top").height(topHeight);
+    $("#"+ tag +" .main-data-bottom").height(bottomHeight - navHeight);
+    $("#"+ tag +" .bottom-content").height(bottomHeight);
+    callback();
+}

+ 2 - 15
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){
@@ -244,21 +245,7 @@ var Bills = {
             calcFees.setFee(node.data, field, newValue);
             let updateData = [];
             let data = {'ID': node.getID(), 'projectID': this.project.ID()};
-            if (field === 'quantity') {
-                data[field] = newValue;
-                data.isFromDetail=0;
-                // to do Calculate
-                if (node.data.fees) {
-                    data.fees = node.data.fees;
-                }
-            } else if (field === 'feesIndex.common.unitFee') {
-                // to do Calculate
-                if (node.data.fees) {
-                    data.fees = node.data.fees;
-                }
-            } else {
-                data[field] = newValue;
-            }
+            data[field] = newValue;
             updateData.push({'updateType': 'ut_update', 'updateData': tools.formatBillsUpdateData(data)});
             this.project.pushNow('updateBills', this.getSourceType(), updateData);
         };

+ 94 - 26
web/building_saas/main/js/models/calc_program.js

@@ -6,7 +6,7 @@
  *  用到费率的规则必须有feeRateID属性,当有该属性时,会自动显示费率值。
  */
 
-let defaultBillTemplate = {
+/*let defaultBillTemplate = {
     ID: 15,
     name: "清单公式",
     calcItems: [
@@ -98,7 +98,7 @@ let defaultBillTemplate = {
             memo: ''
         }
     ]
-};
+};*/
 
 const baseCalcType = {baseCalc: 0, adjustCalc: 1, budgetCalc: 2, diffCalc: 3,  offerCalc: 4};
 
@@ -411,7 +411,7 @@ class CalcProgram {
 
     doAfterUpdate (err, data) {
         if(!err){
-            // do
+            $.bootstrapLoading.end();
         }
     };
 
@@ -434,7 +434,7 @@ class CalcProgram {
         me.calcBases = rationCalcBase;
         me.templates = this.project.calcProgram.datas.templates;
 
-        me.templates.push(defaultBillTemplate);
+        // me.templates.push(defaultBillTemplate);
         // 先编译公用的基础数据
         me.compilePublics();
         for (let t of me.templates){
@@ -595,7 +595,30 @@ class CalcProgram {
                treeNode.source.children.length === 0;
     };
 
-    // 仅内部调用。注意:外部不能直接使用,因为这里传入的树节点必须有一定的初始化。
+    isNullBill(treeNode){
+        let me = this;
+        return me.isLeafBill(treeNode) && (treeNode.children.length ===0) && (!treeNode.data.calcBase);
+    };
+
+    initFeeField(treeNode, fieldName){
+        if (!treeNode.data.fees) {
+            treeNode.data.fees = [];
+            treeNode.data.feesIndex = {};
+        };
+        if (!treeNode.data.feesIndex[fieldName]) {
+            let fee = {
+                'fieldName': fieldName,
+                'unitFee': 0,
+                'totalFee': 0,
+                'tenderUnitFee': 0,
+                'tenderTotalFee': 0
+            };
+            treeNode.data.fees.push(fee);
+            treeNode.data.feesIndex[fieldName] = fee;
+        };
+    };
+
+  // 仅内部调用。注意:外部不能直接使用,因为这里传入的树节点必须有一定的初始化。
     InnerCalc(treeNode){
         let me = this;
         let project = me.project;
@@ -657,10 +680,10 @@ class CalcProgram {
                     for (let item of objsArr) {
                         let data = item.data;
                         if (data.feesIndex && data.feesIndex[ft.type]) {
-                            buf = (buf + parseFloat(data.feesIndex[ft.type].unitFee)).toDecimal(decimalObj.process);
-                            btf = (btf + parseFloat(data.feesIndex[ft.type].totalFee)).toDecimal(decimalObj.process);
-                            btuf = (btuf + parseFloat(data.feesIndex[ft.type].tenderUnitFee)).toDecimal(decimalObj.process);
-                            bttf = (bttf + parseFloat(data.feesIndex[ft.type].tenderTotalFee)).toDecimal(decimalObj.process);
+                            buf = (buf + parseFloatPlus(data.feesIndex[ft.type].unitFee)).toDecimal(decimalObj.process);
+                            btf = (btf + parseFloatPlus(data.feesIndex[ft.type].totalFee)).toDecimal(decimalObj.process);
+                            btuf = (btuf + parseFloatPlus(data.feesIndex[ft.type].tenderUnitFee)).toDecimal(decimalObj.process);
+                            bttf = (bttf + parseFloatPlus(data.feesIndex[ft.type].tenderTotalFee)).toDecimal(decimalObj.process);
                         };
                     };
                 }
@@ -688,11 +711,11 @@ class CalcProgram {
                         sum_rttf = (sum_rttf + rttf).toDecimal(decimalObj.process);
                     };
 
-                    if (me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationPrice || me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationPriceConverse) {
+                    if (me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationPriceConverse || me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationPrice) {
                         buf = (sum_rtf / bq).toDecimal(decimalObj.process);
                         btuf = (sum_rttf / bq).toDecimal(decimalObj.process);
                     };
-                    if (isBaseFeeType(ft.type) || (me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationPriceConverse && ft.type == "common")){
+                    if (isBaseFeeType(ft.type) || (me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationPrice && ft.type == "common")){
                         btf = sum_rtf;
                         bttf = sum_rttf;
                     }
@@ -712,16 +735,54 @@ class CalcProgram {
             };
             treeNode.data.calcTemplate = {"calcItems": rst};
         }
+        // 叶子清单的手工综合单价计算
+        else if (treeNode.calcType == treeNodeCalcType.ctCommonUnitFee){
+            delete treeNode.data.gljList;
+            if (treeNode.data.calcBase) treeNode.data.calcBase = null;  // 不能直接删除该属性,否则无法冲掉库中已存储的值
+            if (treeNode.data.programID) treeNode.data.programID = null;
+
+            let uf = (treeNode.data.feesIndex && treeNode.data.feesIndex.common && treeNode.data.feesIndex.common.unitFee) ? treeNode.data.feesIndex.common.unitFee : 0;
+            let tuf = (treeNode.data.feesIndex && treeNode.data.feesIndex.common && treeNode.data.feesIndex.common.tenderUnitFee) ? treeNode.data.feesIndex.common.tenderUnitFee : 0;
+            let q = treeNode.data.quantity ? treeNode.data.quantity : 0;
+            let tf = (uf * q).toDecimal(decimalObj.bills.totalPrice);
+            let ttf = (tuf * q).toDecimal(decimalObj.bills.totalPrice);
+
+            delete treeNode.data.fees;    // 直接删掉再新增,不用一个个费判断更新,效率更高。
+            delete treeNode.data.feesIndex;
+            me.initFeeField(treeNode, 'common');
+            treeNode.data.feesIndex.common.unitFee = uf.toDecimal(decimalObj.bills.unitPrice);
+            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.data.calcTemplate = {"calcItems": []};
+        }
+        // 叶子清单的计算基数计算
+        else if (treeNode.calcType == treeNodeCalcType.ctCalcBaseValue){
+            delete treeNode.data.gljList;
+            if (treeNode.data.programID) treeNode.data.programID = null;
+
+            let f = treeNode.data.feeRate ? treeNode.data.feeRate : 100;
+            let q = treeNode.data.quantity ? treeNode.data.quantity : 0;
+            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);
+            let ttf = tf;
+
+            delete treeNode.data.fees;    // 直接删掉再新增,不用一个个费判断更新,效率更高。
+            delete treeNode.data.feesIndex;
+            me.initFeeField(treeNode, 'common');
+            treeNode.data.feesIndex.common.unitFee = uf;
+            treeNode.data.feesIndex.common.totalFee = tf;
+            treeNode.data.feesIndex.common.tenderUnitFee = tuf;
+            treeNode.data.feesIndex.common.tenderTotalFee = ttf;
+            treeNode.changed = true;
+            treeNode.data.calcTemplate = {"calcItems": []};
+        }
+        // 定额或清单自己的计算程序计算
         else{
-            // 叶子清单的公式计算:使用缺省清单计算程序。需要提供总金额作为计算基数(不需要工料机),然后每条按比例(费率)计算,不需要工料机明细。
-            if (treeNode.calcType == treeNodeCalcType.ctCalcBaseValue){
-                delete treeNode.data.gljList;
-
-                if (treeNode.data.programID == undefined){
-                    treeNode.data.programID = defaultBillTemplate.ID;
-                };
-            }
-            else if (treeNode.calcType == treeNodeCalcType.ctRationCalcProgram) {
+            if (treeNode.calcType == treeNodeCalcType.ctRationCalcProgram) {
                 if (treeNode.data.type == rationType.volumePrice){
                     delete treeNode.data.gljList;
                     let muf = treeNode.data.marketUnitFee ? treeNode.data.marketUnitFee : 0;
@@ -743,7 +804,8 @@ class CalcProgram {
                 let rations = project.Ration.getBillsSortRation(treeNode.source.getID());
                 treeNode.data.gljList = project.ration_glj.getGatherGljArrByRations(rations);
 
-                if (treeNode.data.programID == undefined || treeNode.data.programID == defaultBillTemplate.ID){
+                // if (treeNode.data.programID == undefined || treeNode.data.programID == defaultBillTemplate.ID){
+                if (treeNode.data.programID == undefined){
                     treeNode.data.programID = projectInfoObj.projectInfo.property.engineering;
                 }
             };
@@ -781,17 +843,19 @@ class CalcProgram {
         let me = this;
         let isRation = treeNode.sourceType === me.project.Ration.getSourceType();
         let isBill = treeNode.sourceType === me.project.Bills.getSourceType();
-        let isBillPriceCalc = me.project.projSetting.billsCalcMode === leafBillGetFeeType.billsPrice;
-        let isLeafBill = me.isLeafBill(treeNode);
 
         if (isRation){
             treeNode.calcType = treeNodeCalcType.ctRationCalcProgram;
         }
-        else if (isLeafBill) {
+        else  if (me.isNullBill(treeNode)){
+            treeNode.calcType = treeNodeCalcType.ctCommonUnitFee;
+        }
+        else if (me.isLeafBill(treeNode)) {
             if (treeNode.children && treeNode.children.length > 0){
                 // me.calcLeafBillChildren(treeNode);
 
-                if (isBillPriceCalc)                        // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。(汇总清单所有定额的工料机)
+                // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。(汇总清单所有定额的工料机)
+                if (me.project.projSetting.billsCalcMode === leafBillGetFeeType.billsPrice)
                     treeNode.calcType = treeNodeCalcType.ctBillCalcProgram;
                 else                                        // 前三种计算模式下的叶子清单:汇总定额的计算程序的费用类别
                     treeNode.calcType = treeNodeCalcType.ctGatherRationsFees;
@@ -837,6 +901,8 @@ class CalcProgram {
                 let data = {
                     ID: node.data.ID,
                     projectID: me.project.ID(),
+                    /*  subType、quantity、calcBase、programID、marketUnitFee等等字段较为特殊,它们的改变一定会触发计算并导致计算
+                    结果的变化,从而引发保存动作。将这些字段放在该位置跟计算结果一起保存,可减少前端跟后端的通讯频率。              */
                     subType: node.data.subType,
                     quantity: node.data.quantity,
                     calcBase: node.data.calcBase,
@@ -844,7 +910,9 @@ class CalcProgram {
                     marketUnitFee: node.data.marketUnitFee,
                     marketTotalFee: node.data.marketTotalFee,
                     fees: node.data.fees,
-                    isFromDetail:node.data.isFromDetail
+                    isFromDetail:node.data.isFromDetail,
+                    feeRate: node.data.feeRate,
+                    feeRateID: node.data.feeRateID
                 };
                 let newData = {'updateType': 'ut_update', 'updateData': data};
                 me.project.push(node.sourceType, [newData]);

+ 36 - 21
web/building_saas/main/js/models/fee_rate.js

@@ -50,6 +50,7 @@ var FeeRate = {
             }
         };
         FeeRate.prototype.getFeeRateByID=function (ID) {
+            ID=parseInt(ID);
             var rates = this.getActivateFeeRate().rates;
             return _.find(rates,{'ID':ID})
         };
@@ -123,12 +124,13 @@ var FeeRate = {
                 rateIndex:params.sourceIndex,
                 rate:params.dataItem
             }
-            doc.rate.rate =doc.rate.rate.toDecimal(feeRate_consts.decimal);
+            doc.rate.rate =doc.rate.rate.toDecimal(getDecimal("feeRate"));
             this.updateFeeRate(query,doc);
             if(this.ifRateChange(params)){
                 //this.synchronizeFeeRate();
                 this.onFeeRateChange(params.dataItem.ID,params.dataItem.rate);
             }
+            $.bootstrapLoading.end();
         };
 
         FeeRate.prototype.batchUpdateFeeRate = function (items,feerate) {
@@ -190,6 +192,7 @@ var FeeRate = {
                     calcProgramObj.showData(node);
                 }
             }
+            project.calcProgram.calcAllNodes(calcAllType.catBills);
             socket.emit('feeRateChangeNotify', this.getActivateFeeRateFileID());
         };
         FeeRate.prototype.onFeeRateFileChange=function () {
@@ -201,6 +204,7 @@ var FeeRate = {
                     calcProgramObj.showData(node);
                 }
             }
+            project.calcProgram.calcAllNodes(calcAllType.catBills);
             socket.emit('feeRateChangeNotify', this.getActivateFeeRateFileID());
         };
 
@@ -211,7 +215,7 @@ var FeeRate = {
                     if(n.data.hasOwnProperty("feeRateID")&&n.data.feeRateID){
                         var rate = me.getFeeRateByID(n.data.feeRateID);
                         if(rate){
-                            n.data.feeRate=number_util.roundToString(rate.rate,feeRate_consts.decimal);
+                            n.data.feeRate=number_util.roundToString(rate.rate,getDecimal("feeRate"));
                             return true;
                         }else {
                             n.data.feeRate=null;
@@ -256,7 +260,7 @@ var FeeRate = {
         FeeRate.prototype.refreshBillsByRateID=function(rateID,value){
             var nodes = _.filter(projectObj.project.mainTree.items,function (n) {
                 if(n.sourceType==ModuleNames.bills&&n.data.feeRateID==rateID){
-                    n.data.feeRate=number_util.roundToString(value,feeRate_consts.decimal);
+                    n.data.feeRate=number_util.roundToString(value,getDecimal("feeRate"));
                     return true;
                 }else {
                     return false;
@@ -338,19 +342,23 @@ var FeeRate = {
         FeeRate.prototype.updateFeeRateFromBills=function(value,node){
             var me =this;
             if(node.sourceType === project.Bills.getSourceType()){
-                var value= number_util.checkNumberValue(value,feeRate_consts.decimal);
-                if(value){
+                var fee_value= number_util.checkNumberValue(value,getDecimal("feeRate"));
+                if(fee_value!=null){
                     var bill = node.data;
                     var rate =me.getFeeRateByID(bill.feeRateID);
-                    var data=me.getfbUpdateData(rate,bill,value);
+                    var data=me.getfbUpdateData(rate,bill,fee_value,value);
+                    if(data==null){//只更改清单的值的情况下,由计算程序更新
+                        project.calcProgram.calculate(node);
+                        project.calcProgram.saveNode(node);
+                    }
                     this.setFeeRateToBill(data,function (result) {
                         if(data.hasOwnProperty('feeRate')){
-                            rate.rate=value;
-                            me.onFeeRateChange(rate.ID,value);
-                        }else {
+                            rate.rate=fee_value;
+                            me.onFeeRateChange(rate.ID,fee_value);
+                        }/*else {
                             bill.feeRate=value;
                             projectObj.mainController.refreshTreeNode([node])
-                        }
+                        }*/
                     });
                 }else {
                     projectObj.mainController.refreshTreeNode([node]);
@@ -359,7 +367,7 @@ var FeeRate = {
         };
 
         FeeRate.prototype.updateFeeRateFromCalc=function (value,editInfo) {
-            var value= number_util.checkNumberValue(value,feeRate_consts.decimal);
+            var value= number_util.checkNumberValue(value,getDecimal("feeRate"));
             if(value){
                 if(editInfo.calcItem.feeRateID){
                     var rate = projectObj.project.FeeRate.getFeeRateByID(editInfo.calcItem.feeRateID);
@@ -396,9 +404,10 @@ var FeeRate = {
             });
         }
 
-        FeeRate.prototype.getfbUpdateData=function (rate,bill,value) {
-            var data={};
-            if(bill.feeRateID){
+        FeeRate.prototype.getfbUpdateData=function (rate,bill,value,editText) {
+            var data=null;
+            if(bill.feeRateID&&editText!=null){
+                data = {};
                 data.feeRate={
                     query:{
                         'ID':this.getActivateFeeRateID(),
@@ -408,8 +417,12 @@ var FeeRate = {
                         'rates.$.rate':value
                     }
                 }
-            }else {
-                data.bills={
+            }else  if(editText==null){
+                bill.feeRateID = null;
+                bill.feeRate =null;
+            }else { //这里只改变当前清单的费率值,不在这里提交后台,交给计算程序处理。
+                bill["feeRate"]=value
+              /*  data.bills={
                     query:{
                         ID:bill.ID,
                         projectID:bill.projectID,
@@ -418,7 +431,7 @@ var FeeRate = {
                     doc:{
                         feeRate:value
                     }
-                }
+                }*/
             }
             return data;
         };
@@ -462,15 +475,17 @@ var FeeRate = {
        
 
         FeeRate.prototype.setFeeRateToBill=function(data,callback){
-            CommonAjax.post('/feeRates/setFeeRateToBill', data, function (data) {
-                callback(data);
-            });
+            if(data){
+                CommonAjax.post('/feeRates/setFeeRateToBill', data, function (data) {
+                    callback(data);
+                });
+            }
         };
         FeeRate.prototype.loadFeeRateToBill=function (node) {
             if(node.data.feeRateID){
                 var feeRate = this.getFeeRateByID(node.data.feeRateID);
                 if(feeRate){
-                    node.data.feeRate=number_util.roundToString(feeRate.rate,feeRate_consts.decimal);// parseFloat(feeRate.rate).toFixed(feeRate_consts.decimal);
+                    node.data.feeRate=number_util.roundToString(feeRate.rate,getDecimal("feeRate"));// parseFloat(feeRate.rate).toFixed(feeRate_consts.decimal);
                 }
             }
         };

+ 4 - 6
web/building_saas/main/js/models/main_consts.js

@@ -48,9 +48,6 @@ const gljType = {
     EQUIPMENT: 5
 };
 
-const feeRate_consts={
-    decimal:3
-};
 
 const CP_Col_Width = {          // 多处计算程序界面的列宽统一设置
     rowHeader: 30,
@@ -72,7 +69,8 @@ const treeNodeCalcType = {
     ctBillCalcProgram: 2,       // 汇总清单下所有定额的工料机
     ctGatherRationsFees: 3,     // 汇总定额的各个费
     ctGatherBillsFees: 4,       // 汇总清单的各个费
-    ctCalcBaseValue: 5
+    ctCalcBaseValue: 5,
+    ctCommonUnitFee: 6
 };
 
 const calcAllType = {
@@ -119,8 +117,8 @@ const rationType = {
 
 const leafBillGetFeeType = {
     rationContent: 0,
-    rationPrice: 1,
-    rationPriceConverse: 2,
+    rationPriceConverse: 1,
+    rationPrice: 2,
     billsPrice: 3
 };
 

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

@@ -26,7 +26,7 @@ let rationPM = {
             {headerName:"费用代号",headerWidth:CP_Col_Width.code, dataCode:"code", dataType: "String"},
             {headerName:"费用名称",headerWidth:CP_Col_Width.name, dataCode:"name", dataType: "String"},
             {headerName:"计算基数",headerWidth:CP_Col_Width.dispExprUser, dataCode:"dispExprUser", dataType: "String"},
-            {headerName:"费率",headerWidth:CP_Col_Width.feeRate, dataCode:"feeRate", dataType: "Number",hAlign: "right",tofix: feeRate_consts.decimal},
+            {headerName:"费率",headerWidth:CP_Col_Width.feeRate, dataCode:"feeRate", dataType: "Number",hAlign: "right",decimalField:"feeRate"},
             {headerName:"费用类别",headerWidth:CP_Col_Width.displayFieldName, dataCode:"displayFieldName", dataType: "String", hAlign: "center"},
             {headerName:"基数说明",headerWidth:CP_Col_Width.statement, dataCode:"statement", dataType: "String"},
             {headerName:"备注",headerWidth:CP_Col_Width.memo, dataCode:"memo", dataType: "String"}

+ 13 - 8
web/building_saas/main/js/views/fee_rate_view.js

@@ -19,7 +19,7 @@ var feeRateObject={
     sheetSetting: {
         header: [
             {headerName: "专业名称", headerWidth: 200, dataCode: "name", dataType: "String"},
-            {headerName: "值%", headerWidth: 150, dataCode: "rate", dataType: "Number",hAlign: "right",tofix:feeRate_consts.decimal},
+            {headerName: "值%", headerWidth: 150, dataCode: "rate", dataType: "Number",hAlign: "right",decimalField:"feeRate"},
             {headerName: "备注", dataCode: "memo", dataType: "String"}
         ],
         view: {
@@ -39,7 +39,6 @@ var feeRateObject={
             id: 'rate',
             caption: '值%',
             dataField: 'rate',
-            format: '0.000',
             width: 120,
             minWidth: 50,
             allowEditing: true
@@ -113,7 +112,6 @@ var feeRateObject={
             if(!$('#cascadeSet').prop('checked')||params.hasOwnProperty('viewIndex')){
                 projectObj.project.FeeRate.updateFeeRateByEdit(params,feeRateObject.activateFeeRate);
             }
-
         }
     },
     createSheet:function(){
@@ -151,10 +149,12 @@ var feeRateObject={
             for (var row = 0; row < data.length; row++) {
                 var val = data[row][setting.header[col].dataCode];
                 if(val&&setting.header[col].dataType === "Number"){
-                    if(setting.header[col].hasOwnProperty('tofix')){
-                        val =parseFloat(val).toFixed(setting.header[col].tofix);
+                    if(setting.header[col].hasOwnProperty('decimalField')){
+                        var decimal = getDecimal(setting.header[col].decimalField);
+                        val =scMathUtil.roundToString(val,decimal);
+                        sheet.setFormatter(-1, col,getFormatter(decimal), GC.Spread.Sheets.SheetArea.viewport);
                     }else {
-                        val =parseFloat(val).toFixed(2);
+                        val =scMathUtil.roundToString(val,2);
                     }
                 }
                 sheet.setValue(row, col, val, ch);
@@ -358,6 +358,8 @@ var feeRateObject={
         }
         this.activateFeeRate = projectObj.project.FeeRate.getActivateFeeRate();
         this.datas = this.activateFeeRate.rates;
+        var rateColSetting = _.find(this.columns,{"id":"rate"});
+        rateColSetting?rateColSetting.format=getFormatter(getDecimal("feeRate")):"";
         this.mainViews = new GC.Spread.Views.DataView($('#divFee')[0],
             this.dataSource, this.columns, new GC.Spread.Views.Plugins.GridLayout(this.options));
         this.mainViews["rowClick"].addHandler(subRateObject.reFreshRateViews);
@@ -648,8 +650,11 @@ var feeRateObject={
        var selected = projectObj.project.mainTree.selected;
         projectObj.project.FeeRate.submitFeeRateFromBill(rate,selected.data,function (data) {
             selected.data.feeRateID=rate.ID.toString();
-            selected.data.feeRate=parseFloat(rate.rate).toFixed(feeRate_consts.decimal);
-            projectObj.mainController.refreshTreeNode([selected]);
+            selected.data.feeRate=scMathUtil.roundToString(rate.rate,getDecimal("feeRate"));
+            selected.changed = true;
+            projectObj.project.calcProgram.calculate(selected);
+            projectObj.project.calcProgram.saveNode(selected);
+            //projectObj.mainController.refreshTreeNode([selected]);
             $("#fee_rate_tree").modal('hide');
         });
     },

+ 46 - 11
web/building_saas/main/js/views/glj_view.js

@@ -18,10 +18,6 @@ var gljOprObj = {
     selectedGLJClass:null,
     parentNodeIds:{},
     activeTab:'#linkGLJ',
-    decimalSetting:{
-        marketPrice:2,
-        customQuantity:3
-    },
     setting: {
         header: [
             {headerName: "编码", headerWidth: 100, dataCode: "code", dataType: "String", formatter: "@"},
@@ -32,6 +28,7 @@ var gljOprObj = {
             {headerName: "定额消耗量", headerWidth: 80, dataCode: "rationItemQuantity", dataType: "Number", hAlign: "right",decimalField:"glj.quantity"},    // dataType: "Number", formatter: "0.00"
             {headerName: "自定义消耗量", headerWidth: 80, dataCode: "customQuantity", dataType: "Number", hAlign: "right",decimalField:"glj.quantity"},
             {headerName: "消耗量", headerWidth: 80, dataCode: "quantity", dataType: "Number", hAlign: "right",decimalField:"glj.quantity"},
+            {headerName: "总消耗量", headerWidth: 80, dataCode: "totalQuantity", dataType: "Number", hAlign: "right",decimalField:"glj.quantity"},
             {headerName: "基价单价", headerWidth: 80, dataCode: "basePrice", dataType: "Number", hAlign: "right",decimalField:"glj.unitPrice"},
             {headerName: "调整基价", headerWidth: 80, dataCode: "adjustPrice", dataType: "Number", hAlign: "right",decimalField:"glj.unitPrice"},
             {headerName: "市场单价", headerWidth: 80, dataCode: "marketPrice", dataType: "Number", hAlign: "right",decimalField:"glj.unitPrice"},
@@ -68,7 +65,7 @@ var gljOprObj = {
         header:[
             {headerName: "名称", headerWidth: 100, dataCode: "name", dataType: "String"},
             {headerName: "计算式", headerWidth: 120, dataCode: "regex", dataType: "String"},
-            {headerName: "结果(C)", headerWidth: 120, dataCode: "result", dataType: "Number",formatter:"0.0000",tofix:4},
+            {headerName: "结果(C)", headerWidth: 120, dataCode: "result", dataType: "Number",decimalField:"quantity_detail"},
             {headerName: "累加", headerWidth: 120, dataCode: "isSummation", dataType: "String",cellType:"checkBox"}
         ],
         view:{
@@ -541,6 +538,8 @@ var gljOprObj = {
      //   $('#dropdown').hide();
     },
     showRationGLJData:function (node) {
+        console.log("showRationGLJData");
+        console.log(+new Date());
         var gljList = [];
         var ration_glj = projectObj.project.ration_glj;
         node=node?node:projectObj.project.mainTree.selected;
@@ -551,12 +550,24 @@ var gljOprObj = {
         }
     },
     showRationGLJSheetData:function (init) {
-        this.sheet.getRange(0,-1,this.sheet.getRowCount(),-1).visible(true);
+        this.sheet.setRowCount(0);
+        console.log("showRationGLJSheetData---init")
+        console.log(+new Date())
+        //this.sheet.getRange(0,-1,this.sheet.getRowCount(),-1).visible(true); //这个方法导致加载缓慢
         this.sheetData=_.sortBy(this.sheetData,'type');
-        this.addMixRatioToShow();
+        console.log("addMixRatioToShow");
+        console.log(+new Date())
+        this.sumQuantity();//计算总消耗量
+        this.addMixRatioToShow();//显示组成物信息
+        console.log("start initRationTree");
+        console.log(+new Date());
         this.initRationTree(init);
-        sheetCommonObj.showData(this.sheet,this.setting,this.sheetData);
+        console.log("end initRationTree");
+        console.log(+new Date());
 
+        sheetCommonObj.showData(this.sheet,this.setting,this.sheetData);
+        console.log("end show");
+        console.log(+new Date())
     },
     initRationTree:function (init) {
         this.sheet.getRange(-1, 0, -1, 1).cellType(this.getTreeNodeCellType(this.sheetData));
@@ -569,7 +580,11 @@ var gljOprObj = {
                 }else {
                     collapsed = this.sheetData[i].collapsed==undefined?true:this.sheetData[i].collapsed;
                 }
-                this.sheet.getRange(i+1, -1, this.sheetData[i].subList.length, -1).visible(!collapsed);// this.sheet.getRange(i+1, -1, this.sheetData[i].subList.length, -1).locked(true);
+                if(collapsed==true){
+                    this.sheet.getRange(i+1, -1, this.sheetData[i].subList.length, -1).visible(false);
+                }
+                //this.sheet.getRange(i+1, -1, this.sheetData[i].subList.length, -1).visible(!collapsed);// this.sheet.getRange(i+1, -1, this.sheetData[i].subList.length, -1).locked(true);
+                //这个方法导致加载缓慢
             }
         }
     },
@@ -584,6 +599,25 @@ var gljOprObj = {
         this.sheetData=this.combineWithProjectGlj(gljList);
         this.showRationGLJSheetData(true);
     },
+    sumQuantity:function (node) {
+      if(this.sheetData.length>0){
+          node=node?node:projectObj.project.mainTree.selected;
+          let ration = node.data;
+          let quantity = ration.quantity;
+          quantity = (quantity==0||quantity==undefined||quantity==null||quantity=="")?1:quantity;
+          for(let glj of this.sheetData){
+              if(glj.isMixRatio==true){//如果是用于显示的组成物,则不用计算,跳过
+                  continue;
+              }
+              glj.totalQuantity = scMathUtil.roundToString(quantity*glj.quantity,getDecimal("glj.quantity"));
+              if(glj.hasOwnProperty('subList')){//需要计算glj下挂的组成物的总消耗量
+                  for(let subG of glj.subList){
+                      subG.totalQuantity = scMathUtil.roundToString(subG.rationItemQuantity*glj.totalQuantity,getDecimal("glj.quantity"));
+                  }
+              }
+          }
+      }
+    },
     addMixRatioToShow:function () {
         var newList=[];
         _.remove(this.sheetData,{'isMixRatio':true});
@@ -722,7 +756,8 @@ var gljOprObj = {
             if(args.editingText==null){
                 newval="";
             }else {
-                newval = number_util.checkNumberValue(args.editingText,this.decimalSetting[updateField]);
+                var decimal = updateField=='customQuantity'?getDecimal("glj.quantity"):getDecimal("glj.unitPrice");
+                newval = number_util.checkNumberValue(args.editingText,decimal);
                 if(newval==null){
                     me.sheet.getCell(args.row, args.col).value(recode[updateField]);
                     return;
@@ -1246,7 +1281,7 @@ $(function(){
 function getDecimal(fieldID,node) {
     if(node){
         return decimalObj.decimal(fieldID,node);
-    }else if(fieldID.indexOf(".")){
+    }else if(fieldID.indexOf(".")!=-1){
         var keyArray = fieldID.split(".");
         return decimalObj[keyArray[0]][keyArray[1]];
     }else {

+ 7 - 4
web/building_saas/main/js/views/main_tree_col.js

@@ -30,10 +30,10 @@ let MainTreeCol = {
         }
     },
     readOnly: {
+        // CSL, 2017-11-28
         subType: function (node){
             return (node.data.type != 2 && node.data.type != 3);
         },
-        // CSL, 2017-11-28
         calcProgramName: function (node) {
             if (
                 node.sourceType === projectObj.project.Ration.getSourceType() ||
@@ -41,7 +41,11 @@ let MainTreeCol = {
             ) return false
             else return true;
         },
-        //根据节点、父节点类型判断是否可用计算基数
+
+commonUnitFee: function(node){
+            return !projectObj.project.calcProgram.isNullBill(node);
+        },
+//根据节点、父节点类型判断是否可用计算基数
         calcBaseType: function (node) {
             function isDef (v) {
                 return v !== undefined && v !== null;
@@ -66,8 +70,7 @@ let MainTreeCol = {
                     return this.calcBaseType(parent);
                 }
             }
-        },
-        bills: function (node) {
+        },        bills: function (node) {
             return node.sourceType === projectObj.project.Bills.getSourceType();
         },
         ration: function (node) {

+ 16 - 7
web/building_saas/main/js/views/project_view.js

@@ -119,7 +119,7 @@ var projectObj = {
         return value;
     },
     checkSpreadEditingText: function (editingText, colSetting) {
-        if (colSetting.data.field === 'quantity' || colSetting.data.field === 'feesIndex.common.unitFee') {
+        if (colSetting.data.field === 'quantity') {
             return this.checkFormulaValidField(editingText, colSetting);
         }
         else if (colSetting.data.field === 'programID') {
@@ -273,9 +273,10 @@ var projectObj = {
             else if(fieldName ==='feeRate'){
                 project.FeeRate.updateFeeRateFromBills(value,node,fieldName);
             }
-            else if (fieldName === 'quantity' || fieldName === 'marketUnitFee' || fieldName === 'programID' || fieldName === 'subType' || fieldName === 'calcBase'){
+            else if (fieldName === 'quantity' || fieldName === 'marketUnitFee' || fieldName === 'programID' ||
+                fieldName === 'subType' || fieldName === 'calcBase' || fieldName === 'feesIndex.common.unitFee'){
                 if (fieldName === 'quantity') {
-                    if (value) {value = value.toDecimal(decimalObj.decimal(fieldName,node))};
+                   if (value) {value = value.toDecimal(decimalObj.decimal(fieldName,node))};
                    if(project.quantity_detail.quantityEditChecking(value,node,fieldName)){
                        node.data.isFromDetail=0;
                        project.quantity_detail.cleanQuantityDetail(node,true);
@@ -283,16 +284,23 @@ var projectObj = {
                        projectObj.mainController.refreshTreeNode([node]);
                        return;
                    }
-                } else if (fieldName === 'marketUnitFee') {
+                }
+                else if (fieldName === 'marketUnitFee' || fieldName === 'feesIndex.common.unitFee') {
                     if (value) {value = parseFloat(value).toDecimal(decimalObj.decimal("unitPrice", node))};
-                } else if (fieldName === 'calcBase') {
+                }
+                else if (fieldName === 'calcBase') {
                     if (value) {value = parseFloat(value).toDecimal(decimalObj.decimal("totalPrice", node))};
                 };
 
                 node.changed = true;
-                node.data[fieldName] = value;
+                if (fieldName == 'feesIndex.common.unitFee'){
+                    project.calcProgram.initFeeField(node, 'common');
+                    node.data.feesIndex.common.unitFee = value;
+                }
+                else node.data[fieldName] = value;
                 project.calcProgram.calculate(node);
                 project.calcProgram.saveNode(node);
+                gljOprObj.showRationGLJSheetData();
             }
             else {
                 if (node.sourceType === project.Bills.getSourceType()) {
@@ -314,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];
@@ -610,8 +619,8 @@ $('#poj-set').on('show.bs.modal', function () {
         let mode = projectObj.project.projSetting.billsCalcMode;
         let settingConst = projectObj.project.projSetting.settingConst;
         setCalcFlag($('#rationContent'), settingConst.billsCalcMode.rationContent, mode);
-        setCalcFlag($('#rationPrice'), settingConst.billsCalcMode.rationPrice, mode);
         setCalcFlag($('#rationPriceConverse'), settingConst.billsCalcMode.rationPriceConverse, mode);
+        setCalcFlag($('#rationPrice'), settingConst.billsCalcMode.rationPrice, mode);
         setCalcFlag($('#billsPrice'), settingConst.billsCalcMode.billsPrice, mode);
 
         mode = projectObj.project.projSetting.zanguCalcMode;

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