Sfoglia il codice sorgente

Merge branch 'GuangdongTax'

vian 5 anni fa
parent
commit
f0443462cb
38 ha cambiato i file con 3585 aggiunte e 872 eliminazioni
  1. 8 3
      modules/all_models/compleGlj_glj.js
  2. 2 1
      modules/all_models/std_glj.js
  3. 1 0
      modules/all_models/unit_price.js
  4. 4 0
      modules/complementary_glj_lib/controllers/gljController.js
  5. 5 2
      modules/complementary_glj_lib/models/gljModel.js
  6. 2 0
      modules/complementary_ration_lib/controllers/compleViewController.js
  7. 1 1
      modules/glj/controllers/glj_controller.js
  8. 4 4
      modules/glj/models/glj_list_model.js
  9. 1 0
      modules/glj/models/unit_price_model.js
  10. 5 4
      modules/main/facade/ration_facade.js
  11. 18 7
      modules/pm/facade/pm_facade.js
  12. 4 0
      modules/ration_glj/facade/ration_glj_facade.js
  13. 29 0
      public/common_constants.js
  14. 12 0
      public/web/sheet/sheet_common.js
  15. 4 0
      web/building_saas/complementary_glj_lib/html/tools-gongliaoji.html
  16. 115 65
      web/building_saas/complementary_glj_lib/js/components.js
  17. 652 384
      web/building_saas/complementary_glj_lib/js/glj.js
  18. 361 305
      web/building_saas/complementary_glj_lib/js/gljComponent.js
  19. 146 5
      web/building_saas/complementary_glj_lib/js/sheetOpr.js
  20. 1 0
      web/building_saas/complementary_ration_lib/html/dinge.html
  21. 6 0
      web/building_saas/complementary_ration_lib/js/gljSelect.js
  22. 12 0
      web/building_saas/complementary_ration_lib/js/ration_glj.js
  23. 86 3
      web/building_saas/main/js/models/importStdInterfaceBase.js
  24. 2 21
      web/building_saas/main/js/models/main_consts.js
  25. 7 2
      web/building_saas/main/js/models/project_glj.js
  26. 8 3
      web/building_saas/main/js/models/ration_glj.js
  27. 1 1
      web/building_saas/main/js/views/character_content_view.js
  28. 3 0
      web/building_saas/main/js/views/glj_col.js
  29. 1 0
      web/building_saas/main/js/views/glj_view.js
  30. 14 17
      web/building_saas/main/js/views/project_glj_view.js
  31. 498 1
      web/building_saas/main/js/views/project_property_projFeature.js
  32. 2 1
      web/building_saas/pm/html/project-management.html
  33. 0 1
      web/building_saas/pm/js/pm_import.js
  34. 2 1
      web/building_saas/pm/js/pm_newMain.js
  35. 2 1
      web/building_saas/main/js/models/importStandardInterface.js
  36. 89 0
      web/over_write/js/guangdong_2018.js
  37. 38 26
      web/over_write/js/guangdong_2018_export.js
  38. 1439 13
      web/over_write/js/guangdong_2018_import.js

+ 8 - 3
modules/all_models/compleGlj_glj.js

@@ -5,7 +5,7 @@
 //补充工料机的组成物可能来自标准工料机和补充工料机
 const mongoose = require('mongoose');
 const Schema = mongoose.Schema;
-const comple_gljComponent = new Schema(
+/* const comple_gljComponent = new Schema(
     {
         isStd: Boolean, //组成物里的工料机是否是标准的,否则是补充的
         ID: Number,
@@ -13,7 +13,7 @@ const comple_gljComponent = new Schema(
     },
     {_id: false},
     {versionKey: false}
-);
+); */
 //补充工料机跟用户和编办绑定
 const comple_glj = new Schema({
     userId: String,
@@ -24,11 +24,16 @@ const comple_glj = new Schema({
     specs: String,
     unit: String,
     basePrice: String,
+    priceProperty: {
+        type: Schema.Types.Mixed,
+        default: {}
+    },
     gljClass: String,
     gljType: Number,
     model: Number,
     shortName: String,
-    component: [comple_gljComponent]
+    component: Array,
+    taxRate: String //税率
 }, {versionKey: false});
 
 mongoose.model('complementary_glj_lib', comple_glj, 'complementary_glj_lib');

+ 2 - 1
modules/all_models/std_glj.js

@@ -42,7 +42,8 @@ const std_glj = new Schema({
     materialIndexType:String,//工料指标类别
     materialIndexUnit:String,//工料指标单位
     materialIndexCoe:Number,//单位转换系数
-    component: [std_gljComponent]
+    component: [std_gljComponent],
+    taxRate:String//税率
 },{versionKey: false});
 
 mongoose.model('std_glj_lib_gljList', std_glj, 'std_glj_lib_gljList');

+ 1 - 0
modules/all_models/unit_price.js

@@ -16,6 +16,7 @@ let modelSchema = {
     base_price: String,
     // 市场单价
     market_price: String,
+    taxRate:String,//税率
     // 编码
     code: {
         type: String,

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

@@ -35,11 +35,15 @@ class GljController extends BaseController{
         }
         let overWriteUrl = req.session.sessionCompilation && req.session.sessionCompilation.overWriteUrl &&
                             req.session.sessionCompilation._id !== '5b4d581023a924000b760f2d' ? req.session.sessionCompilation.overWriteUrl : null;
+        const priceProperties = sessionCompilation.priceProperties || [];
+        const consumeAmtProperties = sessionCompilation.consumeAmtProperties || [];
         res.render('building_saas/complementary_glj_lib/html/tools-gongliaoji.html',{
             userID: req.session.sessionUser.id,
             gljLibId: gljLibId,
             compilationId: sessionCompilation._id,
             compilationName: sessionCompilation.name,
+            priceProperties: JSON.stringify(priceProperties),
+            consumeAmtProperties: JSON.stringify(consumeAmtProperties),
             versionName: req.session.compilationVersion,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
             overWriteUrl: overWriteUrl,

+ 5 - 2
modules/complementary_glj_lib/models/gljModel.js

@@ -354,8 +354,11 @@ class GljDao {
                 componentIdListCpt.push(component.ID);
             }
             let isStdFlag = component.isStd ? 'std' : 'cpt';
-            //对于补充人材机的组成物,不会有多单价的情况
-            componentConsume[component.ID + '_' + isStdFlag] = component.consumeAmt;
+            if(component.consumeAmt != undefined && component.consumeAmt != null) {
+                componentConsume[component.ID + '_' + isStdFlag] = component.consumeAmt;
+            }else if(component.consumeAmtProperty){
+                componentConsume[component.ID + '_' + isStdFlag] = component.consumeAmtProperty;
+            }
         }
 
         // 查找标准库数据

+ 2 - 0
modules/complementary_ration_lib/controllers/compleViewController.js

@@ -42,6 +42,7 @@ class CompleViewController extends BaseController{
         const redirectGlj = `/complementaryRation/glj`;
         const redirectCoe = `/complementaryRation/coe`;
         const redirectInstallation = `/complementaryRation/installation`;
+        const priceProperties = req.session.sessionCompilation.priceProperties || [];
         res.render('building_saas/complementary_ration_lib/html/dinge.html', {
             userID: req.session.sessionUser.id,
             redirectGlj: redirectGlj,
@@ -49,6 +50,7 @@ class CompleViewController extends BaseController{
             redirectInstallation: redirectInstallation,
             gljLibId: gljLibId,
             compilationName: req.session.sessionCompilation.name,
+            priceProperties: JSON.stringify(priceProperties),
             versionName: req.session.compilationVersion,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
         });

+ 1 - 1
modules/glj/controllers/glj_controller.js

@@ -85,7 +85,7 @@ class GLJController extends BaseController {
         };
         try {
             // 可编辑的字段
-            let editableField = ['is_evaluate', 'unit_price.market_price', 'is_adjust_price', 'mix_ratio.consumption','is_eval_material','no_tax_eqp','is_coe_adjust','is_info_adjust','FI','FO','standardPrice','riskCoe',
+            let editableField = ['is_evaluate','unit_price.taxRate', 'unit_price.market_price', 'is_adjust_price', 'mix_ratio.consumption','is_eval_material','no_tax_eqp','is_coe_adjust','is_info_adjust','FI','FO','standardPrice','riskCoe',
                 'supply', 'supply_quantity','delivery_address','delivery','materialType','materialCoe','is_main_material','originPlace','vender','qualityGrace','brand','remark'];
             if (editableField.indexOf(field) < 0) {
                 throw '对应字段不能编辑';

+ 4 - 4
modules/glj/models/glj_list_model.js

@@ -569,8 +569,8 @@ class GLJListModel extends BaseModel {
         let mixRatioInsertData = [];
         for (let tmp of compositionGljList) {
             let consumpiton = tmp.consumption;
-            //只有标准的工料机的组成物才会有多单价、多组成物消耗量的情况 fromTable
-            if(fromTable == 'std' && ext && ext.quantityField &&( tmp.consumption[ext.quantityField]!= undefined && tmp.consumption[ext.quantityField]!=null)){
+            //多单价、多组成物消耗量的情况 fromTable
+            if(ext && ext.quantityField &&( tmp.consumption[ext.quantityField]!= undefined && tmp.consumption[ext.quantityField]!=null)){
                 consumpiton = tmp.consumption[ext.quantityField];
             }
             // 配合比数据插入
@@ -602,8 +602,8 @@ class GLJListModel extends BaseModel {
                 gljInsertData.push(gljData);
             }
             let basePrice = tmp.basePrice;
-            //只有标准的工料机的组成物才会有多单价、多组成物消耗量的情况 fromTable
-            if(fromTable == 'std' && ext && ext.priceField &&( tmp.priceProperty[ext.priceField]!= undefined && tmp.priceProperty[ext.priceField]!=null)){
+            //多单价、多组成物消耗量的情况 fromTable
+            if(ext && ext.priceField &&( tmp.priceProperty[ext.priceField]!= undefined && tmp.priceProperty[ext.priceField]!=null)){
                 basePrice = tmp.priceProperty[ext.priceField];
             }
             basePrice = scMathUtil.roundTo(basePrice,-6);

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

@@ -113,6 +113,7 @@ class UnitPriceModel extends BaseModel {
             code: data.code,
             base_price: data.base_price,
             market_price: data.market_price,
+            taxRate:data.taxRate,
             unit_price_file_id: unitPriceFileId,
             name: data.name,
             specs:data.specs,

+ 5 - 4
modules/main/facade/ration_facade.js

@@ -441,10 +441,10 @@ async function addRationGLJ(std,newRation,compilation) {
             }else {
                 std_glj = stdGLJMap[sub.gljId];
                 newGLJ.from = 'std';
-                //多单价情况处理
-                if(ext && ext.priceField && std_glj && std_glj.priceProperty){
-                    std_glj.basePrice =  std_glj.priceProperty[ext.priceField];
-                }
+            }
+            //多单价情况处理
+            if(ext && ext.priceField && std_glj && std_glj.priceProperty){
+                std_glj.basePrice =  std_glj.priceProperty[ext.priceField];
             }
             if(std_glj){
                 newGLJ.name = std_glj.name;
@@ -455,6 +455,7 @@ async function addRationGLJ(std,newRation,compilation) {
                 newGLJ.model = std_glj.model;
                 newGLJ.basePrice = std_glj.basePrice;
                 newGLJ.marketPrice = std_glj.basePrice;
+                newGLJ.taxRate= std_glj.taxRate;
                 newGLJ.shortName = std_glj.shortName;
                 newGLJ.type = std_glj.gljType;
                 newGLJ.repositoryId = std_glj.repositoryId;

+ 18 - 7
modules/pm/facade/pm_facade.js

@@ -1591,15 +1591,18 @@ async function importProject(importObj, userID, compilationID) {
     }
     //给单位工程设置一些数据
     async function setupTender(data) {
-        //小数位数 需要修改,所以深拷贝
-        data.property.decimal = JSON.parse(JSON.stringify(defaultDecimal));
-        // 定额工程量、人材机消耗量精度设为最大6
-        data.property.decimal.ration.quantity = 6;
-        data.property.decimal.glj.quantity = 6;
+        if (!data.property.decimal) {     
+            //小数位数 需要修改,所以深拷贝
+            data.property.decimal = JSON.parse(JSON.stringify(defaultDecimal));
+            // 定额工程量、人材机消耗量精度设为最大6
+            data.property.decimal.ration.quantity = 6;
+            data.property.decimal.glj.quantity = 6;
+        }
         //清单工程量精度 需要修改,所以深拷贝
         data.property.billsQuantityDecimal = JSON.parse(JSON.stringify(billsQuantityDecimal));
-        // 清单工程量精度设置最大4
-        data.property.billsQuantityDecimal.forEach(data => data.decimal = 4);
+        // 清单工程量精度默认为4
+        const billsQuantityDecimalValue = data.property.billsQuantityDecimalValue || 4;
+        data.property.billsQuantityDecimal.forEach(data => data.decimal = billsQuantityDecimalValue);
         //呈现选项
         data.property.displaySetting = displaySetting;
 
@@ -1666,6 +1669,10 @@ async function importTenderDetail(tenderData) {
     if (tenderData.bills.length) {
         await billsModel.insertMany(tenderData.bills);
     }
+    // 工程量明细
+    if (tenderData.quantityDetails.length) {
+        await quantityDetailModel.insertMany(tenderData.quantityDetails);
+    }
     //投标文件中,才会有下面这些数据
     if (enterDetail(tenderData)) {
         //匹配标准数据,更新一些标准数据
@@ -1752,6 +1759,7 @@ async function setupStdData(tenderData) {
             r.stdID = stdRation.ID;
             r.prefix = stdRation.rationRepId == tenderData.tender.defaultRationLib ? '' : '借';
             r.content = stdRation.jobContent;
+            r.manageFeeRate = stdRation.manageFeeRate;
             if (stdRation.feeType) {
                 r.programID = stdRation.feeType;
             } else {
@@ -1813,6 +1821,9 @@ async function setupStdData(tenderData) {
             up.glj_id = stdGLJ.ID;
             up.type = stdGLJ.gljType;
             up.short_name = stdGLJ.shortName;
+            if (stdGLJ.taxRate) {
+                up.taxRate = stdGLJ.taxRate;
+            }
         }
     });
     //更新组成物数据

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

@@ -136,6 +136,7 @@ function get_lib_glj_info(ration_glj) {
                 ration_glj.specs = glj.specs;
                 ration_glj.basePrice = glj.basePrice;
                 ration_glj.marketPrice = glj.basePrice;
+                ration_glj.taxRate = glj.taxRate;
                 ration_glj.shortName = glj.shortName;
                 ration_glj.type = glj.gljType;
                 ration_glj.repositoryId = glj.repositoryId;
@@ -605,6 +606,7 @@ function getGLJSearchInfo(ration_glj) {
         type_of_work: ration_glj.subType ? ration_glj.subType : ration_glj.type,
         base_price: ration_glj.basePrice,
         market_price: ration_glj.marketPrice,
+        taxRate:ration_glj.taxRate,//税率
         repositoryId: ration_glj.repositoryId,
         adjCoe: ration_glj.adjCoe,
         materialType:ration_glj.materialType,
@@ -766,6 +768,7 @@ async function updateRationGLJFromDoc(rg,doc,priceInfo) {
     }
     projectGLJ.base_price = priceInfo.base_price;
     projectGLJ.market_price = priceInfo.market_price;
+    projectGLJ.taxRate = priceInfo.taxRate;
     let projcetGLJ_n = await gljListModel.modifyGLJ(projectGLJ, rg);
     doc.code = projcetGLJ_n.code;
     doc.projectGLJID = projcetGLJ_n.id;
@@ -795,6 +798,7 @@ async function doRationGLJUpdate(data) {
     doc.basePrice = projcetGLJ_n.unit_price.base_price;
     doc.marketPrice = projcetGLJ_n.unit_price.market_price;
     doc.adjustPrice = projcetGLJ_n.adjust_price;
+    doc.taxRate = projcetGLJ_n.unit_price.taxRate;
     doc.isAdd = projcetGLJ_n.unit_price.is_add;
     resutl.doc = doc;
     let stateResult = await glj_calculate_facade.calculateQuantity({

+ 29 - 0
public/common_constants.js

@@ -103,10 +103,39 @@ const commonConstants = (() => {
         Engineering: 'Engineering',
         Tender: 'Tender'
     };
+    // 计税方式
+    const TaxType = {
+        NORMAL: 1,
+        SIMPLE: 2
+    };
+    // 供货方式
+    const supplyType = {
+        //自行采购
+        ZXCG: 0,
+        //部分甲供
+        BFJG: 1,
+        //完全甲供
+        WQJG: 2,
+        //甲定乙供
+        JDYG: 3
+    };
+    const supplyText = {
+        //自行采购
+        ZXCG: '自行采购',
+        //部分甲供
+        BFJG: '部分甲供',
+        //完全甲供
+        WQJG: '完全甲供',
+        //甲定乙供
+        JDYG: '甲定乙供'
+    };
     return {
         fixedFlag,
         billType,
         rationType,
         projectType,
+        TaxType,
+        supplyType,
+        supplyText,
     }
 })();

+ 12 - 0
public/web/sheet/sheet_common.js

@@ -1354,6 +1354,18 @@ var sheetCommonObj = {
         workBook.commandManager().setShortcutKey(null, GC.Spread.Commands.Key.esc, false, false, false, false);
         workBook.commandManager().setShortcutKey('myEsc', GC.Spread.Commands.Key.esc, false, false, false, false);
     },
+    //生成列字段与列号映射
+    initColMapping: function (obj, headers) {
+        //colToField 列下标与列字段映射
+        //fieldToCol 列字段与列下标映射
+        let colMapping = {colToField: {}, fieldToCol: {}};
+        for(let header of headers){
+            colMapping['colToField'][headers.indexOf(header)] = header.dataCode;
+            colMapping['fieldToCol'][header.dataCode] = headers.indexOf(header);
+        }
+        console.log(colMapping);
+        obj.colMapping = colMapping
+    },
     //设置默认样式
     spreadDefaultStyle: function (workBook) {
         let defaultStyle = new GC.Spread.Sheets.Style();

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

@@ -24,6 +24,10 @@
         }
         .modal-lg{max-width: 1000px}
     </style>
+    <script type="text/javascript">
+        let priceProperties = JSON.parse('<%- priceProperties %>');
+        let consumeAmtProperties = JSON.parse('<%- consumeAmtProperties %>');
+    </script>
 </head>
 <body>
     <div class="header">

+ 115 - 65
web/building_saas/complementary_glj_lib/js/components.js

@@ -5,7 +5,7 @@
    弹出组成物窗口 组成物表
  * */
 let componentOprObj = {
-    treeObj:null,
+    treeObj: null,
     rootNode: null,//分类树根节点
     parentNodeIds: {},
     radiosSelected: null,//allGljs, stdGljs, complementaryGljs
@@ -14,18 +14,60 @@ let componentOprObj = {
     setting: {
         owner: "components",
         header: [
-            {headerName:"选择", headerWidth: 40, dataCode: "select", hAlign: "center", vAlign: "center"},
-            {headerName:"编码",headerWidth:80,dataCode:"code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
-            {headerName:"名称",headerWidth:120,dataCode:"name", dataType: "String", hAlign: "left", vAlign: "center"},
-            {headerName:"规格型号",headerWidth:80,dataCode:"specs", dataType: "String", hAlign: "center", vAlign: "center"},
-            {headerName:"单位",headerWidth:80,dataCode:"unit", dataType: "String", hAlign: "center", vAlign: "center"},
-            {headerName:"单价",headerWidth:80,dataCode:"basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center"},
-            {headerName:"类型",headerWidth:80,dataCode:"gljType", dataType: "String",  hAlign: "center", vAlign: "center"}
+            { headerName: "选择", headerWidth: 40, dataCode: "select", hAlign: "center", vAlign: "center" },
+            { headerName: "编码", headerWidth: 80, dataCode: "code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center" },
+            { headerName: "名称", headerWidth: 120, dataCode: "name", dataType: "String", hAlign: "left", vAlign: "center" },
+            { headerName: "规格型号", headerWidth: 80, dataCode: "specs", dataType: "String", hAlign: "center", vAlign: "center" },
+            { headerName: "单位", headerWidth: 80, dataCode: "unit", dataType: "String", hAlign: "center", vAlign: "center" },
+            { headerName: "单价", headerWidth: 80, dataCode: "basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center" },
+            { headerName: "类型", headerWidth: 80, dataCode: "gljType", dataType: "String", hAlign: "center", vAlign: "center" }
         ]
     },
+    //生成列头(多单价)
+    initHeaders: function (priceProperties) {
+        let headers = [
+            { headerName: "选择", headerWidth: 40, dataCode: "select", hAlign: "center", vAlign: "center" },
+            { headerName: "编码", headerWidth: 80, dataCode: "code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center" },
+            { headerName: "名称", headerWidth: 120, dataCode: "name", dataType: "String", hAlign: "left", vAlign: "center" },
+            { headerName: "规格型号", headerWidth: 80, dataCode: "specs", dataType: "String", hAlign: "center", vAlign: "center" },
+            { headerName: "单位", headerWidth: 80, dataCode: "unit", dataType: "String", hAlign: "center", vAlign: "center" },
+            { headerName: "类型", headerWidth: 80, dataCode: "gljType", dataType: "String", hAlign: "center", vAlign: "center" }
+
+        ];
+        //生成单价列
+        if (!priceProperties || priceProperties.length === 0) {
+            headers.push({ headerName: "定额价", headerWidth: 80, dataCode: "basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center" });
+        }
+        else {
+            for (let priceProp of priceProperties) {
+                let colData = {
+                    headerName: priceProp.price.dataName,
+                    headerWidth: 90,
+                    dataCode: priceProp.price.dataCode,
+                    dataType: 'Number',
+                    formatter: '0.00',
+                    hAlign: 'right',
+                    vAlign: 'center'
+                };
+                headers.push(colData);
+            }
+        }
+        let tailHeaders = [
+        ];
+        headers = headers.concat(tailHeaders);
+        return headers;
+    },
     buildSheet: function (container) {
         let me = componentOprObj;
+        //生成人材机组成物表格列头
+        me.setting.header = me.initHeaders(priceProperties);
+        //生成人材机组成物列映射
+        sheetCommonObj.initColMapping(me, me.setting.header);
+        repositoryGljObj.initPriceCols.call(me, priceProperties, me.colMapping);
         me.workBook = sheetOpr.buildSheet(container, me.setting, 30);
+        if (priceProperties && priceProperties.length > 0) {
+            me.workBook.getSheet(0).frozenColumnCount(6);
+        }
         sheetCommonObj.spreadDefaultStyle(me.workBook);
         me.workBook.getSheet(0).setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader);
         me.workBook.getSheet(0).setFormatter(-1, 1, "@", GC.Spread.Sheets.SheetArea.viewport);
@@ -46,26 +88,26 @@ let componentOprObj = {
         let val = args.sheet.getValue(args.row, args.col);
         let thisComponent = me.currentCache[args.row];
         thisComponent.isChecked = val;
-        if(args.sheet.isEditing()){
+        if (args.sheet.isEditing()) {
             args.sheet.endEdit(true);
         }
-        else{
+        else {
             //维护选中组成物列表
-            if(val === true){
+            if (val === true) {
                 let isExist = false;
-                for(let i = 0, len = me.selectedList.length; i < len; i++){
-                    if(me.selectedList[i].ID === thisComponent.ID){
+                for (let i = 0, len = me.selectedList.length; i < len; i++) {
+                    if (me.selectedList[i].ID === thisComponent.ID) {
                         isExist = true;
                         break;
                     }
                 }
-                if(!isExist){
+                if (!isExist) {
                     me.selectedList.push(thisComponent);
                 }
             }
-            else if(val === false){
-                for(let i = 0, len = me.selectedList.length; i < len; i++){
-                    if(me.selectedList[i].ID === thisComponent.ID){
+            else if (val === false) {
+                for (let i = 0, len = me.selectedList.length; i < len; i++) {
+                    if (me.selectedList[i].ID === thisComponent.ID) {
                         me.selectedList.splice(i, 1);
                         break;
                     }
@@ -75,27 +117,27 @@ let componentOprObj = {
     },
     setShowGljList: function (gljList, clearChecked) {
         let that = repositoryGljObj, me = componentOprObj;
-            for(let i = 0; i < gljList.length; i++){
-                if(machineAllowComponent.includes(that.currentGlj.gljType) && machineComponent.includes(gljList[i].gljType) ||
-                    materialAllowComponent.includes(that.currentGlj.gljType) && gljList[i].gljType === 201 ||
-                    that.currentGlj.gljType === 4 && gljList[i].gljType === 4 && (!gljList[i].component || gljList[i].component.length === 0) && gljList[i].ID !== that.currentGlj.ID){
-                    //去除与已添加的组成物重复的条目
-                    let isExist = false;
-                    for(let j = 0; j < that.currentComponent.length; j++){
-                        if(that.currentComponent[j].ID === gljList[i].ID){
-                            isExist = true;
-                            break;
-                        }
-                    }
-                    if(!isExist){
-                        gljList[i].isChecked = false;
-                    }
-                    else {
-                        gljList[i].isChecked = true;
+        for (let i = 0; i < gljList.length; i++) {
+            if (machineAllowComponent.includes(that.currentGlj.gljType) && machineComponent.includes(gljList[i].gljType) ||
+                materialAllowComponent.includes(that.currentGlj.gljType) && gljList[i].gljType === 201 ||
+                that.currentGlj.gljType === 4 && gljList[i].gljType === 4 && (!gljList[i].component || gljList[i].component.length === 0) && gljList[i].ID !== that.currentGlj.ID) {
+                //去除与已添加的组成物重复的条目
+                let isExist = false;
+                for (let j = 0; j < that.currentComponent.length; j++) {
+                    if (that.currentComponent[j].ID === gljList[i].ID) {
+                        isExist = true;
+                        break;
                     }
-                    me.showGljList.push(gljList[i]);
                 }
+                if (!isExist) {
+                    gljList[i].isChecked = false;
+                }
+                else {
+                    gljList[i].isChecked = true;
+                }
+                me.showGljList.push(gljList[i]);
             }
+        }
     },
     //初始化分类树
     //@param {String}type(标准或补充) {Array}treeData(树数据)
@@ -107,10 +149,10 @@ let componentOprObj = {
         }
         zTreeHelper.createTree(treeData, componentSetting, "componentTree", componentOprObj);
         let rootNode = componentOprObj.treeObj.getNodes()[0];
-        if(rootNode && rootNode.isParent && rootNode.isFirstNode){
+        if (rootNode && rootNode.isParent && rootNode.isFirstNode) {
             componentOprObj.rootNode = rootNode;
         }
-        if(me.rootNode){
+        if (me.rootNode) {
             me.treeObj.selectNode(me.rootNode);
             componentTypeTreeOprObj.onClick(null, 'componentTree', me.rootNode);
         }
@@ -122,14 +164,14 @@ let componentOprObj = {
         //初始化组成物列表
         me.selectedList = [].concat(that.currentComponent);
         //默认radio所有工料机
-        if(typeof $("input[name='glj']:checked")[0] !== 'undefined'){
+        if (typeof $("input[name='glj']:checked")[0] !== 'undefined') {
             $("input[name='glj']:checked")[0].checked = false;
         }
         $("input[value = 'stdGljs']")[0].checked = true;
         me.radiosSelected = 'stdGljs';
         //初始为所有工料机,机械类型可添加机械组成物,混凝土,砂浆、配合比可添加普通材料
         me.showGljList = [];
-        if(me.radiosSelected === 'stdGljs'){
+        if (me.radiosSelected === 'stdGljs') {
             me.setShowGljList(that.stdGljList, true);
             //me.setShowGljList(that.complementaryGljList, true);
             that.sortGlj(me.showGljList);
@@ -141,19 +183,19 @@ let componentOprObj = {
         me.radiosSelected = val;
         //选择改变,数据重新筛选显示
         me.showGljList = [];
-        if(me.radiosSelected === 'allGljs'){
+        if (me.radiosSelected === 'allGljs') {
             me.setShowGljList(re.stdGljList);
             me.setShowGljList(re.complementaryGljList);
         }
-        else if(me.radiosSelected === 'stdGljs'){
+        else if (me.radiosSelected === 'stdGljs') {
             me.setShowGljList(re.stdGljList);
         }
-        else if(me.radiosSelected === 'complementaryGljs'){
+        else if (me.radiosSelected === 'complementaryGljs') {
             me.setShowGljList(re.complementaryGljList);
         }
         //搜索匹配
         let searchStr = $('#gljSearchKeyword').val();
-        if(searchStr && searchStr.trim() != ''){
+        if (searchStr && searchStr.trim() != '') {
             let reg = new RegExp(searchStr);
             me.showGljList = _.filter(me.showGljList, function (data) {
                 return reg.test(data.code) || reg.test(data.name);
@@ -164,10 +206,10 @@ let componentOprObj = {
         me.showGljItems(me.showGljList, me.gljCurTypeId);
         //切换radio后更新cache
         if (me.currentOprParent = 1) {
-            if(me.parentNodeIds["_pNodeId_" + me.gljCurTypeId]){
+            if (me.parentNodeIds["_pNodeId_" + me.gljCurTypeId]) {
                 me.currentCache = me.getParentCache(me.parentNodeIds["_pNodeId_" + me.gljCurTypeId]);
             }
-            else{
+            else {
                 me.currentCache = [];
             }
         } else {
@@ -178,30 +220,31 @@ let componentOprObj = {
     radiosChange: function () {
         let me = componentOprObj, gc = gljClassTreeObj;
         $('.glj-radio').change(function () {
-            if($(this).val() === 'stdGljs') {
+            me.filterDatasAndShow();
+            if ($(this).val() === 'stdGljs') {
                 me.initClassTree('std', gc.treeData.std);
             } else {
                 me.initClassTree('comple', gc.treeData.comple);
             }
-            me.filterDatasAndShow();
+            //me.filterDatasAndShow();
         });
     },
     getParentCache: function (nodes) {
         let me = componentOprObj, rst = [];
-        for(let i = 0; i < me.showGljList.length; i++){
-            if(nodes.indexOf(me.showGljList[i].gljClass) !== -1){
+        for (let i = 0; i < me.showGljList.length; i++) {
+            if (nodes.indexOf(me.showGljList[i].gljClass) !== -1) {
                 rst.push(me.showGljList[i]);
             }
         }
         rst.sort(function (a, b) {
             let rst = 0;
-            if(a.code > b.code) rst = 1;
-            else if(a.code < b.code)rst = -1;
+            if (a.code > b.code) rst = 1;
+            else if (a.code < b.code) rst = -1;
             return rst;
         });
         return rst;
     },
-    getCache: function() {
+    getCache: function () {
         let me = componentOprObj, rst = [];
         for (let i = 0; i < me.showGljList.length; i++) {
             if (me.showGljList[i].gljClass == me.gljCurTypeId) {
@@ -210,7 +253,7 @@ let componentOprObj = {
         }
         return rst;
     },
-    showGljItems: function(data, type) {
+    showGljItems: function (data, type) {
         let me = componentOprObj, re = repositoryGljObj;
         if (me.workBook) {
             let cacheSection = [];
@@ -222,7 +265,7 @@ let componentOprObj = {
                     cacheSection.push(data[i]);
                 }
             }
-            sheetOpr.showData(me.workBook.getSheet(0), me.setting, cacheSection, re.distTypeTree);
+            sheetOpr.showData(me, me.workBook.getSheet(0), me.setting, cacheSection, re.distTypeTree);
             me.workBook.getSheet(0).setRowCount(cacheSection.length);
             cacheSection = null;
         }
@@ -235,25 +278,32 @@ let componentOprObj = {
             let updateArr = [];
             let newComponent = [];
             //re.currentGlj.component = [];
-            for(let i = 0, len = me.selectedList.length; i < len; i++){
+            for (let i = 0, len = me.selectedList.length; i < len; i++) {
                 let isExist = false;
-                for(let j = 0, jLen = re.currentGlj.component.length; j < jLen; j++){
-                    if(me.selectedList[i].ID === re.currentGlj.component[j].ID){
-                        newComponent.push({isStd: typeof me.selectedList[i].isStd !== 'undefined' ? me.selectedList[i].isStd : false
-                            , ID: me.selectedList[i].ID, consumeAmt: re.currentGlj.component[j].consumeAmt});
+                for (let j = 0, jLen = re.currentGlj.component.length; j < jLen; j++) {
+                    if (me.selectedList[i].ID === re.currentGlj.component[j].ID) {
+                        let newComponentObj = { isStd: typeof me.selectedList[i].isStd !== 'undefined' ? me.selectedList[i].isStd : false, ID: me.selectedList[i].ID }
+                        that.copyConsumeAmt(newComponentObj, re.currentGlj.component[j]);
+                        newComponent.push(newComponentObj);
+                        /* newComponent.push({
+                            isStd: typeof me.selectedList[i].isStd !== 'undefined' ? me.selectedList[i].isStd : false
+                            , ID: me.selectedList[i].ID, consumeAmt: re.currentGlj.component[j].consumeAmt
+                        }); */
                         isExist = true;
                         break;
                     }
                 }
-                if(!isExist){
-                    newComponent.push({isStd: typeof me.selectedList[i].isStd !== 'undefined' ? me.selectedList[i].isStd : false, ID: me.selectedList[i].ID, consumeAmt: 0});
+                if (!isExist) {
+                    let newComponentObj = { isStd: typeof me.selectedList[i].isStd !== 'undefined' ? me.selectedList[i].isStd : false, ID: me.selectedList[i].ID };
+                    that.initConsumeAmt(newComponentObj);
+                    newComponent.push(newComponentObj);
                 }
                 //re.currentGlj.component.push({ID: me.selectedList[i].ID, consumeAmt: 0});
             }
             re.currentGlj.component = newComponent;
             let gljBasePrc = that.reCalGljBasePrc(re.getCurrentComponent(re.currentGlj.component));
-            if(gljBasePrc !== re.currentGlj.basePrice){
-                re.currentGlj.basePrice = gljBasePrc;
+            if (re.isGljPriceChange(re.currentGlj, gljBasePrc)) {
+                re.setPrice(re.currentGlj, gljBasePrc);
                 re.reshowGljBasePrc(re.currentGlj);
                 //updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
             }
@@ -265,9 +315,9 @@ let componentOprObj = {
 };
 
 let componentTypeTreeOprObj = {
-    onClick: function(event,treeId,treeNode) {
+    onClick: function (event, treeId, treeNode) {
         let me = componentOprObj, re = repositoryGljObj, that = gljComponentOprObj, gljTypeId = treeNode.ID;
-        if(me.gljCurTypeId !== treeNode.ID){
+        if (me.gljCurTypeId !== treeNode.ID) {
             me.gljCurTypeId = treeNode.ID;
             if (me.parentNodeIds["_pNodeId_" + treeNode.ID]) {
                 me.currentOprParent = 1;

File diff suppressed because it is too large
+ 652 - 384
web/building_saas/complementary_glj_lib/js/glj.js


+ 361 - 305
web/building_saas/complementary_glj_lib/js/gljComponent.js

@@ -7,29 +7,94 @@ let gljComponentOprObj = {
     processDecimal: -6,
     setting: {
         owner: "gljComponent",
-        header:[
-            {headerName:"编码",headerWidth:80,dataCode:"code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
-            {headerName:"名称",headerWidth:90,dataCode:"name", dataType: "String", hAlign: "left", vAlign: "center"},
-            {headerName:"单位",headerWidth:45,dataCode:"unit", dataType: "String", hAlign: "center", vAlign: "center"},
-            {headerName:"单价",headerWidth:60,dataCode:"basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center"},
-            {headerName:"消耗量",headerWidth:70,dataCode:"consumeAmt", dataType: "Number", formatter: "0.000", hAlign: "right", vAlign: "center"}
+        header: [
+            { headerName: "编码", headerWidth: 80, dataCode: "code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center" },
+            { headerName: "名称", headerWidth: 90, dataCode: "name", dataType: "String", hAlign: "left", vAlign: "center" },
+            { headerName: "单位", headerWidth: 45, dataCode: "unit", dataType: "String", hAlign: "center", vAlign: "center" },
+            { headerName: "单价", headerWidth: 60, dataCode: "basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center" },
+            { headerName: "消耗量", headerWidth: 70, dataCode: "consumeAmt", dataType: "Number", formatter: "0.000", hAlign: "right", vAlign: "center" }
         ],
         view: {
-            lockedCols:[0, 1, 2, 3]
+            lockedCols: [0, 1, 2, 3]
+        }
+    },
+    //生成列头(多单价)(多消耗量)
+    initHeaders: function (priceProperties, consumeAmtProperties) {
+        let headers = [
+            { headerName: "编码", headerWidth: 80, dataCode: "code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center" },
+            { headerName: "名称", headerWidth: 90, dataCode: "name", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center" },
+            { headerName: "单位", headerWidth: 45, dataCode: "unit", dataType: "String", hAlign: "center", vAlign: "center" },
+        ];
+        //生成消耗量列
+        if (!consumeAmtProperties || consumeAmtProperties.length === 0) {
+            headers.push({ headerName: "消耗量", headerWidth: 70, dataCode: "consumeAmt", dataType: "Number", formatter: "0.000", hAlign: "right", vAlign: "center" });
+        }
+        else {
+            for (let consumeAmtProp of consumeAmtProperties) {
+                let colData = {
+                    headerName: consumeAmtProp.consumeAmt.dataName,
+                    headerWidth: 60,
+                    dataCode: consumeAmtProp.consumeAmt.dataCode,
+                    dataType: 'Number',
+                    formatter: '0.000',
+                    hAlign: 'right',
+                    vAlign: 'center'
+                };
+                headers.push(colData);
+            }
+        }
+        //生成单价列
+        if (!priceProperties || priceProperties.length === 0) {
+            headers.push({ headerName: "定额价", headerWidth: 80, dataCode: "basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center" });
+        }
+        else {
+            for (let priceProp of priceProperties) {
+                let colData = {
+                    headerName: priceProp.price.dataName,
+                    headerWidth: 100,
+                    dataCode: priceProp.price.dataCode,
+                    dataType: 'Number',
+                    formatter: '0.00',
+                    hAlign: 'right',
+                    vAlign: 'center'
+                };
+                headers.push(colData);
+            }
+        }
+        return headers;
+    },
+    setFrozen: function (sheet) {
+        const fixedHeadersLen = 3;
+        let frozenCol = 0;
+        if (consumeAmtProperties && consumeAmtProperties.length > 0) {
+            frozenCol = fixedHeadersLen + consumeAmtProperties.length;
+        }
+        else if (priceProperties && priceProperties.length > 0) {
+            frozenCol = fixedHeadersLen + 1;
+        }
+        if (frozenCol > 0) {
+            sheet.frozenColumnCount(frozenCol);
         }
     },
     buildHeader: function (sheet, header) {
         sheet.setRowCount(2, GC.Spread.Sheets.SheetArea.colHeader);
         for (let i = 0; i < header.length; i++) {
             sheet.setValue(1, i, header[i].headerName, GC.Spread.Sheets.SheetArea.colHeader);
-            sheet.setColumnWidth(i, header[i].headerWidth? header[i].headerWidth:100);
+            sheet.setColumnWidth(i, header[i].headerWidth ? header[i].headerWidth : 100);
         }
         sheet.setValue(0, 0, '组成物信息', GC.Spread.Sheets.SheetArea.colHeader);
         sheet.addSpan(0, 0, 1, header.length, GC.Spread.Sheets.SheetArea.colHeader);
     },
-    buildSheet: function(container) {
+    buildSheet: function (container) {
         let me = gljComponentOprObj;
+        //生成人材机组成物表格列头
+        me.setting.header = me.initHeaders(priceProperties, consumeAmtProperties);
+        //生成人材机组成物列映射
+        sheetCommonObj.initColMapping(me, me.setting.header);
+        repositoryGljObj.initPriceCols.call(me, priceProperties, me.colMapping);
+        me.initConsumeAmtCols(consumeAmtProperties, me.colMapping);
         me.workBook = sheetOpr.buildSheet(container, me.setting, 30, false);
+        me.setFrozen(me.workBook.getSheet(0));
         me.buildHeader(me.workBook.getSheet(0), me.setting.header);
         sheetCommonObj.spreadDefaultStyle(me.workBook);
         me.workBook.getSheet(0).setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader);
@@ -45,15 +110,24 @@ let gljComponentOprObj = {
 
     },
     getRowData: function (sheet, row, setting) {
-        let rst = {};
-        for(let i = 0; i < setting.header.length; i++){
-            rst[setting.header[i].dataCode] = sheet.getValue(row, i);
+        let rst = { priceProperty: {}, consumeAmtProperty: {} };
+        for (let i = 0; i < setting.header.length; i++) {
+            let v = sheet.getValue(row, i);
+            if (this.pricePropertyCols.includes(i)) {
+                rst.priceProperty[setting.header[i].dataCode] = v && v !== '' ? v : 0;
+            }
+            else if (this.consumeAmtPropertyCols.includes(i)) {
+                rst.consumeAmtProperty[setting.header[i].dataCode] = v && v !== '' ? v : 0;
+            }
+            else {
+                rst[setting.header[i].dataCode] = v;
+            }
         }
         return rst;
     },
     getComponent: function (sheet, rowCount) {
         let component = [];
-        for(let row = 0; row < rowCount; row++){
+        for (let row = 0; row < rowCount; row++) {
             let obj = {};
             obj.consumeAmt = sheet.getValue(row, 4);
             obj.ID = sheet.getTag(row, 0);
@@ -61,122 +135,194 @@ let gljComponentOprObj = {
         }
         return component;
     },
+    //根据消耗量字段设置组成物消耗量
+    setConsumeAmt: function (component, field, value) {
+        const compareStr = 'consumeAmt';
+        if (field.includes(compareStr)) {
+            if (field === compareStr) {
+                component[field] = value;
+            }
+            else {
+                component['consumeAmtProperty'][field] = value;
+            }
+        }
+    },
+    initConsumeAmtCols: function (consumeAmtProperties, colMapping) {
+        let consumeAmtCols = [],
+            consumeAmtPropertyCols = [];
+        if (!consumeAmtProperties || consumeAmtProperties.length === 0) {
+            consumeAmtCols.push(colMapping.fieldToCol['consumeAmt']);
+        }
+        for (let consumeAmtProp of consumeAmtProperties) {
+            consumeAmtPropertyCols.push(colMapping.fieldToCol[consumeAmtProp.consumeAmt.dataCode]);
+            consumeAmtCols.push(colMapping.fieldToCol[consumeAmtProp.consumeAmt.dataCode]);
+        }
+        this.consumeAmtCols = consumeAmtCols;
+        this.consumeAmtPropertyCols = consumeAmtPropertyCols;
+    },
+    //消耗量赋初值
+    initConsumeAmt: function (component) {
+        if (!consumeAmtProperties || consumeAmtProperties.length === 0) {
+            component.consumeAmt = 0;
+        } else {
+            let consumeAmtProperty = {};
+            for (let consumeAmtProp of consumeAmtProperties) {
+                consumeAmtProperty[consumeAmtProp.consumeAmt.dataCode] = 0;
+            }
+            component.consumeAmtProperty = consumeAmtProperty;
+        }
+    },
+    copyConsumeAmt: function (gljA, gljB) {
+        if (!consumeAmtProperties || consumeAmtProperties.length === 0) {
+            gljA.consumeAmt = gljB.consumeAmt;
+        } else {
+            gljA.consumeAmtProperty = _.cloneDeep(gljB.consumeAmtProperty);
+        }
+    },
+    consumeAmtChanged: function (component, consumeAmt, col) {
+        if (!consumeAmtProperties || consumeAmtProperties.length === 0) {
+            if (consumeAmt !== component.consumeAmt) {
+                return true;
+            }
+        }
+        else {
+            if (consumeAmt !== component.consumeAmtProperty[this.colMapping.colToField[col]]) {
+                return true;
+            }
+        }
+        return false;
+    },
+    consumeAmtIsEqual: function (consumeAmtA, consumeAmtB) {
+        if (!consumeAmtProperties || consumeAmtProperties.length === 0) {
+            return consumeAmtA.consumeAmt === consumeAmtB.consumeAmt;
+        }
+        return _.isEqual(consumeAmtA.consumeAmtProperty, consumeAmtB.consumeAmtProperty);
+    },
     onContextmenuOpr: function () {
         let me = gljComponentOprObj, that = repositoryGljObj, co = componentOprObj;
         $.contextMenu({
             selector: '#gljComponentSheet',
-            build: function($triggerElement, e){
+            build: function ($triggerElement, e) {
                 //控制允许右键菜单在哪个位置出现
                 let sheet = me.workBook.getSheet(0);
                 let offset = $("#gljComponentSheet").offset(),
                     x = e.pageX - offset.left,
                     y = e.pageY - offset.top;
                 let target = sheet.hitTest(x, y);
-                if(target.hitTestType === 3 && typeof target.row !== 'undefined' && typeof target.col !== 'undefined'){//在表格内
+                if (target.hitTestType === 3 && typeof target.row !== 'undefined' && typeof target.col !== 'undefined') {//在表格内
                     sheet.setActiveCell(target.row, target.col);
                     //getCurrentGlj
                     let thatRow = that.workBook.getSheet(0).getSelections()[0].row
                     that.currentGlj = thatRow < that.currentCache.length ? that.currentCache[thatRow] : null;
-                    that.currentComponent = that.currentGlj ?  that.getCurrentComponent(that.currentGlj.component) : [];
+                    that.currentComponent = that.currentGlj ? that.getCurrentComponent(that.currentGlj.component) : [];
                     //控制按钮是否可用
                     let insertDis = false,
                         delDis = false;
-                    if(!(that.currentGlj && allowComponent.includes(that.currentGlj.gljType)) || (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.stdGljList.concat(that.complementaryGljList)))){
+                    if (!(that.currentGlj && allowComponent.includes(that.currentGlj.gljType)) || (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.stdGljList.concat(that.complementaryGljList)))) {
                         insertDis = true;
                     }
-                    if(!that.currentGlj || typeof that.currentComponent === 'undefined' || (typeof that.currentComponent !== 'undefined' && target.row >= that.currentComponent.length)){//右键定位在有组成物的行,删除键才显示可用
+                    if (!that.currentGlj || typeof that.currentComponent === 'undefined' || (typeof that.currentComponent !== 'undefined' && target.row >= that.currentComponent.length)) {//右键定位在有组成物的行,删除键才显示可用
                         delDis = true;
                     }
                     return {
-                        callback: function(){},
+                        callback: function () { },
                         items: {
-                            "insert": {name: "插入", disabled: insertDis, icon: "fa-sign-in", callback: function (key, opt) {
-                                let oprFunc = function () {
-                                    //默认radio所有工料机
-                                    co.initRadio();
-                                    co.gljCurTypeId = null;
-                                    //默认点击树根节点
-                                    co.initClassTree('std', gljClassTreeObj.treeData.std);
-                                    //弹出窗口
-                                    $('#component').modal('show');
-                                };
-                                if (repositoryGljObj.pullCompleteData) {
-                                    oprFunc();
-                                } else {
-                                    repositoryGljObj.getStdItems(pageOprObj.stdGljLibId, oprFunc);
-                                }
-                            }},
-                            "delete": {name: "删除", disabled: delDis, icon: "fa-remove", callback: function (key, opt) {
-                                //删除
-                                let deleteObj = that.currentComponent[target.row];
-                                let gljComponent = that.currentGlj.component;
-                                let updateArr = [];
-                                //更新当前工料机的组成物列表
-                                for(let i = 0, len = gljComponent.length; i < len; i++){
-                                    if(gljComponent[i].ID === deleteObj.ID){
-                                        gljComponent.splice(i, 1);
-                                        break;
+                            "insert": {
+                                name: "插入", disabled: insertDis, icon: "fa-sign-in", callback: function (key, opt) {
+                                    let oprFunc = function () {
+                                        //默认radio所有工料机
+                                        co.initRadio();
+                                        co.gljCurTypeId = null;
+                                        //默认点击树根节点
+                                        co.initClassTree('std', gljClassTreeObj.treeData.std);
+                                        //弹出窗口
+                                        $('#component').modal('show');
+                                    };
+                                    if (repositoryGljObj.pullCompleteData) {
+                                        oprFunc();
+                                    } else {
+                                        repositoryGljObj.getStdItems(pageOprObj.stdGljLibId, oprFunc);
                                     }
                                 }
-                                //重新计算工料机
-                                let gljBasePrc = me.reCalGljBasePrc(that.getCurrentComponent(gljComponent));
-                                if(gljBasePrc !== that.currentGlj.basePrice){
-                                    that.currentGlj.basePrice = gljBasePrc;
-                                    that.reshowGljBasePrc(that.currentGlj);
-                                    //updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
+                            },
+                            "delete": {
+                                name: "删除", disabled: delDis, icon: "fa-remove", callback: function (key, opt) {
+                                    //删除
+                                    let deleteObj = that.currentComponent[target.row];
+                                    let gljComponent = that.currentGlj.component;
+                                    let updateArr = [];
+                                    //更新当前工料机的组成物列表
+                                    for (let i = 0, len = gljComponent.length; i < len; i++) {
+                                        if (gljComponent[i].ID === deleteObj.ID) {
+                                            gljComponent.splice(i, 1);
+                                            break;
+                                        }
+                                    }
+                                    //重新计算工料机
+                                    let gljBasePrc = me.reCalGljBasePrc(that.getCurrentComponent(gljComponent));
+                                    if (that.isGljPriceChange(that.currentGlj, gljBasePrc)) {
+                                        that.setPrice(that.currentGlj, gljBasePrc);
+                                        that.reshowGljBasePrc(that.currentGlj);
+                                        //updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
+                                    }
+                                    /* if (gljBasePrc !== that.currentGlj.basePrice) {
+                                        that.currentGlj.basePrice = gljBasePrc;
+                                        that.reshowGljBasePrc(that.currentGlj);
+                                        //updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
+                                    } */
+                                    updateArr.push(that.currentGlj);
+                                    me.updateComponent(updateArr);
                                 }
-                                updateArr.push(that.currentGlj);
-                                me.updateComponent(updateArr);
-                            }}
+                            }
                         }
                     };
                 }
-                else{
+                else {
                     return false;
                 }
             }
         });
     },
     gljComponentDelOpr: function () {
-        let me = gljComponentOprObj, that = repositoryGljObj, updateArr = [], removeArr = [], isUpdate = false, updateBasePrc= [];
-        me.workBook.commandManager().register('gljComponentDel', function () {
+        let me = gljComponentOprObj, that = repositoryGljObj, updateArr = [], removeArr = [], isUpdate = false, updateBasePrc = [];
+        /* me.workBook.commandManager().register('gljComponentDel', function () {
             let sels = me.workBook.getSheet(0).getSelections();
-            if(sels.length > 0 && that.currentComponent.length > 0){
+            if (sels.length > 0 && that.currentComponent.length > 0) {
                 let component = that.currentGlj.component;
-                for(let i = 0; i < sels.length > 0; i++){
-                    if(sels[i].colCount === me.setting.header.length){//可删除
-                        for(let j = 0; j < sels[i].rowCount; j++){
-                            if(sels[i].row + j < that.currentComponent.length){
+                for (let i = 0; i < sels.length > 0; i++) {
+                    if (sels[i].colCount === me.setting.header.length) {//可删除
+                        for (let j = 0; j < sels[i].rowCount; j++) {
+                            if (sels[i].row + j < that.currentComponent.length) {
                                 removeArr.push(that.currentComponent[sels[i].row + j].ID);
 
                             }
                         }
                     }
-                    else if(sels[i].col === 0){
-                            //编码不可为空
-                            alert("编码不可为空!");
+                    else if (sels[i].col === 0) {
+                        //编码不可为空
+                        alert("编码不可为空!");
 
                     }
-                    else if(sels[i].col === 4){//消耗量修改为0
-                        if(sels[i].row === -1){//全修改
-                           for(let j = 0; j < that.currentComponent.length; j++){
-                               isUpdate = true;
-                               that.currentComponent[j].consumeAmt = 0;
-                               for(let k = 0; k < component.length; k++){
-                                   if(component[k].ID === that.currentComponent[j].ID){
-                                       component[k].consumeAmt = 0;
-                                       break;
-                                   }
-                               }
-                           }
+                    else if (sels[i].col === 4) {//消耗量修改为0
+                        if (sels[i].row === -1) {//全修改
+                            for (let j = 0; j < that.currentComponent.length; j++) {
+                                isUpdate = true;
+                                that.currentComponent[j].consumeAmt = 0;
+                                for (let k = 0; k < component.length; k++) {
+                                    if (component[k].ID === that.currentComponent[j].ID) {
+                                        component[k].consumeAmt = 0;
+                                        break;
+                                    }
+                                }
+                            }
                         }
-                        else{//部分修改
-                            for(let j = 0; j < sels[i].rowCount; j++){
-                                if(sels[i].row + j < that.currentComponent.length){
+                        else {//部分修改
+                            for (let j = 0; j < sels[i].rowCount; j++) {
+                                if (sels[i].row + j < that.currentComponent.length) {
                                     isUpdate = true;
                                     that.currentComponent[sels[i].row + j].consumeAmt = 0;
-                                    for(let k = 0; k < component.length; k++){
-                                        if(component[k].ID === that.currentComponent[sels[i].row + j].ID){
+                                    for (let k = 0; k < component.length; k++) {
+                                        if (component[k].ID === that.currentComponent[sels[i].row + j].ID) {
                                             component[k].consumeAmt = 0;
                                             break;
                                         }
@@ -187,47 +333,48 @@ let gljComponentOprObj = {
                         }
                     }
                 }
-                if(removeArr.length > 0 || isUpdate){
-                    for(let i = 0; i < removeArr.length; i++){
-                        for(let j = 0; j < that.currentComponent.length; j++){
-                            if(that.currentComponent[j].ID === removeArr[i]){
+                if (removeArr.length > 0 || isUpdate) {
+                    for (let i = 0; i < removeArr.length; i++) {
+                        for (let j = 0; j < that.currentComponent.length; j++) {
+                            if (that.currentComponent[j].ID === removeArr[i]) {
                                 that.currentComponent.splice(j--, 1);
                             }
                         }
-                        for(let j = 0; j < component.length; j++){
-                            if(component[j].ID === removeArr[i]){
+                        for (let j = 0; j < component.length; j++) {
+                            if (component[j].ID === removeArr[i]) {
                                 component.splice(j--, 1);
                             }
                         }
                     }
                     //重新计算工料机
                     let gljBasePrc = me.reCalGljBasePrc(that.currentComponent);
-                    if(gljBasePrc !== that.currentGlj.basePrice){
+                    if (gljBasePrc !== that.currentGlj.basePrice) {
                         that.currentGlj.basePrice = gljBasePrc;
                         that.reshowGljBasePrc(that.currentGlj);
-                        updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
+                        updateBasePrc.push({ gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice });
                     }
                     updateArr.push(that.currentGlj);
                     me.updateComponent(updateArr);
-                    if(updateBasePrc.length > 0){
+                    if (updateBasePrc.length > 0) {
                         that.updateRationBasePrcRq(updateBasePrc);
                     }
                 }
             }
-        });
+        }); */
         me.workBook.commandManager().setShortcutKey(null, GC.Spread.Commands.Key.del, false, false, false, false);
         //me.workBook.commandManager().setShortcutKey('gljComponentDel', GC.Spread.Commands.Key.del, false, false, false, false);
     },
-    onCellEditStart: function(sender, args) {
+    onCellEditStart: function (sender, args) {
         let me = gljComponentOprObj, that = repositoryGljObj;
         let rObj = me.getRowData(args.sheet, args.row, me.setting);
         me.currentEditingComponent = rObj;
         let thatRow = that.workBook.getSheet(0).getSelections()[0].row;
-        if(thatRow < that.currentCache.length){
+        if (thatRow < that.currentCache.length) {
             that.currentGlj = that.currentCache[thatRow];
-            if(me.setting.view.lockedCols.indexOf(args.col) !== -1 || !allowComponent.includes(that.currentGlj.gljType) ||
-                (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.stdGljList.concat(that.complementaryGljList))) ||
-                (args.col === 4 && (!that.currentComponent|| args.row >= that.currentComponent.length))){
+            //消耗量可编辑
+            if (!(me.colMapping.colToField[args.col].includes('consumeAmt')) || !allowComponent.includes(that.currentGlj.gljType) ||
+                (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.gljList)) ||
+                (args.col === 4 && (!that.currentComponent || args.row >= that.currentComponent.length))) {
                 args.cancel = true;
             }
         }
@@ -237,124 +384,44 @@ let gljComponentOprObj = {
     },
     onCellEditEnd: function (sender, args) {
         let me = gljComponentOprObj, that = repositoryGljObj, updateBasePrc = [];
-        let gljList = that.gljList, updateArr = [], materialComponent = [202, 203, 204], machineComponent = [302, 303];
-        // if(args.editingText !== me.currentEditingComponent.code){
-        //编码
-      /*  if(args.col === 0 && args.editingText && args.editingText.trim().length > 0 &&args.editingText !== me.currentEditingComponent.code){
-            let component = that.currentGlj.component, hasCode = false;
-            for(let i = 0; i < gljList.length; i++){
-                if(gljList[i].code === args.editingText){//有效的组成物
-                    hasCode = true;
-                    if((materialComponent.indexOf(that.currentGlj.gljType) !== -1 && gljList[i].gljType === 201)
-                        || (that.currentGlj.gljType === 301 && machineComponent.indexOf(gljList[i].gljType) !== -1 )){//普通材料
-                        //是否与原有组成物不同
-                        let isExist = false;
-                        for(let j = 0; j < component.length; j++){
-                            if(component[j].ID === gljList[i].ID){
-                                isExist = true;
-                                break;
-                            }
-                        }
-                        if(!isExist){
-                            let rObj = {};
-                            rObj.ID = gljList[i].ID;
-                            //rObj.basePrice = gljList[i].basePrice;
-                            if(typeof that.currentComponent[args.row] !== 'undefined'){
-                                rObj.consumeAmt = that.currentComponent[args.row].consumeAmt;
-                                let index;
-                                for(let j = 0; j < component.length; j++){
-                                    if(component[j].ID === that.currentComponent[args.row].ID){
-                                        index = j;
-                                        break;
-                                    }
-                                }
-                                component.splice(index, 1);
-                                component.splice(index, 0, rObj);
-                                //计算工料机单价
-                                let gljBasePrc = me.reCalGljBasePrc(that.getCurrentComponent(component));
-                                if(gljBasePrc !== that.currentGlj.basePrice){
-                                    that.currentGlj.basePrice = gljBasePrc;
-                                    that.reshowGljBasePrc(that.currentGlj);
-                                    //工料机单价改变,重算引用了该工料机的定额单价
-                                    updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
-                                }
-                                updateArr.push(that.currentGlj);
-                            }
-                            else{
-                                rObj.consumeAmt = 0;
-                                component.push(rObj);
-                                //计算工料机单价
-                                let gljBasePrc = me.reCalGljBasePrc(that.getCurrentComponent(component));
-                                if(gljBasePrc !== that.currentGlj.basePrice){
-                                    that.currentGlj.basePrice = gljBasePrc;
-                                    that.reshowGljBasePrc(that.currentGlj);
-                                    //工料机单价改变,重算引用了该工料机的定额单价
-                                    updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
-                                }
-                                updateArr.push(that.currentGlj);
-                            }
-                            break;
-                        }
-                        else{
-                            //已存在
-                            alert("已存在!");
-                            args.sheet.setValue(args.row, args.col, me.currentEditingComponent[me.setting.header[args.col].dataCode] ?
-                                me.currentEditingComponent[me.setting.header[args.col].dataCode]: '');
-                        }
-
-                    }
-                    else{
-                        if(materialComponent.indexOf(that.currentGlj.gljType) === 1){
-                            alert("该组成物只能是普通材料!");
-                        }
-                        else if(that.currentGlj.gljType === 301){
-                            alert("该组成物只能是机械组成物或机上人工!")
-                        }
-                        args.sheet.setValue(args.row, args.col, me.currentEditingComponent[me.setting.header[args.col].dataCode] ?
-                            me.currentEditingComponent[me.setting.header[args.col].dataCode]: '');
-                        //无效
-                    }
-                }
-            }
-            if(!hasCode){
-                alert("不存在此工料机,请先添加!");
-                args.sheet.setValue(args.row, args.col, me.currentEditingComponent[me.setting.header[args.col].dataCode] ?
-                    me.currentEditingComponent[me.setting.header[args.col].dataCode] : '');
-                //不存在
-            }
-        }*/
-         if(args.col === 4 && me.currentEditingComponent.code && args.editingText && args.editingText.trim().length > 0){//消耗量
+        let updateArr = [];
+        let dataCode = me.colMapping.colToField[args.col];
+        if (dataCode.includes('consumeAmt') && me.currentEditingComponent.code && args.editingText && args.editingText.trim().length > 0) {//消耗量
             let consumeAmt = parseFloat(args.editingText);
-            if(!isNaN(consumeAmt) && consumeAmt !== me.currentEditingComponent.consumeAmt){
+            if (!isNaN(consumeAmt) && me.consumeAmtChanged(me.currentEditingComponent, consumeAmt, args.col)) {
                 let roundCons = scMathUtil.roundTo(parseFloat(consumeAmt), -3);
                 let component = that.currentGlj.component;
-                for(let i = 0; i < component.length; i++){
-                    if(component[i].ID === that.currentComponent[args.row].ID){
-                        component[i].consumeAmt = roundCons;
+                for (let i = 0; i < component.length; i++) {
+                    if (component[i].ID === that.currentComponent[args.row].ID) {
+                        me.setConsumeAmt(component[i], dataCode, roundCons);
+                        //component[i].consumeAmt = roundCons;
                     }
                 }
-                that.currentComponent[args.row].consumeAmt = roundCons;
+                //that.currentComponent[args.row].consumeAmt = roundCons;
+                me.setConsumeAmt(that.currentComponent[args.row], dataCode, roundCons);
                 //计算工料机单价
                 let gljBasePrc = me.reCalGljBasePrc(that.currentComponent);
-                if(gljBasePrc !== that.currentGlj.basePrice){
-                    that.currentGlj.basePrice = gljBasePrc;
+                if (that.isGljPriceChange(that.currentGlj, gljBasePrc)) {
+                    that.setPrice(that.currentGlj, gljBasePrc);
                     that.reshowGljBasePrc(that.currentGlj);
                     //工料机单价改变,重算引用了该工料机的定额单价
                     //updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
                 }
                 updateArr.push(that.currentGlj);
             }
-            else{
+            else {
                 //只能输入数值
-                args.sheet.setValue(args.row, args.col, me.currentEditingComponent[me.setting.header[args.col].dataCode] ?
-                    me.currentEditingComponent[me.setting.header[args.col].dataCode]: 0);
+                sheetOpr.showData(me, me.workBook.getSheet(0), me.setting, that.currentComponent);
+                /* args.sheet.setValue(args.row, args.col, me.currentEditingComponent[me.setting.header[args.col].dataCode] ?
+                    me.currentEditingComponent[me.setting.header[args.col].dataCode] : 0); */
 
             }
         }
-        else{
-            args.sheet.setValue(args.row, args.col, me.currentEditingComponent.consumeAmt);
+        else {
+            //args.sheet.setValue(args.row, args.col, me.currentEditingComponent.consumeAmt);
+            sheetOpr.showData(me, me.workBook.getSheet(0), me.setting, that.currentComponent);
         }
-        if(updateArr.length > 0){
+        if (updateArr.length > 0) {
             me.updateComponent(updateArr);
             /*if(updateBasePrc.length > 0){
                 that.updateRationBasePrcRq(updateBasePrc)
@@ -364,123 +431,86 @@ let gljComponentOprObj = {
     onClipboardPasting: function (sender, info) {
         let me = gljComponentOprObj, that = repositoryGljObj;
         let maxCol = info.cellRange.col + info.cellRange.colCount - 1;
+        /*  if (info.cellRange.col !== 4 && info.cellRange.colCount > 1 || (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.stdGljList.concat(that.complementaryGljList)))) {
+             args.cancel = true;
+         } */
         //复制的列数超过正确的列数,不可复制
-        if(info.cellRange.col !== 4 && info.cellRange.colCount > 1 || (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.stdGljList.concat(that.complementaryGljList)))){
-            args.cancel = true;
+        if (maxCol > me.setting.header.length - 1) {
+            return info.cancel = true;
+        }
+        if (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.stdGljList.concat(that.complementaryGljList))) {
+            return info.cancel = true;
+        }
+        //粘贴的字段只能是消耗量
+        for (let i = 0; i < info.cellRange.colCount; i++) {
+            let col = info.cellRange.col + i;
+            let dataCode = me.colMapping.colToField[col];
+            if (!dataCode.includes('consumeAmt')) {
+                return info.cancel = true;
+            }
         }
     },
     onClipboardPasted: function (sender, info) {
-        let me = gljComponentOprObj, that = repositoryGljObj, updateArr = [] ,materialComponent = [202, 203, 204], machineComponent = [302, 303],
+        let me = gljComponentOprObj, that = repositoryGljObj, updateArr = [], materialComponent = [202, 203, 204], machineComponent = [302, 303],
             component = that.currentGlj.component, newComponent = [], concatComponent = [], isChange = false, updateBasePrc = [];
-        let items = sheetOpr.analyzePasteData(me.setting, info);
         let gljCache = that.gljList;
-        //编码
-   /*     if(info.cellRange.col === 0){
-            for(let i = 0; i < items.length; i++){
-                for(let j = 0; j < gljCache.length; j++){
-                    if(items[i].code === gljCache[j].code){
-                        if((materialComponent.indexOf(that.currentGlj.gljType) !== -1 && gljCache[j].gljType === 201)
-                            || (that.currentGlj.gljType === 301 && machineComponent.indexOf(gljCache[j].gljType) !== -1 )){
-                            //是否与原有组成物不同
-                            let isExist = false;
-                            for(let k = 0; k < component.length; k++){
-                                if(component[k].ID === gljCache[j].ID){
-                                    isExist = true;
-                                    me.workBook.getSheet(0).setValue(info.cellRange.row + i, info.cellRange.col,
-                                        typeof that.currentComponent[info.cellRange.row + i] !== 'undefined'? that.currentComponent[info.cellRange.row + i].code : '');
+        //消耗量
+        if (me.colMapping.colToField[info.cellRange.col].includes('consumeAmt')) {
+            let items = sheetCommonObj.analyzePasteData(me.setting, info);
+            let row = info.cellRange.row;
+            for (let i = 0; i < items.length; i++) {
+                if (row + i < that.currentComponent.length) {
+                    let currentObj = that.currentComponent[row + i];
+                    if (!me.consumeAmtIsEqual(items[i], currentObj)) {
+                        isChange = true;
+                        if (!consumeAmtProperties || consumeAmtProperties.length === 0) {
+                            let roundCons = scMathUtil.roundTo(parseFloat(items[i].consumeAmt), -3);
+                            currentObj.consumeAmt = roundCons;
+                            for (let j = 0; j < component.length; j++) {
+                                if (component[j].ID === currentObj.ID) {
+                                    component[j].consumeAmt = currentObj.consumeAmt;
                                     break;
                                 }
                             }
-                            if(!isExist){
-                                isChange = true;
-                                let obj = {};
-                                obj.ID = gljCache[j].ID;
-                                if(typeof that.currentComponent[info.cellRange.row + i] !== 'undefined'){//更新
-                                    obj.consumeAmt = that.currentComponent[info.cellRange.row + i].consumeAmt;
-                                    let index;
-                                    for(let k = 0; k < component.length; k++){
-                                        if(that.currentComponent[info.cellRange.row + i].ID === component[k].ID){
-                                            index = k;
-                                            break;
-                                        }
-                                    }
-                                    component.splice(index, 1);
-                                    component.splice(index, 0, obj);
-                                }
-                                else{//新增
-                                    obj.consumeAmt = 0;
-                                    component.push(obj);
+                        } else {
+                            for (let attr in items[i]) {
+                                //是消耗量字段
+                                if (attr.includes('consumeAmt') && items[i][attr] && !isNaN(parseFloat(items[i][attr]))) {
+                                    let roundCons = scMathUtil.roundTo(parseFloat(items[i][attr]), -3);
+                                    currentObj.consumeAmtProperty[attr] = roundCons;
                                 }
-                                break;
                             }
-
-                        }
-                        else{
-                            me.workBook.getSheet(0).setValue(info.cellRange.row + i, info.cellRange.col,
-                            typeof that.currentComponent[info.cellRange.row + i] !== 'undefined'? that.currentComponent[info.cellRange.row + i].code : '');
-
-                        }
-
-                    }
-                    else{
-                        me.workBook.getSheet(0).setValue(info.cellRange.row + i, info.cellRange.col,
-                            typeof that.currentComponent[info.cellRange.row + i] !== 'undefined'? that.currentComponent[info.cellRange.row + i].code : '');
-                    }
-                }
-            }
-            if(isChange){
-                //计算工料机单价
-                let gljBasePrc = me.reCalGljBasePrc(that.getCurrentComponent(component));
-                if(gljBasePrc !== that.currentGlj.basePrice){
-                    that.currentGlj.basePrice = gljBasePrc;
-                    that.reshowGljBasePrc(that.currentGlj);
-                    updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
-                }
-                updateArr.push(that.currentGlj);
-            }
-        }*/
-        //消耗量
-         if(info.cellRange.col === 4){
-            let items = sheetOpr.analyzePasteData(me.setting, info);
-            let row = info.cellRange.row;
-            for(let i = 0; i < items.length; i++){
-                if(row + i < that.currentComponent.length){
-                    let currentObj = that.currentComponent[row + i];
-                    if(items[i].consumeAmt.trim().length > 0 && items[i].consumeAmt !== currentObj.consumeAmt){
-                        let roundCons = scMathUtil.roundTo(parseFloat(items[i].consumeAmt), -3);
-                        isChange = true;
-                        currentObj.consumeAmt = roundCons;
-                        for(let j = 0; j < component.length; j++){
-                            if(component[j].ID === currentObj.ID){
-                                component[j].consumeAmt = currentObj.consumeAmt;
-                                break;
+                            for (let j = 0; j < component.length; j++) {
+                                if (component[j].ID === currentObj.ID) {
+                                    component[j].consumeAmtProperty = currentObj.consumeAmtProperty;
+                                    break;
+                                }
                             }
                         }
+                    } else {
+                        sheetOpr.showData(me, me.workBook.getSheet(0), me.setting, that.currentComponent);
+                        //me.workBook.getSheet(0).setValue(row + i, info.cellRange.col, currentObj.consumeAmt);
                     }
-                    else{
-                        me.workBook.getSheet(0).setValue(row + i, info.cellRange.col, currentObj.consumeAmt);
-                    }
-                }
-                else{
+                } else {
                     me.workBook.getSheet(0).setValue(row + i, info.cellRange.col, '');
                 }
             }
-            if(isChange){
+            if (isChange) {
                 //计算工料机单价
                 let gljBasePrc = me.reCalGljBasePrc(that.currentComponent);
-                if(gljBasePrc !== that.currentGlj.basePrice){
-                    that.currentGlj.basePrice = gljBasePrc;
+                if (that.isGljPriceChange(that.currentGlj, gljBasePrc)) {
+                    that.setPrice(that.currentGlj, gljBasePrc);
                     that.reshowGljBasePrc(that.currentGlj);
                     //updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
                 }
                 updateArr.push(that.currentGlj);
             }
         }
-        if(updateArr.length > 0){
+        if (updateArr.length > 0) {
             me.updateComponent(updateArr);
-           /* if(updateBasePrc.length > 0){
-                that.updateRationBasePrcRq(updateBasePrc);
-            }*/
+            /* if(updateBasePrc.length > 0){
+                 that.updateRationBasePrcRq(updateBasePrc);
+             }*/
         }
     },
     updateComponent: function (updateArr) {
@@ -489,15 +519,15 @@ let gljComponentOprObj = {
         $.ajax({
             type: 'post',
             url: 'complementartGlj/api/updateComponent',
-            data: {"userId": pageOprObj.userId, "updateArr": JSON.stringify(updateArr)},
+            data: { "userId": pageOprObj.userId, "updateArr": JSON.stringify(updateArr) },
             dataType: 'json',
             success: function (result) {
-                if(!result.error){
-                        that.currentComponent =  that.getCurrentComponent(result.data[0].component);
-                        sheetOpr.cleanData(me.workBook.getSheet(0), me.setting, -1);
-                        sheetOpr.showData(me.workBook.getSheet(0), me.setting, that.currentComponent);
+                if (!result.error) {
+                    that.currentComponent = that.getCurrentComponent(result.data[0].component);
+                    sheetOpr.cleanData(me.workBook.getSheet(0), me.setting, -1);
+                    sheetOpr.showData(me, me.workBook.getSheet(0), me.setting, that.currentComponent);
                 }
-                else{
+                else {
                     sheetOpr.cleanData(me.workBook.getSheet(0), me.setting, -1);
                 }
                 $('#componentsCacnel').click();
@@ -505,18 +535,44 @@ let gljComponentOprObj = {
         })
     },
     round: function (v, e) {
-        let t=1;
-        for(;e>0;t*=10,e--);
-        for(;e<0;t/=10,e++);
-        return Math.round(v*t)/t;
+        let t = 1;
+        for (; e > 0; t *= 10, e--);
+        for (; e < 0; t /= 10, e++);
+        return Math.round(v * t) / t;
     },
-    reCalGljBasePrc: function (component) {
-        let me = gljComponentOprObj, gljBasePrc = 0;
-        for(let i = 0; i < component.length; i++){
-            let roundBasePrc = scMathUtil.roundTo(parseFloat(component[i].basePrice), -2);
-            let roundConsumeAmt = scMathUtil.roundTo(parseFloat(component[i].consumeAmt), -3);
-            gljBasePrc = scMathUtil.roundTo(scMathUtil.roundTo(roundBasePrc * roundConsumeAmt, me.processDecimal) + gljBasePrc, me.processDecimal);
+    reCalGljBasePrc: function (components) {
+        /*         let me = gljComponentOprObj;
+                let gljBasePrc = 0;
+                for(let i = 0; i < component.length; i++){
+                    let roundBasePrc = scMathUtil.roundTo(parseFloat(component[i].basePrice), -2);
+                    let roundConsumeAmt = scMathUtil.roundTo(parseFloat(component[i].consumeAmt), -3);
+                    gljBasePrc = scMathUtil.roundTo(scMathUtil.roundTo(roundBasePrc * roundConsumeAmt, me.processDecimal) + gljBasePrc, me.processDecimal);
+                }
+                return gljBasePrc;
+         */
+
+        let me = gljComponentOprObj, re = repositoryGljObj;
+        // 只有一个单价的情况,只有一个单价则只有一个消耗量
+        if (!priceProperties || priceProperties.length === 0) {
+            let gljBasePrc = 0;
+            for (let i = 0; i < components.length; i++) {
+                let roundBasePrc = scMathUtil.roundTo(parseFloat(components[i].basePrice), -2);
+                let roundConsumeAmt = scMathUtil.roundTo(parseFloat(components[i].consumeAmt), -3);
+                gljBasePrc = scMathUtil.roundTo(scMathUtil.roundTo(roundBasePrc * roundConsumeAmt, me.processDecimal) + gljBasePrc, me.processDecimal);
+            }
+            return scMathUtil.roundTo(gljBasePrc, -2);
+        } else { // 多单价的情况
+            let gljPriceProperty = re.getPriceProperty(priceProperties);
+            for (let priceProp in gljPriceProperty) {
+                let consumeAmtField = re.getConsumeAmtField(consumeAmtProperties, priceProp);
+                for (let component of components) {
+                    let roundBasePrc = scMathUtil.roundTo(parseFloat(component['priceProperty'][priceProp]), -2);
+                    let roundConsumeAmt = scMathUtil.roundTo(parseFloat(component['consumeAmtProperty'][consumeAmtField]), -3);
+                    gljPriceProperty[priceProp] = scMathUtil.roundTo(scMathUtil.roundTo(roundBasePrc * roundConsumeAmt, me.processDecimal) + gljPriceProperty[priceProp], me.processDecimal);
+                }
+                scMathUtil.roundTo(gljPriceProperty[priceProp], -2);
+            }
+            return gljPriceProperty;
         }
-        return gljBasePrc;
     }
 };

+ 146 - 5
web/building_saas/complementary_glj_lib/js/sheetOpr.js

@@ -114,7 +114,7 @@ let sheetOpr = {
             area.vAlign(GC.Spread.Sheets.VerticalAlign.center);
         }
     },
-    showData: function(sheet, setting, data, distTypeTree, machineModelIdx) {
+    /* showData: function(sheet, setting, data, distTypeTree, machineModelIdx) {
         var me = this, ch = GC.Spread.Sheets.SheetArea.viewport;
         sheet.suspendPaint();
         sheet.suspendEvent();
@@ -169,7 +169,7 @@ let sheetOpr = {
         sheet.resumeEvent();
         sheet.resumePaint();
         //me.shieldAllCells(sheet);
-    },
+    }, */
     analyzePasteData: function(setting, pastedInfo) {
         var rst = [], propId = pastedInfo.cellRange.col, preStrIdx = 0, itemObj = {};
         for (var i = 0; i < pastedInfo.pasteData.text.length; i++) {
@@ -196,12 +196,153 @@ let sheetOpr = {
         }
         return rst;
     },
+    showData: function(obj, sheet, setting, data, distTypeTree, materialTypeIdx, machineModelIdx) {
+        var me = this, ch = GC.Spread.Sheets.SheetArea.viewport;
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        if(typeof setting.owner !== 'undefined' && setting.owner === 'gljComponent'){
+            sheet.setRowCount(data.length + 5);
+        }
+        else{
+            sheet.setRowCount(typeof repositoryGljObj !== 'undefined' && repositoryGljObj.currentOprParent === 1 ? data.length : data.length + 10);
+        }
+        let checkBoxType = new GC.Spread.Sheets.CellTypes.CheckBox();
+        for (var col = 0; col < setting.header.length; col++) {
+            var hAlign = "left", vAlign = "center";
+            if (setting.header[col].hAlign) {
+                hAlign = setting.header[col].hAlign;
+            } else if (setting.header[col].dataType !== "String"){
+                hAlign = "right";
+            }
+            vAlign = setting.header[col].vAlign?setting.header[col].vAlign:vAlign;
+            me.setAreaAlign(sheet.getRange(-1, col, -1, 1), hAlign, vAlign);
+            if (setting.header[col].formatter) {
+                sheet.setFormatter(-1, col, setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
+            }
+            for (var row = 0; row < data.length; row++) {
+                if(obj.pricePropertyCols.includes(col)){
+                    let price = data[row]['priceProperty'] && data[row]['priceProperty'][obj.colMapping.colToField[col]] !== undefined
+                        && data[row]['priceProperty'][obj.colMapping.colToField[col]] !== null
+                        ? data[row]['priceProperty'][obj.colMapping.colToField[col]] : '';
+                    sheet.setValue(row, col, price);
+                }
+                else if(obj.consumeAmtPropertyCols && obj.consumeAmtPropertyCols.includes(col)){
+                    let consumeAmt = data[row]['consumeAmtProperty'] && data[row]['consumeAmtProperty'][obj.colMapping.colToField[col]] !== undefined
+                    && data[row]['consumeAmtProperty'][obj.colMapping.colToField[col]] !== null
+                        ? data[row]['consumeAmtProperty'][obj.colMapping.colToField[col]] : '';
+                    sheet.setValue(row, col, consumeAmt);
+                }
+                else if(setting.header[col].dataCode === 'gljType' && data[row].gljType){
+                    let distTypeVal =  distTypeTree.distTypes[distTypeTree.prefix + data[row].gljType].data.fullName;
+                    sheet.setValue(row, col, distTypeVal, ch);
+                }
+                else if(setting.header[col].dataCode === 'materialType' && data[row].materialType){
+                    sheet.setValue(row, col, materialTypeIdx[data[row].materialType]);
+                }
+                else if(setting.header[col].dataCode === 'model' && data[row].model){
+                    sheet.setValue(row, col, machineModelIdx[data[row].model]);
+                }
+                else if(setting.header[col].dataCode === 'select'){
+                    if(data[row].isChecked === true){
+                        sheet.getCell(row, col).value(1);
+                    }
+                }
+                else {
+                    sheet.setValue(row, col, data[row][setting.header[col].dataCode], ch);
+                    sheet.setTag(row, 0, data[row].ID, ch);
+                }
+                //复选框
+                if(setting.header[col].dataCode === 'isComplementary'){
+                    sheet.setCellType(row, col, checkBoxType);
+                    sheet.getCell(row, col).value(1);
+                }
+                //新增组成物表,选择复选框
+                if(setting.header[col].dataCode === 'select'){
+                    sheet.setCellType(row, col, checkBoxType)
+                    if(data[row].isChecked === true){
+                        sheet.getCell(row, col).value(1);
+                    }
+                }
+            }
+        }
+        sheet.resumeEvent();
+        sheet.resumePaint();
+    },
     combineRowData: function(sheet, setting, row, repositoryGljObj) {
         let me = this;
+        var rst = {priceProperty: {}};
+        let gljTypeCombo = sheet.getCellType(row, repositoryGljObj.colMapping.fieldToCol['gljType']);
+        let items = gljTypeCombo.items();
+        let materialTypeCombo = sheet.getCellType(row, repositoryGljObj.colMapping.fieldToCol['materialType']);
+        let machineItems = sheet.getCellType(row, repositoryGljObj.colMapping.fieldToCol['model']).items();
+        let codeCol = 0;
+        for (var col = 0; col < setting.header.length; col++) {
+            if(repositoryGljObj.pricePropertyCols.includes(col)){
+                v = sheet.getValue(row, col);
+                rst.priceProperty[setting.header[col].dataCode] = v && v !== '' ? v : 0;
+            }
+            else if(setting.header[col].dataCode === 'gljType'){
+                items.forEach(function(item){
+                    if(sheet.getValue(row, col) === item.text){
+                        rst[setting.header[col].dataCode] = item.value;
+                        if(repositoryGljObj){
+                            rst.shortName = repositoryGljObj.distTypeTree.distTypes[repositoryGljObj.distTypeTree.prefix + item.value].data.shortName;
+                        }
+                    }
+                });
+            }
+            else if(setting.header[col].dataCode === 'model'){
+                machineItems.forEach(function(item){
+                    if(sheet.getValue(row, col) === item.text){
+                        rst[setting.header[col].dataCode] = item.value;
+                    }
+                });
+            }
+            else if (setting.header[col].dataCode === 'code'){
+                codeCol = col;
+                if(repositoryGljObj){
+                    let gljList = repositoryGljObj.gljList,
+                        orgCode = repositoryGljObj.orgCode,
+                        isExist = false;
+                    for(let i=0; i< gljList.length; i++){
+                        if(gljList[i].code === sheet.getValue(row, col) && sheet.getValue(row, col)!== orgCode){
+                            $('#alertText').text("输入的编号已存在,请重新输入!");
+                            $('#codeAlertBtn').click();
+                            $('#codAleConfBtn').click(function () {
+                                sheet.setValue(row, codeCol, orgCode);
+                                sheet.getCell(row, codeCol).formatter("@");
+                                sheet.setActiveCell(row, codeCol);
+                            });
+                            $('#codAleClose').click(function () {
+                                sheet.setValue(row, codeCol, orgCode);
+                                sheet.getCell(row, codeCol).formatter("@");
+                                sheet.setActiveCell(row, codeCol);
+                            });
+                            isExist = true
+                        }
+                    }
+                    if(!isExist){
+                        rst[setting.header[col].dataCode] = sheet.getValue(row, col);
+                    }
+                }
+                else{
+                    rst[setting.header[col].dataCode] = sheet.getValue(row, col);
+                }
+            }
+            else{
+                rst[setting.header[col].dataCode] = sheet.getValue(row, col);
+            }
+        }
+        return rst;
+    },
+    /* combineRowData: function(sheet, setting, row, repositoryGljObj) {
+        let me = this;
         var rst = {};
-        let comboBoxCellType = sheet.getCellType(row, 5);
+        const gljTypeCol = setting.header.findIndex(item => item.dataCode === 'gljType');
+        const modelCol = setting.header.findIndex(item => item.dataCode === 'model');
+        let comboBoxCellType = sheet.getCellType(row, gljTypeCol);
         let items = comboBoxCellType.items();
-        let machineItems = sheet.getCellType(row, 6).items();
+        let machineItems = sheet.getCellType(row, modelCol).items();
         for (var col = 0; col < setting.header.length; col++) {
             if(setting.header[col].dataCode === 'gljType'){
                 items.forEach(function(item){
@@ -277,7 +418,7 @@ let sheetOpr = {
             }
         }
         return rst;
-    },
+    }, */
     combineRationRowData: function(sheet, setting, row) {
         var rst = {};
         for (var col = 0; col < setting.header.length; col++) {

+ 1 - 0
web/building_saas/complementary_ration_lib/html/dinge.html

@@ -54,6 +54,7 @@
     <script>
         const gljLibId = '<%= gljLibId %>';
         const userID = '<%=userID %>';
+        let priceProperties = JSON.parse('<%- priceProperties %>');
     </script>
 </head>
 <body>

+ 6 - 0
web/building_saas/complementary_ration_lib/js/gljSelect.js

@@ -55,6 +55,12 @@ let gljSelOprObj = {
         this.sortGlj(this.stdGljList);
         this.sortGlj(this.complementaryGljList);
         gljAdjOprObj.gljList = this.stdGljList.concat(this.complementaryGljList);
+        if(priceProperties && priceProperties.length){
+            const priceField = priceProperties[0].price.dataCode;
+            for(let glj of gljAdjOprObj.gljList){
+                glj.basePrice = glj.priceProperty && glj.priceProperty[priceField] ? glj.priceProperty[priceField] : 0;
+            }
+        }
     },
     initClassTree: function (type, treeData) {
         let me = this;

+ 12 - 0
web/building_saas/complementary_ration_lib/js/ration_glj.js

@@ -424,6 +424,12 @@ var rationGLJOprObj = {
         let me = this;
         CommonAjax.post('api/getGljItemsByCodes', {gljCodes: codes, rationRepId: repId}, function (rstData) {
             if(rstData.length > 0){
+                if(priceProperties && priceProperties.length > 0){
+                    let priceField = priceProperties[0].price.dataCode;
+                    for(let glj of rstData){
+                        glj.basePrice = glj.priceProperty && glj.priceProperty[priceField] ? glj.priceProperty[priceField] : 0;
+                    }
+                }
                 sheetCommonObj.cleanData(me.sheet, me.setting, -1);
                 let rstArr = [], dummyR = {gljId: 0, consumeAmt:0}, newAddArr = [];
                 for (let i = 0; i < rstData.length; i++) {
@@ -605,6 +611,12 @@ var rationGLJOprObj = {
             }
             CommonAjax.post('api/getGljItemsByIds', {ids: gljIds}, function (rstData) {
                 sheetCommonObj.cleanSheet(me.sheet, me.setting, -1);
+                if(priceProperties && priceProperties.length > 0){
+                    let priceField = priceProperties[0].price.dataCode;
+                    for(let glj of rstData){
+                        glj.basePrice = glj.priceProperty && glj.priceProperty[priceField] ? glj.priceProperty[priceField] : 0;
+                    }
+                }
                 var cacheArr = [];
                 for (let i = 0; i < rstData.length; i++) {
                     for (let j = 0; j < rationGljList.length; j++) {

+ 86 - 3
web/building_saas/main/js/models/importStdInterfaceBase.js

@@ -1,5 +1,3 @@
-'use strict';
-
 /**
  *
  *
@@ -8,6 +6,8 @@
  * @version
  */
 
+'use strict';
+
 const importXMLBase = (() => {
     //人材机调整法
     const AdjustType = {
@@ -111,12 +111,70 @@ const importXMLBase = (() => {
             return '0';
         }
         const feeData = fees.find(fee => fee.fieldName === fields[0]);
-        return feeData[fields[1]] || '0';
+        return feeData && feeData[fields[1]] || '0';
+    }
+    // 合并价格
+    function mergeFees(feesA, feesB) {
+        if (!feesA) {
+            return feesB;
+        }
+        if (!feesB) {
+            return [];
+        }
+        feesB.forEach(feeB => {
+            const sameKindFee = feesA.find(feeA => feeA.fieldName === feeB.fieldName);
+            if (sameKindFee) {
+                Object.assign(sameKindFee, feeB);
+            } else {
+                feesA.push(feeB);
+            }
+        });
+        return feesA;
+    }
+    // 将A对象的一部分属性赋值到B对象上
+    function assignAttr(target, source, attrs, isExcepted = false) {
+        if (!source || !target) {
+            return;
+        }
+        const sourceAttrs = attrs
+            ? isExcepted
+                ? Object.keys(source).filter(attr => !attrs.includes(attr))
+                : attrs
+            : Object.keys(source);
+        sourceAttrs.forEach(attr => {
+            // 如果是价格,不能简单地覆盖,要合并两个对象的价格
+            target[attr] = attr === 'fees' ? mergeFees(target[attr], source[attr]) : source[attr];
+        });
     }
     // 获取固定ID
     function getFlag(data) {
         return data.flags && data.flags[0] && data.flags[0].flag || 0;
     }
+    // 获取布尔型的数据
+    function getBool(v) {
+        return v === 'true' ? true : false;
+    }
+    // 设置成树结构数据
+    function setTreeData(data, parent, next) {
+        const defalutID = -1;
+        data.ID = uuid.v1();
+        data.ParentID = parent && parent.ID || defalutID;
+        data.NextSiblingID = next && next.ID || defalutID;
+    }
+    // 递归设置树结构数据,并返回设置好的数据,递归items数组
+    function mergeDataRecur(parent, items) {
+        const rst = [];
+        for (let i = 0; i < items.length; i++) {
+            const cur = items[i];
+            const next = items[i + 1];
+            setTreeData(cur, parent, next);
+            rst.push(cur);
+            if (cur.items && cur.items.length) {
+                rst.push(...mergeDataRecur(cur, cur.items));
+            }
+        }
+        return rst;
+    }
     /*
      * 递归获取相关数据,eg:获取组织措施清单下的所有子清单,该子清单们可能由分类及公式措施项各种组合组成。(参考调用处)
      * @param {Object}src(数据源) {Array}fields(二维数组,数组里的成员由需要取的字段组成)
@@ -140,6 +198,25 @@ const importXMLBase = (() => {
             return obj;
         });
     }
+
+    // 递归获取相关数据,与上方的方法不同的点在:同层可能出现不同节点,上方方法暂时不取消(防止bug)
+    // fields内字段的顺序即决定了提取数据类型的顺序,如fields = [['gruop'], ['item']],则提取的数据同层中group数据在item数据之前
+    function extractItemsRecur(src, fields, extractFuc) {
+        const rst = [];
+        for (const field of fields) {
+            const itemsSrc = arrayValue(src, field);
+            if (itemsSrc.length) {
+                const items = itemsSrc.map(itemSrc => {
+                    const obj = extractFuc(itemSrc, field);
+                    obj.items = extractItemsRecur(itemSrc, fields, extractFuc);
+                    return obj;
+                });
+                rst.push(...items);
+            }
+        }
+        return rst;
+    }
+
     /*
     * 转换计算基数
     * 1.有子项数据,则清空基数
@@ -219,8 +296,14 @@ const importXMLBase = (() => {
         getValue,
         arrayValue,
         getFee,
+        mergeFees,
+        assignAttr,
+        setTreeData,
+        mergeDataRecur,
         getFlag,
+        getBool,
         getItemsRecur,
+        extractItemsRecur,
         readAsTextSync,
     });
 

+ 2 - 21
web/building_saas/main/js/models/main_consts.js

@@ -156,27 +156,8 @@ const zanguCalcType = {
 };
 
 //供货方式
-const supplyType = {
-    //自行采购
-    ZXCG: 0,
-    //部分甲供
-    BFJG: 1,
-    //完全甲供
-    WQJG: 2,
-    //甲定乙供
-    JDYG: 3
-};
-
-const supplyText = {
-    //自行采购
-    ZXCG: '自行采购',
-    //部分甲供
-    BFJG: '部分甲供',
-    //完全甲供
-    WQJG: '完全甲供',
-    //甲定乙供
-    JDYG: '甲定乙供'
-};
+const supplyType = commonConstants.supplyType;
+const supplyText = commonConstants.supplyText;
 
 //三材类别
 const materialType = {

+ 7 - 2
web/building_saas/main/js/models/project_glj.js

@@ -481,11 +481,16 @@ ProjectGLJ.prototype.batchUpdateConsumption = function (updateData,updateMap,cal
 
 ProjectGLJ.prototype.pGljUpdate= function (data,callback) {
     let me = this;
+    let glj = me.getByID(data.id);
+    if(data.field == 'taxRate'){
+        data.field = "unit_price.taxRate";
+        data.id = glj.unit_price.id;
+    }
     $.bootstrapLoading.start();
     CommonAjax.specialPost( '/glj/update',data,function (result) {
-        let glj = me.getByID(data.id);//更新缓存
         let impactList = [];
-        glj[data.field] = data.value;
+        _.set(glj,data.field,data.value);//更新缓存
+       // glj[data.field] = data.value;
         if(data.extend&&data.extend!=""){
             let extend = JSON.parse(data.extend);
             for (let key in extend) {

+ 8 - 3
web/building_saas/main/js/models/ration_glj.js

@@ -437,7 +437,8 @@ let ration_glj = {
             };
             let priceInfo = {
                 base_price: recode.basePrice,
-                market_price: recode.marketPrice
+                market_price: recode.marketPrice,
+                taxRate:recode.taxRate
             };
             if(updateData['type'] != undefined || updateData['type'] != null){
                 updateData.shortName = projectObj.project.projectGLJ.getShortNameByID(updateData['type']);
@@ -548,7 +549,8 @@ let ration_glj = {
                     let tmp = _.find(data.priceProperties, {region: property.region, taxModel: parseInt(property.taxType)});
                     if (tmp) {
                         let dataCode = tmp.price.dataCode;
-                        for (let glj of data.stdGLJ) {
+                        let allData = data.stdGLJ.concat(data.complementaryGLJs);
+                        for (let glj of allData) {
                             if (glj.priceProperty && gljUtil.isDef(glj.priceProperty[dataCode])) {
                                 glj.basePrice = glj.priceProperty[dataCode];
                             }
@@ -572,7 +574,8 @@ let ration_glj = {
                      let tem = _.find(data.datas.priceProperties,{region:property.region,taxModel:parseInt(property.taxType)});
                      if(tem){
                          let dataCode = tem.price.dataCode;
-                         for(let glj of data.datas.stdGLJ){
+                         let allData = data.datas.stdGLJ.concat(data.datas.complementaryGLJs);
+                         for(let glj of allData){
                              if(glj.priceProperty && gljUtil.isDef(glj.priceProperty[dataCode])) glj.basePrice = glj.priceProperty[dataCode];
                          }
                      }
@@ -622,6 +625,7 @@ let ration_glj = {
                         model:glj.model,
                         basePrice: glj.basePrice,
                         marketPrice:glj.basePrice,
+                        taxRate:glj.taxRate,
                         original_code: glj.code,
                         shortName: glj.shortName,
                         serialNo: serialNo,
@@ -704,6 +708,7 @@ let ration_glj = {
                 specs: glj.specs,
                 basePrice: glj.basePrice,
                 marketPrice:glj.basePrice,
+                taxRate:glj.taxRate,
                 shortName: glj.shortName,
                 type: glj.gljType,
                 model:glj.model,

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

@@ -184,7 +184,7 @@ let contentOprObj = {
         if (!billsNode || !Array.isArray(billsNode.data.jobContent)) {
             return '';
         }
-        return billsNode.data.jobContent.length>0?billsNode.data.jobContent[0].content:"";
+         return billsNode.data.jobContent.length>0?billsNode.data.jobContent[0].content:"";
     },
     // 从清单节点获取工作内容文本数据
     getContentTexts: function (billsNode) {

+ 3 - 0
web/building_saas/main/js/views/glj_col.js

@@ -2,6 +2,7 @@
  * Created by zhang on 2018/7/3.
  */
 let gljCol = {
+    showTaxRate:false,
     ration_glj_setting: {
         header: [
             {headerName: "编码", headerWidth: 110, dataCode: "code", dataType: "String", formatter: "@"},
@@ -42,6 +43,7 @@ let gljCol = {
             {headerName: "单位", headerWidth: 45, dataCode: "unit", hAlign: "center", dataType: "String",spanRows: [2]},
             {headerName: "类型", headerWidth: 45, dataCode: "short_name", hAlign: "center", dataType: "String",spanRows: [2]},
             {headerName: "市场价", headerWidth: 70, dataCode: "marketPrice", hAlign: "right", dataType: "Number",validator:"number",spanRows: [2]},//,decimalField:"glj.unitPrice"
+            {headerName: "税率", headerWidth: 70, dataCode: "taxRate", hAlign: "right", dataType: "Number",validator:"number",spanRows: [2]},//,decimalField:"glj.unitPrice"
             {headerName: "调整价", headerWidth: 70, dataCode: "adjustPrice", hAlign: "right", dataType: "Number",spanRows: [2]},//,decimalField:"glj.unitPrice"
             {headerName: "定额价", headerWidth: 70, dataCode: "basePrice", hAlign: "right", dataType: "Number",validator:"number",spanRows: [2]},//decimalField:'glj.unitPrice',
             {headerName: "总消耗量", headerWidth: 90, dataCode: "quantity", hAlign: "right", dataType: "Number",decimalField:'glj.quantity',spanRows: [2]},
@@ -251,6 +253,7 @@ let gljCol = {
             me.removeCol('adjustPrice',me.project_glj_setting);
             me.removeCol('adjustPrice',me.mixRatio_Setting);
         };
+        if(me.showTaxRate == false)  me.removeCol('taxRate',me.project_glj_setting);
         me.showTenderFields(showTenderFields, false);
 
         gljOprObj.setting = me.ration_glj_setting;

+ 1 - 0
web/building_saas/main/js/views/glj_view.js

@@ -800,6 +800,7 @@ var gljOprObj = {
             data.basePrice =  result.basePrice;
             data.adjustPrice = result.adjustPrice;
             data.marketUnitFee = data.marketPrice;//更新树节点市场单价列的值
+            data.taxRate = glj.unit_price.taxRate;//税率
         }
         return data;
 

+ 14 - 17
web/building_saas/main/js/views/project_glj_view.js

@@ -271,30 +271,24 @@ let projectGljObject={
         }
         let dataCode = setting.header[col].dataCode;
         let lockColumns = setting.view.lockColumns;
-
-        if(lockColumns.indexOf(col)!= -1){
-            return false;
-        }
+        if(lockColumns.indexOf(col)!= -1) return false;
 
         if(isPaste == false &&(dataCode=='is_adjust_price'||dataCode=='is_evaluate'||dataCode=='is_main_material'||dataCode == 'is_eval_material'||dataCode=='no_tax_eqp')){//除了粘贴,拖动填充等操作,其它的都不能编辑
             return false;
         }
         if(dataCode=='basePrice'||dataCode=='marketPrice'||dataCode=='supply'){//有组成物时,市场单价、定额价、供货方式不能修改
-            if (data.ratio_data  && data.ratio_data.length > 0){
-                return false;
-            }
-            if(dataCode=='basePrice'&&data.is_add!=1){//如果不是新增,定额价不可修改。
-                return false;
-            }
+            if (data.ratio_data  && data.ratio_data.length > 0)  return false;
+            if(dataCode=='basePrice'&&data.is_add!=1)   return false;//如果不是新增,定额价不可修改。
         }
-        if(dataCode == 'supply_quantity'){
-            if (data.supply != 1) {// 如果为部分甲供则甲供数量需要可编辑,其它的都不能编辑
-                return false;
-            }
+        if(dataCode == 'supply_quantity' && data.supply != 1) return false;// 如果为部分甲供则甲供数量需要可编辑,其它的都不能编辑
+
+        if(dataCode == 'materialCoe') {//三材类别为空时,三材系数应只读,不允许输入。
+            if (data.materialType == undefined || data.materialType == null || data.materialType == '') return false;
         }
-        if(dataCode == 'materialCoe'){//三材类别为空时,三材系数应只读,不允许输入。
-            if(data.materialType == undefined || data.materialType == null||data.materialType==''){
-                return false;
+        if(dataCode == 'taxRate') {
+            //普通材料、商品混凝土、商品砂浆、机械组成物、主材、设备才能编辑
+            if(!_.includes([gljType.GENERAL_MATERIAL,gljType.COMMERCIAL_CONCRETE,gljType.COMMERCIAL_MORTAR,gljType.MACHINE_COMPOSITION,gljType.MAIN_MATERIAL,gljType.EQUIPMENT],data.type)){
+                return false
             }
         }
 
@@ -747,6 +741,7 @@ let projectGljObject={
             vender:glj.vender,
             qualityGrace:glj.qualityGrace,
             brand:glj.brand,
+            unitPriceID:glj.unit_price.id,
             remark:glj.remark
         };
         gljOprObj.setGLJPrice(data,glj);
@@ -989,6 +984,8 @@ let projectGljObject={
             if(dataCode == 'materialCoe'){
                 value = scMathUtil.roundForObj(value,getDecimal("material"));
             }
+            if(dataCode == 'taxRate') value = scMathUtil.roundToString(value,2);
+
             extend = Object.keys(extend).length > 0 ?  JSON.stringify(extend) : '';
             if(recode[dataCode] == value) return;
 

+ 498 - 1
web/building_saas/main/js/views/project_property_projFeature.js

@@ -3,6 +3,503 @@
  */
 let projFeatureView = {
     orgDatas: [],//for compare
+    datas: [], // 这个数据是显示和操作时用的,入库的时候需要将这份数据转换成可入库的数据结构
+    workBook: null,
+    firstData: { dispName: '工程特征', key: 'projFeature', items: [] },//for show
+    setting: {
+        header: [
+            { name: '属性', dataCode: 'dispName', width: 200, vAlign: 'center', hAlign: 'left' },
+            { name: '值', dataCode: 'value', width: 300, vAlign: 'center', hAlign: 'left' }
+        ],
+        options: {
+            allowContextMenu: false,
+            tabStripVisible: false,
+            allowCopyPasteExcelStyle: false,
+            allowExtendPasteRange: false,
+            allowUserDragDrop: false,
+            allowUserDragFill: false,
+            scrollbarMaxAlign: true
+        },
+        numRows: [],
+        dateRows: [],
+        locked: {
+            rows: [],
+            cols: [0]
+        }
+    },
+
+    renderSheetFuc: function (sheet, fuc) {
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        fuc();
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+
+    setOptions: function (workbook, opts) {
+        for (let opt in opts) {
+            workbook.options[opt] = opts[opt];
+        }
+    },
+
+    setCombo: function (sheet, row, items) {
+        let dynamicCombo = sheetCommonObj.getDynamicCombo();
+        dynamicCombo.items(items);
+        dynamicCombo.editable(false);
+        sheet.getCell(row, 1).cellType(dynamicCombo);
+    },
+
+    getComboItemsByRow: function (row) {
+        let data = this.datas[row];
+        if (!data) {
+            return null;
+        }
+        if (!data.cellType || data.cellType !== 'comboBox') {
+            return null;
+        }
+        return data.options ? data.options.split('@') : [];
+    },
+
+    buildHeader: function (sheet, headers) {
+        let me = projFeatureView;
+        let fuc = function () {
+            sheet.options.clipBoardOptions = GC.Spread.Sheets.ClipboardPasteOptions.values;
+            sheet.setColumnCount(headers.length);
+            sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
+            for (let i = 0, len = headers.length; i < len; i++) {
+                sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
+                sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
+                sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]);
+                sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]);
+
+            }
+        };
+        me.renderSheetFuc(sheet, fuc);
+    },
+
+    buildSheet: function () {
+        if (!this.workBook) {
+            this.workBook = new GC.Spread.Sheets.Workbook($('#projFeatureSpread')[0], { sheetCount: 1 });
+            sheetCommonObj.spreadDefaultStyle(this.workBook);
+            sheetCommonObj.bindEscKey(this.workBook, [{ sheet: this.workBook.getSheet(0), editStarting: this.onEditStarting, editEnded: this.onEditEnded }]);
+            this.setOptions(this.workBook, this.setting.options);
+            this.buildHeader(this.workBook.getActiveSheet(), this.setting.header);
+            this.bindEvent(this.workBook);
+        }
+    },
+
+    bindEvent: function (workBook) {
+        const _events = GC.Spread.Sheets.Events;
+        let sheet = workBook.getActiveSheet();
+        sheet.bind(_events.EditStarting, this.onEditStarting);
+        sheet.bind(_events.EditEnded, this.onEditEnded);
+        sheet.bind(_events.EnterCell, this.onEnterCell);
+        sheet.bind(_events.ClipboardPasting, this.onClipboardPasting);
+        sheet.bind(_events.ClipboardPasted, this.onClipboardPasted);
+    },
+
+    showData(datas) {
+        let me = projFeatureView;
+        let sheet = this.workBook.getActiveSheet();
+        let cols = this.setting.header;
+        let fuc = function () {
+            sheet.setRowCount(datas.length);
+            me.initTree(sheet, true, datas);
+            sheet.setFormatter(-1, 1, '@');
+            //兼容旧数据
+            // org: compatLockedKeys = ['engineering']
+            let compatLockedKeys = [],
+                compatNumKeys = [
+                    'buildingArea',
+                    'basementBuildingArea',
+                    'totalFloors',
+                    'basementFloors',
+                    'buildingFloors',
+                    'buildingHeight',
+                    'basementHeight',
+                    'firstFloorHeight',
+                    'podiumBuildingHeight',
+                    'standardFloorHeight'
+                ];
+            for (let row = 0; row < datas.length; row++) {
+                if (datas[row].cellType == 'comboBox') {
+                    let options = datas[row].options ? datas[row].options.split("@") : [];
+                    me.setCombo(sheet, row, options);
+                } else if (datas[row].cellType == 'number' || compatNumKeys.includes(datas[row].key)) {
+                    me.setting.numRows.push(row);
+                } else if (datas[row].cellType === 'date') {
+                    me.setting.dateRows.push(row);
+                }
+                let readOnly = typeof datas[row].readOnly === 'string' ? JSON.parse(datas[row].readOnly) : datas[row].readOnly;
+                if (readOnly || datas[row].items || compatLockedKeys.includes(datas[row].key)) {
+                    me.setting.locked.rows.push(row);
+                }
+                for (let col = 0; col < cols.length; col++) {
+                    sheet.setValue(row, col, datas[row][cols[col]['dataCode']]);
+                }
+            }
+            basicInfoView.setDatePicker(sheet, me.setting.dateRows);
+        };
+        this.renderSheetFuc(sheet, fuc);
+    },
+
+    onEditStarting: function (sender, args) {
+        let me = projFeatureView;
+        if (me.setting.locked.cols.indexOf(args.col) !== -1) {
+            args.cancel = true;
+        }
+        if (args.col === 1 && me.setting.locked.rows.indexOf(args.row) !== -1) {
+            args.cancel = true;
+        }
+    },
+
+    onEditEnded: function (sender, args) {
+        let me = projFeatureView;
+        let v = args.editingText ? args.editingText.toString().trim() : '';
+        if (args.row < me.datas.length) {
+            let required = typeof me.datas[args.row].required === 'string' ? JSON.parse(me.datas[args.row].required) : me.datas[args.row].required;
+            if (required && !v) {
+                v = me.datas[args.row].value;
+                args.sheet.setValue(args.row, args.col, v);
+            } else if (me.setting.numRows.indexOf(args.row) !== -1) {//控制数值
+                if (!me.isNum(v)) {
+                    alert('只能输入数值');
+                    v = me.datas[args.row].value && me.isNum(me.datas[args.row].value) ? me.datas[args.row].value : '';
+                    args.sheet.setValue(args.row, args.col, v);
+                }
+            } else if (me.setting.dateRows.indexOf(args.row) !== -1) {
+                if (v.length > 0) {
+                    v = formatDate(new Date(v), 'yyyy-MM-dd');
+                    v = basicInfoView.filtDate(v);
+                    if (!v) {
+                        alert('请输入正确的日期格式yyyy-mm-dd');
+                        args.sheet.setValue(args.row, args.col, me.datas[args.row].value ? me.datas[args.row].value : '');
+                        return;
+                    }
+                }
+            }
+            me.datas[args.row].value = v;
+        }
+    },
+
+    onEnterCell: function (sender, args) {
+        args.sheet.repaint();
+    },
+
+    onClipboardPasting: function (sender, args) {
+        let me = projFeatureView;
+        if (me.setting.locked.cols.indexOf(args.cellRange.col) !== -1) {
+            args.cancel = true;
+        }
+    },
+
+    onClipboardPasted: function (sender, args) {
+        let me = projFeatureView;
+        let items = sheetCommonObj.analyzePasteData(me.setting, args);
+        let recRows = [];
+        if (items.length === 0) {
+            return;
+        }
+        for (let i = 0, len = items.length; i < len; i++) {
+            let row = i + args.cellRange.row;
+            let comboItems = me.getComboItemsByRow(row);
+            let required = typeof me.datas[row].required === 'string' ? JSON.parse(me.datas[row].required) : me.datas[row].required;
+            if (me.setting.locked.rows.indexOf(row) !== -1) {
+                recRows.push(row);
+            }
+            else if (required && !items[i].value) {
+                recRows.push(row);
+            }
+            //粘贴下拉框数据过滤
+            else if (comboItems && !comboItems.includes(items[i].value)) {
+                recRows.push(row);
+            }
+            else if (me.setting.numRows.indexOf(row) !== -1 && !me.isNum(items[i].value)) {
+                recRows.push(row);
+            }
+            else if (me.setting.dateRows.indexOf(row) !== -1) {
+                items[i].value = basicInfoView.filtDate(items[i].value);
+                if (!me.isDef(items[i].value)) {
+                    recRows.push(row);
+                } else {
+                    me.datas[row].value = items[i].value;
+                }
+            }
+            else {
+                me.datas[row].value = items[i].value;
+            }
+        }
+        if (recRows.length > 0) {
+            me.renderSheetFuc(args.sheet, function () {
+                for (let i = 0, len = recRows.length; i < len; i++) {
+                    let staticV = me.datas[recRows[i]].value || '';
+                    args.sheet.setValue(recRows[i], args.cellRange.col, staticV);
+                }
+            })
+        }
+    },
+
+    getFeature: function (featureKey) {
+        let datas = this.datas;
+        if (datas.length === 0) {
+            datas = projectObj.project.property.projectFeature;
+        }
+        for (let feature of datas) {
+            if (feature.key === featureKey) {
+                return feature.value;
+            }
+        }
+        return null;
+    },
+
+    isDef: function (v) {
+        return v !== undefined && v !== null;
+    },
+    isNum: function (v) {
+        return this.isDef(v) && !isNaN(v);
+    },
+
+    copyObj: function (obj) {
+        let newObj = {};
+        for (let attr in obj) {
+            newObj[attr] = obj[attr];
+        }
+        return newObj;
+    },
+
+    initDatas: function (datas) {
+        this.datas = _.cloneDeep(datas);
+        //datas.forEach(item => this.datas.push(_.cloneDeep(item)));
+    },
+
+    //数据库读到的数据转换为展示的结构
+    toViewDatas: function (datas) {
+        // 将数据打平(原数据一些子项数据会嵌套在items数组中)
+        this.firstData.items = datas;
+        let curID = 1;
+        return extractDataFromItems([this.firstData]);
+        // 为了与sheet_common.js -> getTreeNodeCellType共用树结构功能
+        // 需要设置数据的ID、ParentID
+
+        function extractDataFromItems(items, parentID) {
+            const rst = [];
+            items.forEach(item => {
+                // 为了与sheet_common.js -> getTreeNodeCellType共用树结构功能
+                // 需要设置数据的ID、ParentID
+                item.ID = curID++;
+                item.ParentID = parentID || null;
+                rst.push(item);
+                if (item.items && item.items.length) {
+                    rst.push(...extractDataFromItems(item.items, item.ID));
+                }
+            });
+            return rst;
+        }
+    },
+
+    //展示的结构转换为入库的结构
+    toSaveDatas: function (datas) {
+        // ParentID为null的数据是为显示而加入的“工程特征” ParentID为1的数据即为工程特征下的第一层数据,其他数据是从ParentID为1的数据中的items递归打平出来的
+        // 因此原数据格式就是ParentID为1的数据
+        const saveData = datas.filter(item => item.ParentID === 1);
+        saveData.forEach(item => delete item.ID && delete item.ParentID);
+        return saveData;
+    },
+
+    toUpdate: function (orgDatas, newDatas) {
+        if (orgDatas.length !== newDatas.length) {
+            return true;
+        }
+        for (let i = 0, len = orgDatas.length; i < len; i++) {
+            let orgObj = orgDatas[i], newObj = newDatas[i];
+            if (orgObj.value !== newObj.value) {
+                return true;
+            }
+        }
+        return false;
+    },
+
+
+    a_updateInfo: function (datas) {
+        let me = this;
+        let url = '/pm/api/updateProjects',
+            updateData = {
+                updateType: 'update',
+                updateData: { ID: parseInt(scUrlUtil.GetQueryString('project')), 'property.projectFeature': datas }
+            },
+            postData = {
+                user_id: userID,
+                updateData: [updateData]
+            };
+        CommonAjax.post(url, postData, function (rstData) {
+            me.orgDatas = me.toViewDatas(datas);
+        });
+    },
+
+    initTree: function (sheet, init, datas) {
+        //sheet.getRange(-1, 0, -1, 1).cellType(this.getTreeNodeCellType(datas));
+        const parentType = _.groupBy(datas, 'ParentID');
+        for (let i = 0, len = datas.length; i < len; i++) {
+            if (datas[i].hasOwnProperty('items')) {
+                let collapsed = false;
+                if (init) {
+                    datas[i].collapsed = false;
+                    collapsed = true;
+                } else {
+                    collapsed = datas[i].collapsed == undefined ? true : datas[i].collapsed;
+                }
+            }
+            sheet.getCell(i, 0).cellType(sheetCommonObj.getTreeNodeCellType(datas, i, parentType))
+        }
+    },
+
+    getTreeNodeCellType: function (data) {
+        var ns = GC.Spread.Sheets;
+        var rectW = 10;
+        var rectH = 10;
+        var margin = 3;
+        const indent = 6;
+        function TreeNodeCellType() {
+        }
+
+        function drowRect(ctx, x, y, w, h) {
+            ctx.save();
+            ctx.strokeStyle = "gray";
+            ctx.translate(0.5, 0.5);
+            ctx.beginPath();
+            var rectX = x + margin;
+            var rectY = y + Math.round(h / 2) - rectH / 2;
+            ctx.moveTo(rectX, rectY);
+            ctx.lineTo(rectX, rectY + rectH);
+            ctx.lineTo(rectX + rectW, rectY + rectH);
+            ctx.lineTo(rectX + rectW, rectY);
+            ctx.lineTo(rectX, rectY);
+            ctx.moveTo(rectX + rectW, y + Math.round(h / 2));
+            ctx.lineTo(rectX + rectW + 5, y + Math.round(h / 2));
+            ctx.stroke();
+            ctx.restore();
+        }
+
+        function drowSymbol(ctx, x, y, w, h, collapsed) {
+            ctx.save();
+            ctx.strokeStyle = "#000000";
+            ctx.translate(0.5, 0.5);
+            ctx.beginPath();
+            ctx.moveTo(x + margin + 2, y + Math.round(h / 2));
+            ctx.lineTo(x + margin + 8, y + Math.round(h / 2));
+            var rectY = y + Math.round(h / 2) - rectH / 2;
+            if (collapsed) {
+                ctx.moveTo(x + margin + rectW / 2, rectY + 2);
+                ctx.lineTo(x + margin + rectW / 2, rectY + 2 + 6);
+            }
+            ctx.stroke();
+            ctx.restore();
+        }
+
+        function drowSubItem(ctx, x, y, w, h, offset, nextItem) {
+            offset += indent;
+            ctx.save();
+            ctx.strokeStyle = "gray";
+            ctx.translate(0.5, 0.5);
+            ctx.beginPath();
+            ctx.moveTo(x + offset, y);
+            ctx.lineTo(x + offset, y + Math.round(h / 2));
+            offset += 9;
+            ctx.lineTo(x + offset, y + Math.round(h / 2));
+            if (nextItem && !nextItem.hasOwnProperty('items')) {
+                ctx.moveTo(x + offset - 9, y + Math.round(h / 2));
+                ctx.lineTo(x + offset - 9, y + h);
+            }
+            ctx.stroke();
+            ctx.restore();
+            return offset;
+        }
+
+        TreeNodeCellType.prototype = new ns.CellTypes.Text();
+        TreeNodeCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
+            if (value != null) {
+                var offset = margin + rectW + indent;
+                var recode = data[options.row];
+                if (recode && recode.hasOwnProperty('items')) {
+                    debugger;
+                    drowRect(ctx, x, y, w, h);
+                    var collapsed = recode.collapsed == undefined ? true : recode.collapsed;//options.sheet.getTag(options.row,options.col);
+                    drowSymbol(ctx, x, y, w, h, collapsed);
+                } else if (recode && !recode.hasOwnProperty('items')) {
+                    offset = drowSubItem(ctx, x, y, w, h, offset, data[options.row + 1]);
+                    offset += 1;
+                }
+                arguments[2] = x + offset;
+                arguments[4] = w - offset;
+                GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
+            }
+        };
+        // override getHitInfo to allow cell type get mouse messages
+        TreeNodeCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
+            return {
+                x: x,
+                y: y,
+                row: context.row,
+                col: context.col,
+                cellStyle: cellStyle,
+                cellRect: cellRect,
+                sheetArea: context.sheetArea
+            };
+        }
+        TreeNodeCellType.prototype.processMouseDown = function (hitinfo) {
+            var recode = data[hitinfo.row];
+            let offset = -1,
+                indent = 20,
+                halfBoxLength = 5;
+            let centerX = hitinfo.cellRect.x + offset + indent / 2;
+            let centerY = (hitinfo.cellRect.y + offset + (hitinfo.cellRect.y + offset + hitinfo.cellRect.height)) / 2
+            if (recode && recode.hasOwnProperty('items')) {
+                //方框外1像素内都有效
+                const boxLengh = 10;
+                if (hitinfo.x >= centerX - halfBoxLength - 1 && hitinfo.x <= centerX + halfBoxLength + 1 &&
+                    hitinfo.y >= centerY - halfBoxLength - 1 && hitinfo.y <= centerY + halfBoxLength + 1) {
+                    var collapsed = recode.collapsed == undefined ? true : recode.collapsed;
+                    collapsed = !collapsed
+                    recode.collapsed = collapsed;
+                    //hitinfo.sheet.setTag(hitinfo.row,hitinfo.col,collapsed);
+                    hitinfo.sheet.getRange(hitinfo.row + 1, -1, recode.items.length, -1).visible(!collapsed);
+                    hitinfo.sheet.invalidateLayout();
+                    hitinfo.sheet.repaint();
+                }
+            }
+        };
+        return new TreeNodeCellType()
+    },
+
+};
+
+$(document).ready(function () {
+
+    $('#poj-set').on('shown.bs.modal', function (e) {
+        //init Spread
+        projFeatureView.initDatas(projFeatureView.orgDatas);
+        projFeatureView.buildSheet();
+        projFeatureView.showData(projFeatureView.datas);
+        if (projectReadOnly) {
+            disableSpread(projFeatureView.workBook);
+        }
+    });
+
+    $('#poj-set').on('hidden.bs.modal', function (e) {
+        //destroy Spread
+        if (projFeatureView.workBook) {
+            projFeatureView.workBook.destroy();
+            projFeatureView.workBook = null;
+        }
+        projFeatureView.datas = [];
+    });
+
+    $('#tab_poj-settings-projFeature').on('shown.bs.tab', function () {
+        sheetCommonObj.refreshWorkbookDelDefer(projFeatureView.workBook, 100);
+    });
+});
+/* let projFeatureView = {
+    orgDatas: [],//for compare
     datas: [],//just for view
     workBook: null,
     firstData: {dispName: '工程特征', key: 'projFeature', items: []},//for show
@@ -478,4 +975,4 @@ $(document).ready(function () {
     $('#tab_poj-settings-projFeature').on('shown.bs.tab', function () {
         sheetCommonObj.refreshWorkbookDelDefer(projFeatureView.workBook, 100);
     });
-});
+}); */

+ 2 - 1
web/building_saas/pm/html/project-management.html

@@ -1018,7 +1018,7 @@
 <script src="/public/billsUtil.js"></script>
 <script src="/public/common_constants.js"></script>
 <script src="/web/building_saas/main/js/models/importStdInterfaceBase.js"></script>
-<script src="/web/building_saas/main/js/models/importStandardInterface.js"></script>
+<!-- <script src="/web/building_saas/main/js/models/importStandardInterface.js"></script> -->
 <script src="/web/building_saas/pm/js/pm_ajax.js"></script>
 <script src="/web/building_saas/pm/js/pm_newMain.js"></script>
 <script src="/web/building_saas/pm/js/pm_import.js"></script>
@@ -1031,6 +1031,7 @@
 <!-- endinject -->
 <% if (overWriteUrl != undefined) { %>
     <script type="text/javascript" src="<%= overWriteUrl%>"></script>
+    <script type="text/javascript" src="<%= overWriteUrl.slice(0, -3) + '_import.js' %>"></script>
 <% } %>
 
 </body>

+ 0 - 1
web/building_saas/pm/js/pm_import.js

@@ -298,7 +298,6 @@ const importView = (() => {
                     //转换数据
                     xmlObj = await importXML.extractData(file, false);
                     console.log(xmlObj);
-                    debugger;
                     $('.selFile input:eq(0)').val(xmlObj && xmlObj.name ? xmlObj.name : '');
                     $('.selFile input[name="fileKind-import"]:eq(0)').prop('checked', true);    //文件类型恢复成投标
                     $('#import-taxType').val('1');  //计税方法显示回默认的一般计税法

+ 2 - 1
web/building_saas/pm/js/pm_newMain.js

@@ -386,7 +386,8 @@ const projTreeObj = {
             name: '导入招投标接口文件',
             icon: 'fa-cloud-upload',
             visible: function () {
-                return compilationData && compilationData.name === '重庆定额(2018)';
+                //return compilationData && compilationData.name === '重庆定额(2018)';
+                return true;
             },
             callback: function () {
                 $('#importInterface').modal('show');

+ 2 - 1
web/building_saas/main/js/models/importStandardInterface.js

@@ -95,6 +95,7 @@ const importXML = (() => {
     };
     //标段
     function loadProject(source) {
+        Object.keys(countData).forEach(key => countData[key] = 0); // 清缓存
         countData.projectCount++;
         importFileKind = FileKind[getValue(source, ['标段', '_文件类型'])];
         let obj = {
@@ -193,7 +194,7 @@ const importXML = (() => {
                 gljSummary: loadGljSummary(src),
                 differentiaSummary: loadDifferentiaSummary(src),//承包人材料差额法表
                 exponentialSummary: loadExponentialSummary(src),//承包人材料指数法表
-                evalBidSummary: loadEvalBidSummary(src),    //评标材料表
+                evalBidSummary:   loadEvalBidSummary(src),    //评标材料表
                 evalSummary: loadEvalSummary(src) // 暂估价材料表
             };
         });

+ 89 - 0
web/over_write/js/guangdong_2018.js

@@ -126,3 +126,92 @@ if (typeof module !== 'undefined') {
         };
     }
 }
+
+if(typeof gljCol !== 'undefined'){
+    gljCol.showTaxRate = true;
+}
+
+// 人材机库追加的列头
+if (typeof repositoryGljObj !== 'undefined') {
+    repositoryGljObj.setting.header = [
+        {headerName:"税率",headerWidth:60,dataCode:"taxRate", dataType: "Number", hAlign: "center", vAlign: "center"},
+        { headerName: "机型", headerWidth: 60, dataCode: "model", dataType: "Number", hAlign: "center", vAlign: "center" },
+        { headerName: "是否新增", headerWidth: 60, dataCode: "isComplementary", hAlign: "center", vAlign: "center" }
+    ]
+}
+
+// 定额人材机选择页面表头
+if (typeof gljOprObj !== 'undefined') {
+    gljOprObj.gljLibSheetSetting.header = [
+        {headerName: "选择", headerWidth: 40, dataCode: "select", hAlign: "center", vAlign: "center", cellType: "checkBox"},
+        {headerName: "编码", headerWidth: 80, dataCode: "code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
+        {headerName: "名称", headerWidth: 160, dataCode: "name", dataType: "String", hAlign: "left", vAlign: "center"},
+        {headerName: "规格型号", headerWidth: 160, dataCode: "specs", dataType: "String", hAlign: "left", vAlign: "center"},
+        {headerName: "单位", headerWidth: 40, dataCode: "unit", dataType: "String", hAlign: "center", vAlign: "center"},
+        {headerName: "单价", headerWidth: 55, dataCode: "basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center"},
+        {headerName: "税率", headerWidth: 40, dataCode: "taxRate", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center"},
+        {headerName: "类型", headerWidth: 60, dataCode: "typeName", dataType: "String", hAlign: "center", vAlign: "center"},
+        {headerName: "新增", headerWidth: 40, dataCode: "isComplementary", dataType: "String", hAlign: "center", vAlign: "center", cellType: "checkBox", readOnly: true}
+    ]
+}
+
+// 导入导出接口
+// 需要用固定类别关联的费用字典,用固定类别来映射
+// 数据节选自标准pdf文件《《建设工程政府投资项目造价数据标准》信息公开版》,附录C-费用名称与费用代号
+// 若映射表中没有映射关系,则费用字典取名称首字母
+let FlagFeeCodeMap = {};
+let FormulaFeeCodeMap = {};
+if (typeof commonConstants !== 'undefined') {
+    FlagFeeCodeMap = {
+        // 分部分项工程
+        [commonConstants.fixedFlag.SUB_ENGINERRING]: 'QDF',
+        // 措施项目
+        [commonConstants.fixedFlag.MEASURE]: 'CSF',
+        // 其他项目
+        [commonConstants.fixedFlag.OTHER]: 'QTF',
+        // 措施项目的子项
+        [commonConstants.fixedFlag.GREEN_MEASURE_FEE]: 'AQWMSGF', // 绿色施工安全防护措施费
+        [commonConstants.fixedFlag.OTHER_MEASURE_FEE]: 'QTCSF', // 其他措施费
+        // 其他项目的子项
+        [commonConstants.fixedFlag.PROVISIONAL]: 'ZLF', // 暂列金额
+        [commonConstants.fixedFlag.ESTIMATE]: 'ZGJ', // 暂估价
+        [commonConstants.fixedFlag.MATERIAL_PROVISIONAL]: 'ZGC', // 材料(工程设备)暂估价
+        [commonConstants.fixedFlag.ENGINEERING_ESITIMATE]: 'ZGGC', // 专业工程暂估价
+        [commonConstants.fixedFlag.DAYWORK]: 'LXF', // 计日工
+        [commonConstants.fixedFlag.TURN_KEY_CONTRACT]: 'ZCBFWF', // 总承包服务费
+        [commonConstants.fixedFlag.BUDGET_INCLUDE_WORK_FEE]: 'YSBGF', // 预算包干费
+        [commonConstants.fixedFlag.PROJECT_HIGH_QUALITY_FEE]: 'GCYZF', // 工程优质费
+        [commonConstants.fixedFlag.BUDGET_ESTIMATE_DIFF]: 'GSFDC', // 概算幅度差
+        [commonConstants.fixedFlag.CLAIM_VISA]: 'SPYXCQZ', // 索赔与现场签证
+        [commonConstants.fixedFlag.CLAIM]: 'SPFY', // 索赔费用
+        [commonConstants.fixedFlag.VISA]: 'XCQZFY', // 现场签证
+        [commonConstants.fixedFlag.OTHER_FEE]: 'QTFY', // 其他费用
+        // 税金
+        [commonConstants.fixedFlag.TAX]: 'SJ',
+        // 工程造价
+        [commonConstants.fixedFlag.ENGINEERINGCOST]: 'ZZJ',
+    };
+    // 需要用计算基数关联的费用字典
+    FormulaFeeCodeMap = {
+        '{分部分项工程费}': 'QDF',
+        '{分部分项人工费}': 'QRG',
+        '{分部分项材料费}': 'QCL',
+        '{分部分项施工机具费}': 'QJX',
+        '{分部分项主材费}': 'QZCF',
+        '{分部分项设备费}': 'QSBF',
+        '{分部分项人工工日}': 'FBFXRGGR', // 标准没有,自增
+        '{建筑面积}': 'JZMZ', // 自增
+        '{措施项目费}': 'CSF',
+        '{其他项目费}': 'QTF',
+        '{甲供人工费}': 'JGRGF', // 自增
+        '{甲供材料费}': 'JGC',
+        '{甲供施工机具费}': 'JGSGJJF', // 自增
+        '{甲定人工费}': 'JDRGF', // 自增
+        '{甲定材料费}': 'JDCLF', // 自增
+        '{甲定施工机具费}': 'JDSGJJF', // 自增
+        '{甲定主材费}': 'JDZCF', // 自增
+        '{甲定设备费}': 'JDSBF', // 自增
+        '{暂估材料费(从子目汇总)}': 'ZGCLFCZMHZ', // 自增
+        '{税金}': 'SJ',
+    };
+}

+ 38 - 26
web/over_write/js/guangdong_2018_export.js

@@ -93,7 +93,7 @@ const XMLStandard = (function () {
         '修复': '23',
         '其他': '99',
     };
-    // 需要用固定类别关联的费用字典,用固定类别来映射
+/*     // 需要用固定类别关联的费用字典,用固定类别来映射
     // 数据节选自标准pdf文件《《建设工程政府投资项目造价数据标准》信息公开版》,附录C-费用名称与费用代号
     // 若映射表中没有映射关系,则费用字典取名称首字母
     const FlagFeeCodeMap = {
@@ -123,9 +123,9 @@ const XMLStandard = (function () {
         [fixedFlag.TAX]: 'SJ',
         // 工程造价
         [fixedFlag.ENGINEERINGCOST]: 'ZZJ',
-    };
+    }; */
     // 需要用计算基数关联的费用字典
-    const FormulaFeeCodeMap = {
+/*     const FormulaFeeCodeMap = {
         '{分部分项工程费}': 'QDF',
         '{分部分项人工费}': 'QRG',
         '{分部分项材料费}': 'QCL',
@@ -147,7 +147,7 @@ const XMLStandard = (function () {
         '{暂估材料费(从子目汇总)}': 'ZGCLFCZMHZ', // 自增
         '{税金}': 'SJ',
 
-    };
+    }; */
     // 费用字典占用列表,普通清单根据首字母获取费用字典时,与下列占用费用字典重复时,需要加上_序号后缀
     const feeCodeList = [
         'QDF', 'QRG', 'QCL', 'QJX', 'ZCSB', 'QZCF', 'QSBF', 'QGL', 'QLR', 'QZGJ', 'CSF', 'AQWMSGF', 'AXSJSCSXMF',
@@ -251,10 +251,9 @@ const XMLStandard = (function () {
     };
     // 供料方式
     const Provider = {
-        [supplyType.ZXCG]: '1',
-        [supplyType.BFJG]: '2',
-        [supplyType.WQJG]: '2',
-        [supplyType.WQJG]: '3',
+        [commonConstants.supplyType.ZXCG]: '1',
+        [commonConstants.supplyType.BFJG]: '2',
+        [commonConstants.supplyType.WQJG]: '3',
     }
 
     // 通用设置和工具
@@ -365,6 +364,12 @@ const XMLStandard = (function () {
             //普通基数转费用字典
             normalBase.forEach(base => {
                 const feeCode = getFeeCode(null, base);
+                if (/[\(\)]/.test(base)) {
+                    // 将()进行处理不然会被当成组
+                    base = base.replace(/[\(\)]/g, function(matched) {
+                        return matched === '(' ? '\\(' : '\\)'
+                    });
+                }
                 expr = expr.replace(new RegExp(base, 'g'), feeCode);
             });
             //id引用转换为费用字典
@@ -540,7 +545,7 @@ const XMLStandard = (function () {
                 // 总说明 编制说明
                 {
                     name: 'Explains',
-                    value: projectData.property.compilationIllustrationProject
+                    value: projectData.property.compilationIllustration
                 }
             ];
             //唯一约束
@@ -990,7 +995,7 @@ const XMLStandard = (function () {
                 // 工程编号
                 {
                     name: 'Number',
-                    value: ''
+                    value: _util.getValueByKey(basicInformation, 'projNum')
                 },
                 // 工程名称
                 {
@@ -1005,7 +1010,7 @@ const XMLStandard = (function () {
                 // 建设规模
                 {
                     name: 'Scale', dName: '建设规模', type: _type.DECIMAL, required: true,
-                    value: _util.getValueByKey(basicInformation, 'projectScale')
+                    value: _util.getValueByKey(basicInformation, 'scale')
                 },
                 // 建设规模单位
                 {
@@ -1488,7 +1493,7 @@ const XMLStandard = (function () {
         function ExpressElement(quantityDetail) {
             const attrs = [
                 // 序号
-                { name: 'OrderNumber', dName: '序号', required: true, value: quantityDetail.name },
+                { name: 'OrderNumber', dName: '序号', required: true, value: quantityDetail.seq },
                 // 工程量计算式
                 { name: 'Express', dName: '工程量计算式', required: true, value: quantityDetail.regex },
                 // 工程量
@@ -1510,7 +1515,11 @@ const XMLStandard = (function () {
             _base.Element.call(this, 'WorkContent', attrs, '工序内容');
         }
         // 定额子目
-        function Norm(ration, libCode, kind, specialty) {
+        function Norm(ration, libCode, kind) {
+            // 通过定额库编码,读取编码中间的数字,如房建定额库编码是“GD 1 2018",工程专业取“1”。
+            const reg = /GD (\d+)/;
+            const matched = libCode.match(reg);
+            const specialty = matched && matched[1] || '1';
             const attrs = [
                 // 定额编码
                 { name: 'Number', dName: '定额编码', required: true, value: ration.code },
@@ -1943,9 +1952,11 @@ const XMLStandard = (function () {
                 { name: 'NoTaxOrgPrice', type: _type.DECIMAL, value: price.basePrice },
                 // 除税编制价(市场价)
                 { name: 'NoTaxPrice', type: _type.DECIMAL, value: price.marketPrice },
-                // 含税定额价 不存在这个字段,输出"0"
-                { name: 'TaxOrgPrice', type: _type.DECIMAL, value: '0' },
-                // 含税编制价 暂时取市场价
+                // 含税定额价 含税与不含税是对应项目的计税方式(一般、简易)
+                // 人材机含税和不含税的数据在项目创建时就确定,并且都赋在一个属性上
+                // 因此导出都取项目中的basePriceh额marketPrice就行
+                { name: 'TaxOrgPrice', type: _type.DECIMAL, value: price.basePrice },
+                // 含税编制价 
                 { name: 'TaxPrice', type: _type.DECIMAL, value: price.marketPrice },
                 // 引进部分
                 { name: 'ForeignCurrency', type: _type.DECIMAL, value: '0' },
@@ -2358,8 +2369,9 @@ const XMLStandard = (function () {
                 // 有子清单的是分部
                 if (node.source.children.length) {
                     ele = new DivisionalWorks(node.data);
+                    const summaryCost = new SummaryOfBasicCost(tenderDetail.mainTree.items, node.data);
                     // 递归获取子元素
-                    ele.children = loadFBFX(node.children);
+                    ele.children = [summaryCost, ...loadFBFX(node.children)];
                 } else { // 无子清单的是分项
                     ele = loadBills(node, kind);
                 }
@@ -2383,7 +2395,7 @@ const XMLStandard = (function () {
                 .entries(workMap)
                 .map(([contentText, rationNodes]) => {
                     const workContent = new WorkContent(contentText, _util.getAggregateFee(rationNodes));
-                    workContent.children = rationNodes.map(node => loadRation(node, kind, specialty));
+                    workContent.children = rationNodes.map(node => loadRation(node, kind));
                     return workContent;
                 });
             workElement.children.push(...workContents);
@@ -2392,7 +2404,7 @@ const XMLStandard = (function () {
 
         // 加载工程量计算表
         function loadQuantityExpressions(quantityDetails, isBills, ID) {
-            if (quantityDetails.length) {
+            if (!quantityDetails.length) {
                 return [];
             }
             quantityDetails.sort((a, b) => a.seq - b.seq);
@@ -2408,10 +2420,10 @@ const XMLStandard = (function () {
             return theLib ? theLib.libCode : '';
         }
         // 加载定额
-        function loadRation(node, kind, specialty) {
+        function loadRation(node, kind) {
             // 定额
             const libCode = getLibCode(node.data, tenderDetail.projectInfo.engineeringInfo.ration_lib);
-            const norm = new Norm(node.data, libCode, kind, specialty);
+            const norm = new Norm(node.data, libCode, kind);
             // 工程量计算表
             const expressElement = loadQuantityExpressions(tenderDetail.quantity_detail.datas, false, node.data.ID);
             if (expressElement.length) {
@@ -2426,15 +2438,15 @@ const XMLStandard = (function () {
             let rationGLJs = tenderDetail.ration_glj.datas.filter(rGLJ => rGLJ.rationID === node.data.ID);
             rationGLJs = gljUtil.sortRationGLJ(rationGLJs); // 定额人材机排序
             const rationGLJElements = rationGLJs
-                .filter(rGLJ => {
+                /* .filter(rGLJ => {
                     // 总消耗量为0的,不输出
                     const totalQuantity = gljUtil.getTotalQuantity(rGLJ, node.data, Decimal.GLJ, Decimal.QUANTITY);
                     const parsedTotalQuantity = parseFloat(totalQuantity);
                     return parsedTotalQuantity;
-                })
+                }) */
                 .map(rGLJ => {
-                    const totalQuantity = gljUtil.getTotalQuantity(rGLJ, node.data, Decimal.GLJ, Decimal.QUANTITY);
-                    return new LabourMaterialsEquipmentsMachinesElement(rGLJ, totalQuantity)
+                    //const totalQuantity = gljUtil.getTotalQuantity(rGLJ, node.data, Decimal.GLJ, Decimal.QUANTITY);
+                    return new LabourMaterialsEquipmentsMachinesElement(rGLJ, rGLJ.quantity)
                 });
             norm.children.push(...rationGLJElements);
             // 子目单价计算(定额计算程序)
@@ -2542,7 +2554,7 @@ const XMLStandard = (function () {
                 (node) => new ClaimVisaCostGroup('SiteInstructionCostGroup', node),
                 (node) => new ClaimVisaCostItem('SiteInstructionCostItem', node)
             );
-            sundry.children.push(sundryCosts, provisionalSums, specialtyProvisional, dayworkRate, mainContractorAttendance, claimsCost, siteInstructionCost);
+            sundry.children.push(sundryCosts, provisionalSums, provisionalMaterialEle, specialtyProvisional, dayworkRate, mainContractorAttendance, claimsCost, siteInstructionCost);
             return sundry;
         }
 

File diff suppressed because it is too large
+ 1439 - 13
web/over_write/js/guangdong_2018_import.js