|
@@ -1,5 +1,6 @@
|
|
|
/**
|
|
|
* Created by CSL on 2017-07-19.
|
|
|
+ * 计算程序。所有定额、清单、父清单的计算都从此入。
|
|
|
* dispExpr: F8*(L-1); expression: "@('8') * (L-1)";
|
|
|
* 说明:F后跟行号,L替换人工系数值,@后跟ID。用到L的规则必须有labourCoeID属性(反过来不要求),
|
|
|
* 用到费率的规则必须有feeRateID属性,当有该属性时,会自动显示费率值。
|
|
@@ -7,7 +8,7 @@
|
|
|
|
|
|
let defaultBillTemplate = {
|
|
|
ID: 15,
|
|
|
- name: "清单缺省",
|
|
|
+ name: "清单公式",
|
|
|
calcItems: [
|
|
|
{
|
|
|
ID: 1,
|
|
@@ -99,14 +100,305 @@ let defaultBillTemplate = {
|
|
|
]
|
|
|
};
|
|
|
|
|
|
+const baseCalcType = {baseCalc: 0, adjustCalc: 1, budgetCalc: 2, diffCalc: 3, offerCalc: 4};
|
|
|
+
|
|
|
+let rationCalcBase = [
|
|
|
+ {
|
|
|
+ 'dispName': '定额基价人工费',
|
|
|
+ 'calcType': baseCalcType.baseCalc,
|
|
|
+ 'gljTypes': [gljType.LABOUR]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ 'dispName': '定额基价材料费',
|
|
|
+ 'calcType': baseCalcType.baseCalc,
|
|
|
+ 'gljTypes': [gljType.GENERAL_MATERIAL, gljType.CONCRETE, gljType.MORTAR, gljType.MIX_RATIO, gljType.COMMERCIAL_CONCRETE, gljType.COMMERCIAL_MORTAR]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ 'dispName': '定额基价机械费',
|
|
|
+ 'calcType': baseCalcType.baseCalc,
|
|
|
+ 'gljTypes': [gljType.GENERAL_MACHINE]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ 'dispName': '定额基价机上人工费',
|
|
|
+ 'calcType': baseCalcType.baseCalc,
|
|
|
+ 'gljTypes': [gljType.MACHINE_LABOUR]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ 'dispName': '人工费价差',
|
|
|
+ 'calcType': baseCalcType.diffCalc,
|
|
|
+ 'gljTypes': [gljType.LABOUR]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ 'dispName': '材料费价差',
|
|
|
+ 'calcType': baseCalcType.diffCalc,
|
|
|
+ 'gljTypes': [gljType.GENERAL_MATERIAL, gljType.CONCRETE, gljType.MORTAR, gljType.MIX_RATIO, gljType.COMMERCIAL_CONCRETE, gljType.COMMERCIAL_MORTAR]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ 'dispName': '机械费价差',
|
|
|
+ 'calcType': baseCalcType.diffCalc,
|
|
|
+ 'gljTypes': [gljType.GENERAL_MACHINE]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ 'dispName': '主材费',
|
|
|
+ 'calcType': baseCalcType.budgetCalc,
|
|
|
+ 'gljTypes': [gljType.MAIN_MATERIAL]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ 'dispName': '设备费',
|
|
|
+ 'calcType': baseCalcType.budgetCalc,
|
|
|
+ 'gljTypes': [gljType.EQUIPMENT]
|
|
|
+ }
|
|
|
+];
|
|
|
+
|
|
|
+let analyzer = {
|
|
|
+ calcTemplate: null,
|
|
|
+ success: true,
|
|
|
+
|
|
|
+ standard: function(expr){
|
|
|
+ let str = expr;
|
|
|
+ str = str.replace(/\s/g, ""); // 去空格、去中文空格
|
|
|
+ str = str.replace(/(/g, "("); // 中文括号"("换成英文括号"("
|
|
|
+ str = str.replace(/)/g, ")"); // 中文括号")"换成英文括号")"
|
|
|
+ str = str.replace(/f/g, "F"); // f换成F
|
|
|
+ return str;
|
|
|
+ },
|
|
|
+
|
|
|
+ analyzeCalcBase: function(expr){
|
|
|
+ // 前提:必须无空格、无特殊符号
|
|
|
+ function getCalcBase(expr){
|
|
|
+ let base = '',
|
|
|
+ iPos1 = -1, iPos2 = -1;
|
|
|
+ for (let i = 0; i < expr.length; i++) {
|
|
|
+ if (expr[i] === '['){
|
|
|
+ iPos1 = i;
|
|
|
+ }
|
|
|
+ else if (iPos1 != -1 && expr[i]===']'){
|
|
|
+ iPos2 = i;
|
|
|
+ };
|
|
|
+
|
|
|
+ if (iPos1 != -1 && iPos2 != -1){
|
|
|
+ base = expr.slice(iPos1, iPos2 + 1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ return base;
|
|
|
+ };
|
|
|
+ function calcBaseToIDExpr(base){
|
|
|
+ /*// for test. 公路模式,基数到ID
|
|
|
+ let id = -1;
|
|
|
+ if (base == '[人工费]'){
|
|
|
+ id = 111;
|
|
|
+ }
|
|
|
+ else if (base == '[材料费]'){
|
|
|
+ id = 222;
|
|
|
+ }
|
|
|
+ else if (base == '[机械费]'){
|
|
|
+ id = 333;
|
|
|
+ }
|
|
|
+ else id = "错误";
|
|
|
+
|
|
|
+ return "@('" + id + "')";*/
|
|
|
+ let baseValue = base.slice(1, -1);
|
|
|
+ return "base('" + baseValue + "')";
|
|
|
+ };
|
|
|
+
|
|
|
+ while (expr.indexOf('[') > 0) {
|
|
|
+ let base = getCalcBase(expr);
|
|
|
+ let id = calcBaseToIDExpr(base);
|
|
|
+ let baseValue = base.slice(1, -1); // []会给下面的正则带来干扰,这里去掉
|
|
|
+ var pattBase =new RegExp(baseValue, "g");
|
|
|
+ expr = expr.replace(pattBase, id);
|
|
|
+ expr = expr.replace(/\[base\('/g, "base('"); // [@(' [base('
|
|
|
+ expr = expr.replace(/'\)\]/g, "')"); // ')]
|
|
|
+ };
|
|
|
+
|
|
|
+ return expr;
|
|
|
+ },
|
|
|
+
|
|
|
+ analyzeLineRef: function(expr){
|
|
|
+ let me = this;
|
|
|
+ function isOperator(char){
|
|
|
+ var operator = "+-*/()";
|
|
|
+ return operator.indexOf(char) > -1;
|
|
|
+ };
|
|
|
+ function lineNumToID(lineNum){
|
|
|
+ if (lineNum > me.calcTemplate.calcItems.length){
|
|
|
+ me.success = false;
|
|
|
+ return '越界';
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ let id = me.calcTemplate.calcItems[lineNum - 1].ID;
|
|
|
+ return id;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ // 前提:必须无空格、无特殊符号、标准大写F
|
|
|
+ function getSection(expr){
|
|
|
+ let section = '',
|
|
|
+ iPos1 = -1, iPos2 = -1;
|
|
|
+ for (let i = 0; i < expr.length; i++) {
|
|
|
+ if (expr[i] === 'F'){
|
|
|
+ iPos1 = i;
|
|
|
+ }
|
|
|
+ else if (iPos1 != -1 && isOperator(expr[i])){
|
|
|
+ iPos2 = i;
|
|
|
+ }
|
|
|
+ else if (iPos1 != -1 && i == expr.length - 1){
|
|
|
+ iPos2 = i + 1;
|
|
|
+
|
|
|
+ };
|
|
|
+ if (iPos1 != -1 && iPos2 != -1){
|
|
|
+ section = expr.slice(iPos1, iPos2);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ return section;
|
|
|
+ };
|
|
|
+ function sectionToIDExpr(section){
|
|
|
+ if (section){
|
|
|
+ let lineNum = section.slice(1);
|
|
|
+ if (isNaN(lineNum)){
|
|
|
+ me.success = false;
|
|
|
+ return '错误'; // 这里的返回提示不能加上section,因为会无限循环
|
|
|
+ }
|
|
|
+ else
|
|
|
+ return "@('" + lineNumToID(lineNum) + "')";
|
|
|
+ }
|
|
|
+ else return '';
|
|
|
+ };
|
|
|
+
|
|
|
+ while (expr.indexOf('F') > 0) {
|
|
|
+ let sec = getSection(expr);
|
|
|
+ let id = sectionToIDExpr(sec);
|
|
|
+ var pattSec =new RegExp(sec, "g");
|
|
|
+ expr = expr.replace(pattSec, id);
|
|
|
+ };
|
|
|
+ return expr;
|
|
|
+ },
|
|
|
+
|
|
|
+ analyzeUserExpr: function(calcTemplate, calcItem){
|
|
|
+ let me = this;
|
|
|
+ me.calcTemplate = calcTemplate;
|
|
|
+ let expr = calcItem.dispExpr;
|
|
|
+ // 标准化:处理特殊字符、中文符号、大小写
|
|
|
+ expr = me.standard(expr);
|
|
|
+ calcItem.dispExpr = expr;
|
|
|
+ // 先换掉计算基数
|
|
|
+ expr = me.analyzeCalcBase(expr);
|
|
|
+ // 再换掉行引用
|
|
|
+ expr = me.analyzeLineRef(expr);
|
|
|
+ calcItem.expression = expr;
|
|
|
+ return me.success;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+let executeObj = {
|
|
|
+ treeNode: null,
|
|
|
+ template: null,
|
|
|
+ calcBase: null,
|
|
|
+
|
|
|
+ at: function(ID) {
|
|
|
+ let me = executeObj,
|
|
|
+ rst = 0;
|
|
|
+ rst = me.template.compiledCalcItems[ID].unitFee;
|
|
|
+ rst = parseFloat(rst);
|
|
|
+ return rst;
|
|
|
+ },
|
|
|
+ base: function(calcBaseName) {
|
|
|
+ let me = executeObj, rst = 0,
|
|
|
+ base = me.calcBase[calcBaseName];
|
|
|
+
|
|
|
+ if (base != null) {
|
|
|
+ function isSubset(sub, arr){
|
|
|
+ for(var i = 0, len = sub.length; i < len; i++){
|
|
|
+ if(arr.indexOf(sub[i]) == -1) return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ };
|
|
|
+ // 机上人工费:多一层
|
|
|
+ function machineLabourFee() {
|
|
|
+ if (!me.treeNode.data.gljList) return 0;
|
|
|
+ let result = 0, mdSum = 0;
|
|
|
+ for (let glj of me.treeNode.data.gljList) {
|
|
|
+ if (glj.type == gljType.GENERAL_MACHINE) {
|
|
|
+ // 获取机械组成物
|
|
|
+ let mds = projectObj.project.composition.getCompositionByCode(glj.code);
|
|
|
+ if (!mds) mds = [];
|
|
|
+ for (let md of mds){
|
|
|
+ if (base.gljTypes.indexOf(md.glj_type) >= 0) {
|
|
|
+ let q = md["consumption"] ? md["consumption"] : 0;
|
|
|
+ let p = md["base_price"] ? md["base_price"] : 0;
|
|
|
+ mdSum = mdSum + (q * p).toDecimal(decimalObj.process);
|
|
|
+ mdSum = (mdSum).toDecimal(decimalObj.process);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ result = result + (glj["quantity"] * mdSum).toDecimal(decimalObj.process);
|
|
|
+ result = (result).toDecimal(decimalObj.process);
|
|
|
+ };
|
|
|
+ };
|
|
|
+ return result;
|
|
|
+ };
|
|
|
+ function commonGLJFee(){
|
|
|
+ if (!me.treeNode.data.gljList) return 0;
|
|
|
+ let result = 0;
|
|
|
+ for (let glj of me.treeNode.data.gljList) {
|
|
|
+ let price = 0;
|
|
|
+ if (base.gljTypes.indexOf(glj.type) >= 0) {
|
|
|
+ if (base.calcType == baseCalcType.baseCalc){ price = parseFloat(glj["basePrice"]);}
|
|
|
+ else if (base.calcType == baseCalcType.adjustCalc){price = parseFloat(glj["adjustPrice"]);}
|
|
|
+ else if (base.calcType == baseCalcType.budgetCalc){price = parseFloat(glj["marketPrice"]);}
|
|
|
+ else if (base.calcType == baseCalcType.diffCalc){
|
|
|
+ let aprice = glj["adjustPrice"] ? glj["adjustPrice"] : 0;
|
|
|
+ let mprice = glj["marketPrice"] ? glj["marketPrice"] : 0;
|
|
|
+ price = (parseFloat(mprice) - parseFloat(aprice)).toDecimal(decimalObj.process);
|
|
|
+ };
|
|
|
+ result = result + (glj["quantity"] * price).toDecimal(decimalObj.process);
|
|
|
+ result = (result).toDecimal(decimalObj.process);
|
|
|
+ };
|
|
|
+ };
|
|
|
+ return result;
|
|
|
+ };
|
|
|
+ // 量价没有具体的工料机类型,但仍然要用定额的计算程序,所以要给计算基数直接指定。
|
|
|
+ function volumePriceFee() {
|
|
|
+ let result = 0;
|
|
|
+ if (
|
|
|
+ ( me.treeNode.data.subType === gljType.LABOUR && base.dispName === '定额基价人工费') ||
|
|
|
+ ( me.treeNode.data.subType === gljType.GENERAL_MATERIAL && base.dispName === '定额基价材料费') ||
|
|
|
+ ( me.treeNode.data.subType === gljType.GENERAL_MACHINE && base.dispName === '定额基价机械费') ||
|
|
|
+ ( me.treeNode.data.subType === gljType.MAIN_MATERIAL && base.dispName === '主材费') ||
|
|
|
+ ( me.treeNode.data.subType === gljType.EQUIPMENT && base.dispName === '设备费')
|
|
|
+ ) result = me.treeNode.data.marketUnitFee ? me.treeNode.data.marketUnitFee : 0;
|
|
|
+
|
|
|
+ return result;
|
|
|
+ };
|
|
|
+
|
|
|
+ if (me.treeNode.data.type == rationType.volumePrice || me.treeNode.data.type == rationType.gljRation){
|
|
|
+ rst = volumePriceFee();
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ if (isSubset(base.gljTypes, [gljType.MACHINE_LABOUR]))
|
|
|
+ rst = machineLabourFee()
|
|
|
+ else
|
|
|
+ rst = commonGLJFee();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ return rst;
|
|
|
+ },
|
|
|
+ HJ: function () {
|
|
|
+ let me = this;
|
|
|
+ let p = me.treeNode.data.calcBase ? me.treeNode.data.calcBase : 0;
|
|
|
+ let q = me.treeNode.data.quantity ? me.treeNode.data.quantity : 1;
|
|
|
+ let u = (p / q).toDecimal(decimalObj.decimal('unitPrice', me.treeNode));
|
|
|
+ return u;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
class CalcProgram {
|
|
|
constructor(project){
|
|
|
- this.project = project;
|
|
|
- this.datas = [];
|
|
|
- this.digit = 2;
|
|
|
- this.digitDefault = 6;
|
|
|
- this.calc = new Calculation();
|
|
|
- project.registerModule(ModuleNames.calc_program, this);
|
|
|
+ let me = this;
|
|
|
+ me.project = project;
|
|
|
+ me.datas = [];
|
|
|
+ project.registerModule(ModuleNames.calc_program, me);
|
|
|
};
|
|
|
|
|
|
getSourceType () {
|
|
@@ -125,201 +417,486 @@ class CalcProgram {
|
|
|
|
|
|
// 经测试,全部编译一次耗时0.003~0.004秒。耗时基本忽略不计。
|
|
|
compileAllTemps(){
|
|
|
- let calcFeeRates = this.project.FeeRate.datas.rates;
|
|
|
- let calcLabourCoes = this.project.labourCoe.datas.coes;
|
|
|
- let calcTemplates = this.project.calcProgram.datas.templates;
|
|
|
- calcTemplates.push(defaultBillTemplate);
|
|
|
-
|
|
|
- this.calc.compilePublics(calcFeeRates, calcLabourCoes, feeType, rationCalcBase);
|
|
|
- for (let ct of calcTemplates){
|
|
|
- this.calc.compileTemplate(ct);
|
|
|
+ let me = this;
|
|
|
+ me.compiledFeeRates = {};
|
|
|
+ me.compiledLabourCoes = {};
|
|
|
+ me.compiledTemplates = {};
|
|
|
+ me.compiledTemplateMaps = {};
|
|
|
+ me.compiledTemplateNames = [];
|
|
|
+ me.compiledFeeTypeMaps = {};
|
|
|
+ me.compiledFeeTypeNames = [];
|
|
|
+ me.compiledCalcBases = {};
|
|
|
+ me.saveForReports = [];
|
|
|
+
|
|
|
+ me.feeRates = this.project.FeeRate.datas.rates;
|
|
|
+ me.labourCoes = this.project.labourCoe.datas.coes;
|
|
|
+ me.feeTypes = feeType;
|
|
|
+ me.calcBases = rationCalcBase;
|
|
|
+ me.templates = this.project.calcProgram.datas.templates;
|
|
|
+
|
|
|
+ me.templates.push(defaultBillTemplate);
|
|
|
+ // 先编译公用的基础数据
|
|
|
+ me.compilePublics();
|
|
|
+ for (let t of me.templates){
|
|
|
+ me.compileTemplate(t);
|
|
|
};
|
|
|
|
|
|
// 存储费率临时数据,报表用。
|
|
|
- if (this.calc.saveForReports.length > 0){
|
|
|
+ if (me.saveForReports.length > 0){
|
|
|
let saveDatas = {};
|
|
|
saveDatas.projectID = projectInfoObj.projectInfo.ID;
|
|
|
- saveDatas.calcItems = this.calc.saveForReports;
|
|
|
+ saveDatas.calcItems = me.saveForReports;
|
|
|
CommonAjax.post('/calcProgram/saveCalcItems', saveDatas, function (data) {
|
|
|
- this.calc.saveForReports = [];
|
|
|
+ me.saveForReports = [];
|
|
|
});
|
|
|
};
|
|
|
};
|
|
|
|
|
|
- calculate(treeNode){
|
|
|
+ compilePublics(){
|
|
|
let me = this;
|
|
|
- me.calc.calculate(treeNode);
|
|
|
- // 存储、刷新本结点、所有父结点
|
|
|
- if (treeNode.changed) {
|
|
|
- me.saveAndCalcParents(treeNode);
|
|
|
- delete treeNode.changed;
|
|
|
- };
|
|
|
+ for (let rate of me.feeRates) {
|
|
|
+ me.compiledFeeRates[rate.ID] = rate;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (let coe of me.labourCoes) {
|
|
|
+ me.compiledLabourCoes[coe.ID] = coe;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (let ft of me.feeTypes) {
|
|
|
+ me.compiledFeeTypeMaps[ft.type] = ft.name;
|
|
|
+ me.compiledFeeTypeMaps[ft.name] = ft.type; // 中文预编译,可靠性有待验证
|
|
|
+ me.compiledFeeTypeNames.push(ft.name);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (let cb of me.calcBases) {
|
|
|
+ me.compiledCalcBases[cb.dispName] = cb; // 中文预编译,可靠性有待验证
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
- saveAndCalcParents(treeNode) {
|
|
|
- if (treeNode.parent) {
|
|
|
- projectObj.converseCalculateBills(treeNode.parent);
|
|
|
+ compileTemplate(template){
|
|
|
+ let me = this;
|
|
|
+ me.compiledTemplates[template.ID] = template;
|
|
|
+ me.compiledTemplateMaps[template.ID] = template.name;
|
|
|
+ me.compiledTemplateMaps[template.name] = template.ID;
|
|
|
+ me.compiledTemplateNames.push(template.name);
|
|
|
+ template.hasCompiled = false;
|
|
|
+ template.errs = [];
|
|
|
+
|
|
|
+ let private_extract_ID = function(str, idx){
|
|
|
+ let rst = '', lBracket = 0, rBracket = 0, firstIdx = idx, lastIdx = 0;
|
|
|
+ for (let i = idx; i < str.length; i++) {
|
|
|
+ if (str[i] === '(') {
|
|
|
+ lBracket++;
|
|
|
+ if (lBracket == 1) firstIdx = i + 1;
|
|
|
+ }
|
|
|
+ if (str[i] === ')') {
|
|
|
+ rBracket++;
|
|
|
+ if (lBracket == rBracket) {
|
|
|
+ lastIdx = i - 1;
|
|
|
+ if (lastIdx > firstIdx) {
|
|
|
+ if (str[firstIdx] === "'") firstIdx++;
|
|
|
+ if (str[lastIdx] !== "'") lastIdx++;
|
|
|
+ if (lastIdx > firstIdx) {
|
|
|
+ rst = str.slice(firstIdx, lastIdx);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return rst;
|
|
|
+ };
|
|
|
+ let private_parse_ref = function(item, itemIdx){
|
|
|
+ let idx = item.expression.indexOf('@(', 0);
|
|
|
+ while (idx >= 0) {
|
|
|
+ let ID = private_extract_ID(item.expression, idx);
|
|
|
+ if (ID.length > 0) {
|
|
|
+ let subItem = template.compiledCalcItems[ID];
|
|
|
+ if (subItem) {
|
|
|
+ if (subItem.ID !== item.ID) {
|
|
|
+ private_parse_ref(subItem, template.compiledCalcItems[ID + "_idx"]);
|
|
|
+ } else {
|
|
|
+ template.errs.push("There exists the self refer ID: " + ID);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ template.errs.push("There exists the invalid ID by which could not find the item: " + ID);
|
|
|
+ console.log('invalid ID: ' + ID);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ idx = item.expression.indexOf('@(', idx + ID.length + 3);
|
|
|
+ }
|
|
|
+ if (template.compiledSeq.indexOf(itemIdx) < 0) {
|
|
|
+ template.compiledSeq.push(itemIdx);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ let private_setup_seq = function(item, itemIdx){
|
|
|
+ if (template.compiledSeq.indexOf(itemIdx) < 0) {
|
|
|
+ private_parse_ref(item, itemIdx);
|
|
|
+ }
|
|
|
};
|
|
|
+ let private_compile_items = function() {
|
|
|
+ for (let idx of template.compiledSeq) {
|
|
|
+ let item = template.calcItems[idx];
|
|
|
+ item.dispExprUser = item.dispExpr; // 用于界面显示。disExpr是公式模板,不允许修改:人工系数占位符被修改后变成数值,第二次无法正确替换。
|
|
|
+ if (item.expression == 'HJ')
|
|
|
+ item.compiledExpr = '$CE.HJ()'
|
|
|
+ else{
|
|
|
+ item.compiledExpr = item.expression.split('@(').join('$CE.at(');
|
|
|
+ item.compiledExpr = item.compiledExpr.split('base(').join('$CE.base(');
|
|
|
+ };
|
|
|
|
|
|
- let data = {ID: treeNode.data.ID, projectID: projectObj.project.ID(), fees: treeNode.data.fees};
|
|
|
- let newDta = {'updateType': 'ut_update', 'updateData': data};
|
|
|
- let newDataArr = [];
|
|
|
- newDataArr.push(newDta);
|
|
|
- projectObj.project.pushNow('', treeNode.sourceType, newDataArr);
|
|
|
- projectObj.mainController.refreshTreeNode([treeNode]);
|
|
|
- };
|
|
|
+ if (item.labourCoeID){
|
|
|
+ let lc = me.compiledLabourCoes[item.labourCoeID].coe;
|
|
|
+ item.dispExprUser = item.dispExpr.replace(/L/gi, lc.toString());
|
|
|
+ item.compiledExpr = item.compiledExpr.replace(/L/gi, lc.toString());
|
|
|
+ };
|
|
|
+
|
|
|
+ if (item.feeRateID) {
|
|
|
+ let orgFeeRate = item.feeRate;
|
|
|
+ let cmf = me.compiledFeeRates[item.feeRateID];
|
|
|
+ item.feeRate = cmf?cmf.rate:100;
|
|
|
+
|
|
|
+ if (!orgFeeRate || (orgFeeRate && orgFeeRate != item.feeRate)){
|
|
|
+ me.saveForReports.push({templatesID: template.ID, calcItem: item});
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
- initFees(treeNode){
|
|
|
- if (!treeNode.data.fees) {
|
|
|
- treeNode.data.fees = [];
|
|
|
- treeNode.data.feesIndex = {};
|
|
|
- treeNode.changed = true;
|
|
|
+ // 字段名映射
|
|
|
+ item.displayFieldName = me.compiledFeeTypeMaps[item.fieldName];
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ if (template && template.calcItems && template.calcItems.length > 0) {
|
|
|
+ template.compiledSeq = [];
|
|
|
+ template.compiledCalcItems = {};
|
|
|
+
|
|
|
+ for (let i = 0; i < template.calcItems.length; i++) {
|
|
|
+ let item = template.calcItems[i];
|
|
|
+ template.compiledCalcItems[item.ID] = item;
|
|
|
+ template.compiledCalcItems[item.ID + "_idx"] = i;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (let i = 0; i < template.calcItems.length; i++) {
|
|
|
+ private_setup_seq(template.calcItems[i], i);
|
|
|
+ }
|
|
|
+ if (template.errs.length == 0) {
|
|
|
+ private_compile_items();
|
|
|
+ template.hasCompiled = true;
|
|
|
+ } else {
|
|
|
+ console.log('errors: ' + template.errs.toString());
|
|
|
+ }
|
|
|
};
|
|
|
};
|
|
|
|
|
|
- checkFee(treeNode, ftObj){
|
|
|
- if (!treeNode.data.feesIndex[ftObj.fieldName]){
|
|
|
- let fee = {
|
|
|
- 'fieldName': ftObj.fieldName,
|
|
|
- 'unitFee': ftObj.unitFee,
|
|
|
- 'totalFee': ftObj.totalFee,
|
|
|
- 'tenderUnitFee': 0,
|
|
|
- 'tenderTotalFee': 0
|
|
|
- };
|
|
|
- treeNode.data.fees.push(fee);
|
|
|
- treeNode.data.feesIndex[ftObj.fieldName] = fee;
|
|
|
- treeNode.changed = true;
|
|
|
- }
|
|
|
- else{
|
|
|
- if (treeNode.data.feesIndex[ftObj.fieldName].unitFee != ftObj.unitFee){
|
|
|
- treeNode.data.feesIndex[ftObj.fieldName].unitFee = ftObj.unitFee;
|
|
|
- treeNode.changed = true;
|
|
|
- };
|
|
|
+ isLeafBill(treeNode){
|
|
|
+ let me = this;
|
|
|
+ return treeNode.sourceType === me.project.Bills.getSourceType() &&
|
|
|
+ treeNode.source.children &&
|
|
|
+ treeNode.source.children.length === 0;
|
|
|
+ };
|
|
|
|
|
|
- if (treeNode.data.feesIndex[ftObj.fieldName].totalFee != ftObj.totalFee){
|
|
|
- treeNode.data.feesIndex[ftObj.fieldName].totalFee = ftObj.totalFee;
|
|
|
+ // 仅内部调用。注意:外部不能直接使用,因为这里传入的树节点必须有一定的初始化。
|
|
|
+ InnerCalc(treeNode){
|
|
|
+ let me = this;
|
|
|
+ let project = me.project;
|
|
|
+
|
|
|
+ function initFees(treeNode){
|
|
|
+ if (!treeNode.data.fees) {
|
|
|
+ treeNode.data.fees = [];
|
|
|
+ treeNode.data.feesIndex = {};
|
|
|
treeNode.changed = true;
|
|
|
};
|
|
|
};
|
|
|
- };
|
|
|
|
|
|
- gatherFeeTypes(treeNode, gatherType){
|
|
|
- let me = this;
|
|
|
- let rst = [];
|
|
|
+ function checkFee(treeNode, feeObj){
|
|
|
+ if (feeObj.fieldName == '') return;
|
|
|
|
|
|
- if (treeNode.sourceType === this.project.Bills.getSourceType()) {
|
|
|
- me.initFees(treeNode);
|
|
|
+ if (!treeNode.data.feesIndex[feeObj.fieldName]){
|
|
|
+ let fee = {
|
|
|
+ 'fieldName': feeObj.fieldName,
|
|
|
+ 'unitFee': feeObj.unitFee,
|
|
|
+ 'totalFee': feeObj.totalFee,
|
|
|
+ 'tenderUnitFee': 0,
|
|
|
+ 'tenderTotalFee': 0
|
|
|
+ };
|
|
|
+ treeNode.data.fees.push(fee);
|
|
|
+ treeNode.data.feesIndex[feeObj.fieldName] = fee;
|
|
|
+ treeNode.changed = true;
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ if (treeNode.data.feesIndex[feeObj.fieldName].unitFee != feeObj.unitFee){
|
|
|
+ treeNode.data.feesIndex[feeObj.fieldName].unitFee = feeObj.unitFee;
|
|
|
+ treeNode.changed = true;
|
|
|
+ };
|
|
|
|
|
|
- let objsArr = [];
|
|
|
- if (gatherType == CP_GatherType.rations){
|
|
|
- objsArr = this.project.Ration.getRationsByNode(treeNode);
|
|
|
- }else if (gatherType == CP_GatherType.bills){
|
|
|
- objsArr = treeNode.children;
|
|
|
+ if (treeNode.data.feesIndex[feeObj.fieldName].totalFee != feeObj.totalFee){
|
|
|
+ treeNode.data.feesIndex[feeObj.fieldName].totalFee = feeObj.totalFee;
|
|
|
+ treeNode.changed = true;
|
|
|
+ };
|
|
|
};
|
|
|
+ };
|
|
|
|
|
|
+ function isBaseFeeType(type){
|
|
|
+ return ['labour', 'material', 'machine', 'mainMaterial', 'equipment'].indexOf(type) > -1;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 汇总定额或子清单的费用类别
|
|
|
+ if (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees || treeNode.calcType == treeNodeCalcType.ctGatherBillsFees){
|
|
|
+ treeNode.data.programID = null;
|
|
|
+ initFees(treeNode);
|
|
|
+
|
|
|
+ let objsArr = (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees) ? project.Ration.getRationsByNode(treeNode) : treeNode.children;
|
|
|
+ let rst = [];
|
|
|
for (let ft of feeType) {
|
|
|
let ftObj = {};
|
|
|
ftObj.fieldName = ft.type;
|
|
|
ftObj.name = ft.name;
|
|
|
- let uf = 0, tf = 0, tuf = 0, ttf = 0;
|
|
|
- for (let item of objsArr) {
|
|
|
- let data = {};
|
|
|
- if (gatherType == CP_GatherType.rations){
|
|
|
- data = item;
|
|
|
- }else if (gatherType == CP_GatherType.bills){
|
|
|
- data = item.data;
|
|
|
+ let buf = 0, btf = 0, btuf = 0, bttf = 0;
|
|
|
+
|
|
|
+ if (treeNode.calcType == treeNodeCalcType.ctGatherBillsFees){
|
|
|
+ for (let item of objsArr) {
|
|
|
+ let data = item.data;
|
|
|
+ if (data.feesIndex && data.feesIndex[ft.type]) {
|
|
|
+ buf = (buf + parseFloat(data.feesIndex[ft.type].unitFee)).toDecimal(decimalObj.process);
|
|
|
+ btf = (btf + parseFloat(data.feesIndex[ft.type].totalFee)).toDecimal(decimalObj.process);
|
|
|
+ btuf = (btuf + parseFloat(data.feesIndex[ft.type].tenderUnitFee)).toDecimal(decimalObj.process);
|
|
|
+ bttf = (bttf + parseFloat(data.feesIndex[ft.type].tenderTotalFee)).toDecimal(decimalObj.process);
|
|
|
+ };
|
|
|
+ };
|
|
|
+ }
|
|
|
+ else if (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees){ // 这里的算法要配合冷姐姐的神图才能看懂^_^
|
|
|
+ let sum_rtf = 0, sum_rttf = 0;
|
|
|
+ let bq = parseFloat(treeNode.data.quantity ? treeNode.data.quantity : 1);
|
|
|
+
|
|
|
+ for (let data of objsArr) {
|
|
|
+ let rq = parseFloat(data.quantity ? data.quantity : 0);
|
|
|
+
|
|
|
+ let ruf = 0, rtuf = 0, rtf = 0, rttf = 0;
|
|
|
+ if (data.feesIndex && data.feesIndex[ft.type]) {
|
|
|
+ ruf = parseFloat(data.feesIndex[ft.type].unitFee);
|
|
|
+ rtuf = parseFloat(data.feesIndex[ft.type].tenderUnitFee);
|
|
|
+ rtf = parseFloat(data.feesIndex[ft.type].totalFee);
|
|
|
+ rttf = parseFloat(data.feesIndex[ft.type].tenderTotalFee);
|
|
|
+ };
|
|
|
+
|
|
|
+ if (me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationContent) {
|
|
|
+ buf = (buf + (ruf * rq / bq).toDecimal(decimalObj.process)).toDecimal(decimalObj.process);
|
|
|
+ btuf = (btuf + (rtuf * rq / bq).toDecimal(decimalObj.process)).toDecimal(decimalObj.process);
|
|
|
+ };
|
|
|
+
|
|
|
+ sum_rtf = (sum_rtf + rtf).toDecimal(decimalObj.process);
|
|
|
+ sum_rttf = (sum_rttf + rttf).toDecimal(decimalObj.process);
|
|
|
};
|
|
|
- if (data.feesIndex && data.feesIndex[ft.type]) {
|
|
|
- uf = (uf + parseFloat(data.feesIndex[ft.type].unitFee)).toDecimal(me.digitDefault);
|
|
|
- tf = (tf + parseFloat(data.feesIndex[ft.type].totalFee)).toDecimal(me.digitDefault);
|
|
|
- tuf = (tuf + parseFloat(data.feesIndex[ft.type].tenderUnitFee)).toDecimal(me.digitDefault);
|
|
|
- ttf = (ttf + parseFloat(data.feesIndex[ft.type].tenderTotalFee)).toDecimal(me.digitDefault);
|
|
|
+
|
|
|
+ if (me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationPrice || me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationPriceConverse) {
|
|
|
+ buf = (sum_rtf / bq).toDecimal(decimalObj.process);
|
|
|
+ btuf = (sum_rttf / bq).toDecimal(decimalObj.process);
|
|
|
+ };
|
|
|
+ if (isBaseFeeType(ft.type) || (me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationPriceConverse && ft.type == "common")){
|
|
|
+ btf = sum_rtf;
|
|
|
+ bttf = sum_rttf;
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ btf = (buf * bq).toDecimal(decimalObj.process);
|
|
|
+ bttf = (btuf * bq).toDecimal(decimalObj.process);
|
|
|
};
|
|
|
};
|
|
|
- ftObj.unitFee = uf.toDecimal(me.digit);
|
|
|
- ftObj.totalFee = tf.toDecimal(me.digit);
|
|
|
- ftObj.tenderUnitFee = tuf.toDecimal(me.digit);
|
|
|
- ftObj.tenderTotalFee = ttf.toDecimal(me.digit);
|
|
|
|
|
|
- me.checkFee(treeNode, ftObj);
|
|
|
+ ftObj.unitFee = buf.toDecimal(decimalObj.bills.unitPrice);
|
|
|
+ ftObj.totalFee = btf.toDecimal(decimalObj.bills.totalPrice);
|
|
|
+ ftObj.tenderUnitFee = btuf.toDecimal(decimalObj.bills.unitPrice);
|
|
|
+ ftObj.tenderTotalFee = bttf.toDecimal(decimalObj.bills.totalPrice);
|
|
|
+ checkFee(treeNode, ftObj);
|
|
|
|
|
|
rst.push(ftObj);
|
|
|
};
|
|
|
+ treeNode.data.calcTemplate = {"calcItems": rst};
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ // 叶子清单的公式计算:使用缺省清单计算程序。需要提供总金额作为计算基数(不需要工料机),然后每条按比例(费率)计算,不需要工料机明细。
|
|
|
+ if (treeNode.calcType == treeNodeCalcType.ctCalcBaseValue){
|
|
|
+ delete treeNode.data.gljList;
|
|
|
+
|
|
|
+ if (treeNode.data.programID == undefined){
|
|
|
+ treeNode.data.programID = defaultBillTemplate.ID;
|
|
|
+ };
|
|
|
+ }
|
|
|
+ else if (treeNode.calcType == treeNodeCalcType.ctRationCalcProgram) {
|
|
|
+ if (treeNode.data.type == rationType.volumePrice){
|
|
|
+ delete treeNode.data.gljList;
|
|
|
+ let muf = treeNode.data.marketUnitFee ? treeNode.data.marketUnitFee : 0;
|
|
|
+ let q = treeNode.data.quantity ? treeNode.data.quantity : 0;
|
|
|
+ treeNode.data.marketTotalFee = (muf * q).toDecimal(decimalObj.ration.totalPrice);
|
|
|
+ }
|
|
|
+ else if (treeNode.data.type == rationType.gljRation){
|
|
|
+
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ treeNode.data.gljList = me.project.ration_glj.getGljArrByRation(treeNode.data.ID);
|
|
|
+ };
|
|
|
+
|
|
|
+ if (treeNode.data.programID == undefined){
|
|
|
+ treeNode.data.programID = projectInfoObj.projectInfo.property.engineering;
|
|
|
+ };
|
|
|
+ }
|
|
|
+ else if (treeNode.calcType == treeNodeCalcType.ctBillCalcProgram) {
|
|
|
+ let rations = project.Ration.getBillsSortRation(treeNode.source.getID());
|
|
|
+ treeNode.data.gljList = project.ration_glj.getGatherGljArrByRations(rations);
|
|
|
|
|
|
- if (treeNode.changed) {
|
|
|
- me.saveAndCalcParents(treeNode);
|
|
|
- delete treeNode.changed;
|
|
|
+ if (treeNode.data.programID == undefined || treeNode.data.programID == defaultBillTemplate.ID){
|
|
|
+ treeNode.data.programID = projectInfoObj.projectInfo.property.engineering;
|
|
|
+ }
|
|
|
};
|
|
|
- };
|
|
|
|
|
|
- return rst;
|
|
|
- };
|
|
|
+ let template = me.compiledTemplates[treeNode.data.programID];
|
|
|
+ treeNode.data.calcTemplate = template;
|
|
|
|
|
|
- calcDefaultBillTemp(treeNode, totalPrice){
|
|
|
- let me = this;
|
|
|
- let rst = [];
|
|
|
- if (treeNode.sourceType != me.project.Bills.getSourceType()){return rst};
|
|
|
+ if (treeNode && template.hasCompiled) {
|
|
|
+ let $CE = executeObj;
|
|
|
+ $CE.treeNode = treeNode;
|
|
|
+ $CE.template = template;
|
|
|
+ $CE.calcBase = me.compiledCalcBases;
|
|
|
|
|
|
- treeNode.data.baseTotalPrice = totalPrice;
|
|
|
- treeNode.data.programID = defaultBillTemplate.ID;
|
|
|
- me.calc.calculate(treeNode);
|
|
|
+ initFees(treeNode);
|
|
|
|
|
|
- if (treeNode.changed) {
|
|
|
- me.saveAndCalcParents(treeNode);
|
|
|
- delete treeNode.changed;
|
|
|
- };
|
|
|
+ for (let idx of template.compiledSeq) {
|
|
|
+ let calcItem = template.calcItems[idx];
|
|
|
|
|
|
- rst = treeNode.data.calcTemplate.calcItems;
|
|
|
- return rst;
|
|
|
+ let feeRate = calcItem.feeRate;
|
|
|
+ if (!feeRate) feeRate = 100; // 100%
|
|
|
+ calcItem.unitFee = (eval(calcItem.compiledExpr) * feeRate * 0.01).toDecimal(decimalObj.decimal('unitPrice', treeNode)); // 如果eval()对清单树有影响,就换成小麦的Expression对象再试
|
|
|
+
|
|
|
+ let quantity = treeNode.data.quantity;
|
|
|
+ if (!quantity) quantity = 0;
|
|
|
+ calcItem.totalFee = (calcItem.unitFee * quantity).toDecimal(decimalObj.decimal('totalPrice', treeNode));
|
|
|
+
|
|
|
+ checkFee(treeNode, calcItem);
|
|
|
+ };
|
|
|
+ }
|
|
|
+ };
|
|
|
};
|
|
|
|
|
|
- getCalcDatas(treeNode){
|
|
|
+ // 计算本节点(默认同时递归计算所有父节点,可选)
|
|
|
+ calculate(treeNode, calcParents = true){
|
|
|
let me = this;
|
|
|
- let rst = [];
|
|
|
let isRation = treeNode.sourceType === me.project.Ration.getSourceType();
|
|
|
let isBill = treeNode.sourceType === me.project.Bills.getSourceType();
|
|
|
- let isLeafBill = isBill && treeNode.source.children && treeNode.source.children.length === 0;
|
|
|
- let isBillPriceCalc = me.project.projSetting.billsCalcMode === billsPrice;
|
|
|
+ let isBillPriceCalc = me.project.projSetting.billsCalcMode === leafBillGetFeeType.billsPrice;
|
|
|
+ let isLeafBill = me.isLeafBill(treeNode);
|
|
|
|
|
|
- if (isRation) { // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。
|
|
|
- me.calculate(treeNode);
|
|
|
- rst = treeNode.data.calcTemplate.calcItems;
|
|
|
+ if (isRation){
|
|
|
+ treeNode.calcType = treeNodeCalcType.ctRationCalcProgram;
|
|
|
}
|
|
|
else if (isLeafBill) {
|
|
|
- let ct = '';
|
|
|
if (treeNode.children && treeNode.children.length > 0){
|
|
|
- if (treeNode.children[0].sourceType == me.project.Ration.getSourceType()){
|
|
|
- ct = childrenType.ration;
|
|
|
- }
|
|
|
- else if (treeNode.children[0].sourceType == me.project.VolumePrice.getSourceType()){
|
|
|
- ct = childrenType.volumePrice;
|
|
|
- };
|
|
|
+ // me.calcLeafBillChildren(treeNode);
|
|
|
+
|
|
|
+ if (isBillPriceCalc) // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。(汇总清单所有定额的工料机)
|
|
|
+ treeNode.calcType = treeNodeCalcType.ctBillCalcProgram;
|
|
|
+ else // 前三种计算模式下的叶子清单:汇总定额的计算程序的费用类别
|
|
|
+ treeNode.calcType = treeNodeCalcType.ctGatherRationsFees;
|
|
|
}
|
|
|
- else{
|
|
|
- ct = childrenType.formula;
|
|
|
+ else{ // 公式计算
|
|
|
+ treeNode.calcType = treeNodeCalcType.ctCalcBaseValue;
|
|
|
};
|
|
|
+ }
|
|
|
+ else if (isBill) // 父清单:汇总子清单的费用类别
|
|
|
+ treeNode.calcType = treeNodeCalcType.ctGatherBillsFees;
|
|
|
+
|
|
|
+ me.InnerCalc(treeNode);
|
|
|
+
|
|
|
+ // 计算所有父结点
|
|
|
+ if (treeNode.changed && calcParents && treeNode.parent) {
|
|
|
+ me.calculate(treeNode.parent);
|
|
|
+ };
|
|
|
+ };
|
|
|
+
|
|
|
+ // 存储、刷新本节点(默认存储刷新所有父节点,可选)
|
|
|
+ saveNode(treeNode, saveParents = true) {
|
|
|
+ if (!treeNode.changed) return;
|
|
|
+ let me = this;
|
|
|
+ let nodesArr = [];
|
|
|
+ let curNode = treeNode;
|
|
|
+ while (curNode) {
|
|
|
+ if (curNode.changed){nodesArr.push(curNode)};
|
|
|
+ if (saveParents) curNode = curNode.parent
|
|
|
+ else break;
|
|
|
+ };
|
|
|
+ me.saveNodes(nodesArr);
|
|
|
+ };
|
|
|
|
|
|
- if (ct == childrenType.ration){
|
|
|
- if (isBillPriceCalc){ // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。
|
|
|
- me.calculate(treeNode);
|
|
|
- rst = treeNode.data.calcTemplate.calcItems;
|
|
|
- }else{ // 前三种计算模式下的叶子清单:汇总定额的计算程序的费用类别
|
|
|
- rst = me.gatherFeeTypes(treeNode, CP_GatherType.rations);
|
|
|
+ // 多个树结点入库存储,刷新界面显示。
|
|
|
+ saveNodes(treeNodes){
|
|
|
+ if (treeNodes.length < 1) return;
|
|
|
+
|
|
|
+ let me = this;
|
|
|
+
|
|
|
+ me.project.beginUpdate('');
|
|
|
+ for (let node of treeNodes){
|
|
|
+ if (node.changed){
|
|
|
+ let data = {
|
|
|
+ ID: node.data.ID,
|
|
|
+ projectID: me.project.ID(),
|
|
|
+ subType: node.data.subType,
|
|
|
+ quantity: node.data.quantity,
|
|
|
+ calcBase: node.data.calcBase,
|
|
|
+ programID: node.data.programID,
|
|
|
+ marketUnitFee: node.data.marketUnitFee,
|
|
|
+ marketTotalFee: node.data.marketTotalFee,
|
|
|
+ fees: node.data.fees,
|
|
|
+ isFromDetail:node.data.isFromDetail
|
|
|
};
|
|
|
+ let newData = {'updateType': 'ut_update', 'updateData': data};
|
|
|
+ me.project.push(node.sourceType, [newData]);
|
|
|
}
|
|
|
- else if (ct == childrenType.volumePrice){
|
|
|
- let totalPrice = 10000;
|
|
|
- rst = me.calcDefaultBillTemp(treeNode, totalPrice);
|
|
|
+ };
|
|
|
+ me.project.endUpdate();
|
|
|
+
|
|
|
+ for (let node of treeNodes){delete node.changed};
|
|
|
+ projectObj.mainController.refreshTreeNode(treeNodes);
|
|
|
+
|
|
|
+ if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
|
|
|
+ calcProgramObj.showData(me.project.mainTree.selected, false);
|
|
|
+ };
|
|
|
+ };
|
|
|
+
|
|
|
+/* 计算所有树结点(分3种情况),并将发生计算改动的结点入库存储。
|
|
|
+ 参数取值如下:
|
|
|
+ calcAllType.catAll 计算所有树结点 (不指定参数时的默认值)
|
|
|
+ calcAllType.catBills 计算所有清单 (改变项目属性中清单取费算法时会用到)
|
|
|
+ calcAllType.catRations 计算所有定额、工料机形式的定额、量价,因为它们都走自己的计算程序 (改变人工系数、费率值、工料机单价时会用到) */
|
|
|
+ calcAllNodes(calcType = calcAllType.catAll){
|
|
|
+ let me = this;
|
|
|
+ let needSaveNodes = [];
|
|
|
+
|
|
|
+ function calcNodes(nodes) {
|
|
|
+ for (let node of nodes) {
|
|
|
+ if (node.children.length > 0) {
|
|
|
+ calcNodes(node.children);
|
|
|
+ };
|
|
|
+
|
|
|
+ if ((calcType == calcAllType.catAll) || (calcType == node.sourceType)) {
|
|
|
+ me.calculate(node, false);
|
|
|
+ if (node.changed) needSaveNodes.push(node);
|
|
|
+ };
|
|
|
}
|
|
|
- else if (ct == childrenType.formula){
|
|
|
- let totalPrice = 20000;
|
|
|
- rst = me.calcDefaultBillTemp(treeNode, totalPrice);
|
|
|
- };
|
|
|
- }
|
|
|
- else if (isBill){ // 父清单:汇总子清单的费用类别
|
|
|
- rst = me.gatherFeeTypes(treeNode, CP_GatherType.bills);
|
|
|
};
|
|
|
|
|
|
- return rst;
|
|
|
- }
|
|
|
+ calcNodes(me.project.mainTree.roots);
|
|
|
+ me.saveNodes(needSaveNodes);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 重新计算叶子清单下的所有子结点:如定额、工料机定额等(calculate算法基于定额、工料机定额的计算结果是正确的,实际上有时它们的计算结果并不是最新的)
|
|
|
+ calcLeafBillChildren(treeNode){
|
|
|
+ let me = this;
|
|
|
+ if(!me.isLeafBill(treeNode)) return;
|
|
|
+ if (treeNode.children && treeNode.children.length > 0) {
|
|
|
+ let needSaveNodes = [];
|
|
|
+ for (let child of treeNode.children){
|
|
|
+ me.calculate(child, false);
|
|
|
+ if (child.changed) needSaveNodes.push(child);
|
|
|
+ };
|
|
|
+ me.saveNodes(needSaveNodes);
|
|
|
+ };
|
|
|
+ };
|
|
|
}
|