소스 검색

Merge branch 'master' of http://192.168.1.41:3000/SmartCost/YangHuCost

vian 5 년 전
부모
커밋
a0aab089b7

+ 2 - 0
modules/all_models/material_calc.js

@@ -81,6 +81,7 @@ let freightSchema = {
     loadingTimes:String,//装卸次数
     otherFee:String,//其它费用
     freightIncreaseRate:String,//运价增加率
+    heightFee:String,//高原增加费
     weightCoe:String,//加权系数
     rations:[ration_schema],
     ration_gljs:[ration_glj],
@@ -97,6 +98,7 @@ let originalSchema = {
     supplyLocation:String,//供应地点
     supplyPrice:String,//供应价
     coe:String,//加权系数
+    heightFee:String,//高原增加费
     rations:[ration_schema],
     ration_gljs:[ration_glj]
 };

+ 2 - 0
modules/all_models/unit_price.js

@@ -53,7 +53,9 @@ let modelSchema = {
     },
     supplyLocation:String,//供应地点
     originalPrice:String,//原价
+    priceHeightFee:String,//自采高原增加费
     unitFreight:String,//单价运费
+    freightHeightFee:String,//自办运输高原增加费
     totalLoadingTimes:String,//装卸总次数
     offSiteTransportLoss:String,//场外运输损耗
     purchaseStorage:String,//采购及保管费

+ 4 - 1
modules/all_models/unit_price_file.js

@@ -11,7 +11,10 @@ let Schema = mongoose.Schema;
 let collectionName = 'unit_price_file';
 let modelSchema = {
     // 自增id
-    id: Number,
+    id: {
+      type: Number,
+      index: true
+    },
     // 标段id
     project_id: {
         type: Number,

+ 1 - 1
modules/glj/models/unit_price_model.js

@@ -346,7 +346,7 @@ class UnitPriceModel extends BaseModel {
     }
 
     async updateParentUnitPrice(mixRatio,fieid,project_id,newValueMap,batchUpdate){//batchUpdate 批量更新标记,如果true,只生成task
-        let  decimalObject =await decimal_facade.getProjectDecimal(project_id);
+        let  decimalObject =project_id?await decimal_facade.getProjectDecimal(project_id):null;
         let quantity_decimal = (decimalObject&&decimalObject.glj&&decimalObject.glj.quantity)?decimalObject.glj.quantity:3;
         let price_decimal = (decimalObject&&decimalObject.glj&&decimalObject.glj.unitPrice)?decimalObject.glj.unitPrice:2;
         //查找该工料机所有组成物

+ 50 - 0
modules/unit_price_file/controllers/unit_price_controller.js

@@ -0,0 +1,50 @@
+
+let mongoose = require("mongoose")
+let logger = require("../../../logs/log_helper").logger;
+let config = require("../../../config/config.js");
+let unitPriceFileModel = mongoose.model('unit_price_file');
+let projectModel = mongoose.model('projects');
+const ProjectDao = require('../../pm/models/project_model').project;
+let unitPriceModel = mongoose.model('unit_price');
+let mixRatioModel = mongoose.model('mix_ratio');
+let glj_type_util = require('../../../public/cache/std_glj_type_util');
+let _ = require("lodash");
+
+module.exports={
+    index:async function(req,res){
+      let unitPriceFileID = req.params.unitPriceFileID;
+      let unitPriceFile = await unitPriceFileModel.findOne({id:unitPriceFileID}).lean();
+      let project = await projectModel.findOne({ID:unitPriceFile.root_project_id}).lean();
+      let tenderData = await ProjectDao.getTenderByUnitPriceFileId(unitPriceFileID);
+      let unitpriceList = await unitPriceModel.find({unit_price_file_id:unitPriceFileID},{supplyLocation:0}).lean();
+      let mixRatioList = await mixRatioModel.find({unit_price_file_id:unitPriceFileID}).lean();
+      let mixRatioMap = _.groupBy(mixRatioList,"connect_key");
+
+
+
+      let gljTypeMap = glj_type_util.getStdGljTypeCacheObj().innerGljTypeObj;
+      let usedTenderList = [];
+      if (tenderData !== null) {
+          for (let tmp of tenderData) {
+              usedTenderList.push(tmp.name);
+          }
+      }
+      let usedTenderString = "人材机单价的变化,将自动影响以下单位工程造价:<br>"+usedTenderList.join("<br>");
+      res.render('building_saas/unit_price_file/index.html',
+        {
+          userAccount: req.session.userAccount,
+          userID: req.session.sessionUser.id,
+          versionName: req.session.compilationVersion,
+          unitFileName:unitPriceFile.name,
+          rootProjectName:project.name,
+          usedTenderList:usedTenderList,
+          usedTenderString:usedTenderString,
+          unitpriceList:JSON.stringify(unitpriceList),
+          gljTypeMap:JSON.stringify(gljTypeMap),
+          mixRatioMap:JSON.stringify(mixRatioMap),
+          LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
+        });
+    }
+}
+
+// engineerID = req.params.engineerID;

+ 14 - 0
modules/unit_price_file/routes/unit_price_router.js

@@ -0,0 +1,14 @@
+let express = require('express');
+let unitPirceController = require('../controllers/unit_price_controller');
+
+module.exports = function (app) {
+
+    var Router = express.Router();
+    Router.get('/index/:unitPriceFileID', unitPirceController.index);
+    // Router.post('/getGLJDataByCodes',unitPirceController.getGLJDataByCodes);
+    // Router.post('/addGLJ',unitPirceController.addGLJ);
+    // Router.post('/replaceGLJ',unitPirceController.replaceGLJ);
+    
+
+    app.use('/unitPrice',Router);
+}

+ 6 - 8
public/web/gljUtil.js

@@ -265,12 +265,9 @@ let gljUtil = {
         if (!this.isConcreteType(glj.unit_price.type)&& this.notEditType.indexOf(glj.unit_price.type)!=-1&&glj.ratio_data.length>0) {//对于机械台班等有组成物的材料,价格需根据组成物计算得出(排除混凝土、配合比、砂浆这几个类型直接为0)。
             let p =0;
             for(let ratio of glj.ratio_data){
-                let tem =  _.find(projectGLJDatas.gljList,{
-                    'code': ratio.code,
-                    'name': ratio.name,
-                    'specs':ratio.specs,
-                    'type': ratio.type,
-                    'unit': ratio.unit
+                let rIndex = gljUtil.getIndex(ratio);
+                let tem =  _.find(projectGLJDatas.gljList,function(item){
+                  return rIndex == gljUtil.getIndex(item);
                 });
                 if(tem){
                     let priceData=this.getGLJPrice(tem,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,true,_,scMathUtil);
@@ -399,8 +396,9 @@ let gljUtil = {
         let lo = lodash?lodash:_;
         let specialMap = {1:-1,303:0,202:9,203:10,204:11};//,人工、机械工排在最前,混凝土、砂浆、配合比 排到最后
         list = lo.sortByAll(list, [function (item) {
-            if(specialMap[item.unit_price.type] != undefined) return specialMap[item.unit_price.type];
-            return gljUtil.getMainType(item.unit_price.type);
+            let unit_price = item.unit_price?item.unit_price:item;
+            if(specialMap[unit_price.type] != undefined) return specialMap[unit_price.type];
+            return gljUtil.getMainType(unit_price.type);
         }, gljUtil.getCodeSortMath()]);
         return list;
     },

+ 6 - 5
public/web/sheet/sheet_common.js

@@ -132,13 +132,14 @@ var sheetCommonObj = {
             if (setting.header[col].formatter) {
                 sheet.setFormatter(-1, col, setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
             }
-            if (setting.header[col].cellType === "checkBox" || setting.header[col].cellType === "button") {//clear and reset
+           /*  直接在showrowdata时当val为null时返回一个text类型的单元格 
+              if (setting.header[col].cellType === "checkBox" || setting.header[col].cellType === "button") {//clear and reset
                 var me = this, header = GC.Spread.Sheets.SheetArea.colHeader;
                 sheet.deleteColumns(col, 1);
                 sheet.addColumns(col, 1);
                 sheet.setValue(0, col, setting.header[col].headerName, header);
                 sheet.setColumnWidth(col, setting.header[col].headerWidth ? setting.header[col].headerWidth : 100);
-            }
+            } */
             if (setting.header[col].visible !== null && setting.header[col].visible !== undefined) {
                 sheet.setColumnVisible(col, setting.header[col].visible);
             }
@@ -177,7 +178,7 @@ var sheetCommonObj = {
                     val = val + '';
                 }
             }
-            if (val != null && setting.header[col].cellType === "checkBox") {
+            if (setting.header[col].cellType === "checkBox") {
                 this.setCheckBoxCell(row, col, sheet, val)
             }
             if (setting.header[col].cellType === "comboBox") {
@@ -301,8 +302,8 @@ var sheetCommonObj = {
         }
     },
     setCheckBoxCell(row, col, sheet, val) {
-        var c = new GC.Spread.Sheets.CellTypes.CheckBox();
-        c.isThreeState(false);
+        var c = val==null?new GC.Spread.Sheets.CellTypes.Text():new GC.Spread.Sheets.CellTypes.CheckBox();
+        if(val != null) c.isThreeState(false);
         sheet.setCellType(row, col, c, GC.Spread.Sheets.SheetArea.viewport);
         sheet.getCell(row, col).value(val);
         sheet.getCell(row, col).hAlign(GC.Spread.Sheets.HorizontalAlign.center);

+ 7 - 2
web/building_saas/css/custom.css

@@ -433,6 +433,11 @@ input.text-right{
     background: #f7f7f9;
 }
 .form-control-inline {
-    display: inline-block !important;
-    width: 80% !important;
+  display: inline-block !important;
+  width: 80% !important;
+}
+.unit_price_header{
+  padding-top:6px;
+  margin-left: 50px;
+  margin-right: 100px !important;
 }

+ 1 - 0
web/building_saas/glj/html/project_glj.html

@@ -14,6 +14,7 @@
                 <option>福建车船税标准(2012)</option>
             </select>
         </div>
+        <a class="btn btn-sm ml-1" id="editUnitFile" href="/unitPrice/index/123" target="_"> 编辑单价文件</a>
     </div>
 
 </div>

+ 0 - 1
web/building_saas/main/html/main.html

@@ -1957,7 +1957,6 @@
     <script type="text/javascript" src="/public/web/common_ajax.js"></script>
     <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>
     <script type="text/javascript" src="/public/web/slideResize.js"></script>
     <!-- JS. -->
     <!--<script src="/lib/popper/popper.min.js"></script>

+ 27 - 8
web/building_saas/main/js/models/project_glj.js

@@ -431,14 +431,16 @@ ProjectGLJ.prototype.materialCal = function (id,dataMap,tglj,tfreightList,tprice
     if(!glj) return;
     let unitPrice = {projectGLJID:glj.id,id:glj.unit_price.id,'unit_price_file_id':glj.unit_price.unit_price_file_id,doc:{}};
     //先计算原价
-    let [originalPrice,supplyLocation] = this.priceCalc(glj,dataMap,tpriceList);
+    let [originalPrice,supplyLocation,priceHeightFee] = this.priceCalc(glj,dataMap,tpriceList);
     doc['originalPrice'] = originalPrice+'';
     doc['supplyLocation'] = supplyLocation;
+    doc['priceHeightFee'] = priceHeightFee;
     //再计算运费
     let grossWeightCoe_n = doc['grossWeightCoe_n']?doc['grossWeightCoe_n']:glj.unit_price.grossWeightCoe_n;
     grossWeightCoe_n = scMathUtil.roundForObj(grossWeightCoe_n,process);
-    let unitFreight = this.freightCalc(glj,grossWeightCoe_n,dataMap,tfreightList);
+    let [unitFreight,freightHeightFee] = this.freightCalc(glj,grossWeightCoe_n,dataMap,tfreightList);
     doc['unitFreight'] = unitFreight+'';
+    doc['freightHeightFee'] = freightHeightFee+'';
     //计算场外运输损耗
     let sum_o_f = scMathUtil.roundForObj(originalPrice+unitFreight,process);//(原价+单位运费)
     let totalLoadingTimes = doc["totalLoadingTimes"]?doc["totalLoadingTimes"]:glj.unit_price.totalLoadingTimes;//装卸总次数
@@ -478,10 +480,12 @@ ProjectGLJ.prototype.freightCalc= function (glj,grossWeightCoe_n,dataMap,tfreigh
     let unitPirce = getDecimal("glj.unitPrice");
     let unitPriceHasMix = getDecimal("glj.unitPriceHasMix");//这里暂时没用到
     let sum = 0;
+    let height_sum=0;
     let freightList = tfreightList?tfreightList:_.filter(this.datas.freightList,{"connect_key":gljUtil.getIndex(glj)});
     if(dataMap["freight"] && dataMap["freight"]["add"])  freightList = freightList.concat(dataMap["freight"]["add"]); //把添加的加进去
     for(let f of freightList){
         let unitFreight = f.unitFreight,kmDistance = f.kmDistance,freightIncreaseRate = f.freightIncreaseRate,unitLoadingFee= f.unitLoadingFee,loadingTimes = f.loadingTimes,otherFee = f.otherFee,weightCoe = f.weightCoe,conveyance = f.conveyance,calcType=f.calcType,materialType=f.materialType;
+        let heightFee= f.heightFee?f.heightFee:0;  
         if(dataMap["freight"] && dataMap["freight"]["update"]){//覆盖更新的数据
             let t = dataMap["freight"]["update"][f.ID];
             if(t){
@@ -495,6 +499,7 @@ ProjectGLJ.prototype.freightCalc= function (glj,grossWeightCoe_n,dataMap,tfreigh
                 if(t['conveyance']) conveyance = t['conveyance'];
                 if(t['calcType']) calcType = t['calcType'];
                 if(t['materialType']) materialType = t['materialType'];
+                if(t['heightFee']) heightFee = t['heightFee'];
             }
         }
         if(dataMap["freight"] && dataMap["freight"]["delete"]){//忽略删除的数据
@@ -505,6 +510,7 @@ ProjectGLJ.prototype.freightCalc= function (glj,grossWeightCoe_n,dataMap,tfreigh
         freightIncreaseRate = scMathUtil.roundForObj(1+freightIncreaseRate/100,process);//(1+运距增加率%)
         unitFreight = scMathUtil.roundForObj(unitFreight,unitPirce);
         kmDistance = scMathUtil.roundForObj(kmDistance,unitPirce);
+        heightFee = scMathUtil.roundForObj(heightFee,unitPirce);
 
         let t = getPrice(unitFreight,kmDistance,conveyance,calcType,materialType,process);//单位运价×km运距
         t = scMathUtil.roundForObj(t*freightIncreaseRate,process);//单位运价×km运距×(1+运距增加率%)
@@ -519,12 +525,14 @@ ProjectGLJ.prototype.freightCalc= function (glj,grossWeightCoe_n,dataMap,tfreigh
         weightCoe = scMathUtil.roundForObj(weightCoe,unitPirce);
         t = scMathUtil.roundForObj(t*weightCoe,process);//(单位运价×km运距×(1+运距增加率%)+装卸费单价×装卸次数+其它费用)×单位毛重×加权系数
         sum = scMathUtil.roundForObj(sum + t,process);
+        heightFee = scMathUtil.roundForObj(heightFee*weightCoe,process);
+        height_sum = scMathUtil.roundForObj(height_sum + heightFee,process);
     }
     if(freightList.length == 0){//如果运费计算表没有数据,则读取输入的或单价文件的值
         let doc = dataMap['material']&&dataMap['material']['update']?dataMap['material']['update']:{};
         sum = doc['unitFreight']?doc['unitFreight']:glj.unit_price.unitFreight;
     }
-    return scMathUtil.roundForObj(sum,unitPirce);
+    return [scMathUtil.roundForObj(sum,unitPirce),scMathUtil.roundForObj(height_sum,unitPirce)];
 
 
     function getPrice(unitFreight,kmDistance,conveyance,calcType,materialType,process){
@@ -542,25 +550,31 @@ ProjectGLJ.prototype.priceCalc = function (glj,dataMap,tpriceList) {
     let unitPirce = getDecimal("glj.unitPrice");
     let unitPriceHasMix = getDecimal("glj.unitPriceHasMix");
     let original_price = 0;
+    let sumFeightFee = 0;
     let supplyList = [];
     let supplyLocation = "";
     let priceList = tpriceList?tpriceList:_.filter(this.datas.originalList,{"connect_key":gljUtil.getIndex(glj)});
     if(dataMap["price"] && dataMap["price"]["add"])  priceList = priceList.concat(dataMap["price"]["add"]); //把添加的加进去
     for(let p of priceList){
         let supplyPrice = p.supplyPrice ,coe = p.coe,supplyLocation=p.supplyLocation;
+        let heightFee = p.heightFee?p.heightFee:0;
         if(dataMap["price"] && dataMap["price"]["update"]){//覆盖更新的数据
             let t = dataMap["price"]["update"][p.ID];
             if(t && t["supplyPrice"]) supplyPrice =t["supplyPrice"];
             if(t && t["coe"]) coe =t["coe"];
             if(t && t["supplyLocation"]) supplyLocation = t["supplyLocation"];
+            if(t && t["heightFee"]) heightFee = t["heightFee"];
         }
         if(dataMap["price"] && dataMap["price"]["delete"]){//忽略删除的数据
             if(dataMap["price"]["delete"][p.ID]) continue;
         }
         supplyPrice = scMathUtil.roundForObj(supplyPrice,unitPirce);
         coe = scMathUtil.roundForObj(coe,unitPirce);
+        heightFee = scMathUtil.roundForObj(heightFee,unitPirce);
         let t_p = scMathUtil.roundForObj(supplyPrice *  coe,process);
+        let t_h = scMathUtil.roundForObj(heightFee *  coe,process);
         original_price=scMathUtil.roundForObj(original_price+t_p,process);
+        sumFeightFee = scMathUtil.roundForObj(sumFeightFee+t_h,process);
         supplyList.push(supplyLocation);
     }
     supplyLocation = supplyList.join(',');
@@ -569,7 +583,7 @@ ProjectGLJ.prototype.priceCalc = function (glj,dataMap,tpriceList) {
         original_price = doc['originalPrice']!==undefined?doc['originalPrice']:glj.unit_price.originalPrice;
         supplyLocation = doc['supplyLocation']!==undefined?doc['supplyLocation']:glj.unit_price.supplyLocation;
     }
-    return [scMathUtil.roundForObj(original_price,unitPriceHasMix),supplyLocation];
+    return [scMathUtil.roundForObj(original_price,unitPriceHasMix),supplyLocation,scMathUtil.roundForObj(sumFeightFee,unitPirce)];
 };
 
 
@@ -912,6 +926,7 @@ ProjectGLJ.prototype.calcEachFreightOrPrice = function (temp,type,priceMap) {//
     if(temp){
          if(type == "freight" && temp.conveyance !="自办运输") return null;
         let sum =0;
+        let heightFee = 0;
         let gljMap = {};
         let decimal = type == "freight"?getDecimal("glj.unitPrice"):getDecimal("glj.unitPriceHasMix");
         //因为材料计算的数据是保存在单价文件里的,有可能存在共享的情况,这样的话就不能用单价文件里的项目工料机ID来匹配,要用5大项匹配
@@ -926,18 +941,21 @@ ProjectGLJ.prototype.calcEachFreightOrPrice = function (temp,type,priceMap) {//
         }
         if(temp.rations) {
             for(let r of temp.rations){
-                sum = scMathUtil.roundForObj(sum + calcRation(r,gljMap[r.ID],pgljMap,priceMap),6);
+                let [tsum,thei] = calcRation(r,gljMap[r.ID],pgljMap,priceMap);
+                heightFee = scMathUtil.roundForObj(heightFee+thei,6);
+                sum = scMathUtil.roundForObj(sum + tsum,6);
             }
         }
         sum = scMathUtil.roundForObj(sum,decimal)+"";
-        if(type == "freight" && temp.unitFreight!= sum) return {ID:temp.ID,doc:{unitFreight:sum}};
-        if(type == "price" && temp.supplyPrice !=sum) return {ID:temp.ID,doc:{supplyPrice:sum}};
+        if(type == "freight" && temp.unitFreight!= sum) return {ID:temp.ID,doc:{unitFreight:sum,heightFee:heightFee}};
+        if(type == "price" && temp.supplyPrice !=sum) return {ID:temp.ID,doc:{supplyPrice:sum,heightFee:heightFee}}
     }
     return null;
 
 
     function calcRation(ration,gljs,pMap,priceMap){
         let result = 0;
+        let heightFee = 0;
         if(gljs){
             let processDecimal = getDecimal("process");
             let hightFeeRate = projectObj.project.projectGLJ.getHighlandFee(ration.feeType);//高原取费类别费率
@@ -960,8 +978,9 @@ ProjectGLJ.prototype.calcEachFreightOrPrice = function (temp,type,priceMap) {//
             let hs = scMathUtil.roundForObj(tt*hightFeeRate,processDecimal);//(人工定额消耗量*定额价*定额工程量+机械定额消耗量*定额价*定额工程量)*高原取费类别费率
             result = scMathUtil.roundForObj(as + result,processDecimal);
             result = scMathUtil.roundForObj(hs + result,processDecimal);
+            heightFee = hs;
         }
-        return  result;
+        return  [result,heightFee];
     }
 
 

+ 8 - 5
web/building_saas/main/js/views/project_glj_view.js

@@ -132,6 +132,7 @@ projectGljObject={
         $("#current-name").text(me.usedUnitPriceInfo.name);
         let usedCount = me.usedTenderList.length <= 0 ? 1 : me.usedTenderList.length;
         $("#used-project-count").text(usedCount);
+        $("#editUnitFile").attr("href",`/unitPrice/index/${me.usedUnitPriceInfo.id}`)
     },
     getUsedTenderInfo:function() {
         return "人材机单价的变化,将自动影响以下单位工程造价:<br>"+projectGljObject.usedTenderList.join("<br>");
@@ -315,9 +316,11 @@ projectGljObject={
             let style = gljOprObj.getSelStyle(true,{});
             me.projectGljSheet.setStyle(newSel.row, -1, style);
             let orow = oldSel.row==''||oldSel.row==-1?0:oldSel.row;
-            let tstyle = gljOprObj.getSelStyle(false,{},me.projectGljSheetData[orow].bgColour);
-            me.projectGljSheet.setStyle(orow, -1, tstyle);
-            me.projectGljRowChang();
+            if(me.projectGljSheetData[orow]){
+              let tstyle = gljOprObj.getSelStyle(false,{},me.projectGljSheetData[orow].bgColour);
+              me.projectGljSheet.setStyle(orow, -1, tstyle);
+              me.projectGljRowChang();
+            }
         }else{
           me.projectGljSheet.repaint();
         }
@@ -881,10 +884,10 @@ projectGljObject={
         if(info.newValue === undefined ){
             return;
         }
-        if (value&&!me.checkData(col,setting,value)) {
+        if(value && !me.checkData(col,setting,value)) {
             alert('输入的数据类型不对,请重新输入!');
             info.sheetName =="materialTreeSheet"?me.materialTreeController.refreshTreeNode([me.materialTree.selected]):me.refreshProjectGljRow(row);
-            return ;
+            return;
         }
         let callback=function (impactList) {
             info.sheet.suspendPaint();

+ 169 - 0
web/building_saas/unit_price_file/index.html

@@ -0,0 +1,169 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>纵横公路养护云造价</title>
+
+
+    <link rel="stylesheet" href="/lib/jquery-ui/jquery-ui.css" type="text/css">
+    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
+    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap-submenu.css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.sc.css" type="text/css">
+    <link rel="stylesheet" href="/web/building_saas/css/main.css">
+    <link rel="stylesheet" href="/web/building_saas/css/custom.css">
+    <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
+    <link rel="stylesheet" href="/lib/jquery-contextmenu/jquery.contextMenu.css" type="text/css">
+    <link rel="stylesheet" href="/lib/jquery-editable-select/jquery.editable-select.min.css" type="text/css">
+    <!--zTree-->
+    <link rel="stylesheet" href="/lib/ztree/css/zTreeStyle.css" type="text/css">
+    <!--SpreadJs-->
+   <!-- <link rel="stylesheet" href="/lib/jquery-ui/jquery-ui.css" type="text/css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.sc.css" type="text/css">-->
+    <link rel="stylesheet" href="/lib/spreadjs/views/gc.spread.views.dataview.10.0.0.css">
+    <!-- jquery.contextmenu -->
+   <!-- <link rel="stylesheet" href="/lib/jquery-contextmenu/jquery.contextMenu.css" type="text/css">-->
+
+    <link rel="shortcut icon" href="/web/building_saas/css/favicon.ico">
+    <link rel="icon" type="image/gif" href="/web/building_saas/css/animated_favicon1.gif">
+    <style type="text/css">
+        .ztree * {
+            font-family: Calibri;
+            font-size: 0.9rem;
+        }
+    </style>
+
+</head>
+<script type="text/javascript">
+  let unitPriceList = JSON.parse(`<%- unitpriceList %>`);
+  let gljTypeMap = JSON.parse(`<%- gljTypeMap %>`);
+  let mixRatioMap = JSON.parse(`<%- mixRatioMap %>`);
+</script>
+<body oncontextmenu="return false;">  <!--屏蔽input鼠标右键-->
+<!--<div id="toolToastWrap" style="left: 20px; right: 30px; position: fixed; z-index: 10001; top: 100px;">
+    <div id="toolToast" class="toolToast">
+        <span id="tool-toast-content">右键不支持粘贴外部内容,请使用Ctrl+V粘贴。<span id="toolToastBtn">我知道了</span></span>
+    </div>
+</div>-->
+
+    <div class="header">
+         <div class="top-msg clearfix">
+            <div class="alert alert-warning alert-dismissible" role="alert" id="notify" style="display: none">
+                <button type="button" class="close" aria-label="Close" onclick="$('#notify').hide();">
+                  <span aria-hidden="true">&times;</span>
+                </button>
+                <strong id="message"></strong>-
+            </div>
+        </div>
+        <nav class="navbar navbar-expand-lg p-0 d-flex <%= versionName.includes('免费') ? 'free-version' : 'pro-version' %>">
+          <div class="unit_price_header header-logo ">
+            <h5>单价文件编辑器</h5>
+          </div>
+          <div class="navbar-text navbar-crumb px-1 mr-auto" id="fullpath">   
+            <span class="text-muted px-1"></span>
+            <span data-toggle="tooltip" data-placement="bottom" data-original-title="<%= rootProjectName%>"><i class="fa fa-cubes"></i>...</span>
+            <span class="text-muted px-1"></span>
+             <span><i class="fa fa-puzzle-piece"></i></span>
+            <span class="text-truncate" data-toggle="tooltip" data-placement="bottom" data-original-title="<%= unitFileName%>">&nbsp;<%= unitFileName%></span>
+            &nbsp;(<span class="a_color" data-toggle="tooltip" id="pop-used-list"  style="float: none;" data-original-title="" title="<%= usedTenderString%>">与<span id="used-project-count" style="float: none;">1</span>个单位工程同步</span>)
+          </div>
+        </nav>
+    </div>
+    <div class="main">
+        <div class="content" style="margin-left: 0px;">
+          <div class="tab-content">
+              <!--造价书-->
+              <div class="container-fluid">
+                  <div class="row" id="mainRow">
+                      <!--col-lg-12 p-0-->
+                      <div class="main-content" style="width: 100%; display: inline-block" id="main">
+                          <div class="top-content" id="top_div" style="overflow:hidden;">
+                              <div class="main-data-top" id="mainSpread"></div>
+                          </div>
+                          <div class="resize-y" id="mainVerticalResize"></div>
+                          <div class="bottom-content" id="bottom_div">
+                              <ul class="nav nav-tabs" role="tablist" id="bottom_div_ul">  
+                                  <li class="nav-item" id="GLJ_div">
+                                      <a class="nav-link sub-item active" id="linkGLJ" data-toggle="tab" href="#subSpread" role="tab">组成物计算</a>
+                                  </li>                                
+                              </ul>
+                              <!-- Tab panes -->
+                              <div class="tab-content" id="tabCon">
+                                  <div class="tab-pane active" id="subItems" role="tabpanel">
+                                     <div class="main-data-bottom ovf-hidden" id="subSpread" tabindex="0"></div>
+                                  </div>
+                              </div>
+                          </div>
+                      </div>
+                      </div>
+                  </div>
+              </div>
+            </div>
+
+
+        </div>
+    </div>
+   
+
+   
+ 
+   
+    <img src="/web/dest/css/img/folder_open.png" id="folder_open_pic" style="display: none">
+    <img src="/web/dest/css/img/folder_close.png" id="folder_close_pic" style="display: none">
+    <img src="/web/dest/css/img/project.png" id="proj_pic" style="display: none">
+    <img src="/web/dest/css/img/engineering.png" id="eng_pic" style="display: none">
+    <img src="/web/dest/css/img/tender.png" id="tender_pic" style="display: none">
+
+    <img src="/web/dest/css/img/blockLib.png" id="blockLib_pic" style="display: none">
+    <img src="/web/dest/css/img/folder_open.png" id="folder_pic" style="display: none">
+    <img src="/web/dest/css/img/tender.png" id="block_pic" style="display: none">
+
+        <!-- JS. -->
+    <script src="/lib/jquery/jquery-3.2.1.min.js"></script>
+    <script type="text/javascript" src="/lib/jquery-ui/jquery-ui.min.js"></script>
+    <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>
+    <script src="/lib/spreadjs/sheets/interop/gc.spread.excelio.11.1.2.min.js"></script>
+    <script>GC.Spread.Sheets.LicenseKey =  '<%- LicenseKey %>';</script>
+    <script type="text/javascript" src="/lib/jquery-ui/jquery-ui-datepickerCN.js"></script>
+    <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.contextMenu.js"></script>
+    <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.ui.position.js"></script>
+    <script src="/lib/spreadjs/views/gc.spread.views.dataview.10.0.0.min.js" type="text/javascript"></script>
+    <script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
+    <script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>
+    <!--<script src="/lib/spreadjs/views/common/gc.spread.common.10.0.0.min.js" type="text/javascript"></script>-->
+    <script src="/lib/spreadjs/views/plugins/gc.spread.views.gridlayout.10.0.0.min.js" type="text/javascript"></script>
+    <script src="/lib/js-xlsx/xlsx.core.min.js"></script>
+    <script src="/lib/lz-string/lz-string.min.js"></script>
+    <script type="text/javascript" src="/lib/jspdf/jspdf.min.js"></script>
+    <!-- inject:js -->
+    <script src="/lib/popper/popper.min.js"></script>
+    <script src="/lib/bootstrap/bootstrap.min.js"></script>
+    <script src="/lib/bootstrap/bootstrap-submenu.js"></script>
+    <script type="text/javascript" src="/web/building_saas/js/moment.min.js"></script>
+    <script type="text/javascript" src="/web/building_saas/js/message.js"></script>
+    <script type="text/javascript" src="/public/web/scMathUtil.js"></script>
+    <script type="text/javascript" src="/public/web/gljUtil.js"></script>
+    <script type="text/javascript" src="/public/web/PerfectLoad.js"></script>
+    <script type="text/javascript" src="/lib/lodash/lodash.js"></script>
+    <script type="text/javascript" src="/public/web/commonAlert.js"></script>
+    <script type="text/javascript" src="/public/web/headerOpr.js"></script>
+    <script type="text/javascript" src="/public/web/common_ajax.js"></script>
+    <script type="text/javascript" src="/public/common_util.js"></script>
+    <script src="/public/common_constants.js"></script>
+    <script type="text/javascript" src="/lib/jquery-editable-select/jquery.editable-select.min.js"></script>
+    <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_helper.js"></script>
+    <script type="text/javascript" src="/public/web/sheet/sheet_data_helper.js"></script>
+    <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
+
+
+
+    <script type="text/javascript" src="/web/building_saas/unit_price_file/index.js"></script>
+    <!-- endinject -->
+
+
+        
+   
+</body>
+</html>

+ 293 - 0
web/building_saas/unit_price_file/index.js

@@ -0,0 +1,293 @@
+
+let unitPriceObj = {
+  unitPriceMap:{},
+  setUntiPriceMap:function(){
+    for(let u of unitPriceList){
+      this.unitPriceMap[gljUtil.getIndex(u)] = u;
+    }
+  },
+  mainSpread:null,
+  mainSetting:{
+    header: [
+        {headerName: "编号", headerWidth: 80, dataCode: "code", dataType: "String"},
+        {headerName: "名称", headerWidth: 160, dataCode: "name", dataType: "String"},
+        {headerName: "单位", headerWidth: 45, dataCode: "unit", hAlign: "center", dataType: "String"},
+        {headerName: "规格", headerWidth: 120, dataCode: "specs", hAlign: "left", dataType: "String"},
+        {headerName: "类型", headerWidth: 45, dataCode: "short_name", hAlign: "center", dataType: "String"},
+        {headerName: "定额价", headerWidth: 70, dataCode: "basePrice", hAlign: "right", dataType: "Number",validator:"number"},//decimalField:'glj.unitPrice',
+        {headerName: "预算价", headerWidth: 70, dataCode: "marketPrice", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:"glj.unitPrice"
+        {headerName: "是否新增", headerWidth: 50, dataCode: "is_add", hAlign: "center", dataType: "String",cellType:'checkBox'}
+    ],
+    view: {
+        lockColumns: ["code","name","specs","unit","short_name","basePrice","is_add"],
+        colHeaderHeight:36
+    },
+    getStyle:function (data,row,activeRow) {
+      if(row == activeRow){//选中黄色显示
+          return {backColor:"#FFFACD"};
+      }
+      return null;
+    }
+  },
+  subSpread:null,
+  subSetting:{
+    header:[
+        {headerName: "编号", headerWidth: 80, dataCode: "code", dataType: "String"},
+        {headerName: "名称", headerWidth: 240, dataCode: "name", dataType: "String"},
+        {headerName: "规格", headerWidth: 190, dataCode: "specs", dataType: "String"},
+        {headerName: "单位", headerWidth: 45, dataCode: "unit", hAlign: "center", dataType: "String"},
+        {headerName: "类型", headerWidth: 45, dataCode: "short_name", hAlign: "center", dataType: "String"},
+        {headerName: "定额价", headerWidth: 80, dataCode: "basePrice", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:'glj.unitPrice'
+        {headerName: "预算价", headerWidth: 80, dataCode: "marketPrice", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:"glj.unitPrice"
+        {headerName: "消耗量", headerWidth: 80, dataCode: "consumption", hAlign: "right", dataType: "Number",validator:"number",tofix:3}
+    ],
+    view: {
+        lockColumns: [0,1,2,3,4,5,6,7],
+        rowHeaderWidth: 25
+    }
+  },
+  initMainSpread:function () {
+    if(this.mainSpread) return this.mainSpread.refresh();
+    this.mainSpread = SheetDataHelper.createNewSpread($("#mainSpread")[0]);
+    sheetCommonObj.spreadDefaultStyle(this.mainSpread);
+    this.mainSheet = this.mainSpread.getSheet(0);
+    sheetCommonObj.initSheet(this.mainSheet, this.mainSetting, 30);
+    this.mainSheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onMainSelectionChange);
+    this.mainSpread.bind(GC.Spread.Sheets.Events.RangeChanged, this.onMainRangeChange);
+    this.mainSheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onMainValueChange);
+    // this.sheet.bind(GC.Spread.Sheets.Events.EditStarting,this.onElectrovalenceEditStarting);
+
+    /* if(projectReadOnly){
+        disableSpread(this.spread);
+    } */
+  },
+  showMainDatas:function(){
+    unitPriceList = gljUtil.sortProjectGLJ(unitPriceList);
+    this.setData(unitPriceList);
+    let sel = this.mainSheet.getSelections()[0];
+    let oldData = sel.row<unitPriceList.length?unitPriceList[sel.row]:"";
+    sheetCommonObj.showData(this.mainSheet, this.mainSetting,unitPriceList);
+    this.mainSheet.setRowCount(unitPriceList.length);
+    sel.row =  oldData?_.findIndex(unitPriceList,{'id':oldData.id}):sel.row ;
+    this.mainSheet.setSelection(sel.row==-1?0:sel.row,sel.col,sel.rowCount,sel.colCount);
+  
+  },
+  getShortNameByType : function (type) {
+    return gljTypeMap["typeId" + type]?gljTypeMap["typeId" + type].shortName:'';
+  },
+  setData:function(list){
+    for(let l of list){
+      l.bgColour = "white";
+      l.basePrice = this.getPrice('base_price',l);
+      l.marketPrice = this.getPrice('market_price',l);
+      l.short_name = this.getShortNameByType(l.type);
+      if(l.base_price == l.market_price){//如果定额价等于市场价时,改底色。 优先度低于有组成物时的底色
+        l.bgColour = "#C4CAFB";
+      }
+      let lindex = gljUtil.getIndex(l);
+      if (gljUtil.notEditType.indexOf(l.type) >= 0 && mixRatioMap[lindex] && mixRatioMap[lindex].length>0) {//有组成物时
+        l.bgColour = "#E0E0E0";
+      }
+      if(gljUtil.isConcreteType(l.type)) l.bgColour = "#E0E0E0";//混凝土、砂浆、配合比的底色显示为 灰色#E0E0E0,灰色底色提醒用户不可修改。
+
+    }
+  },
+  getSelectedUnitPrice:function () {
+    let me = this,data = null;
+    let sheet = me.mainSpread.getActiveSheet();
+    let sel = sheet.getSelections()[0];
+        let srow = sel.row == -1||sel.row == ""?0:sel.row;
+        if(unitPriceList.length>srow){
+            data = unitPriceList[srow];
+        }
+    return data;
+  },
+  onMainSelectionChange:function(sender,args){
+    let me = unitPriceObj;
+    let newSel = args.newSelections[0];
+    let oldSel = args.oldSelections?args.oldSelections[0]:{};
+    args.sheet.suspendPaint();
+    args.sheet.suspendEvent();
+    if(newSel.row != oldSel.row){
+      let style = me.getSelStyle(true,{});
+      args.sheet.setStyle(newSel.row, -1, style);
+      let orow = oldSel.row==''||oldSel.row==-1?0:oldSel.row;
+      if(unitPriceList[orow]){
+        let tstyle = me.getSelStyle(false,{},unitPriceList[orow].bgColour);
+        args.sheet.setStyle(orow, -1, tstyle);
+        me.showSubDatas();
+      }
+    }else{
+      args.sheet.repaint();
+    }
+    args.sheet.resumeEvent();
+    args.sheet.resumePaint();
+
+  },
+  onMainValueChange:function(e,info){
+    let me = unitPriceObj;
+    let value = info.newValue;
+    if(info.newValue === undefined){
+      return;
+    }
+    if(value && !sheetCommonObj.checkData(info.col,me.mainSetting,value)) {
+      alert('输入的数据类型不对,请重新输入!');
+      return me.showMainDatas();
+    }
+    me.batchUpdateUnitPrice([{row:info.row,col:info.col,value:value}]);
+
+  },
+  onMainRangeChange:function(sender,info){
+    let me = unitPriceObj;
+    let canChange = true;
+    for(let c of info.changedCells){
+      let value=  info.sheet.getCell(c.row, c.col).text();
+      changeInfo.push({row:c.row,col:c.col,value:value});
+      if (!sheetCommonObj.checkData(c.col,me.mainSetting,value)) {
+          alert('输入的数据类型不对,请重新输入!');
+          canChange = false;
+          break;
+      }
+    }
+    if(canChange == false) return me.showMainDatas();
+    me.batchUpdateUnitPrice(changeInfo);
+  },
+  batchUpdateUnitPrice:async function(changeInfo){
+    let me = unitPriceObj;
+    let updateData = [];
+    let newValueMap = {};
+    let refreshList = [];
+    try {
+      for(let ci of changeInfo){
+        let dataCode = me.mainSetting.header[ci.col].dataCode;
+        let recode = unitPriceList[ci.row];
+        if(dataCode=='basePrice'||dataCode=='marketPrice'){
+            let editField = dataCode === 'basePrice'?"base_price":"market_price";
+            let newValue = ci.value;
+            if(recode && recode[editField]!=newValue){
+                newValue= scMathUtil.roundForObj(ci.value,3);
+                updateData.push({unit_price: recode, field: editField, newval: newValue});
+                newValueMap[recode.id]={field:editField,value:newValue};
+                refreshList.push(recode);
+            }
+        }
+      }
+      if(updateData.length > 0){
+        $.bootstrapLoading.start();
+        let result = await ajaxPost("/glj/batchUpdatePrices",updateData);
+        for(let r of refreshList){
+           r[newValueMap[r.id].field] = newValueMap[r.id].value;
+        }
+        for(let r of result){
+          let pdata = r.updateOne.filter;
+          let set = r.updateOne.update.$set;
+          for(let skey in set){
+              let pindex = gljUtil.getIndex(pdata);
+              me.unitPriceMap[pindex][skey] = set[skey];
+          }
+        }
+      }
+    } catch (error) {
+        alert(error);
+    }
+    $.bootstrapLoading.end();
+    me.showMainDatas();
+
+  },
+
+  initSubSpread:function () {
+    if(this.subSpread) return this.subSpread.refresh();
+    this.subSpread = SheetDataHelper.createNewSpread($("#subSpread")[0]);
+    sheetCommonObj.spreadDefaultStyle(this.subSpread);
+    this.subSheet = this.subSpread.getSheet(0);
+    sheetCommonObj.initSheet(this.subSheet, this.subSetting, 30);
+    // this.sheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onElectrovalenceSelectionChange);
+    // this.sheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onElectrovalenceValueChange);
+    // this.sheet.bind(GC.Spread.Sheets.Events.EditStarting,this.onElectrovalenceEditStarting);
+
+    /* if(projectReadOnly){
+        disableSpread(this.spread);
+    } */
+  },
+  showSubDatas:function(){
+    let parentData = this.getSelectedUnitPrice();
+    this.mixRatioList = mixRatioMap[gljUtil.getIndex(parentData)];
+    this.mixRatioList = this.mixRatioList?this.mixRatioList:[];
+    this.setMixRatioData(this.mixRatioList);
+    let sel = this.subSheet.getSelections()[0];
+    this.subSheet.setRowCount(0);
+    sheetCommonObj.showData(this.subSheet, this.subSetting,this.mixRatioList);
+    this.subSheet.setRowCount(this.mixRatioList.length);
+    this.subSheet.setSelection(sel.row==-1?0:sel.row,sel.col,sel.rowCount,sel.colCount);
+  },
+  setMixRatioData:function(mixRatioList){
+    for(let m of mixRatioList){
+      m.short_name = this.getShortNameByType(m.type);
+      let mu = this.unitPriceMap[gljUtil.getIndex(m)];
+      if(mu){
+        m.basePrice = this.getPrice("base_price",mu);
+        m.marketPrice = this.getPrice("market_price",mu);
+      }else{
+        console.log("组成物的单价信息未找到---"+m.code);
+      }
+    }
+  },
+  getPrice:function(pricefield,unitprice){
+    let quantity = 3;
+    let unitPriceHasMix = 2;
+    let unitPrice = 3;
+    let process_decimal = 6;
+    let uIndex = gljUtil.getIndex(unitprice);
+    if(mixRatioMap[uIndex] && mixRatioMap[uIndex].length > 0){
+      let total = unitprice[pricefield];
+      if(pricefield == "market_price"){
+        total = 0;
+        for(let m of mixRatioMap[uIndex]){
+          let mu = unitPriceObj.unitPriceMap[gljUtil.getIndex(m)];
+          let price_m =  unitPriceObj.getPrice(pricefield,mu);
+          let temP = scMathUtil.roundForObj(price_m * scMathUtil.roundForObj(m.consumption,quantity),process_decimal);
+          total = scMathUtil.roundForObj(temP+total,process_decimal);
+        }
+      }
+      return scMathUtil.roundForObj(unitprice[pricefield],unitPriceHasMix);
+    }else{
+      return scMathUtil.roundForObj(unitprice[pricefield],unitPrice);
+    }
+  },
+  getSelStyle: function (selected,settingStyle,rcolor) {
+    let style = new GC.Spread.Sheets.Style();
+    if(settingStyle){
+        for(let key in settingStyle){
+            style[key] = settingStyle[key];
+        }
+    }
+    style.borderLeft = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+    style.borderTop = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+    style.borderRight = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+    style.borderBottom = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+    let selectedColor = "#FFFACD",
+        recColor = rcolor?rcolor:'White';
+    style.backColor = selected ? selectedColor : recColor;
+    return style;
+  },
+}
+
+
+
+function initPageHeight(){
+  let headerHeight = $(".header").height();
+  $(".main-data-top").height($(window).height()*0.6-headerHeight);
+  $(".main-data-bottom").height($(window).height()-headerHeight-$(".main-data-top").height()-$(".nav-item").height());
+}
+function initPage(){
+  $('[data-toggle="tooltip"]').tooltip({html: true});
+  initPageHeight();
+  unitPriceObj.initMainSpread();
+  unitPriceObj.initSubSpread();
+  unitPriceObj.showMainDatas();
+}
+
+unitPriceObj.setUntiPriceMap();
+initPage();
+$(window).resize(initPage);
+