calc_program.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /**
  2. * Created by CSL on 2017-07-19.
  3. * dispExpr: F8*(L-1); expression: "@('8') * (L-1)";
  4. * 说明:F后跟行号,L替换人工系数值,@后跟ID。用到L的规则必须有labourCoeID属性(反过来不要求),
  5. * 用到费率的规则必须有feeRateID属性,当有该属性时,会自动显示费率值。
  6. */
  7. let defaultBillTemplate = {
  8. ID: 15,
  9. name: "清单缺省",
  10. calcItems: [
  11. {
  12. ID: 1,
  13. code: "1",
  14. name: "定额直接费",
  15. dispExpr: "F2+F3+F4",
  16. expression: "@('2')+@('3')+@('4')",
  17. statement: "人工费+材料费+机械费",
  18. feeRate: null,
  19. memo: ''
  20. },
  21. {
  22. ID: 2,
  23. code: "1.1",
  24. name: "人工费",
  25. dispExpr: "HJ",
  26. expression: "HJ",
  27. statement: "合计",
  28. feeRate: 50,
  29. fieldName: 'labour',
  30. memo: ''
  31. },
  32. {
  33. ID: 3,
  34. code: "1.2",
  35. name: "材料费",
  36. dispExpr: "HJ",
  37. expression: "HJ",
  38. statement: "合计",
  39. feeRate: 30,
  40. fieldName: 'material',
  41. memo: ''
  42. },
  43. {
  44. ID: 4,
  45. code: "1.3",
  46. name: "机械费",
  47. dispExpr: "HJ",
  48. expression: "HJ",
  49. statement: "合计",
  50. feeRate: 20,
  51. fieldName: 'machine',
  52. memo: ''
  53. },
  54. {
  55. ID: 5,
  56. code: "2",
  57. name: "企业管理费",
  58. dispExpr: "F1",
  59. expression: "@('1')",
  60. statement: "定额直接费",
  61. feeRate: null,
  62. fieldName: 'manage',
  63. memo: ''
  64. },
  65. {
  66. ID: 6,
  67. code: "3",
  68. name: "利润",
  69. dispExpr: "F1",
  70. expression: "@('1')",
  71. statement: "定额直接费",
  72. feeRate: null,
  73. fieldName: 'profit',
  74. memo: ''
  75. },
  76. {
  77. ID: 7,
  78. code: "4",
  79. name: "风险费用",
  80. dispExpr: "F1",
  81. expression: "@('1')",
  82. statement: "定额直接费",
  83. feeRate: null,
  84. fieldName: 'risk',
  85. memo: ''
  86. },
  87. {
  88. ID: 8,
  89. code: "5",
  90. name: "综合单价",
  91. dispExpr: "F1+F5+F6+F7",
  92. expression: "@('1')+@('5')+@('6')+@('7')",
  93. statement: "定额直接费+企业管理费+利润+风险费用",
  94. feeRate: null,
  95. fieldName: 'common',
  96. memo: ''
  97. }
  98. ]
  99. };
  100. class CalcProgram {
  101. constructor(project){
  102. this.project = project;
  103. this.datas = [];
  104. this.digit = 2;
  105. this.digitDefault = 6;
  106. this.calc = new Calculation();
  107. project.registerModule(ModuleNames.calc_program, this);
  108. };
  109. getSourceType () {
  110. return ModuleNames.calc_program;
  111. };
  112. loadData (datas) {
  113. this.datas = datas;
  114. };
  115. doAfterUpdate (err, data) {
  116. if(!err){
  117. // do
  118. }
  119. };
  120. // 经测试,全部编译一次耗时0.003~0.004秒。耗时基本忽略不计。
  121. compileAllTemps(){
  122. let calcFeeRates = this.project.FeeRate.datas.rates;
  123. let calcLabourCoes = this.project.labourCoe.datas.coes;
  124. let calcTemplates = this.project.calcProgram.datas.templates;
  125. calcTemplates.push(defaultBillTemplate);
  126. this.calc.compilePublics(calcFeeRates, calcLabourCoes, feeType, rationCalcBase);
  127. for (let ct of calcTemplates){
  128. this.calc.compileTemplate(ct);
  129. };
  130. // 存储费率临时数据,报表用。
  131. if (this.calc.saveForReports.length > 0){
  132. let saveDatas = {};
  133. saveDatas.projectID = projectInfoObj.projectInfo.ID;
  134. saveDatas.calcItems = this.calc.saveForReports;
  135. CommonAjax.post('/calcProgram/saveCalcItems', saveDatas, function (data) {
  136. this.calc.saveForReports = [];
  137. });
  138. };
  139. };
  140. calculate(treeNode){
  141. let me = this;
  142. me.calc.calculate(treeNode);
  143. // 存储、刷新本结点、所有父结点
  144. if (treeNode.changed) {
  145. me.saveAndCalcParents(treeNode);
  146. delete treeNode.changed;
  147. };
  148. };
  149. saveAndCalcParents(treeNode) {
  150. if (treeNode.parent) {
  151. projectObj.converseCalculateBills(treeNode.parent);
  152. };
  153. let data = {ID: treeNode.data.ID, projectID: projectObj.project.ID(), fees: treeNode.data.fees};
  154. let newDta = {'updateType': 'ut_update', 'updateData': data};
  155. let newDataArr = [];
  156. newDataArr.push(newDta);
  157. projectObj.project.pushNow('', treeNode.sourceType, newDataArr);
  158. projectObj.mainController.refreshTreeNode([treeNode]);
  159. };
  160. initFees(treeNode){
  161. if (!treeNode.data.fees) {
  162. treeNode.data.fees = [];
  163. treeNode.data.feesIndex = {};
  164. treeNode.changed = true;
  165. };
  166. };
  167. checkFee(treeNode, ftObj){
  168. if (!treeNode.data.feesIndex[ftObj.fieldName]){
  169. let fee = {
  170. 'fieldName': ftObj.fieldName,
  171. 'unitFee': ftObj.unitFee,
  172. 'totalFee': ftObj.totalFee,
  173. 'tenderUnitFee': 0,
  174. 'tenderTotalFee': 0
  175. };
  176. treeNode.data.fees.push(fee);
  177. treeNode.data.feesIndex[ftObj.fieldName] = fee;
  178. treeNode.changed = true;
  179. }
  180. else{
  181. if (treeNode.data.feesIndex[ftObj.fieldName].unitFee != ftObj.unitFee){
  182. treeNode.data.feesIndex[ftObj.fieldName].unitFee = ftObj.unitFee;
  183. treeNode.changed = true;
  184. };
  185. if (treeNode.data.feesIndex[ftObj.fieldName].totalFee != ftObj.totalFee){
  186. treeNode.data.feesIndex[ftObj.fieldName].totalFee = ftObj.totalFee;
  187. treeNode.changed = true;
  188. };
  189. };
  190. };
  191. gatherFeeTypes(treeNode, gatherType){
  192. let me = this;
  193. let rst = [];
  194. if (treeNode.sourceType === this.project.Bills.getSourceType()) {
  195. me.initFees(treeNode);
  196. let objsArr = [];
  197. if (gatherType == CP_GatherType.rations){
  198. objsArr = this.project.Ration.getRationsByNode(treeNode);
  199. }else if (gatherType == CP_GatherType.bills){
  200. objsArr = treeNode.children;
  201. };
  202. for (let ft of feeType) {
  203. let ftObj = {};
  204. ftObj.fieldName = ft.type;
  205. ftObj.name = ft.name;
  206. let uf = 0, tf = 0, tuf = 0, ttf = 0;
  207. for (let item of objsArr) {
  208. let data = {};
  209. if (gatherType == CP_GatherType.rations){
  210. data = item;
  211. }else if (gatherType == CP_GatherType.bills){
  212. data = item.data;
  213. };
  214. if (data.feesIndex && data.feesIndex[ft.type]) {
  215. uf = (uf + parseFloat(data.feesIndex[ft.type].unitFee)).toDecimal(me.digitDefault);
  216. tf = (tf + parseFloat(data.feesIndex[ft.type].totalFee)).toDecimal(me.digitDefault);
  217. tuf = (tuf + parseFloat(data.feesIndex[ft.type].tenderUnitFee)).toDecimal(me.digitDefault);
  218. ttf = (ttf + parseFloat(data.feesIndex[ft.type].tenderTotalFee)).toDecimal(me.digitDefault);
  219. };
  220. };
  221. ftObj.unitFee = uf.toDecimal(me.digit);
  222. ftObj.totalFee = tf.toDecimal(me.digit);
  223. ftObj.tenderUnitFee = tuf.toDecimal(me.digit);
  224. ftObj.tenderTotalFee = ttf.toDecimal(me.digit);
  225. me.checkFee(treeNode, ftObj);
  226. rst.push(ftObj);
  227. };
  228. if (treeNode.changed) {
  229. me.saveAndCalcParents(treeNode);
  230. delete treeNode.changed;
  231. };
  232. };
  233. return rst;
  234. };
  235. calcDefaultBillTemp(treeNode, totalPrice){
  236. let me = this;
  237. let rst = [];
  238. if (treeNode.sourceType != me.project.Bills.getSourceType()){return rst};
  239. treeNode.data.baseTotalPrice = totalPrice;
  240. treeNode.data.programID = defaultBillTemplate.ID;
  241. me.calc.calculate(treeNode);
  242. if (treeNode.changed) {
  243. me.saveAndCalcParents(treeNode);
  244. delete treeNode.changed;
  245. };
  246. rst = treeNode.data.calcTemplate.calcItems;
  247. return rst;
  248. };
  249. getCalcDatas(treeNode){
  250. let me = this;
  251. let rst = [];
  252. let isRation = treeNode.sourceType === me.project.Ration.getSourceType();
  253. let isBill = treeNode.sourceType === me.project.Bills.getSourceType();
  254. let isLeafBill = isBill && treeNode.source.children && treeNode.source.children.length === 0;
  255. let isBillPriceCalc = me.project.projSetting.billsCalcMode === billsPrice;
  256. if (isRation) { // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。
  257. me.calculate(treeNode);
  258. rst = treeNode.data.calcTemplate.calcItems;
  259. }
  260. else if (isLeafBill) {
  261. let ct = '';
  262. if (treeNode.children && treeNode.children.length > 0){
  263. if (treeNode.children[0].sourceType == me.project.Ration.getSourceType()){
  264. ct = childrenType.ration;
  265. }
  266. else if (treeNode.children[0].sourceType == me.project.VolumePrice.getSourceType()){
  267. ct = childrenType.volumePrice;
  268. };
  269. }
  270. else{
  271. ct = childrenType.formula;
  272. };
  273. if (ct == childrenType.ration){
  274. if (isBillPriceCalc){ // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。
  275. me.calculate(treeNode);
  276. rst = treeNode.data.calcTemplate.calcItems;
  277. }else{ // 前三种计算模式下的叶子清单:汇总定额的计算程序的费用类别
  278. rst = me.gatherFeeTypes(treeNode, CP_GatherType.rations);
  279. };
  280. }
  281. else if (ct == childrenType.volumePrice){
  282. let totalPrice = 10000;
  283. rst = me.calcDefaultBillTemp(treeNode, totalPrice);
  284. }
  285. else if (ct == childrenType.formula){
  286. let totalPrice = 20000;
  287. rst = me.calcDefaultBillTemp(treeNode, totalPrice);
  288. };
  289. }
  290. else if (isBill){ // 父清单:汇总子清单的费用类别
  291. rst = me.gatherFeeTypes(treeNode, CP_GatherType.bills);
  292. };
  293. return rst;
  294. }
  295. }