فهرست منبع

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

TonyKang 4 سال پیش
والد
کامیت
cd3136ab77

+ 1 - 0
config/gulpConfig.js

@@ -91,6 +91,7 @@ module.exports = {
         'public/web/socket/connection.js',
         'public/web/uuid.js',
         'public/web/sheet/sheet_common.js',
+        'public/calculate_util.js',
         'web/building_saas/main/js/models/calc_program.js',
         'web/building_saas/main/js/models/calc_base.js',
         'web/building_saas/main/js/views/calc_program_manage.js',

+ 32 - 0
modules/all_models/std_progressive_lib.js

@@ -0,0 +1,32 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2019/1/25
+ * @version
+ */
+
+/*
+* 累进区间库
+* 设置清单基数中金额区间与费率的对应关系,清单基数累进算法使用
+* */
+
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+
+const progressiveInterval = new Schema({
+    ID: String,
+    name: String,
+    creator: String,
+    createDate: Date,
+    recentOpr: [oprSchema],
+    data: {
+        type: [Schema.Types.Mixed],
+        default: []
+    },
+}, {versionKey: false});
+
+mongoose.model('std_progressive_lib', progressiveInterval, 'std_progressive_lib');

+ 1 - 0
modules/fee_rates/facade/fee_rates_facade.js

@@ -256,6 +256,7 @@ async function changeFeeRateStandard(jdata){
     let newFeeRate = {};
     newFeeRate.ID =uuidV1();
     newFeeRate.rates=template.rates;
+    (newFeeRate.rates || []).forEach(item => item.originalRate = item.rate);
     await feeRateModel.create(newFeeRate);
     let doc={
         libID:data.newLibID,

+ 88 - 13
modules/main/facade/info_price_facade.js

@@ -55,17 +55,29 @@ async function getClassByAreaID(data,compilation){
   let newList = [];
   let lib = await infoLibModel.findOne({compilationID:compilation._id,period:data.period})
   if(lib){
-    let infoClass =  await infoClassModel.find({areaID:data.areaID,libID:lib.ID}).lean();
+    let tList =await getClassList(data.areaID,lib.ID);
+    newList.push(...tList);
+    if(data.commonInfoPriceID){
+      cList = await getClassList(data.commonInfoPriceID,lib.ID);
+      newList.push(...cList);
+    }  
+  }
+  
+
+
+  async function getClassList(areaID,libID){
+    let temList = [];
+    let infoClass =  await infoClassModel.find({areaID:areaID,libID:libID}).lean();
     let parentMap=_.groupBy(infoClass, 'ParentID');
     for(let key in parentMap){
       parentMap[key] = projectfacade.sortChildren(parentMap[key]);
     }
     
     if(parentMap && parentMap['-1']){
-      getChildern(parentMap['-1'],newList,parentMap)
+      getChildern(parentMap['-1'],temList,parentMap)
     }
+    return temList;
   }
-  
 
 
   function getChildern(children,list,pm){
@@ -130,10 +142,68 @@ async function getDataByCode(code, data) {
 
 
 async function getDataByKeyWord(keyword, data) {
+  //先按全字匹配
+  let fullResult =await getDataByFullKeyWord(keyword, data);
+  if(fullResult.totalSize > 0) return fullResult;
+
+  //如果没有才按模糊匹配
+ return await getDataByFuzzyMatch(keyword, data);
+}
+
+
+//按全关键字匹配
+async function getDataByFullKeyWord(keyword, data){
+  data.condition.name = new RegExp(keyword);
+  let items = await infoItemsModel.find(data.condition).lean().sort({"_id":1});
+  delete data.condition.name;
+  return{totalSize:items.length,items}
+}
+
+
+
+function handelThreeWord(word){
+  let arr = [];
+  getArr(word[0]+word[1],arr);
+  getArr(word[1]+word[2],arr);
+  if(arr.length > 0) return arr;
+  return[word];
+
+  function getArr(tem,list){
+    let nameArray = segment.doSegment(tem, {
+      simple: true, //不返回词性
+      stripPunctuation: true //去除标点符号
+    });
+    //说明是一个词
+    if(nameArray.length == 1) list.push(tem)
+  }
+}
+
+//自定义特殊处理
+function cusSegment(nameArray,keyword){
+  let temArr = [];
+  for (let a of nameArray) { 
+     //混凝土 和 砼 统一认成砼
+    if (a == "混凝土") a = '砼';
+    if(a == '砼'||a == '砖' ){
+      temArr.push(a);
+    }else if(a.length > 1){
+      //如果是三个字的词,优先识别成两个字
+      if(a.length == 3){
+        let sArr = handelThreeWord(a);
+        temArr.push(...sArr);
+      }else{
+        temArr.push(a);
+      }
+    }
+  }
+  if (keyword.length == 1 && temArr.length == 0) temArr.push(keyword);
+  return temArr;
+}
+
+//模糊匹配
+async function getDataByFuzzyMatch(keyword, data){
   let items = [];
   let nameArray = [];
-  //混凝土 和 砼 认成一个
- // keyword = keyword.replace(/混凝土/g, "砼");
   if (keyword.length < 3) {
     nameArray.push(keyword)
   } else { 
@@ -142,13 +212,10 @@ async function getDataByKeyWord(keyword, data) {
       stripPunctuation: true //去除标点符号
     });
   }
-  let temArr = [];
-  for (let a of nameArray) { 
-    if (a == "混凝土") a = '砼';
-    if (a == '砼' || a.length > 1) temArr.push(a);
-  }
-  if (keyword.length == 1 && temArr.length == 0) temArr.push(keyword);
-  nameArray = temArr;
+ 
+  //自定义处理
+  nameArray = cusSegment(nameArray,keyword);
+
   console.log(nameArray);
 
   let allInfoPrice = await infoItemsModel.find(data.condition).lean().sort({"_id":1});
@@ -160,6 +227,7 @@ async function getDataByKeyWord(keyword, data) {
     //specs
     let mstring = info.name + info.spec;
     mstring = mstring.replace(/混凝土/g, "砼");
+    info.mstring = mstring;
     let matchCount = 0;
     for (let na of nameArray) { 
       if (mstring.indexOf(na) != -1) { 
@@ -171,9 +239,16 @@ async function getDataByKeyWord(keyword, data) {
       if (matchCount > maxNum) maxNum = matchCount;
     }
   }
-  
   if (maxNum > 0) items = matchMap[maxNum];
   totalSize = items.length
+
+  //按匹配位置排序 如[ '橡胶', '胶圈', '给水' ] 先显示橡胶
+  items = _.sortBy(items,(item)=>{
+    let ms = item.mstring;
+    for(let i = 0;i < nameArray.length;i ++){
+      if (ms.indexOf(nameArray[i]) != -1) return i;
+    }
+  })
   return {totalSize,items}
 }
 

+ 8 - 0
modules/pm/facade/pm_facade.js

@@ -42,6 +42,7 @@ module.exports={
     changeFile:changeFile,
     getBasicInfo: getBasicInfo,
     getProjectFeature: getProjectFeature,
+    getProgressiveInterval: getProgressiveInterval,
     getProjectByGranularity: getProjectByGranularity,
     importProject: importProject,
     getProjectPlaceholder: getProjectPlaceholder,
@@ -92,6 +93,7 @@ let compilationModel = mongoose.model('compilation');
 let engineeringModel = mongoose.model('engineering_lib');
 let basicInfoModel = mongoose.model('std_basic_info_lib');
 let projectFeatureModel = mongoose.model('std_project_feature_lib');
+let progressiveModel = mongoose.model('std_progressive_lib');
 let stdRationItemModel = mongoose.model('std_ration_lib_ration_items');
 let stdGljItemModel = mongoose.model('std_glj_lib_gljList');
 let evaluateListModel = mongoose.model("evaluate_list");
@@ -1582,6 +1584,12 @@ async function getFullPath(projectID) {
     }
 }
 
+//获取累进区间数据
+async function getProgressiveInterval(libID) {
+    let lib = await progressiveModel.findOne({ID: libID});
+    return lib ? lib.data : [];
+}
+
 // 获取项目链上,自身、父项、爷爷项...的ID
 async function getUpChainIDs(projectID) {
     const rst = [];

+ 4 - 0
modules/pm/models/project_model.js

@@ -160,6 +160,10 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     data.updateData.property.decimal = defaultDecimal;
                     //清单工程量精度
                     data.updateData.property.billsQuantityDecimal = billsQuantityDecimal;
+                    // 累进区间
+                    if (data.updateData.property.progressiveLibID) {
+                        data.updateData.property.progressiveInterval = await pmFacade.getProgressiveInterval(data.updateData.property.progressiveLibID);
+                    }
                     //呈现选项
                     data.updateData.property.displaySetting = displaySetting;
 

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

@@ -306,9 +306,7 @@ class LoginController {
             const userinfo2 = await userModel.findDataByAccount(userData.mobile);
             if (userinfo2.isLoginValid === 1) {
                 // 获取本次访问ip
-                let ip = request.connection.remoteAddress;
-                ip = ip.split(':');
-                ip = ip[3] === undefined ? '' : ip[3];
+                let ip = request.headers["x-real-ip"]? request.headers["x-real-ip"]:"";
                 let logModel = new LogModel();
                 let logCount = await logModel.count();
                 logCount = logCount > 30 ? 30 : logCount;

+ 164 - 0
public/calculate_util.js

@@ -0,0 +1,164 @@
+'use strict';
+
+((factory) => {
+    if (typeof module !== 'undefined') {
+        const scMathUtil = require('./scMathUtil').getUtil();
+        const commonConstants = require('./common_constants');
+        module.exports = factory(scMathUtil, commonConstants);
+    } else {
+        window.calculateUtil = factory(scMathUtil, commonConstants);
+    }
+})((scMathUtil, commonConstants) => {
+    function standar(exp) {
+        //去空格
+        exp = exp.replace(/\s/g, '');
+        //( to (
+        exp = exp.replace(/(/g, '(');
+        //)to )
+        exp = exp.replace(/)/g, ')');
+        //,to ,
+        exp = exp.replace(/,/g, ',');
+        //f to F
+        exp = exp.replace(new RegExp('f', 'g'), 'F');
+        return exp;
+    }
+
+    /**
+     * 获取累进办法计算的金额
+     * @param {Number} baseFee - 基准金额
+     * @param {String} name - 使用累进计算的基数名称(需要与累进库中的名称匹配)
+     * @param {Array} progressiveData - 项目的累进数据(property.progressiveInterval)
+     * @param {Number | String} taxType - 项目的计税方式
+     * @param {Number} decimal - 精度
+     * @param {Object} deficiency - 不足处理映射 @example: {'路线工程监理费': 20000 } // 不足2万按2万
+     * @param {Object} beyond - 超出处理映射 @example: {'路线工程监理费': 500000 } // 超过50万按50万
+     * @return {Number}
+     */
+    function getProgressiveFee(baseFee, name, progressiveData, taxType, decimal, deficiency, beyond) {
+        if (!progressiveData) {
+            throw '该项目不存在累进区间数据';
+        }
+        //根据基数名称匹配累进库数据,标准化以免(())等不同导致不匹配
+        const matchProgressiveData = progressiveData.find(item => standar(item.name) === standar(name));
+        if (!matchProgressiveData) {
+            throw `计算基数{${name}}不存在累进区间数据`;
+        }
+        // 将原始数据转换成方便处理的数据:[{feeRate: xx, min: 0, max: 200, minOpr: '(', maxOpr: ']'}]
+        const progression = matchProgressiveData.progression.map(item => {
+            let feeRateField = +taxType === commonConstants.TaxType.NORMAL
+                ? 'generalRate'
+                : +taxType === commonConstants.TaxType.SIMPLE
+                    ? 'simpleRate'
+                    : '';
+            if (!feeRateField) {
+                throw `计算基数{${name}}累进区间费率数据错误`;
+            }
+            // item.interval内容: eg (0,200]、[300,500) [1000,+)....
+            const interval = standar(item.interval);
+            // ( => 大于 [ => 大于等于 ) => 小于 ] => 小于等于
+            const minReg = /([\(\[])(\d+)/;
+            const minMatch = minReg.exec(interval);
+            if (!minMatch || !minMatch[1] || !minMatch[2]) {
+                throw `计算基数{${name}}累进区间数据错误`;
+            }
+            const minOpr = minMatch[1];
+            // 后台数据单位为万元,这里转为为元
+            const min = parseFloat(minMatch[2]) * 10000;
+            const maxReg = /[\,,]([\d\+]+)([\)\]])/;
+            const maxMatch = maxReg.exec(interval);
+            if (!maxMatch || !maxMatch[1] || !maxMatch[2]) {
+                throw `计算基数{${name}}累进区间数据错误`;
+            }
+            const max = maxMatch[1] === '+' ? 'infinity' : parseFloat(maxMatch[1]) * 10000;
+            const maxOpr = maxMatch[2];
+            return {
+                feeRate: item[feeRateField],
+                min,
+                minOpr,
+                max,
+                maxOpr
+            }
+        });
+        progression.sort((a, b) => a.min - b.min);
+        // 基数所在区间
+        const withinData = progression.find(item => {
+            const oprMiddle = item.max === 'infinity' ? '+' : '';
+            const oprLink = item.minOpr + oprMiddle + item.maxOpr;
+            switch (oprLink) {
+                case '()':
+                    return baseFee > item.min && baseFee < item.max;
+                case '(]':
+                    return baseFee > item.min && baseFee <= item.max;
+                case '[)':
+                    return baseFee >= item.min && baseFee < item.max;
+                case '[]':
+                    return baseFee >= item.min && baseFee <= item.max;
+                case '(+)':
+                case '(+]':
+                    return baseFee > item.min;
+                case '[+)':
+                case '[+]':
+                    return baseFee >= item.min;
+                default:
+                    return false;
+            }
+        });
+        if (!withinData) {
+            return 0;
+        }
+        // 累进计算
+        let fee = 0;
+        //累进之前的区间
+        for (let i = 0; i < progression.indexOf(withinData); i++) {
+            const perData = progression[i];
+            fee += (perData.max - perData.min) * perData.feeRate * 0.01;
+        }
+        //累进所在区间
+        fee = scMathUtil.roundForObj(fee + (baseFee - withinData.min) * withinData.feeRate * 0.01, decimal);
+        // 不足、超出处理
+        const deficiencyFee = deficiency && deficiency[name] || 0;
+        const beyondFee = beyond && beyond[name] || 0;
+        return deficiencyFee && fee > 0 && fee < deficiencyFee
+            ? deficiencyFee
+            : beyondFee && fee > beyondFee
+                ? beyondFee
+                : fee;
+    }
+
+    /**
+     * 该基数包含的累进基数
+     * @param {String} calcBase - 计算基数
+     * @param {Array} progression - 累进基数名称数组
+     * @return {Array}
+     */
+    function getProgressive(calcBase, progression) {
+        if (typeof calcBase !== 'string' || !progression) {
+            return [];
+        }
+        const reg = /{[^}]+}/g;
+        const matched = calcBase.match(reg);
+        if (!matched) {
+            return [];
+        }
+        return matched
+            .filter(mStr => progression.some(pStr => `{${pStr}}` === mStr))
+            .map(mStr => mStr.replace(/[{}]/g, ''));
+    }
+
+    /**
+     * 该基数是否含有累进基数
+     * @param {String} calcBase - 计算基数
+     * @param {Array} progression - 累进基数名称数组
+     * @return {Boolean}
+     */
+    function isProgressive(calcBase, progression) {
+        const progressiveBase = getProgressive(calcBase, progression);
+        return !!progressiveBase.length;
+    }
+
+    return {
+        getProgressiveFee,
+        isProgressive,
+        getProgressive,
+    };
+});

+ 3 - 2
web/building_saas/main/html/main.html

@@ -436,7 +436,7 @@
                               </div>
                             </div>
                           </div>
-                          <!-- <div class="p-0" id="ruleDiv" style="width: 10%; float: left;">
+                          <div class="p-0" id="ruleDiv" style="width: 10%; float: left; display: none;">
                             <div class="p-0" id="openTypeSetting">
                               <div class="tn-nav d-flex align-items-start flex-column" data-toggle="tooltip"
                                 data-placement="left" title="" data-original-title="打开排版规则">
@@ -533,7 +533,7 @@
                                 </div>
                               </div>
                             </div>
-                          </div> -->
+                          </div>
                         </div>
                       </div>
                       <div class="main-data-bottom ovf-hidden qdjl" id="qdzy" style="float: left">
@@ -2727,6 +2727,7 @@
   <script type="text/javascript" src="/web/building_saas/main/js/models/ration_template.js"></script>
   <!--<script type="text/javascript" src="/web/building_saas/main/js/models/volume_price.js"></script>-->
   <script type="text/javascript" src="/web/building_saas/main/js/models/labour_coe.js"></script>
+  <script type="text/javascript" src="/public/calculate_util.js"></script>
   <script type="text/javascript" src="/web/building_saas/main/js/models/calc_program.js"></script>
   <script type="text/javascript" src="/web/building_saas/main/js/models/calc_base.js"></script>
   <script type="text/javascript" src="/web/building_saas/main/js/models/installation_fee.js"></script>

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

@@ -517,7 +517,7 @@ let BlockController = {
                 }
                 if(data.children && data.children.length>0){
                     for(let c of data.children){
-                        eachData(c);
+                        eachData(c, selected);
                     }
                 }
             }

+ 42 - 7
web/building_saas/main/js/models/calc_base.js

@@ -554,6 +554,41 @@ let baseFigureTemplate = {
         }
         return projectObj.project.calcProgram.getBeforeTaxTotalFee(excludeNodes, tender);
     },
+    // 市政道路工程安全文明施工费: 按“税前工程造价”为基数,以累进办法计算。
+    SZDLGCAQWMSGF(tender) {
+        const baseFee = this['SQGCZJ'](tender);
+        return calculateUtil.getProgressiveFee(baseFee, '市政道路工程安全文明施工费', projectObj.project.property.progressiveInterval, projectObj.project.property.taxType, decimalObj.bills.totalPrice);
+    },
+    // 市政桥梁工程安全文明施工费: 按“税前工程造价”为基数,以累进办法计算。
+    SZQLGCAQWMSGF(tender) {
+        const baseFee = this['SQGCZJ'](tender);
+        return calculateUtil.getProgressiveFee(baseFee, '市政桥梁工程安全文明施工费', projectObj.project.property.progressiveInterval, projectObj.project.property.taxType, decimalObj.bills.totalPrice);
+    },
+    // 市政隧道工程安全文明施工费: 按“税前工程造价”为基数,以累进办法计算。
+    SZSDGCAQWMSGF(tender) {
+        const baseFee = this['SQGCZJ'](tender);
+        return calculateUtil.getProgressiveFee(baseFee, '市政隧道工程安全文明施工费', projectObj.project.property.progressiveInterval, projectObj.project.property.taxType, decimalObj.bills.totalPrice);
+    },
+    // 城轨盾构工程安全文明施工费: 按“税前工程造价”为基数,以累进办法计算。
+    CGDGGCAQWMSGF(tender) {
+        const baseFee = this['SQGCZJ'](tender);
+        return calculateUtil.getProgressiveFee(baseFee, '城轨盾构工程安全文明施工费', projectObj.project.property.progressiveInterval, projectObj.project.property.taxType, decimalObj.bills.totalPrice);
+    },
+    // 城轨高架桥工程安全文明施工费: 按“税前工程造价”为基数,以累进办法计算。
+    CGGJQGCAQWMSGF(tender) {
+        const baseFee = this['SQGCZJ'](tender);
+        return calculateUtil.getProgressiveFee(baseFee, '城轨高架桥工程安全文明施工费', projectObj.project.property.progressiveInterval, projectObj.project.property.taxType, decimalObj.bills.totalPrice);
+    },
+    // 城轨地下工程安全文明施工费: 按“税前工程造价”为基数,以累进办法计算。
+    CGDXGCAQWMSGF(tender) {
+        const baseFee = this['SQGCZJ'](tender);
+        return calculateUtil.getProgressiveFee(baseFee, '城轨地下工程安全文明施工费', projectObj.project.property.progressiveInterval, projectObj.project.property.taxType, decimalObj.bills.totalPrice);
+    },
+    // 城轨轨道工程安全文明施工费: 按“税前工程造价”为基数,以累进办法计算。
+    CGGDGCAQWMSGF(tender) {
+        const baseFee = this['SQGCZJ'](tender);
+        return calculateUtil.getProgressiveFee(baseFee, '城轨轨道工程安全文明施工费', projectObj.project.property.progressiveInterval, projectObj.project.property.taxType, decimalObj.bills.totalPrice);
+    },
     'RCJJC': function (tender) {//人材机价差
         return (this['RGJC'](tender) + this['CLJC'](tender) + this['JXJC'](tender)).toDecimal(decimalObj.bills.totalPrice);
     },
@@ -997,15 +1032,15 @@ let baseFigureTemplate = {
         return rst;
     }
 };
-
+const progreesiveBases = ['SZDLGCAQWMSGF', 'SZQLGCAQWMSGF', 'SZSDGCAQWMSGF', 'CGDGGCAQWMSGF', 'CGGJQGCAQWMSGF', 'CGDXGCAQWMSGF', 'CGGDGCAQWMSGF'];
 let figureClassTemplate = {
-    'CONSTRUCTION_ORGANIZATION': {flag: fixedFlag.CONSTRUCTION_ORGANIZATION, filter: ['CSXMF', 'ZZCSXMF', 'ZZCSXMDEJJZJGCF', 'ZZCSXMDEJJRGF', 'ZZCSXMDEJJCLF', 'ZZCSXMDEJJJXF', 'QTXMF', 'GF', 'SJ', 'SQGCZJ', 'AQWMSGZXF']},
+    'CONSTRUCTION_ORGANIZATION': {flag: fixedFlag.CONSTRUCTION_ORGANIZATION, filter: ['CSXMF', 'ZZCSXMF', 'ZZCSXMDEJJZJGCF', 'ZZCSXMDEJJRGF', 'ZZCSXMDEJJCLF', 'ZZCSXMDEJJJXF', 'QTXMF', 'GF', 'SJ', 'SQGCZJ', 'AQWMSGZXF', ...progreesiveBases]},
     'SAFETY_CONSTRUCTION': {flag: fixedFlag.SAFETY_CONSTRUCTION, filter: ['CSXMF', 'ZZCSXMF', 'ZZCSXMDEJJZJGCF', 'ZZCSXMDEJJRGF', 'ZZCSXMDEJJCLF', 'ZZCSXMDEJJJXF', 'QTXMF', 'GF', 'SJ', 'AQWMSGZXF']},
-    'OTHER': {flag: fixedFlag.OTHER, filter: ['QTXMF', 'SQGCZJ', 'AQWMSGZXF']},
-    'CHARGE': {flag: fixedFlag.CHARGE, filter: ['GF', 'SQGCZJ', 'AQWMSGZXF']},
-    'TAX': {flag: fixedFlag.TAX, filter: ['SJ', 'SQGCZJ']},
-    'ENGINEERINGCOST': {flag: fixedFlag.ENGINEERINGCOST, filter: ['SQGCZJ']},
-    'OTHERS': {flag: fixedFlag.ENGINEERINGCOST, filter: ['SQGCZJ', 'AQWMSGZXF']},
+    'OTHER': {flag: fixedFlag.OTHER, filter: ['QTXMF', 'SQGCZJ', 'AQWMSGZXF', ...progreesiveBases]},
+    'CHARGE': {flag: fixedFlag.CHARGE, filter: ['GF', 'SQGCZJ', 'AQWMSGZXF', ...progreesiveBases]},
+    'TAX': {flag: fixedFlag.TAX, filter: ['SJ', 'SQGCZJ', ...progreesiveBases]},
+    'ENGINEERINGCOST': {flag: fixedFlag.ENGINEERINGCOST, filter: ['SQGCZJ', ...progreesiveBases]},
+    'OTHERS': {flag: fixedFlag.ENGINEERINGCOST, filter: ['SQGCZJ', 'AQWMSGZXF', ...progreesiveBases]},
 };
 
 //基数的值不是通过清单节点获得的,则该基数的fixedBill为空,如价差、甲供、分包; class:分类,用于基数选择界面分类显示

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

@@ -461,7 +461,9 @@ var PROJECT = {
                             type:c.sourceType,
                             data:{ID:c.data.ID}
                         };
-                        setData(data.data,newval,fieldName);
+                        //有基数计算的子项值清空
+                        let val = fieldName == "lockUnitPrice" && c.data.calcBase && c.data.calcBase != ""?null:newval;
+                        setData(data.data,val,fieldName);
                         datas.push(data);
                         setChildren(c,newValue,datas)
                     }

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

@@ -221,7 +221,8 @@ let projectGljObject = {
     this.initSheet(this.infoClassSheet, this.infoClassSetting);
     this.infoClassSheet.name('infoClassSheet');
     this.infoClassSheet.setRowCount(0);
-    this.infoClassSheet.bind(GC.Spread.Sheets.Events.SelectionChanged, this.infoClassSelectionChange);
+    //this.infoClassSheet.bind(GC.Spread.Sheets.Events.SelectionChanged, this.infoClassSelectionChange);
+    this.infoClassSheet.bind(GC.Spread.Sheets.Events.CellClick,this.infoClassClick);
     if (projectReadOnly) {
       disableSpread(this.infoClassSpread);
     } 
@@ -644,17 +645,27 @@ let projectGljObject = {
   infoPriceSelectionChange:function(sender, args){
     projectGljObject.setInfoClassSelection();
   },
-  infoClassSelectionChange:function(sender, args){
+  infoClassClick:function(sender,args){
     let me = projectGljObject;
-    let row = args.newSelections[0].row;
+    let row = args.row;
     let infoClass = me.infoClassData[row];
     if(infoClass){
+      if( $("#info_class").val() == infoClass.ID) return; // 不用重复查询
       $("#info_class").val(infoClass.ID);
       $("#info_glj_name").val("")//清除工料机名字搜索项
       me.searchInfoPrice();
     }
-
   },
+ /*  infoClassSelectionChange:function(sender, args){
+    let me = projectGljObject;
+    let row = args.newSelections[0].row;
+    let infoClass = me.infoClassData[row];
+    if(infoClass){
+      $("#info_class").val(infoClass.ID);
+      $("#info_glj_name").val("")//清除工料机名字搜索项
+      me.searchInfoPrice();
+    }
+  }, */
   onProjectGljSelectionChange: function (sender, args) {
     let me = projectGljObject;
     let newSel = args.newSelections[0];
@@ -1699,7 +1710,9 @@ let projectGljObject = {
     try {
       if (year != "" && month != "" && areaID != ""){
         let period = year + "-" + month;
-        datas = await ajaxPost("/infoPrice/getClassByAreaID", {areaID:areaID,period:period});
+        let condition = {areaID:areaID,period:period};
+        if (projectGljObject.addCommonInfoPriceID) projectGljObject.addCommonInfoPriceID(condition);
+        datas = await ajaxPost("/infoPrice/getClassByAreaID", condition);
       }
       me.showInforClassData(datas);
     } catch (error) {

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

@@ -933,6 +933,9 @@ var projectObj = {
                 if (typeof overwriteRationCalcBases === 'function')
                     overwriteRationCalcBases(that.project.property.taxType);
                 //that.project.calcProgram.compileAllTemps();
+                if (typeof dynamicLoadCalcBase !== 'undefined') {
+                    dynamicLoadCalcBase();
+                }
                 that.project.calcBase.init(that.project);
                 // that.project.calcFields = JSON.parse(JSON.stringify(cpFeeTypes));
                 // that.project.initCalcFields();

+ 93 - 6
web/building_saas/main/js/views/std_ration_lib.js

@@ -191,6 +191,95 @@ var rationLibObj = {
             SheetDataHelper.loadSheetData(setting, rationLibObj.sectionRationsSpread.getActiveSheet(), datas);
             rationLibObj.setTagForHint(rationSheet, datas);
         };
+        
+        // 去掉第一个空格及空格前面的文本,去掉后面的“(编号:”及之后的文字和字符。取剩余中间的中文及符号
+        function getMidlleName(name) {
+            const codeReg = /[\((]编码[::]/;
+            const withCodeReg = /\s(.+)(?=[\((]编码[::])/;
+            const withoutCodeReg = /\s(.+)/;
+            if (!name) {
+                return name;
+            }
+            let tempName = name;;
+            if (codeReg.test(name)) {
+                const match = withCodeReg.exec(name);
+                if (match && match[1]) {
+                    tempName = match[1];
+                }
+            } else if (withoutCodeReg.test(name)) {
+                const match = withoutCodeReg.exec(name);
+                if (match && match[1]) {
+                    tempName = match[1];
+                }
+            }
+            return tempName.trim();
+        }
+        // 新的处理:
+        /*
+        1、从定额库提取定额名称,判断其是否含有空格:
+        1.1、无空格,则不处理。
+        
+        1.2、有空格,则取第一个空格前的文本,赋值为a。
+        
+        2、取定额所属节点名称,去掉第一个空格及空格前面的文本,去掉后面的“(编号:”及之后的文字和字符,剩余中间的中文及符号,赋值为b。
+        
+        3、比较a、b是否相同:
+        
+        3.1、相同,则将定额名称显示为去除第一个空格及空格之前的文本f。
+        
+        3.2、不同,则取定额所属节点的父项,去掉第一个空格及空格前面的文本,去掉后面的“(编号:”及之后的文字和字符,剩余中间的中文及符号,赋值为c。
+        
+        比较a、c+b是否相同。
+        
+        3.2.1、相同,则将定额名称显示为去除第一个空格及空格之前的文本f。
+        
+        3.2.2、不同,则比较a、c是否相同。
+        
+        3.2.2.1、相同,则将定额名称显示为去除第一个空格及空格之前的文本f。
+        
+        3.2.2.2、不同,则定额名称显示原始名称。*/
+        //@param {String}sectionName(章节节点) {Array}datas(定额数据)
+        function simplifyName(sectionItem, datas) {
+            if (!sectionItem) {
+                return;
+            }
+            const sectionName = sectionItem.data.name;
+            if (!sectionName || !datas || datas.length === 0) {
+                return;
+            }
+            // 定额所属章节节点,章节名称中间值
+            const midSectionName = getMidlleName(sectionName); // (b)
+            //简化匹配到的定额名称
+            const textBeforeFirstSpaceReg = /([^\s]+)\s/;
+            const textAfterFirstSpaceReg = /\s(.+)/;
+            for (let data of datas) {
+                if (!data.name) {
+                    continue;
+                }
+                console.log(data.name);
+                const firstTextMatch = textBeforeFirstSpaceReg.exec(data.name);
+                const textBeforeFirstSpace = firstTextMatch && firstTextMatch[1]; // (a)
+                if (!textBeforeFirstSpace) { // 没有空格直接跳过
+                    continue;
+                }
+                const afterTextMatch = textAfterFirstSpaceReg.exec(data.name);
+                const textAfterFirstSpace = afterTextMatch && afterTextMatch[1]; // (f)
+                // /\s(.+)/
+                if (textBeforeFirstSpace === midSectionName) { // (a === b)
+                    data.name = textAfterFirstSpace;
+                } else {
+                    const parentSectionName = sectionItem.parent && sectionItem.parent.data.name;
+                    if (!parentSectionName) {
+                        continue;
+                    }
+                    const midParentSectionName = getMidlleName(parentSectionName); // (c)
+                    const combinedSectionName = `${midParentSectionName}${midSectionName}`; // (c + b)
+                    if (textBeforeFirstSpace === combinedSectionName || textBeforeFirstSpace === midParentSectionName) { // (a === c + b) || (a === c)
+                        data.name = textAfterFirstSpace;
+                    }
+                }
+            }
+        }
         //定额名称的处理:
         /*
          * 1、从定额库提取的名称,是否含有空格:
@@ -199,8 +288,7 @@ var rationLibObj = {
          * 1.2.1、不同,则不处理。
          * 1.2.2、相同,则将定额名称显示为去除第一个空格及空格之前的文本。
          */
-        //@param {String}sectionName(章节名称) {Array}datas(定额数据)
-        function simplifyName(sectionName, datas){
+        /* function simplifyName(sectionName, datas){
             if (!sectionName || !datas || datas.length === 0) {
                 return;
             }
@@ -233,12 +321,11 @@ var rationLibObj = {
                     data.name = nameArr.join(' ');
                 }
             }
-        }
+        } */
         if (sectionID) {
             CommonAjax.post('/complementaryRation/api/getRationGljItemsBySection', {user_Id: userID, sectionId: sectionID, type: me.curLibType}, function (datas) {
-                let chapterSheet = me.rationChapterSpread.getActiveSheet();
-                let sectionName = chapterSheet.getText(chapterSheet.getActiveRowIndex(), chapterSheet.getActiveColumnIndex());
-                simplifyName(sectionName, datas);
+                const sectionItem = rationLibObj.tree.findNode(sectionID);
+                simplifyName(sectionItem, datas);
                 showDatas(datas, rationLibObj.sectionRationsSetting);
                 if(me.doAfterLoadGetRations){
                     me.doAfterLoadGetRations(datas);

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

@@ -3871,9 +3871,12 @@ function AddTender() {
         // 一个项目里面,这两个文件必须得有,而界面又没有像费率、单价文件那样给出可选项。所以这里给出提示。
         if (!libs.artificial_lib)  throw '编办没有绑定人工系数标准文件';
 
-        let featureLibID = "";
+        let featureLibID = "",
+            progressiveLibID = "";
         if(libs.feature_lib && libs.feature_lib.length > 0) featureLibID = libs.feature_lib[0].id;
-
+        if(libs.progressive_lib && libs.progressive_lib.length > 0) {
+            progressiveLibID = libs.progressive_lib[0].id;
+        }
 
         let calcProgramName = $('#tender-calcProgram').children("option:selected").text();
         $.bootstrapLoading.start();
@@ -3922,6 +3925,7 @@ function AddTender() {
             templateLibID:templateLibID,
             colLibID:colLibID,
             featureLibID:featureLibID,
+            progressiveLibID:progressiveLibID,
             region: region,
             projectFeature: featureData ? featureData : []
         };

+ 44 - 2
web/over_write/js/chongqing_2018.js

@@ -11,9 +11,9 @@ if(typeof projectGljObject !== 'undefined'){
     ];
     $('#menu_index_info').show();
     //2020-11-06 暂时去掉主城区加载通用 
- /*  projectGljObject.addCommonInfoPriceID = function (condition) { 
+  projectGljObject.addCommonInfoPriceID = function (condition) { 
     if(condition.areaID != projectGljObject.commonInfoPriceID) condition.commonInfoPriceID = projectGljObject.commonInfoPriceID;
-  } */
+  }
 }
 if(typeof gljUtil !== 'undefined'){
     gljUtil.hasCompMachine = [301,304];//有组成物的机械
@@ -314,6 +314,48 @@ if(typeof baseFigureMap !== 'undefined'){
             multiRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.MEASURE, fixedFlag.OTHER, fixedFlag.CHARGE]},//相关固定行
     };
 }
+
+function dynamicLoadCalcBase() {
+    // 兼容旧数据,旧单位工程可能不存在累进区间
+    if (projectObj && projectObj.project.property.progressiveInterval) {
+        baseFigureMap['市政道路工程安全文明施工费'] = {
+            base: 'SZDLGCAQWMSGF', class: 'CSXM',
+            cycleCalcRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.OTHER, fixedFlag.CHARGE],   // 以税前工程造价作为累进基数,因此配置沿用{税前工程造价}
+            multiRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.MEASURE, fixedFlag.OTHER, fixedFlag.CHARGE]
+        };
+        baseFigureMap['市政桥梁工程安全文明施工费'] = {
+            base: 'SZQLGCAQWMSGF', class: 'CSXM',
+            cycleCalcRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.OTHER, fixedFlag.CHARGE],   // 以税前工程造价作为累进基数,因此配置沿用{税前工程造价}
+            multiRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.MEASURE, fixedFlag.OTHER, fixedFlag.CHARGE]
+        };
+        baseFigureMap['市政隧道工程安全文明施工费'] = {
+            base: 'SZSDGCAQWMSGF', class: 'CSXM',
+            cycleCalcRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.OTHER, fixedFlag.CHARGE],   // 以税前工程造价作为累进基数,因此配置沿用{税前工程造价}
+            multiRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.MEASURE, fixedFlag.OTHER, fixedFlag.CHARGE]
+        };
+        baseFigureMap['城轨盾构工程安全文明施工费'] = {
+            base: 'CGDGGCAQWMSGF', class: 'CSXM',
+            cycleCalcRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.OTHER, fixedFlag.CHARGE],   // 以税前工程造价作为累进基数,因此配置沿用{税前工程造价}
+            multiRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.MEASURE, fixedFlag.OTHER, fixedFlag.CHARGE]
+        };
+        baseFigureMap['城轨高架桥工程安全文明施工费'] = {
+            base: 'CGGJQGCAQWMSGF', class: 'CSXM',
+            cycleCalcRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.OTHER, fixedFlag.CHARGE],   // 以税前工程造价作为累进基数,因此配置沿用{税前工程造价}
+            multiRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.MEASURE, fixedFlag.OTHER, fixedFlag.CHARGE]
+        };
+        baseFigureMap['城轨地下工程安全文明施工费'] = {
+            base: 'CGDXGCAQWMSGF', class: 'CSXM',
+            cycleCalcRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.OTHER, fixedFlag.CHARGE],   // 以税前工程造价作为累进基数,因此配置沿用{税前工程造价}
+            multiRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.MEASURE, fixedFlag.OTHER, fixedFlag.CHARGE]
+        };
+        baseFigureMap['城轨轨道工程安全文明施工费'] = {
+            base: 'CGGDGCAQWMSGF', class: 'CSXM',
+            cycleCalcRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.OTHER, fixedFlag.CHARGE],   // 以税前工程造价作为累进基数,因此配置沿用{税前工程造价}
+            multiRef: [fixedFlag.SUB_ENGINERRING, fixedFlag.MEASURE, fixedFlag.OTHER, fixedFlag.CHARGE]
+        };
+    }
+}
+
 if(typeof baseFigureTemplate !== 'undefined'){
     baseFigureTemplate['ZZS'] =  function (tender) {//增值税
         let feeField = 'common',