phase_pay_detail.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Mai
  6. * @date
  7. * @version
  8. */
  9. const payType = {
  10. bqsf: 'bqsf', bqyf: 'bqyf', gcjl: 'gcjl', qtfk: 'qtfk', qtkk: 'qtkk'
  11. };
  12. const defaultPays = [
  13. { tree_id: 1, tree_pid: -1, tree_level: 1, tree_order: 1, tree_is_leaf: 1, tree_full_path: '1', pay_type: 'bqyf', is_minus: 0, is_fixed: 1, name: '本期应付', expr: '' },
  14. { tree_id: 2, tree_pid: -1, tree_level: 1, tree_order: 2, tree_is_leaf: 1, tree_full_path: '2', pay_type: 'bqsf', is_minus: 0, is_fixed: 1, name: '本期实付', expr: '' },
  15. { tree_id: 3, tree_pid: -1, tree_level: 1, tree_order: 3, tree_is_leaf: 0, tree_full_path: '3', pay_type: 'gcjl', is_minus: 0, is_fixed: 1, name: '工程计量款', expr: '' },
  16. { tree_id: 4, tree_pid: -1, tree_level: 1, tree_order: 4, tree_is_leaf: 0, tree_full_path: '4', pay_type: 'qtfk', is_minus: 0, is_fixed: 1, name: '其他付款项', expr: '' },
  17. { tree_id: 5, tree_pid: -1, tree_level: 1, tree_order: 5, tree_is_leaf: 0, tree_full_path: '5', pay_type: 'qtkk', is_minus: 1, is_fixed: 1, name: '其他扣款项', expr: '' },
  18. { tree_id: 6, tree_pid: 3, tree_level: 2, tree_order: 1, tree_is_leaf: 1, tree_full_path: '3-6', pay_type: '', is_minus: 0, is_fixed: 0, name: '本期完成计量', expr: 'bqwc' },
  19. { tree_id: 7, tree_pid: 4, tree_level: 2, tree_order: 1, tree_is_leaf: 1, tree_full_path: '4-7', pay_type: '', is_minus: 0, is_fixed: 0, name: '新增付款项', expr: '' },
  20. { tree_id: 8, tree_pid: 5, tree_level: 2, tree_order: 1, tree_is_leaf: 1, tree_full_path: '5-8', pay_type: '', is_minus: 1, is_fixed: 0, name: '新增扣款项', expr: '' },
  21. ];
  22. const TreeService = require('../base/base_tree_service');
  23. const Ledger = require('../lib/ledger');
  24. const deadlineType = {
  25. phaseCount: { key: 'phaseCount', type: '计量期数', name: '合同支付期数' },
  26. stageCount: { key: 'stageCount', type: '计量期数', name: '计量期数' },
  27. gather: { key: 'gather', type: '计量金额', name: '累计完成金额' },
  28. contract: { key: 'contract', type: '计量金额', name: '累计合同金额' },
  29. qc: { key: 'qc', type: '计量金额', name: '累计变更金额' },
  30. };
  31. const math = require('mathjs');
  32. math.config({
  33. number: 'BigNumber',
  34. });
  35. const validField = ['name', 'is_pause', 'is_gather', 'start_tp', 'start_expr', 'range_tp', 'range_expr', 'tp', 'expr', 'postil', 'dl_type', 'dl_value'];
  36. const infoField = ['name', 'postil'];
  37. const calcField = validField.filter(x => { return infoField.indexOf(x) < 0; });
  38. class PayCalculator {
  39. constructor (ctx, phasePay) {
  40. this.ctx = ctx;
  41. this.phasePay = phasePay;
  42. this.percentReg = /((\d+)|((\d+)(\.\d+)))%/g;
  43. this.tenderInfo = ctx.tender.info;
  44. this.decimal = this.tenderInfo.decimal.pay ? this.tenderInfo.decimal.payTp : this.tenderInfo.decimal.tp;
  45. this.orderReg = /f\d+/ig;
  46. this.nodeReg = /<<[a-z0-9\-]+>>/ig;
  47. /* 以下变量在调用calculate方法后获得
  48. this.add;
  49. this.pre;
  50. this.cur;
  51. this.yf;
  52. */
  53. }
  54. /**
  55. * 获取 计算基数
  56. * @returns {Promise<void>}
  57. */
  58. getCalcBase () {
  59. if (this.bases) return;
  60. const bases = this.ctx.service.phasePay.getPhasePayCalcBase(this.phasePay, this.tenderInfo);
  61. this.bases = bases.sort(function (a, b) {
  62. return a.sort - b.sort;
  63. });
  64. for (const b of this.bases) {
  65. b.reg = new RegExp(b.code, 'igm');
  66. }
  67. }
  68. getCalcAdd() {
  69. if (this.addBase) return;
  70. const calc_base = this.phasePay.calc_base;
  71. this.addBase = {
  72. contract_tp: this.ctx.helper.add(calc_base.contract_tp, calc_base.pre_contract_tp),
  73. qc_tp: this.ctx.helper.add(calc_base.qc_tp, calc_base.pre_qc_tp),
  74. gather_tp: this.ctx.helper.add(calc_base.gather_tp, calc_base.pre_gather_tp),
  75. };
  76. }
  77. checkQuetoExpr(expr) {
  78. if (!this.basesReg) {
  79. this.getCalcBase();
  80. this.basesReg = new RegExp(this.bases.map(x => {return '(' + x.code + ')'}).join('|'));
  81. }
  82. return this.basesReg.test(expr) || this.nodeReg.test(expr);
  83. }
  84. _calculateTpExpr(pay, pays) {
  85. let formula = pay.expr;
  86. const nodeParam = pay.expr.match(this.nodeReg);
  87. if (nodeParam) {
  88. for (const op of nodeParam) {
  89. const id = op.substring(2, op.length - 2);
  90. const payNode = pays.find(x => { return x.uuid === id; });
  91. formula = formula.replace(op, payNode ? payNode.tp || 0 : 0);
  92. }
  93. }
  94. for (const b of this.bases) {
  95. const value = b.checkStart && (!pay.pre_used && pay.start_tp)
  96. // ? Math.max(this.ctx.helper.sub(this.addBase[b.checkStart], pay.start_tp), 0)
  97. ? this.ctx.helper.sub(this.addBase[b.checkStart], pay.start_tp)
  98. : b.value;
  99. formula = formula.replace(b.reg, value);
  100. }
  101. const percent = formula.match(this.percentReg);
  102. if (percent) {
  103. for (const p of percent) {
  104. const v = math.eval(p.replace(new RegExp('%', 'gm'), '/100'));
  105. formula = formula.replace(p, v);
  106. }
  107. }
  108. try {
  109. // 使用mathjs计算 math.eval('17259401.95*0.9') = 15533461.754999999,正确应为 15533461.755
  110. // const value = math.eval(formula);
  111. // 使用逆波兰法四则运算,可防止出现误差,但是只支持四则运算,不支持科学运算
  112. // const value = this.ctx.helper.calcExprStrRpn(formula);
  113. // 使用mathjs的大数运算,可支持所有
  114. const value = parseFloat(math.eval(formula));
  115. return Number.isFinite(value) ? value : 0;
  116. } catch(err) {
  117. return 0;
  118. }
  119. }
  120. _calculateExpr(expr) {
  121. let formula = expr;
  122. for (const b of this.bases) {
  123. formula = formula.replace(b.reg, b.value ? b.value : 0);
  124. }
  125. const percent = formula.match(this.percentReg);
  126. if (percent) {
  127. for (const p of percent) {
  128. const v = math.eval(p.replace(new RegExp('%', 'gm'), '/100'));
  129. formula = formula.replace(p, v);
  130. }
  131. }
  132. try {
  133. // 使用mathjs计算 math.eval('17259401.95*0.9') = 15533461.754999999,正确应为 15533461.755
  134. // const value = math.eval(formula);
  135. // 使用逆波兰法四则运算,可防止出现误差,但是只支持四则运算,不支持科学运算
  136. // const value = this.ctx.helper.calcExprStrRpn(formula);
  137. // 使用mathjs的大数运算,可支持所有
  138. const value = parseFloat(math.eval(formula));
  139. return Number.isFinite(value) ? value : 0;
  140. } catch(err) {
  141. return 0;
  142. }
  143. }
  144. /**
  145. * 计算起扣金额、付(扣)款限额
  146. *
  147. * @param {Array} pays - (标段)合同支付数据
  148. */
  149. calculateStartRangePrice (payTree) {
  150. for (const p of payTree.nodes) {
  151. // 上一期已计量的合同支付项,不予计算起扣金额、扣款限额
  152. if (p.pre_used) continue;
  153. if (p.start_expr) {
  154. p.start_tp = this.ctx.helper.round(this._calculateExpr(p.start_expr), this.decimal);
  155. } else if (p.start_tp && !p.start_expr) {
  156. p.start_tp = this.ctx.helper.round(p.start_tp, this.decimal);
  157. }
  158. if (p.range_expr) {
  159. p.range_tp = this.ctx.helper.round(this._calculateExpr(p.range_expr), this.decimal);
  160. } else if (p.range_tp && !p.range_expr) {
  161. p.range_tp = this.ctx.helper.round(p.range_tp, this.decimal);
  162. }
  163. }
  164. }
  165. /**
  166. * 检查是否到达 计提期限
  167. * @param pay
  168. */
  169. _checkDeadline(pay) {
  170. switch (pay.dl_type) {
  171. case deadlineType.phaseCount.key:
  172. return this.phasePay.phase_order >= pay.dl_value;
  173. case deadlineType.stageCount.key:
  174. const maxStageOrder = this.ctx.helper._.max(this.phasePay.rela_stage.map(x => { return x.stage_order; }));
  175. return maxStageOrder >= pay.dl_value;
  176. case deadlineType.gather.key:
  177. case deadlineType.contract.key:
  178. case deadlineType.qc.key:
  179. const deadlineTp = this.addBase[pay.dl_type + '_tp'];
  180. return deadlineTp >= pay.dl_value;
  181. default :
  182. return false;
  183. }
  184. }
  185. getLeafOrder(data, pays, parentId) {
  186. if (!data || !data.expr) return [];
  187. const nodeParam = data.expr.match(this.nodeReg);
  188. if (!nodeParam || nodeParam.length === 0) return [];
  189. const result = [...nodeParam];
  190. for (const op of nodeParam) {
  191. const id = op.substring(2, op.length - 2);
  192. if (id === data.uuid || id === parentId) {
  193. result.push(op);
  194. } else {
  195. const subPay = pays.find(x => { return x.uuid === id; });
  196. const sub = this.getLeafOrder(subPay, pays, data.uuid);
  197. if (sub.length > 0) {
  198. result.push(...sub);
  199. } else {
  200. result.push(op);
  201. }
  202. }
  203. }
  204. return this.ctx.helper._.uniq(result);
  205. }
  206. sortPaysByCalc(payTree) {
  207. const calcArr = [];
  208. for (const pay of payTree.nodes) {
  209. if (pay.pay_type === payType.bqyf) {
  210. pay.calcSort = 3;
  211. } else if (pay.pay_type === payType.bqsf) {
  212. pay.calcSort = 4;
  213. } else if (pay.children && pay.children.length > 0) {
  214. pay.calcSort = 2;
  215. } else {
  216. pay.calcSort = 1;
  217. pay.calcLeaf = this.getLeafOrder(pay, payTree.nodes);
  218. }
  219. calcArr.push(pay);
  220. }
  221. calcArr.sort((x, y) => {
  222. const calcSort = x.calcSort - y.calcSort;
  223. if (calcSort) return calcSort;
  224. if (x.calcSort === 2) return -(x.tree_level - y.tree_level);
  225. return x.calcLeaf.length - y.calcLeaf.length;
  226. });
  227. return calcArr;
  228. }
  229. _calculateYf(yf, pays) {
  230. yf.tp = 0;
  231. for (const p of pays) {
  232. if (p.pay_type || !p.is_gather || !p.tree_is_leaf) continue;
  233. yf.tp = !p.is_minus ? this.ctx.helper.add(yf.tp, p.tp) : this.ctx.helper.sub(yf.tp, p.tp);
  234. }
  235. const bqyf = this.bases.find(function (x) {return x.code === 'bqyf'});
  236. if (bqyf) bqyf.value = yf.tp;
  237. }
  238. _calculateSf(sf, pays) {
  239. if (sf.expr) {
  240. sf.tp = this.ctx.helper.round(this._calculateTpExpr(sf, pays), this.decimal);
  241. } else {
  242. const yf = pays.find(x => { return x.pay_type === payType.bqyf; });
  243. sf.tp = yf.tp;
  244. }
  245. sf.tp = sf.range_tp ? Math.min(this.ctx.helper.sub(sf.range_tp, sf.pre_tp), sf.tp) : sf.tp;
  246. }
  247. _calculateGather(pay) {
  248. pay.tp = 0;
  249. for (const c of pay.children) {
  250. if (c.children && c.children.length > 0) this._calculateGather(c);
  251. if (!c.is_gather) continue;
  252. pay.tp = this.ctx.helper.add(pay.tp, c.tp);
  253. }
  254. }
  255. _calculateCommon(pay, pays) {
  256. // 暂停计量|未达起扣金额时,不计算
  257. if (pay.is_pause || (pay.start_tp && this.addBase.gather_tp < pay.start_tp)) {
  258. pay.tp = 0;
  259. return;
  260. }
  261. if (this._checkDeadline(pay)) {
  262. pay.tp = this.ctx.helper.sub(pay.range_tp, pay.pre_tp);
  263. } else if (pay.expr) {
  264. pay.tp = this.ctx.helper.round(this._calculateTpExpr(pay, pays), this.decimal);
  265. } else {
  266. pay.tp = this.ctx.helper.round(pay.tp || 0, this.decimal);
  267. }
  268. pay.tp = pay.range_tp ? Math.min(this.ctx.helper.sub(pay.range_tp, pay.pre_tp), pay.tp) : pay.tp;
  269. }
  270. /**
  271. * 计算本期、截止本期金额
  272. * @param {Array} pays - (标段&期)合同支付数据
  273. */
  274. calculate(pays) {
  275. for (const p of pays) {
  276. switch (p.pay_type) {
  277. case payType.bqyf:
  278. this._calculateYf(p, pays); break;
  279. case payType.bqsf:
  280. this._calculateSf(p, pays); break;
  281. case payType.gcjl:
  282. case payType.qtfk:
  283. case payType.qtkk:
  284. this._calculateGather(p); break;
  285. default:
  286. this._calculateCommon(p, pays); break;
  287. }
  288. p.end_tp = this.ctx.helper.add(p.pre_tp, p.tp);
  289. }
  290. }
  291. calculateAll(payTree) {
  292. payTree.nodes.forEach(x => {
  293. x.org_tp = x.tp || 0;
  294. x.org_start_tp = x.start_tp || 0;
  295. x.org_range_tp = x.range_tp || 0;
  296. x.org_end_tp = x.end_tp || 0;
  297. });
  298. this.getCalcBase();
  299. this.getCalcAdd();
  300. this.calculateStartRangePrice(payTree);
  301. const calcPays = this.sortPaysByCalc(payTree);
  302. this.calculate(calcPays);
  303. payTree.nodes.forEach(p => {
  304. p.calcUpdate = !this.ctx.helper.numEqual(p.org_tp, p.tp) || !this.ctx.helper.numEqual(p.org_end_tp, p.end_tp)
  305. || !this.ctx.helper.numEqual(p.org_start_tp, p.start_tp) || !this.ctx.helper.numEqual(p.org_range_tp, p.range_tp) ;
  306. });
  307. }
  308. }
  309. class PhasePayDetail extends TreeService {
  310. /**
  311. * 构造函数
  312. *
  313. * @param {Object} ctx - egg全局变量
  314. * @param {String} tableName - 表名
  315. * @return {void}
  316. */
  317. constructor(ctx, setting) {
  318. super(ctx, {
  319. mid: 'master_id',
  320. kid: 'tree_id',
  321. pid: 'tree_pid',
  322. order: 'tree_order',
  323. level: 'tree_level',
  324. isLeaf: 'tree_is_leaf',
  325. fullPath: 'tree_full_path',
  326. keyPre: '',
  327. uuid: true,
  328. });
  329. this.tableName = 'phase_pay_detail';
  330. this.deadlineType = deadlineType;
  331. }
  332. getMasterKey(phasePay) {
  333. return phasePay.curTimes
  334. ? `${phasePay.id}-${phasePay.curTimes}-${phasePay.curSort}`
  335. : `${phasePay.id}-${phasePay.audit_times}-${phasePay.audit_max_sort}`;
  336. }
  337. async initPhaseDataEmpty(conn, phasePay) {
  338. const user_id = this.ctx.session.sessionUser.accountId;
  339. const insertData = [];
  340. for (const dp of defaultPays) {
  341. insertData.push({
  342. tid: phasePay.tid, phase_id: phasePay.id, create_phase_id: phasePay.id, master_id: phasePay.id + '-1-0',
  343. create_user_id: user_id, update_user_id: user_id,
  344. uuid: this.uuid.v4(), ...dp,
  345. });
  346. }
  347. await conn.insert(this.tableName, insertData);
  348. }
  349. async initPhaseDataByPre(conn, phasePay, prePhase) {
  350. const preData = await this.getAllDataByCondition({
  351. where: { phase_id: prePhase.id, audit_times: prePhase.audit_times, audit_sort: prePhase.audit_max_sort },
  352. });
  353. const payCalc = new PayCalculator(this.ctx, prePhase);
  354. for (const pd of preData) {
  355. delete pd.id;
  356. delete pd.postil;
  357. pd.tp = 0;
  358. pd.pre_tp = pd.end_tp;
  359. pd.phase_id = phasePay.id;
  360. pd.master_id = phasePay.id + '-1-0';
  361. pd.audit_times = 1;
  362. pd.audit_sort = 0;
  363. if (!pd.pre_used) pd.pre_used = pd.pre_tp ? 1 : 0;
  364. if (!pd.pre_finished) pd.pre_finished = pd.end_tp >= pd.range_tp;
  365. if (pd.expr && (!pd.pay_type || pd.pay_type === payType.bqsf) && !payCalc.checkQuetoExpr(pd.expr)) pd.expr = '';
  366. }
  367. await conn.insert(this.tableName, preData);
  368. }
  369. async initPhaseDataByAudit(conn, phasePay, newTimes, newSort) {
  370. const preData = await conn.select(this.tableName, { where: { master_id: this.getMasterKey(phasePay)}});
  371. for (const pd of preData) {
  372. delete pd.id;
  373. pd.master_id = `${phasePay.id}-${newTimes}-${newSort}`;
  374. pd.audit_times = newTimes;
  375. pd.audit_sort = newSort;
  376. }
  377. await conn.insert(this.tableName, preData);
  378. }
  379. async initPhaseDataByAuditCancel(conn, phasePay, oldTimes, oldSort, newTimes, newSort) {
  380. const masterId = `${phasePay.id}-${oldTimes}-${oldSort}`;
  381. const preData = await conn.select(this.tableName, { where: { master_id: masterId } });
  382. for (const pd of preData) {
  383. delete pd.id;
  384. pd.master_id = `${phasePay.id}-${newTimes}-${newSort}`;
  385. pd.audit_times = newTimes;
  386. pd.audit_sort = newSort;
  387. }
  388. await conn.insert(this.tableName, preData);
  389. }
  390. async initPhaseData(conn, phasePay, prePhase){
  391. if (!conn) throw '内部错误';
  392. if (prePhase) {
  393. await this.initPhaseDataByPre(conn, phasePay, prePhase);
  394. } else {
  395. await this.initPhaseDataEmpty(conn, phasePay);
  396. }
  397. }
  398. async getDetailData(phasePay) {
  399. return await this.getAllDataByCondition({ where: { master_id: this.getMasterKey(phasePay)} });
  400. }
  401. calculate(phasePay, details) {
  402. const payTree = new Ledger.baseTree(this.ctx, {
  403. id: 'tree_id', pid: 'tree_pid', order: 'tree_order',
  404. level: 'tree_level', isLeaf: 'tree_is_leaf', fullPath: 'tree_full_path',
  405. rootId: -1, calcField: [],
  406. });
  407. payTree.loadDatas(details);
  408. const payCalculator = new PayCalculator(this.ctx, phasePay);
  409. payCalculator.calculateAll(payTree);
  410. return payTree.getDefaultDatas();
  411. }
  412. getPayTp(datas, type) {
  413. const pay = datas.find(x => { return x.pay_type === type });
  414. return pay ? pay.tp || 0 : 0;
  415. }
  416. getPaySum(datas) {
  417. const result = {};
  418. result.yf_tp = this.getPayTp(datas, payType.bqyf);
  419. result.sf_tp = this.getPayTp(datas, payType.bqsf);
  420. result.calc_tp = this.getPayTp(datas, payType.gcjl);
  421. result.pay_tp = this.ctx.helper.add(this.getPayTp(datas, payType.qtfk), result.calc_tp);
  422. result.cut_tp = this.getPayTp(datas, payType.qtkk);
  423. return result;
  424. }
  425. async calculateSave(phasePay, transaction) {
  426. const details = await this.getDetailData(phasePay);
  427. if (details.length === 0) return false;
  428. const calcResult = this.calculate(phasePay, details);
  429. const updateData = calcResult.filter(x => { return x.calcUpdate; }).map(x => {
  430. return { id: x.id, tp: x.tp, start_tp: x.start_tp, range_tp: x.range_tp, end_tp: x.end_tp };
  431. });
  432. if (updateData.length === 0) return this.getPaySum(calcResult);
  433. if (transaction) {
  434. await transaction.updateRows(this.tableName, updateData);
  435. } else {
  436. await this.defaultUpdateRows(updateData);
  437. }
  438. return this.getPaySum(calcResult);
  439. }
  440. _getDefaultData(data, phasePay, parent) {
  441. data.uuid = this.uuid.v4();
  442. data.tid = phasePay.tid;
  443. data.phase_id = phasePay.id;
  444. data.create_user_id = this.ctx.session.sessionUser.accountId;
  445. data.update_user_id = this.ctx.session.sessionUser.accountId;
  446. data.audit_times = phasePay.audit_times;
  447. data.audit_sort = phasePay.audit_max_sort;
  448. data.master_id = this.getMasterKey(phasePay);
  449. data.create_phase_id = phasePay.id;
  450. data.create_phase_order = phasePay.phase_order;
  451. if (parent) {
  452. data.is_minus = parent.is_minus;
  453. }
  454. }
  455. async addChild(phasePay, select, count = 1) {
  456. if (select.pay_type === payType.bqsf || select.pay_type === payType.bqyf) throw '不可新增子项';
  457. if (select.tree_level >= 2) throw '不可新增子项';
  458. const masterId = this.getMasterKey(phasePay);
  459. const children = await this.getChildrenByParentId(masterId, select[this.setting.kid]);
  460. const maxId = await this._getMaxLid(masterId);
  461. const insertData = [];
  462. for (let i = 1; i <= count ; i++) {
  463. const data = {
  464. tree_id: maxId + i, tree_pid: select.tree_id, tree_order: children.length + i,
  465. tree_level: select.tree_level + 1, tree_is_leaf: 1
  466. };
  467. data.tree_full_path = select.tree_full_path + '-' + data.tree_id;
  468. this._getDefaultData(data, phasePay, select);
  469. insertData.push(data);
  470. }
  471. const conn = await this.db.beginTransaction();
  472. try {
  473. const result = await conn.insert(this.tableName, insertData);
  474. if (children.length === 0) {
  475. await conn.update(this.tableName, { id: select.id, tree_is_leaf: false });
  476. }
  477. await conn.commit();
  478. } catch(err) {
  479. conn.rollback();
  480. throw err;
  481. }
  482. this._cacheMaxLid(masterId, maxId + 1);
  483. // 查询应返回的结果
  484. const resultData = {};
  485. resultData.create = await this.getNextsData(masterId, select.tree_id, children.length);
  486. if (children.length === 0) resultData.update = await this.getDataByKid(masterId, select.tree_id);
  487. return resultData;
  488. }
  489. async addNext(phasePay, select, count = 1) {
  490. const masterId = this.getMasterKey(phasePay);
  491. const parent = await this.getDataByKid(masterId, select[this.setting.pid]);
  492. this.transaction = await this.db.beginTransaction();
  493. try {
  494. if (select) await this._updateChildrenOrder(masterId, select[this.setting.pid], select[this.setting.order] + 1, count);
  495. const newDatas = [];
  496. const maxId = await this._getMaxLid(masterId);
  497. for (let i = 1; i < count + 1; i++) {
  498. const newData = {};
  499. newData[this.setting.kid] = maxId + i;
  500. newData[this.setting.pid] = select ? select[this.setting.pid] : this.rootId;
  501. newData[this.setting.level] = select ? select[this.setting.level] : 1;
  502. newData[this.setting.order] = select ? select[this.setting.order] + i : i;
  503. newData[this.setting.fullPath] = newData[this.setting.level] > 1
  504. ? select[this.setting.fullPath].replace('-' + select[this.setting.kid], '-' + newData[this.setting.kid])
  505. : newData[this.setting.kid] + '';
  506. newData[this.setting.isLeaf] = 1;
  507. this._getDefaultData(newData, phasePay, parent);
  508. newDatas.push(newData);
  509. }
  510. const insertResult = await this.transaction.insert(this.tableName, newDatas);
  511. this._cacheMaxLid(masterId, maxId + count);
  512. if (insertResult.affectedRows !== count) throw '新增节点数据错误';
  513. await this.transaction.commit();
  514. this.transaction = null;
  515. } catch (err) {
  516. await this.transaction.rollback();
  517. this.transaction = null;
  518. throw err;
  519. }
  520. if (select) {
  521. const createData = await this.getChildBetween(masterId, select[this.setting.pid], select[this.setting.order], select[this.setting.order] + count + 1);
  522. const updateData = await this.getNextsData(masterId, select[this.setting.pid], select[this.setting.order] + count);
  523. return {create: createData, update: updateData};
  524. } else {
  525. const createData = await this.getChildBetween(masterId, -1, 0, count + 1);
  526. return {create: createData};
  527. }
  528. }
  529. async addDetailNode(phasePay, targetId, count = 1) {
  530. if (!phasePay) return null;
  531. const select = targetId ? await this.getDataByKid(this.getMasterKey(phasePay), targetId) : null;
  532. if (targetId && !select) throw '新增节点数据错误';
  533. if (select[this.setting.level] === 1) {
  534. return await this.addChild(phasePay, select, count);
  535. } else {
  536. return await this.addNext(phasePay, select, count);
  537. }
  538. }
  539. async upMoveDetailNode(phasePay, targetId, count = 1) {
  540. const masterId = this.getMasterKey(phasePay);
  541. return await this.upMoveNode(masterId, targetId, count);
  542. }
  543. async downMoveDetailNode(phasePay, targetId, count = 1) {
  544. const masterId = this.getMasterKey(phasePay);
  545. return await this.downMoveNode(masterId, targetId, count);
  546. }
  547. async deleteDetailNode(phasePay, targetId, count = 1) {
  548. const masterId = this.getMasterKey(phasePay);
  549. return await this.delete(masterId, targetId, count);
  550. }
  551. _filterValidField(id, data) {
  552. const ud = { id };
  553. for (const prop in data) {
  554. if (validField.indexOf(prop) >= 0) {
  555. ud[prop] = data[prop];
  556. }
  557. }
  558. return ud;
  559. }
  560. checkCalc(data) {
  561. const datas = data instanceof Array ? data : [data];
  562. for (const d of datas) {
  563. for (const prop in d) {
  564. if (calcField.indexOf(prop) >= 0) return true;
  565. }
  566. }
  567. return false;
  568. }
  569. async updateDetail(phasePay, data) {
  570. const masterId = this.getMasterKey(phasePay);
  571. if (Array.isArray(data)) {
  572. const orgData = await this.getAllDataByCondition({ where: { id: data.map(d => { return d.id; }) } });
  573. const updateDatas = [];
  574. for (const d of data) {
  575. const node = orgData.find(x => { return x.id === d.id; });
  576. if (!node || masterId !== node[this.setting.mid]) throw '提交数据错误';
  577. const ud = this._filterValidField(node.id, d);
  578. ud.update_user_id = this.ctx.session.sessionUser.accountId;
  579. updateDatas.push(ud);
  580. }
  581. if (updateDatas.length > 0) {
  582. await this.db.updateRows(this.tableName, updateDatas);
  583. return await this.getAllDataByCondition({ where: { id: data.map(d => { return d.id; }) } });
  584. } else {
  585. return [];
  586. }
  587. } else {
  588. const node = await this.getDataById(data.id);
  589. if (!node || masterId !== node[this.setting.mid]) throw '提交数据错误';
  590. const updateData = this._filterValidField(node.id, data);
  591. updateData.update_user_id = this.ctx.session.sessionUser.accountId;
  592. await this.db.update(this.tableName, updateData);
  593. return this.getDataById(data.id);
  594. }
  595. }
  596. }
  597. module.exports = PhasePayDetail;