|
@@ -1081,12 +1081,23 @@
|
|
|
return projectObj.project.property.valuationType == 'ration';
|
|
return projectObj.project.property.valuationType == 'ration';
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- getTenderCalcType: function () {
|
|
|
|
|
|
|
+ getTenderTypeStr: function () {
|
|
|
let tenderSetting = projectObj.project.property.tenderSetting;
|
|
let tenderSetting = projectObj.project.property.tenderSetting;
|
|
|
let ct = tenderSetting && tenderSetting.calcPriceOption ? tenderSetting.calcPriceOption : "priceBase_RCJ";
|
|
let ct = tenderSetting && tenderSetting.calcPriceOption ? tenderSetting.calcPriceOption : "priceBase_RCJ";
|
|
|
if (ct == 'priceBase') ct = 'priceBase_RCJ'; // 兼容旧项目
|
|
if (ct == 'priceBase') ct = 'priceBase_RCJ'; // 兼容旧项目
|
|
|
return ct;
|
|
return ct;
|
|
|
},
|
|
},
|
|
|
|
|
+ getTenderType: function () {
|
|
|
|
|
+ let rst;
|
|
|
|
|
+ let sOption = calcTools.getTenderTypeStr();
|
|
|
|
|
+ if (sOption == 'coeBase')
|
|
|
|
|
+ rst = tenderTypes.ttCalc
|
|
|
|
|
+ else if (sOption == 'priceBase_RCJ')
|
|
|
|
|
+ rst = tenderTypes.ttReverseGLJ
|
|
|
|
|
+ else if (sOption == 'priceBase_ZM')
|
|
|
|
|
+ rst = tenderTypes.ttReverseRation;
|
|
|
|
|
+ return rst;
|
|
|
|
|
+ },
|
|
|
getProgramArray: function () {
|
|
getProgramArray: function () {
|
|
|
let array = [];
|
|
let array = [];
|
|
|
for (let p of projectObj.project.calcProgram.datas.templates) {
|
|
for (let p of projectObj.project.calcProgram.datas.templates) {
|
|
@@ -1094,7 +1105,7 @@
|
|
|
}
|
|
}
|
|
|
return array;
|
|
return array;
|
|
|
},
|
|
},
|
|
|
- getCodeForBlock: function(node){
|
|
|
|
|
|
|
+ getCodeForBlock: function(node){
|
|
|
let code = node.data.code;
|
|
let code = node.data.code;
|
|
|
if (calcTools.isBillProject()){
|
|
if (calcTools.isBillProject()){
|
|
|
let tempNode = node;
|
|
let tempNode = node;
|
|
@@ -1105,12 +1116,19 @@
|
|
|
};
|
|
};
|
|
|
return code;
|
|
return code;
|
|
|
},
|
|
},
|
|
|
- getCodeFromBlock: function(block){
|
|
|
|
|
|
|
+ getCodeFromBlock: function(block){
|
|
|
let code = '';
|
|
let code = '';
|
|
|
let i = block.data.nodeName.indexOf(' ');
|
|
let i = block.data.nodeName.indexOf(' ');
|
|
|
if (i != -1) code = block.data.nodeName.slice(0, i);
|
|
if (i != -1) code = block.data.nodeName.slice(0, i);
|
|
|
return code;
|
|
return code;
|
|
|
- }
|
|
|
|
|
|
|
+ },
|
|
|
|
|
+ // 取树结点的调价系数。
|
|
|
|
|
+ getCoe: function (node, tender) {
|
|
|
|
|
+ if (tender == tenderTypes.ttReverseGLJ)
|
|
|
|
|
+ return calcTools.isVP_or_GLJR(node) ? node.data.rationQuantityCoe : (node.data.quantityCoe ? node.data.quantityCoe.labour : 0)
|
|
|
|
|
+ else if (tender == tenderTypes.ttReverseRation)
|
|
|
|
|
+ return node.data.rationQuantityCoe;
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
let rationCalcBases = {
|
|
let rationCalcBases = {
|
|
@@ -2600,7 +2618,7 @@
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// 反向调价逼近
|
|
// 反向调价逼近
|
|
|
- reverseTenderApproach(callback){
|
|
|
|
|
|
|
+ reverseTenderApproach(callback, tender){
|
|
|
let me = this;
|
|
let me = this;
|
|
|
|
|
|
|
|
let G_DIGIT = 0.01; // 系数调整步距(0.1最终结果误差大。0.001目标金额与逼前金额差距大时无法有效逼近)
|
|
let G_DIGIT = 0.01; // 系数调整步距(0.1最终结果误差大。0.001目标金额与逼前金额差距大时无法有效逼近)
|
|
@@ -2609,11 +2627,6 @@
|
|
|
let diffProp = 0.0001; // 计算模式=2(速度优先)时有效。 计算可接受的差值D。差值D = 根结点金额 * diffProp
|
|
let diffProp = 0.0001; // 计算模式=2(速度优先)时有效。 计算可接受的差值D。差值D = 根结点金额 * diffProp
|
|
|
let isTest = true; // 测试
|
|
let isTest = true; // 测试
|
|
|
|
|
|
|
|
- // 取树结点的调价系数。
|
|
|
|
|
- function getCoe(node){
|
|
|
|
|
- return (calcTools.isVP_or_GLJR(node)) ? node.data.rationQuantityCoe : node.data.quantityCoe.labour;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
// 按指定的比例获取可接受的差值:如目标金额的万分之一。
|
|
// 按指定的比例获取可接受的差值:如目标金额的万分之一。
|
|
|
function getPropV(node){
|
|
function getPropV(node){
|
|
|
let v = parseFloat((node.data.targetTotalFee * diffProp).toFixed(0)); // node.data.feesIndex.common.totalFee
|
|
let v = parseFloat((node.data.targetTotalFee * diffProp).toFixed(0)); // node.data.feesIndex.common.totalFee
|
|
@@ -2634,7 +2647,7 @@
|
|
|
// 量价还是要参与,因为它贡献了金额,如果它的金额比重很大,它退出了,会导致其它结点过调。
|
|
// 量价还是要参与,因为它贡献了金额,如果它的金额比重很大,它退出了,会导致其它结点过调。
|
|
|
// if (calcTools.isRationCategory(node) && (!calcTools.isVP_or_GLJR(node))){
|
|
// if (calcTools.isRationCategory(node) && (!calcTools.isVP_or_GLJR(node))){
|
|
|
if (calcTools.isRationCategory(node)){
|
|
if (calcTools.isRationCategory(node)){
|
|
|
- let coe = getCoe(node);
|
|
|
|
|
|
|
+ let coe = calcTools.getCoe(node, tender);
|
|
|
if (coe!= 0) {
|
|
if (coe!= 0) {
|
|
|
let diff = Math.abs(node.data.feesIndex.common.tenderTotalFee - node.data.feesIndex.common.totalFee);
|
|
let diff = Math.abs(node.data.feesIndex.common.tenderTotalFee - node.data.feesIndex.common.totalFee);
|
|
|
node.data.tender_diffValuePerCoe = (diff * G_DIGIT / coe).toDecimal(decimalObj.process);
|
|
node.data.tender_diffValuePerCoe = (diff * G_DIGIT / coe).toDecimal(decimalObj.process);
|
|
@@ -2683,22 +2696,29 @@
|
|
|
return {type: 2, node: undefined, nodeIdx: -1}; // arr 被清空了
|
|
return {type: 2, node: undefined, nodeIdx: -1}; // arr 被清空了
|
|
|
|
|
|
|
|
let d = (v > 0) ? -G_DIGIT : G_DIGIT;
|
|
let d = (v > 0) ? -G_DIGIT : G_DIGIT;
|
|
|
- let coe = getCoe(closeNode);
|
|
|
|
|
|
|
+ let coe = calcTools.getCoe(closeNode, tender);
|
|
|
if ((coe + d) < 0)
|
|
if ((coe + d) < 0)
|
|
|
return {type: 3, node: obj.node, nodeIdx: obj.idx}; // 再调的话,系数就变负数了,过调
|
|
return {type: 3, node: obj.node, nodeIdx: obj.idx}; // 再调的话,系数就变负数了,过调
|
|
|
|
|
|
|
|
- if (calcTools.isVP_or_GLJR(closeNode)){
|
|
|
|
|
|
|
+ if (tender == tenderTypes.ttReverseRation){
|
|
|
closeNode.data.tender_previousCoe = closeNode.data.rationQuantityCoe; // tender_previousCoe: 上一次的调整系数,用于撤回
|
|
closeNode.data.tender_previousCoe = closeNode.data.rationQuantityCoe; // tender_previousCoe: 上一次的调整系数,用于撤回
|
|
|
closeNode.data.rationQuantityCoe = (closeNode.data.rationQuantityCoe + d).toDecimal(decimalObj.process);
|
|
closeNode.data.rationQuantityCoe = (closeNode.data.rationQuantityCoe + d).toDecimal(decimalObj.process);
|
|
|
}
|
|
}
|
|
|
- else {
|
|
|
|
|
- closeNode.data.tender_previousCoe = closeNode.data.quantityCoe.labour;
|
|
|
|
|
- closeNode.data.quantityCoe.labour = (closeNode.data.quantityCoe.labour + d).toDecimal(decimalObj.process)
|
|
|
|
|
- closeNode.data.quantityCoe.material = (closeNode.data.quantityCoe.material + d).toDecimal(decimalObj.process)
|
|
|
|
|
- closeNode.data.quantityCoe.machine = (closeNode.data.quantityCoe.machine + d).toDecimal(decimalObj.process)
|
|
|
|
|
- closeNode.data.quantityCoe.main = (closeNode.data.quantityCoe.main + d).toDecimal(decimalObj.process)
|
|
|
|
|
- closeNode.data.quantityCoe.equipment = (closeNode.data.quantityCoe.equipment + d).toDecimal(decimalObj.process)
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ else if (tender == tenderTypes.ttReverseGLJ){
|
|
|
|
|
+ if (calcTools.isVP_or_GLJR(closeNode)){
|
|
|
|
|
+ closeNode.data.tender_previousCoe = closeNode.data.rationQuantityCoe;
|
|
|
|
|
+ closeNode.data.rationQuantityCoe = (closeNode.data.rationQuantityCoe + d).toDecimal(decimalObj.process);
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ closeNode.data.tender_previousCoe = closeNode.data.quantityCoe.labour;
|
|
|
|
|
+ closeNode.data.quantityCoe.labour = (closeNode.data.quantityCoe.labour + d).toDecimal(decimalObj.process)
|
|
|
|
|
+ closeNode.data.quantityCoe.material = (closeNode.data.quantityCoe.material + d).toDecimal(decimalObj.process)
|
|
|
|
|
+ closeNode.data.quantityCoe.machine = (closeNode.data.quantityCoe.machine + d).toDecimal(decimalObj.process)
|
|
|
|
|
+ closeNode.data.quantityCoe.main = (closeNode.data.quantityCoe.main + d).toDecimal(decimalObj.process)
|
|
|
|
|
+ closeNode.data.quantityCoe.equipment = (closeNode.data.quantityCoe.equipment + d).toDecimal(decimalObj.process)
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
me.calculate(closeNode, true, true, tenderTypes.ttCalc);
|
|
me.calculate(closeNode, true, true, tenderTypes.ttCalc);
|
|
|
return {type: 1, node: obj.node, nodeIdx: obj.idx};
|
|
return {type: 1, node: obj.node, nodeIdx: obj.idx};
|
|
|
}
|
|
}
|
|
@@ -2707,17 +2727,22 @@
|
|
|
function undoLastApproach(obj){
|
|
function undoLastApproach(obj){
|
|
|
let closeNode = obj.node;
|
|
let closeNode = obj.node;
|
|
|
let coe = closeNode.data.tender_previousCoe;
|
|
let coe = closeNode.data.tender_previousCoe;
|
|
|
- if (calcTools.isVP_or_GLJR(closeNode)){
|
|
|
|
|
|
|
+ if (tender == tenderTypes.ttReverseRation){
|
|
|
closeNode.data.rationQuantityCoe = coe
|
|
closeNode.data.rationQuantityCoe = coe
|
|
|
|
|
+ } else if (tender == tenderTypes.ttReverseGLJ){
|
|
|
|
|
+ if (calcTools.isVP_or_GLJR(closeNode)){
|
|
|
|
|
+ closeNode.data.rationQuantityCoe = coe
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ closeNode.data.quantityCoe.labour = coe
|
|
|
|
|
+ closeNode.data.quantityCoe.material = coe
|
|
|
|
|
+ closeNode.data.quantityCoe.machine = coe
|
|
|
|
|
+ closeNode.data.quantityCoe.main = coe
|
|
|
|
|
+ closeNode.data.quantityCoe.equipment = coe
|
|
|
|
|
+ };
|
|
|
}
|
|
}
|
|
|
- else {
|
|
|
|
|
- closeNode.data.quantityCoe.labour = coe
|
|
|
|
|
- closeNode.data.quantityCoe.material = coe
|
|
|
|
|
- closeNode.data.quantityCoe.machine = coe
|
|
|
|
|
- closeNode.data.quantityCoe.main = coe
|
|
|
|
|
- closeNode.data.quantityCoe.equipment = coe
|
|
|
|
|
- };
|
|
|
|
|
- me.calculate(closeNode);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ me.calculate(closeNode, true, true, tenderTypes.ttCalc);
|
|
|
if (isTest) {
|
|
if (isTest) {
|
|
|
let _sp = ` `; // 保留空格,打印对齐
|
|
let _sp = ` `; // 保留空格,打印对齐
|
|
|
let _node = `[行${obj.node.data.tender_rowNo} 索引${obj.nodeIdx}]`;
|
|
let _node = `[行${obj.node.data.tender_rowNo} 索引${obj.nodeIdx}]`;
|
|
@@ -2726,23 +2751,24 @@
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
let root = tender_obj.tenderTree.roots[0];
|
|
let root = tender_obj.tenderTree.roots[0];
|
|
|
- let vArr = getNodeDiffs();
|
|
|
|
|
let propV = getPropV(root);
|
|
let propV = getPropV(root);
|
|
|
|
|
+ let vArr = getNodeDiffs();
|
|
|
let d1 = getRootDiff();
|
|
let d1 = getRootDiff();
|
|
|
|
|
|
|
|
if (isTest){
|
|
if (isTest){
|
|
|
- let tq = root.data.feesIndex.common.totalFee;
|
|
|
|
|
- let mb = root.data.targetTotalFee;
|
|
|
|
|
- let bbj = root.data.feesIndex.common.tenderTotalFee;
|
|
|
|
|
- let ms = (calcModel == 2) ? `速度优先(0~${propV})` : "精度优先";
|
|
|
|
|
- console.log(`调前${tq}|目标${mb}|调后无逼近${bbj}|差值${d1}|${ms}`);
|
|
|
|
|
|
|
+ let _tq = `调前${root.data.feesIndex.common.totalFee}`;
|
|
|
|
|
+ let _mb = `目标${root.data.targetTotalFee}`;
|
|
|
|
|
+ let _wbj = `调后无逼近${root.data.feesIndex.common.tenderTotalFee}`;
|
|
|
|
|
+ let _cz = `差值${d1}`;
|
|
|
|
|
+ let _js = `轮${times} 系数步距${G_DIGIT}`;
|
|
|
|
|
+ let _yx = (calcModel == 2) ? `速度优先(差比${diffProp} 差域0~${propV})` : "精度优先";
|
|
|
|
|
+ console.log(`${_tq}|${_mb}|${_wbj}|${_cz}|${_yx}|${_js}`);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 多轮逼进
|
|
// 多轮逼进
|
|
|
for (let i = 1; i <= times; i++) {
|
|
for (let i = 1; i <= times; i++) {
|
|
|
// 与目标金额差值在1以内,整数部分已相同,结果很棒。很多时候能达到完美的差值0,但不能用0判断,因为金额取小数时有问题。
|
|
// 与目标金额差值在1以内,整数部分已相同,结果很棒。很多时候能达到完美的差值0,但不能用0判断,因为金额取小数时有问题。
|
|
|
if (Math.abs(d1) < 1) break;
|
|
if (Math.abs(d1) < 1) break;
|
|
|
-
|
|
|
|
|
// 速度优先模式下,结果到达差值范围内,即熔断逼近。
|
|
// 速度优先模式下,结果到达差值范围内,即熔断逼近。
|
|
|
if (calcModel == 2){
|
|
if (calcModel == 2){
|
|
|
if (Math.abs(d1) < propV) break;
|
|
if (Math.abs(d1) < propV) break;
|
|
@@ -2758,13 +2784,14 @@
|
|
|
let d2 = getRootDiff();
|
|
let d2 = getRootDiff();
|
|
|
|
|
|
|
|
if (isTest){
|
|
if (isTest){
|
|
|
|
|
+ let _time = `【第 ${i} 轮】调整`;
|
|
|
let _node = `[行${obj.node.data.tender_rowNo} 索引${obj.nodeIdx}]`;
|
|
let _node = `[行${obj.node.data.tender_rowNo} 索引${obj.nodeIdx}]`;
|
|
|
- let _coe = `${obj.node.data.tender_previousCoe} → ${getCoe(obj.node)}`;
|
|
|
|
|
|
|
+ let _coe = `${obj.node.data.tender_previousCoe} → ${calcTools.getCoe(obj.node, tender)}`;
|
|
|
let _d = `差值${d1} → ${d2}`;
|
|
let _d = `差值${d1} → ${d2}`;
|
|
|
- console.log(`【第 ${i} 轮】调整${_node} ${_coe},${_d}`);
|
|
|
|
|
|
|
+ console.log(`${_time}${_node} ${_coe},${_d}`);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (Math.abs(d2) > Math.abs(d1)){ // 逼近后差距反而变大,证明过调,回退一步
|
|
|
|
|
|
|
+ if (Math.abs(d2) > Math.abs(d1)){ // 逼近后差值反而变大,证明此轮调节不合适,回退一步,并将结点从列表清除
|
|
|
undoLastApproach(obj);
|
|
undoLastApproach(obj);
|
|
|
vArr.splice(obj.nodeIdx, 1);
|
|
vArr.splice(obj.nodeIdx, 1);
|
|
|
}
|
|
}
|
|
@@ -2774,8 +2801,10 @@
|
|
|
else {d1 = d2}
|
|
else {d1 = d2}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- // 系数已处理就绪,直接正算即可。
|
|
|
|
|
- this.calcAllNodesAndSave(calcAllType.catAll, callback, tenderTypes.ttCalc);
|
|
|
|
|
|
|
+ // 重要注释:到这里,所有系数已处理就绪,最后直接全局正算即可。
|
|
|
|
|
+ // 到这一步,被处理的定额、及其受影响的父结点、引用结点等均已正算完成(approach方法、undoLastApproach方法),但都未保存。
|
|
|
|
|
+ // 最后全局正算目的:⑴计算除第一部以外的其它部分 ⑵保存。正算在调用外面完成。
|
|
|
|
|
+ // this.calcAllNodesAndSave(calcAllType.catAll, callback, tenderTypes.ttCalc);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
setRationMap() {
|
|
setRationMap() {
|
|
@@ -2814,31 +2843,29 @@
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
doTenderCalc(callback) {
|
|
doTenderCalc(callback) {
|
|
|
|
|
+
|
|
|
$.bootstrapLoading.start();
|
|
$.bootstrapLoading.start();
|
|
|
- let sOption = calcTools.getTenderCalcType();
|
|
|
|
|
- let tender;
|
|
|
|
|
- if (sOption == 'coeBase')
|
|
|
|
|
- tender = tenderTypes.ttCalc
|
|
|
|
|
- else if (sOption == 'priceBase_RCJ')
|
|
|
|
|
- tender = tenderTypes.ttReverseGLJ
|
|
|
|
|
- else if (sOption == 'priceBase_ZM')
|
|
|
|
|
- tender = tenderTypes.ttReverseRation;
|
|
|
|
|
- if (tender == tenderTypes.ttReverseGLJ || tender == tenderTypes.ttReverseRation) {
|
|
|
|
|
- if (!tender_obj.tenderTree){
|
|
|
|
|
- tender_obj.createTree();
|
|
|
|
|
- tender_obj.createTreeNodes();
|
|
|
|
|
|
|
+ setTimeout(()=>{
|
|
|
|
|
+ let tender = calcTools.getTenderType();
|
|
|
|
|
+ if (tender == tenderTypes.ttReverseGLJ || tender == tenderTypes.ttReverseRation) {
|
|
|
|
|
+ // 调价计算必须依赖调价树。
|
|
|
|
|
+ if (!tender_obj.tenderTree){
|
|
|
|
|
+ tender_obj.createTree();
|
|
|
|
|
+ tender_obj.createTreeNodes();
|
|
|
|
|
+ }
|
|
|
|
|
+ // 反向调价+逼近原理:
|
|
|
|
|
+ // 清理调价缓存 → 分摊目标金额(从子往父处理满载、从父往子分摊) → 全局反算 → 逼近 → 全局正算、存储
|
|
|
|
|
+ this.reverseTenderInitDatas();
|
|
|
|
|
+ this.prepareForDistribute(tender_obj.tenderTree.roots[0]);
|
|
|
|
|
+ this.distributeTargetTotalFee(tender_obj.tenderTree.roots[0]);
|
|
|
|
|
+ this.calcAllNodes(calcAllType.catAll, tender); // 先全局反算:得到每定额的coe、基础调后金额(误差大,需逼近)
|
|
|
|
|
+ this.reverseTenderApproach(callback, tender); // 逼近上述基础调后金额
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 反向调价原理:清理调价缓存 → 从子往父汇总(处理满载) → 从父往子分摊目标金额 → 反向计算调整系数(再由系数计算调后金额)等 → 调后金额逼近(挑结点,改系数,改完正算) → 全局正算、存储
|
|
|
|
|
- this.reverseTenderInitDatas();
|
|
|
|
|
- this.prepareForDistribute(tender_obj.tenderTree.roots[0]);
|
|
|
|
|
- this.distributeTargetTotalFee(tender_obj.tenderTree.roots[0]);
|
|
|
|
|
- this.calcAllNodes(calcAllType.catAll, tender); // 先来个反算(计算coe),得到基本的调后值(此值误差大,需要逼近)
|
|
|
|
|
- this.reverseTenderApproach(callback); // 逼近上述调后值
|
|
|
|
|
- }
|
|
|
|
|
- else{
|
|
|
|
|
- this.calcAllNodesAndSave(calcAllType.catAll, callback, tender);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 全局正算(用的是主树,无需调价树)
|
|
|
|
|
+ this.calcAllNodesAndSave(calcAllType.catAll, callback, tenderTypes.ttCalc);
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
};
|
|
};
|
|
|
};
|
|
};
|
|
|
|
|
|