ledger.js 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477
  1. 'use strict';
  2. /**
  3. * 标段--台账 数据模型
  4. *
  5. * @author CaiAoLin
  6. * @date 2017/12/1
  7. * @version
  8. */
  9. const needField = {
  10. id: 'ledger_id',
  11. pid: 'ledger_pid',
  12. order: 'order',
  13. level: 'level',
  14. fullPath: 'full_path',
  15. isLeaf: 'is_leaf',
  16. };
  17. const keyFields = {
  18. table: ['id'],
  19. index: ['tender_id', 'ledger_id'],
  20. };
  21. // 以下字段仅可通过树结构操作改变,不可直接通过update方式从接口提交,发现时过滤
  22. const readOnlyFields = ['id', 'tender_id', 'ledger_id', 'ledger_pid', 'order', 'level', 'full_path', 'is_leaf'];
  23. const calcFields = ['quantity', 'unit_price', 'total_price'];
  24. const zeroRange = 0.0000000001;
  25. const rootId = -1;
  26. module.exports = app => {
  27. class Ledger extends app.BaseService {
  28. /**
  29. * 构造函数
  30. *
  31. * @param {Object} ctx - egg全局变量
  32. * @return {void}
  33. */
  34. constructor(ctx) {
  35. super(ctx);
  36. this.tableName = 'ledger';
  37. }
  38. /**
  39. * 新增数据(供内部或其他service类调用, controller不可直接使用)
  40. * @param {Array|Object} data - 新增数据
  41. * @param {Number} tenderId - 标段id
  42. * @param {Object} transaction - 新增事务
  43. * @returns {Promise<boolean>} - {Promise<是否正确新增成功>}
  44. */
  45. async innerAdd(data, tenderId, transaction) {
  46. const datas = data instanceof Array ? data : [data];
  47. if (tenderId <= 0) {
  48. throw '标段id错误';
  49. }
  50. if (datas.length <= 0) {
  51. throw '插入数据为空';
  52. }
  53. if (!transaction) {
  54. throw '内部错误';
  55. }
  56. // 整理数据
  57. const insertData = [];
  58. for (const tmp of datas) {
  59. tmp.ledger_id = tmp.id;
  60. tmp.ledger_pid = tmp.pid;
  61. tmp.tender_id = tenderId;
  62. delete tmp.id;
  63. delete tmp.pid;
  64. insertData.push(tmp);
  65. }
  66. const operate = await transaction.insert(this.tableName, insertData);
  67. return operate.affectedRows === datas.length;
  68. }
  69. /**
  70. * 新增数据
  71. *
  72. * @param {Object} data - 新增的数据(可批量)
  73. * @param {Number} tenderId - 标段id
  74. * @return {Boolean} - 返回新增的结果
  75. */
  76. async add(data, tenderId) {
  77. this.transaction = await this.db.beginTransaction();
  78. let result = false;
  79. try {
  80. result = await this.innerAdd(data, tenderId, this.transaction);
  81. if (!result) {
  82. throw '新增数据错误';
  83. }
  84. this.transaction.commit();
  85. } catch (error) {
  86. this.transaction.rollback();
  87. result = false;
  88. }
  89. return result;
  90. }
  91. /**
  92. * 根据层级获取数据
  93. *
  94. * @param {Number} tenderId - 标段id
  95. * @param {Number} showLevel - 显示层数
  96. * @return {Array} - 返回数据
  97. */
  98. async getDataByTenderId(tenderId, showLevel = 4) {
  99. if (tenderId <= 0) {
  100. return [];
  101. }
  102. this.initSqlBuilder();
  103. this.sqlBuilder.setAndWhere('tender_id', {
  104. value: tenderId,
  105. operate: '=',
  106. });
  107. if (showLevel > 0) {
  108. this.sqlBuilder.setAndWhere('level', {
  109. value: showLevel,
  110. operate: '<=',
  111. });
  112. }
  113. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  114. const data = await this.db.query(sql, sqlParam);
  115. return data;
  116. }
  117. /**
  118. * 根据节点Id获取数据
  119. *
  120. * @param {Number} tenderId - 标段id
  121. * @param {Number} nodeId - 项目节/工程量清单节点id
  122. * @return {Object} - 返回查询到的节点数据
  123. */
  124. async getDataByNodeId(tenderId, nodeId) {
  125. if ((nodeId <= 0) || (tenderId <= 0)) {
  126. return undefined;
  127. }
  128. this.initSqlBuilder();
  129. this.sqlBuilder.setAndWhere('tender_id', {
  130. value: tenderId,
  131. operate: '=',
  132. });
  133. this.sqlBuilder.setAndWhere('ledger_id', {
  134. value: nodeId,
  135. operate: '=',
  136. });
  137. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  138. const data = await this.db.queryOne(sql, sqlParam);
  139. return data;
  140. }
  141. /**
  142. * 根据节点Id获取数据
  143. * @param {Number} tenderId - 标段Id
  144. * @param {Array} nodesIds - 节点Id
  145. * @return {Array}
  146. */
  147. async getDataByNodeIds(tenderId, nodesIds) {
  148. if (tenderId <= 0) {
  149. return [];
  150. }
  151. this.initSqlBuilder();
  152. this.sqlBuilder.setAndWhere('tender_id', {
  153. value: tenderId,
  154. operate: '=',
  155. });
  156. this.sqlBuilder.setAndWhere('ledger_id', {
  157. value: nodesIds,
  158. operate: 'in',
  159. });
  160. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  161. const data = await this.db.query(sql, sqlParam);
  162. return data;
  163. }
  164. /**
  165. * 根据主键id获取数据
  166. * @param {Array|Number} id - 主键id
  167. * @returns {Promise<*>}
  168. */
  169. async getDataByIds(id) {
  170. const ids = id instanceof Array ? id : [id];
  171. this.initSqlBuilder();
  172. this.sqlBuilder.setAndWhere('id', {
  173. value: ids,
  174. operate: 'in',
  175. });
  176. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  177. const data = await this.db.query(sql, sqlParam);
  178. return data;
  179. }
  180. /**
  181. * 根据标准清单源检索
  182. * @param tenderId
  183. * @param source
  184. * @returns {Promise<*>}
  185. */
  186. async getDataBySource(tenderId, source) {
  187. this.initSqlBuilder();
  188. this.sqlBuilder.setAndWhere('tender_id', {
  189. value: tenderId,
  190. operate: '=',
  191. });
  192. this.sqlBuilder.setAndWhere('source', {
  193. value: source,
  194. operate: '=',
  195. });
  196. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  197. const data = await this.db.query(sql, sqlParam);
  198. return data;
  199. }
  200. /**
  201. * 获取最末的子节点
  202. * @param {Number} tenderId - 标段id
  203. * @param {Number} pid - 父节点id
  204. * @return {Object}
  205. */
  206. async getLastChildData(tenderId, pid) {
  207. this.initSqlBuilder();
  208. this.sqlBuilder.setAndWhere('tender_id', {
  209. value: tenderId,
  210. operate: '=',
  211. });
  212. this.sqlBuilder.setAndWhere('ledger_pid', {
  213. value: pid,
  214. operate: '=',
  215. });
  216. this.sqlBuilder.orderBy = [['order', 'DESC']];
  217. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  218. const resultData = this.db.queryOne(sql, sqlParam);
  219. return resultData;
  220. }
  221. /**
  222. * 根据 父节点id 和 节点排序order 获取数据
  223. *
  224. * @param {Number} tenderId - 标段id
  225. * @param {Number} pid - 父节点id
  226. * @param {Number|Array} order - 排序
  227. * @return {Object|Array} - 查询结果
  228. */
  229. async getDataByParentAndOrder(tenderId, pid, order) {
  230. if ((tenderId <= 0) || (pid <= 0) || (order <= 0)) {
  231. return undefined;
  232. }
  233. this.initSqlBuilder();
  234. this.sqlBuilder.setAndWhere('tender_id', {
  235. value: tenderId,
  236. operate: '=',
  237. });
  238. this.sqlBuilder.setAndWhere('ledger_pid', {
  239. value: pid,
  240. operate: '=',
  241. });
  242. if (order instanceof Array) {
  243. this.sqlBuilder.setAndWhere('order', {
  244. value: order,
  245. operate: 'in',
  246. });
  247. } else {
  248. this.sqlBuilder.setAndWhere('order', {
  249. value: order,
  250. operate: '=',
  251. });
  252. }
  253. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  254. let data;
  255. if (order instanceof Array) {
  256. data = await this.db.query(sql, sqlParam);
  257. } else {
  258. data = await this.db.queryOne(sql, sqlParam);
  259. }
  260. return data;
  261. }
  262. /**
  263. * 根据 父节点id 获取子节点
  264. * @param tenderId
  265. * @param nodeId
  266. * @return {Promise<*>}
  267. */
  268. async getChildrenByParentId(tenderId, nodeId) {
  269. if (tenderId <= 0 || !nodeId) {
  270. return undefined;
  271. }
  272. const nodeIds = nodeId instanceof Array ? nodeId : [nodeId];
  273. if (nodeIds.length === 0) {
  274. return [];
  275. }
  276. this.initSqlBuilder();
  277. this.sqlBuilder.setAndWhere('tender_id', {
  278. value: tenderId,
  279. operate: '=',
  280. });
  281. this.sqlBuilder.setAndWhere('ledger_pid', {
  282. value: nodeIds,
  283. operate: 'in',
  284. });
  285. this.sqlBuilder.orderBy = [['order', 'ASC']];
  286. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  287. const data = await this.db.query(sql, sqlParam);
  288. return data;
  289. }
  290. /**
  291. * 根据 父节点ID 和 节点排序order 获取全部后节点数据
  292. * @param {Number} tenderId - 标段id
  293. * @param {Number} pid - 父节点id
  294. * @param {Number} order - 排序
  295. * @return {Array}
  296. */
  297. async getNextsData(tenderId, pid, order) {
  298. if ((tenderId <= 0) || (order < 0)) {
  299. return undefined;
  300. }
  301. this.initSqlBuilder();
  302. this.sqlBuilder.setAndWhere('tender_id', {
  303. value: tenderId,
  304. operate: '=',
  305. });
  306. this.sqlBuilder.setAndWhere('ledger_pid', {
  307. value: pid,
  308. operate: '=',
  309. });
  310. this.sqlBuilder.setAndWhere('order', {
  311. value: order,
  312. operate: '>',
  313. });
  314. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  315. const data = await this.db.query(sql, sqlParam);
  316. return data;
  317. }
  318. /**
  319. * 根据full_path获取数据 full_path Like ‘1.2.3%’(传参full_path = '1.2.3%')
  320. * @param {Number} tenderId - 标段id
  321. * @param {String} full_path - 路径
  322. * @return {Promise<void>}
  323. */
  324. async getDataByFullPath(tenderId, full_path) {
  325. this.initSqlBuilder();
  326. this.sqlBuilder.setAndWhere('tender_id', {
  327. value: tenderId,
  328. operate: '=',
  329. });
  330. this.sqlBuilder.setAndWhere('full_path', {
  331. value: this.db.escape(full_path),
  332. operate: 'Like',
  333. });
  334. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  335. const resultData = await this.db.query(sql, sqlParam);
  336. return resultData;
  337. }
  338. /**
  339. * 根据full_path检索自己及所有父项
  340. * @param {Number} tenderId - 标段id
  341. * @param {Array|String} fullPath - 节点完整路径
  342. * @returns {Promise<*>}
  343. * @private
  344. */
  345. async getFullLevelDataByFullPath(tenderId, fullPath) {
  346. const explodePath = this.ctx.helper.explodePath(fullPath);
  347. this.initSqlBuilder();
  348. this.sqlBuilder.setAndWhere('tender_id', {
  349. value: tenderId,
  350. operate: '=',
  351. });
  352. this.sqlBuilder.setAndWhere('full_path', {
  353. value: explodePath,
  354. operate: 'in'
  355. });
  356. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  357. const data = await this.db.query(sql, sqlParam);
  358. return data;
  359. };
  360. /**
  361. * 统计子节点total_price
  362. * @param {Number} tenderId - 标段id
  363. * @param {Number} pid - 父节点id
  364. * @param {Number} order - order取值
  365. * @param {String} orderOperate - order比较操作符
  366. * @returns {Promise<void>}
  367. */
  368. async addUpChildren(tenderId, pid, order, orderOperate) {
  369. this.initSqlBuilder();
  370. const sql = ['SELECT SUM(??) As value FROM ?? ', ' WHERE ']
  371. const sqlParam = ['total_price', this.tableName];
  372. sql.push(' ?? = ' + tenderId);
  373. sqlParam.push('tender_id');
  374. sql.push(' And ?? = ' + pid);
  375. sqlParam.push('ledger_pid');
  376. sql.push(' And ?? ' + orderOperate + ' ' + order);
  377. sqlParam.push('order');
  378. const result = await this.db.queryOne(sql.join(''), sqlParam);
  379. return result.value;
  380. }
  381. /**
  382. * 更新order
  383. * @param {Number} tenderId - 标段id
  384. * @param {Number} parentId - 父节点id
  385. * @param {Number} order - 自增起始order(含)
  386. * @param {Number} incre - 自增量
  387. * @returns {Promise<*>}
  388. * @private
  389. */
  390. async _updateChildrenOrderAfter(tenderId, parentId, order, incre = 1) {
  391. this.initSqlBuilder();
  392. this.sqlBuilder.setAndWhere('tender_id', {
  393. value: tenderId,
  394. operate: '='
  395. });
  396. this.sqlBuilder.setAndWhere('order', {
  397. value: order,
  398. operate: '>=',
  399. });
  400. this.sqlBuilder.setAndWhere('ledger_pid', {
  401. value: parentId,
  402. operate: '=',
  403. });
  404. this.sqlBuilder.setUpdateData('order', {
  405. value: Math.abs(incre),
  406. selfOperate: incre > 0 ? '+' : '-',
  407. });
  408. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  409. const data = await this.transaction.query(sql, sqlParam);
  410. return data;
  411. }
  412. /**
  413. * select的全部后兄弟节点,Order自增
  414. *
  415. * @param {Object} select - 选中的节点
  416. * @param {Number} incre - 自增值
  417. * @return {Array} - 自增后的数据
  418. * @private
  419. */
  420. async _updateSelectNextsOrder(select, incre = 1) {
  421. return await this._updateChildrenOrderAfter(select.tender_id, select.ledger_pid, select.order + 1, incre);
  422. }
  423. /**
  424. * 从数据库获取标段的最大节点id
  425. *
  426. * @param {Number} tenderId - 标段id
  427. * @return {Number}
  428. * @private
  429. */
  430. async _getMaxNodeId(tenderId) {
  431. const sql = 'SELECT Max(??) As max_id FROM ?? Where tender_id = ' + tenderId;
  432. const sqlParam = ['ledger_id', this.tableName];
  433. const queryResult = await this.db.queryOne(sql, sqlParam);
  434. return queryResult.max_id;
  435. }
  436. /**
  437. * 根据selectData, data 新增数据(新增为selectData的后项,该方法不可单独使用)
  438. *
  439. * @param {Number} tenderId - 标段id
  440. * @param {Object} selectData - 选中节点的数据
  441. * @param {Object} data - 新增节点的初始数据
  442. * @return {Object} - 新增结果
  443. * @private
  444. */
  445. async _addNodeData(tenderId, selectData, data) {
  446. if (tenderId <= 0) {
  447. return undefined;
  448. }
  449. if (!data) {
  450. data = {};
  451. }
  452. const cacheKey = 'tender_node_maxId:' + tenderId;
  453. let maxId = parseInt(await this.cache.get(cacheKey));
  454. if (!maxId) {
  455. maxId = await this._getMaxNodeId(tenderId);
  456. this.cache.set(cacheKey, maxId, 'EX', this.ctx.app.config.cacheTime);
  457. }
  458. data.tender_id = tenderId;
  459. data.ledger_id = maxId + 1;
  460. data.ledger_pid = selectData.ledger_pid;
  461. data.level = selectData.level;
  462. data.order = selectData.order + 1;
  463. data.full_path = selectData.full_path.replace('.' + selectData.ledger_id, '.' + data.ledger_id);
  464. data.is_leaf = true;
  465. const result = await this.transaction.insert(this.tableName, data);
  466. this.cache.set(cacheKey, maxId + 1, 'EX', this.ctx.app.config.cacheTime);
  467. return result;
  468. }
  469. /**
  470. * 根据parentData, data新增数据(新增为parentData的最后一个子项)
  471. * @param {Number} tenderId - 标段id
  472. * @param {Object} parentData - 父项数据
  473. * @param {Object} data - 新增节点,初始数据
  474. * @returns {Promise<*>} - 新增结果
  475. * @private
  476. */
  477. async _addChildNodeData(tenderId, parentData, data) {
  478. if (tenderId <= 0) {
  479. return undefined;
  480. }
  481. if (!data) {
  482. data = {};
  483. }
  484. const pid = parentData ? parentData.ledger_id : rootId;
  485. const cacheKey = 'tender_node_maxId: ' + tenderId;
  486. let maxId = parseInt(await this.cache.get(cacheKey));
  487. if (!maxId) {
  488. maxId = await this._getMaxNodeId(tenderId);
  489. this.cache.set(cacheKey, maxId, 'EX', this.ctx.app.config.cacheTime);
  490. }
  491. data.tender_id = tenderId;
  492. data.ledger_id = maxId + 1;
  493. data.ledger_pid = pid;
  494. if (data.order === undefined) {
  495. data.order = 1;
  496. }
  497. data.level = parentData ? parentData.level + 1 : 1;
  498. data.full_path = parentData ? parentData.full_path + '.' + data.ledger_id : '' + data.ledger_id;
  499. if (data.is_leaf === undefined) {
  500. data.is_leaf = true;
  501. }
  502. const result = await this.transaction.insert(this.tableName, data);
  503. this.cache.set(cacheKey, maxId + 1, 'EX', this.ctx.app.config.cacheTime);
  504. return [result, data];
  505. }
  506. /**
  507. * 根据parentData, data新增数据(自动排序)
  508. * @param tenderId
  509. * @param parentData
  510. * @param data
  511. * @returns {Promise<void>}
  512. * @private
  513. */
  514. async _addChildAutoOrder(tenderId, parentData, data) {
  515. const self = this;
  516. const findPreData = function (list, a) {
  517. if (!list || list.length === 0) { return null; }
  518. for (let i = 0, iLen = list.length; i < iLen; i++) {
  519. if (self.ctx.helper.compareCode(list[i].code, a.code) > 0) {
  520. return i > 0 ? list[i-1] : null;
  521. }
  522. }
  523. return list[list.length -1];
  524. }
  525. const pid = parentData ? parentData.ledger_id : rootId;
  526. const children = await this.getChildrenByParentId(tenderId, pid);
  527. const preData = findPreData(children, data);
  528. let parent = null;
  529. if (!preData || children.indexOf(preData) < children.length - 1) {
  530. await this._updateChildrenOrderAfter(tenderId, pid, preData ? preData.order + 1 : 1);
  531. }
  532. data.order = preData ? preData.order + 1 : 1;
  533. const [addResult, node] = await this._addChildNodeData(tenderId, parentData, data);
  534. return [addResult, node];
  535. }
  536. /**
  537. * tenderId标段中, 在selectId后新增一个节点
  538. *
  539. * @param {Number} tenderId - 标段id
  540. * @param {Number} selectId - 选中节点id
  541. * @param {Object} data - 新增节点初始化数据
  542. * @return {Array} 新增后的数据,其他被修改的数据
  543. */
  544. async addNode(tenderId, selectId, data) {
  545. if ((tenderId <= 0) || (selectId <= 0)) {
  546. return [];
  547. }
  548. const selectData = await this.getDataByNodeId(tenderId, selectId);
  549. if (!selectData) {
  550. throw '新增节点数据错误';
  551. }
  552. if (!this.transaction) {
  553. this.transaction = await this.db.beginTransaction();
  554. }
  555. try {
  556. // 选中节点的所有后兄弟节点,order+1
  557. await this._updateSelectNextsOrder(selectData);
  558. // 数据库创建新增节点数据
  559. const newNode = await this._addNodeData(tenderId, selectData, data);
  560. if (!newNode) { throw '新增节点数据错误'; }
  561. await this.transaction.commit();
  562. } catch (err) {
  563. await this.transaction.rollback();
  564. this.transaction = null;
  565. throw err;
  566. }
  567. this.transaction = null;
  568. // 查询应返回的结果
  569. const createData = await this.getDataByParentAndOrder(selectData.tender_id, selectData.ledger_pid, [selectData.order + 1]);
  570. const updateData = await this.getNextsData(selectData.tender_id, selectData.ledger_pid, selectData.order + 1);
  571. return { create: createData, update: updateData };
  572. }
  573. /**
  574. * 从标准数据中提取有效数据
  575. * @param {Object} stdData - 从标准库中查询所得
  576. * @returns {name, unit, source, code, b_code}
  577. * @private
  578. */
  579. _filterStdData(stdData) {
  580. const result = {
  581. name: stdData.name,
  582. unit: stdData.unit,
  583. source: stdData.source
  584. }
  585. result.code = stdData.code ? stdData.code : '';
  586. result.b_code = stdData.b_code ? stdData.b_code : '';
  587. return result;
  588. }
  589. /**
  590. * 添加节点(来自标准清单)
  591. * @param {Number} tenderId
  592. * @param {Number} selectId
  593. * @param {Object} stdData
  594. * @returns {Promise<*>}
  595. */
  596. async addStdNode(tenderId, selectId, stdData) {
  597. const newData = this.filterStdData(stdData);
  598. const result = await this.addNode(tenderId, selectId, newData);
  599. return result;
  600. }
  601. /**
  602. * 添加节点,并同步添加父节点
  603. * @param {Number} tenderId - 标段id
  604. * @param {Number} selectId - 选中节点id
  605. * @param {Object} stdData - 节点数据
  606. * @param {StandardLib} stdLib - 标准库
  607. * @returns {Promise<void>}
  608. */
  609. async addStdNodeWithParent(tenderId, stdData, stdLib) {
  610. const fullLevel = await stdLib.getFullLevelDataByFullPath(stdData.list_id, stdData.full_path);
  611. fullLevel.sort(function (x, y) {
  612. return x.level - y.level
  613. });
  614. let isNew = false, node, firstNew, updateParent, addResult;
  615. const expandIds = [];
  616. this.transaction = await this.db.beginTransaction();
  617. try {
  618. for (let i = 0, len = fullLevel.length; i < len; i++) {
  619. const stdNode = fullLevel[i];
  620. if (isNew) {
  621. const newData = this._filterStdData(stdNode);
  622. newData.is_leaf = (i === len - 1);
  623. [addResult, node] = await this._addChildNodeData(tenderId, node, newData);
  624. } else {
  625. const parent = node;
  626. node = await this.getDataByCondition({
  627. tender_id: tenderId,
  628. ledger_pid: parent ? parent.ledger_id : rootId,
  629. code: stdNode.code,
  630. name: stdNode.name
  631. });
  632. if (!node) {
  633. isNew = true;
  634. const newData = this._filterStdData(stdNode);
  635. newData.is_leaf = (i === len - 1);
  636. [addResult, node] = await this._addChildAutoOrder(tenderId, parent, newData);
  637. if (parent && parent.is_leaf) {
  638. await this.transaction.update(this.tableName, {id: parent.id, is_leaf: false} );
  639. updateParent = parent;
  640. }
  641. firstNew = node;
  642. } else {
  643. expandIds.push(node.ledger_id);
  644. }
  645. }
  646. }
  647. this.transaction.commit();
  648. } catch (err) {
  649. await this.transaction.rollback();
  650. throw err;
  651. }
  652. // 查询应返回的结果
  653. let createData = [], updateData = [];
  654. if (firstNew) {
  655. createData = await this.getDataByFullPath(tenderId, firstNew.full_path + '%');
  656. updateData = await this.getNextsData(tenderId, firstNew.ledger_pid, firstNew.order);
  657. if (updateParent) {
  658. updateData.push(await this.getDataByCondition({id: updateParent.id}));
  659. }
  660. }
  661. const expandData = await this.getChildrenByParentId(tenderId, expandIds);
  662. return { create: createData, update: updateData, expand: expandData };
  663. }
  664. /**
  665. * 删除节点
  666. * @param {Number} tenderId - 标段id
  667. * @param {Object} deleteData - 删除节点数据
  668. * @returns {Promise<*>}
  669. * @private
  670. */
  671. async _deleteNodeData(tenderId, deleteData) {
  672. this.initSqlBuilder();
  673. this.sqlBuilder.setAndWhere('tender_id', {
  674. value: tenderId,
  675. operate: '=',
  676. });
  677. this.sqlBuilder.setAndWhere('full_path', {
  678. value: this.db.escape(deleteData.full_path + '%'),
  679. operate: 'Like',
  680. });
  681. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'delete');
  682. const result = await this.transaction.query(sql, sqlParam);
  683. return result;
  684. }
  685. /**
  686. * tenderId标段中, 删除选中节点及其子节点
  687. *
  688. * @param {Number} tenderId - 标段id
  689. * @param {Number} selectId - 选中节点id
  690. * @return {Array} - 被删除的数据
  691. */
  692. async deleteNode(tenderId, selectId) {
  693. if ((tenderId <= 0) || (selectId <= 0)) {
  694. return [];
  695. }
  696. const selectData = await this.getDataByNodeId(tenderId, selectId);
  697. if (!selectData) {
  698. throw '删除节点数据错误';
  699. }
  700. const parentData = await this.getDataByNodeId(tenderId, selectData.ledger_pid);
  701. this.transaction = await this.db.beginTransaction();
  702. let deleteData = [];
  703. try {
  704. // 获取将要被删除的数据
  705. deleteData = await this.getDataByFullPath(tenderId, selectData.full_path + '%');
  706. // 删除
  707. const operate = await this._deleteNodeData(tenderId, selectData);
  708. // 选中节点--父节点 只有一个子节点时,应升级is_leaf
  709. if (parentData) {
  710. const count = this.db.count(this.tableName, { ledger_pid: selectData.ledger_pid });
  711. if (count === 1) {
  712. await this.transaction.update(this.tableName, { id: parentData.id, is_leaf: true });
  713. }
  714. }
  715. // 选中节点--全部后节点 order--
  716. await this._updateSelectNextsOrder(selectData, -1);
  717. // 更新父项金额
  718. if (this.ctx.helper.checkZero(selectData.total_price)) {
  719. const parentFullPath = selectData.full_path.replace('.' + selectData.ledger_id, '');
  720. const updateMap = {};
  721. updateMap[parentFullPath] = -selectData.total_price;
  722. await this._increCalcParent(tenderId, updateMap);
  723. }
  724. await this.transaction.commit();
  725. } catch (err) {
  726. deleteData = [];
  727. await this.transaction.rollback();
  728. throw err;
  729. }
  730. // 查询结果
  731. let updateData = [];
  732. if (deleteData.length > 0) {
  733. updateData = await this.getNextsData(tenderId, selectData.ledger_pid, selectData.order - 1);
  734. updateData = updateData ? updateData : [];
  735. const updateData1 = await this.getDataByNodeId(tenderId, selectData.ledger_pid);
  736. if (this.ctx.helper.checkZero(selectData.total_price)) {
  737. const updateData2 = await this.getFullLevelDataByFullPath(tenderId, updateData1.full_path);
  738. updateData = updateData.concat(updateData2);
  739. } else if (updateData1.is_leaf !== parentData.is_leaf) {
  740. updateData.push(updateData1);
  741. }
  742. }
  743. return { delete: deleteData, update: updateData };
  744. }
  745. /**
  746. * tenderId标段中, 选中节点selectId上移
  747. *
  748. * @param {Number} tenderId - 标段id
  749. * @param {Number} selectId - 选中节点id
  750. * @return {Array} - 发生改变的数据
  751. */
  752. async upMoveNode(tenderId, selectId) {
  753. if ((tenderId <= 0) || (selectId <= 0)) {
  754. return [];
  755. }
  756. const selectData = await this.getDataByNodeId(tenderId, selectId);
  757. if (!selectData) {
  758. throw '上移节点数据错误';
  759. }
  760. const preData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, selectData.order - 1);
  761. if (!preData) {
  762. throw '节点不可上移';
  763. }
  764. this.transaction = await this.db.beginTransaction();
  765. try {
  766. const sData = await this.transaction.update(this.tableName, { id: selectData.id, order: selectData.order - 1 });
  767. const pData = await this.transaction.update(this.tableName, { id: preData.id, order: preData.order + 1 });
  768. this.transaction.commit();
  769. } catch (err) {
  770. await this.transaction.rollback();
  771. throw err;
  772. }
  773. const resultData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, [selectData.order, preData.order]);
  774. return { update: resultData };
  775. }
  776. /**
  777. * tenderId标段中, 选中节点selectId下移
  778. *
  779. * @param {Number} tenderId - 标段id
  780. * @param {Number} selectId - 选中节点id
  781. * @return {Array} - 发生改变的数据
  782. */
  783. async downMoveNode(tenderId, selectId) {
  784. if ((tenderId <= 0) || (selectId <= 0)) {
  785. return [];
  786. }
  787. const selectData = await this.getDataByNodeId(tenderId, selectId);
  788. if (!selectData) {
  789. throw '下移节点数据错误';
  790. }
  791. const nextData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, selectData.order + 1);
  792. if (!nextData) {
  793. throw '节点不可下移';
  794. }
  795. this.transaction = await this.db.beginTransaction();
  796. try {
  797. const sData = await this.transaction.update(this.tableName, { id: selectData.id, order: selectData.order + 1 });
  798. const pData = await this.transaction.update(this.tableName, { id: nextData.id, order: nextData.order - 1 });
  799. this.transaction.commit();
  800. } catch (err) {
  801. await this.transaction.rollback();
  802. throw err;
  803. }
  804. const resultData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, [selectData.order, nextData.order]);
  805. return { update: resultData };
  806. }
  807. /**
  808. * 升级selectData, 同步修改所有子节点
  809. * @param {Object} selectData - 升级操作,选中节点
  810. * @return {Object}
  811. * @private
  812. */
  813. async _syncUplevelChildren(selectData) {
  814. this.initSqlBuilder();
  815. this.sqlBuilder.setAndWhere('tender_id', {
  816. value: selectData.tender_id,
  817. operate: '=',
  818. });
  819. this.sqlBuilder.setAndWhere('full_path', {
  820. value: this.db.escape(selectData.full_path + '.%'),
  821. operate: 'like',
  822. });
  823. this.sqlBuilder.setUpdateData('level', {
  824. value: 1,
  825. selfOperate: '-',
  826. });
  827. this.sqlBuilder.setUpdateData('full_path', {
  828. value: ['`full_path`', this.db.escape(selectData.ledger_pid + '.'), this.db.escape('')],
  829. literal: 'Replace',
  830. });
  831. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  832. const data = this.transaction.query(sql, sqlParam);
  833. return data;
  834. }
  835. /**
  836. * 选中节点的后兄弟节点,全部变为当前节点的子节点
  837. * @param {Object} selectData - 选中节点
  838. * @return {Object}
  839. * @private
  840. */
  841. async _syncUpLevelNexts(selectData) {
  842. // 查询selectData的lastChild
  843. const lastChildData = await this.getLastChildData(selectData.tender_id, selectData.ledger_id);
  844. const nextsData = await this.getNextsData(selectData.tender_id, selectData.ledger_pid, selectData.order);
  845. if (nextsData && nextsData.length > 0) {
  846. // 修改nextsData pid, 排序
  847. this.initSqlBuilder();
  848. this.sqlBuilder.setUpdateData('ledger_pid', {
  849. value: selectData.ledger_id,
  850. });
  851. const orderInc = lastChildData ? lastChildData.order - selectData.order : -selectData.order;
  852. this.sqlBuilder.setUpdateData('order', {
  853. value: Math.abs(orderInc),
  854. selfOperate: orderInc > 0 ? '+' : '-',
  855. });
  856. this.sqlBuilder.setAndWhere('ledger_pid', {
  857. value: selectData.ledger_pid,
  858. operate: '=',
  859. });
  860. this.sqlBuilder.setAndWhere('order', {
  861. value: selectData.order,
  862. operate: '>',
  863. });
  864. const [sql1, sqlParam1] = this.sqlBuilder.build(this.tableName, 'update');
  865. await this.transaction.query(sql1, sqlParam1);
  866. // 选中节点 is_leaf应为false
  867. if (selectData.is_leaf) {
  868. const updateData = { id: selectData.id,
  869. is_leaf: false,
  870. };
  871. await this.transaction.update(this.tableName, updateData);
  872. }
  873. // 修改nextsData及其子节点的full_path
  874. const oldSubStr = this.db.escape(selectData.ledger_pid + '.');
  875. const newSubStr = this.db.escape(selectData.ledger_id + '.');
  876. const sqlArr = [];
  877. sqlArr.push('Update ?? SET `full_path` = Replace(`full_path`,' + oldSubStr + ',' + newSubStr + ') Where');
  878. sqlArr.push('(`tender_id` = ' + selectData.tender_id + ')');
  879. sqlArr.push(' And (');
  880. for (const data of nextsData) {
  881. sqlArr.push('`full_path` Like ' + this.db.escape(data.full_path + '%'));
  882. if (nextsData.indexOf(data) < nextsData.length - 1) {
  883. sqlArr.push(' Or ');
  884. }
  885. }
  886. sqlArr.push(')');
  887. const sql = sqlArr.join('');
  888. const resultData = await this.transaction.query(sql, [this.tableName]);
  889. return resultData;
  890. }
  891. }
  892. /**
  893. * 升级节点
  894. *
  895. * @param {Number} tenderId - 标段id
  896. * @param {Number} selectId - 选中节点id
  897. * @return {Array} - 发生改变的数据
  898. */
  899. async upLevelNode(tenderId, selectId) {
  900. if ((tenderId <= 0) || (selectId <= 0)) {
  901. return [];
  902. }
  903. const selectData = await this.getDataByNodeId(tenderId, selectId);
  904. if (!selectData) {
  905. throw '升级节点数据错误';
  906. }
  907. const parentData = await this.getDataByNodeId(tenderId, selectData.ledger_pid);
  908. if (!parentData) {
  909. throw '升级节点数据错误';
  910. }
  911. this.transaction = await this.db.beginTransaction();
  912. const newFullPath = selectData.full_path.replace(selectData.ledger_pid + '.', '');
  913. try {
  914. // 选中节点--父节点 选中节点为firstChild时,修改is_leaf
  915. if (selectData.order === 1) {
  916. this.transaction.update(this.tableName, {
  917. id: parentData.id,
  918. is_leaf: true,
  919. total_price: 0
  920. });
  921. } else {
  922. this.transaction.update(this.tableName, {
  923. id: parentData.id,
  924. total_price: await this.addUpChildren(tenderId, selectData.ledger_pid, selectData.order, '<')
  925. });
  926. }
  927. // 选中节点--父节点--全部后兄弟节点 order+1
  928. await this._updateSelectNextsOrder(parentData);
  929. // 选中节点 修改pid, order, full_path
  930. let totalPrice = selectData.total_price ? selectData.total_price : 0;
  931. const plus = await this.addUpChildren(tenderId, selectData.ledger_pid, selectData.order, '>');
  932. totalPrice = plus ? totalPrice + plus : totalPrice;
  933. const updateData = { id: selectData.id,
  934. ledger_pid: parentData.ledger_pid,
  935. order: parentData.order + 1,
  936. level: selectData.level - 1,
  937. full_path: newFullPath,
  938. total_price: totalPrice
  939. };
  940. await this.transaction.update(this.tableName, updateData);
  941. // 选中节点--全部子节点(含孙) level-1, full_path变更
  942. await this._syncUplevelChildren(selectData);
  943. // 选中节点--全部后兄弟节点 收编为子节点 修改pid, order, full_path
  944. await this._syncUpLevelNexts(selectData);
  945. this.transaction.commit();
  946. } catch (err) {
  947. await this.transaction.rollback();
  948. throw err;
  949. }
  950. // 查询修改的数据
  951. const resultData1 = await this.getDataByFullPath(tenderId, newFullPath + '%');
  952. const resultData2 = await this.getNextsData(tenderId, parentData.ledger_pid, parentData.order + 1);
  953. // 默认原Parent被刷新过,不核对total_price修改
  954. const preParent = await this.getDataByNodeId(tenderId, parentData.ledger_id);
  955. resultData2.push(preParent);
  956. return { update: resultData1.concat(resultData2) };
  957. }
  958. /**
  959. * 降级selectData, 同步修改所有子节点
  960. * @param {Object} selectData - 选中节点
  961. * @param {Object} preData - 选中节点的前一节点(降级后为父节点)
  962. * @return {Promise<*>}
  963. * @private
  964. */
  965. async _syncDownlevelChildren(selectData, preData) {
  966. this.initSqlBuilder();
  967. this.sqlBuilder.setAndWhere('tender_id', {
  968. value: selectData.tender_id,
  969. operate: '=',
  970. });
  971. this.sqlBuilder.setAndWhere('full_path', {
  972. value: this.db.escape(selectData.full_path + '.%'),
  973. operate: 'like',
  974. });
  975. this.sqlBuilder.setUpdateData('level', {
  976. value: 1,
  977. selfOperate: '+',
  978. });
  979. this.sqlBuilder.setUpdateData('full_path', {
  980. value: ['`full_path`', this.db.escape('.' + selectData.ledger_id), this.db.escape('.' + preData.ledger_id + '.' + selectData.ledger_id)],
  981. literal: 'Replace',
  982. });
  983. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  984. const data = this.transaction.query(sql, sqlParam);
  985. return data;
  986. }
  987. /**
  988. * 降级节点
  989. *
  990. * @param {Number} tenderId - 标段id
  991. * @param {Number} selectId - 选中节点id
  992. * @return {Array} - 发生改变的数据
  993. */
  994. async downLevelNode(tenderId, selectId) {
  995. if ((tenderId <= 0) || (selectId <= 0)) {
  996. return [];
  997. }
  998. const selectData = await this.getDataByNodeId(tenderId, selectId);
  999. if (!selectData) {
  1000. throw '降级节点数据错误';
  1001. }
  1002. const preData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, selectData.order - 1);
  1003. if (!preData) {
  1004. throw '节点不可降级';
  1005. }
  1006. const preLastChildData = await this.getLastChildData(tenderId, preData.ledger_id);
  1007. this.transaction = await this.db.beginTransaction();
  1008. const orgLastPath = selectData.level === 1 ? selectData.ledger_id : '.' + selectData.ledger_id;
  1009. const newLastPath = selectData.level === 1 ? preData.ledger_id + '.' + selectData.ledger_id : '.' + preData.ledger_id + '.' + selectData.ledger_id;
  1010. const newFullPath = selectData.full_path.replace(orgLastPath, newLastPath);
  1011. try {
  1012. // 选中节点--全部后节点 order--
  1013. await this._updateSelectNextsOrder(selectData, -1);
  1014. // 选中节点 修改pid, level, order, full_path
  1015. const updateData = {
  1016. id: selectData.id,
  1017. ledger_pid: preData.ledger_id,
  1018. order: preLastChildData ? preLastChildData.order + 1 : 1,
  1019. level: selectData.level + 1,
  1020. full_path: newFullPath,
  1021. };
  1022. await this.transaction.update(this.tableName, updateData);
  1023. // 选中节点--全部子节点(含孙) level++, full_path
  1024. await this._syncDownlevelChildren(selectData, preData);
  1025. // 选中节点--前兄弟节点 is_leaf应为false
  1026. if (preData.is_leaf || this.ctx.helper.checkZero(selectData.total_price)) {
  1027. const updateData2 = {
  1028. id: preData.id,
  1029. is_leaf: false
  1030. };
  1031. if (this.ctx.helper.checkZero(selectData.total_price)) {
  1032. updateData2['total_price'] = preData.total_price ? preData.total_price + selectData.total_price : selectData.total_price;
  1033. }
  1034. await this.transaction.update(this.tableName, updateData2);
  1035. }
  1036. this.transaction.commit();
  1037. } catch (err) {
  1038. this.transaction.rollback();
  1039. throw err;
  1040. }
  1041. // 查询修改的数据
  1042. // 选中节点及子节点
  1043. const resultData1 = await this.getDataByFullPath(tenderId, newFullPath + '%');
  1044. // 选中节点--原前兄弟节点&全部后兄弟节点
  1045. const queryOrder = (preData.is_leaf || this.ctx.helper.checkZero(selectData.total_price)) ? preData.order - 1 : preData.order;
  1046. const resultData2 = await this.getNextsData(tenderId, preData.ledger_pid, queryOrder);
  1047. return { update: resultData1.concat(resultData2) };
  1048. }
  1049. /**
  1050. * 过滤data中update方式不可提交的字段
  1051. * @param {Number} id - 主键key
  1052. * @param {Object} data
  1053. * @return {Object<{id: *}>}
  1054. * @private
  1055. */
  1056. _filterUpdateInvalidField(id, data) {
  1057. const result = {
  1058. id,
  1059. };
  1060. for (const prop in data) {
  1061. if (readOnlyFields.indexOf(prop) === -1) {
  1062. result[prop] = data[prop];
  1063. }
  1064. }
  1065. return result;
  1066. }
  1067. /**
  1068. * newData中,以orgData为基准,过滤掉orgData中未定义或值相等的部分
  1069. * @param {Object} orgData
  1070. * @param {Object} newData
  1071. * @private
  1072. */
  1073. _filterChangedField(orgData, newData) {
  1074. const result= {};
  1075. let bChanged = false;
  1076. for (const prop in orgData) {
  1077. if (newData[prop] && newData[prop] !== orgData[prop]) {
  1078. result[prop] = newData[prop];
  1079. bChanged = true;
  1080. }
  1081. }
  1082. return bChanged ? result : undefined;
  1083. }
  1084. /**
  1085. * 检查data中是否含有计算字段
  1086. * @param {Object} data
  1087. * @returns {boolean}
  1088. * @private
  1089. */
  1090. _checkCalcField(data) {
  1091. for (const prop in data) {
  1092. if (calcFields.indexOf(prop) >= 0) {
  1093. return true;
  1094. }
  1095. }
  1096. return false;
  1097. }
  1098. /**
  1099. * 提交数据 - 不影响计算等未提交项
  1100. * @param {Number} tenderId - 标段id
  1101. * @param {Object} data - 提交数据
  1102. * @return {Object} - 提交后的数据
  1103. */
  1104. async updateInfo(tenderId, data) {
  1105. // 简单校验数据
  1106. if (tenderId <= 0) {
  1107. throw '标段不存在';
  1108. }
  1109. if (tenderId !== data.tender_id) {
  1110. throw '提交数据错误';
  1111. }
  1112. try {
  1113. // 过滤不可提交字段
  1114. const updateNode = await this.getDataById(data.id);
  1115. if (!updateNode || tenderId !== updateNode.tender_id || data.ledger_id !== updateNode.ledger_id) {
  1116. throw '提交数据错误';
  1117. }
  1118. const updateData = this._filterUpdateInvalidField(updateNode.id, data);
  1119. await this.db.update(this.tableName, updateData);
  1120. } catch (err) {
  1121. throw err;
  1122. }
  1123. const result = await this.getDataByNodeId(tenderId, data.ledger_id);
  1124. return result;
  1125. }
  1126. /**
  1127. * 提交多条数据 - 不影响计算等未提交项
  1128. * @param {Number} tenderId - 标段id
  1129. * @param {Array} datas - 提交数据
  1130. * @return {Array} - 提交后的数据
  1131. */
  1132. async updateInfos(tenderId, datas) {
  1133. if (tenderId <= 0) {
  1134. throw '标段不存在';
  1135. }
  1136. for (const data of datas) {
  1137. if (tenderId !== data.tender_id) {
  1138. throw '提交数据错误';
  1139. }
  1140. }
  1141. this.transaction = await this.db.beginTransaction();
  1142. try {
  1143. for (const data of datas) {
  1144. const updateNode = await this.getDataById(data.id);
  1145. if (!updateNode || tenderId !== updateNode.tender_id || data.ledger_id !== updateNode.ledger_id) {
  1146. throw '提交数据错误';
  1147. }
  1148. const updateData = this._filterUpdateInvalidField(updateNode.id, data);
  1149. await this.transaction.update(this.tableName, updateData);
  1150. }
  1151. this.transaction.commit();
  1152. } catch (err) {
  1153. this.transaction.rollback();
  1154. throw err;
  1155. }
  1156. const filter = [];
  1157. for (const data of datas) {
  1158. filter.push(data.id);
  1159. }
  1160. this.initSqlBuilder();
  1161. this.sqlBuilder.setAndWhere('id', {
  1162. value: filter,
  1163. operate: 'in',
  1164. });
  1165. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  1166. const resultData = await this.db.query(sql, sqlParam);
  1167. return resultData;
  1168. }
  1169. /**
  1170. * 复制粘贴整块
  1171. * @param {Number} tenderId - 标段Id
  1172. * @param {Number} selectId - 选中几点Id
  1173. * @param {Array} block - 复制节点Id
  1174. * @return {Object} - 提价后的数据(其中新增粘贴数据,只返回第一层)
  1175. */
  1176. async pasteBlock(tenderId, selectId, block) {
  1177. if ((tenderId <= 0) || (selectId <= 0)) {
  1178. return [];
  1179. }
  1180. const selectData = await this.getDataByNodeId(tenderId, selectId);
  1181. if (!selectData) {
  1182. throw '位置数据错误';
  1183. }
  1184. const newParentPath = selectData.full_path.replace(selectData.ledger_id, '');
  1185. const copyNodes = await this.getDataByNodeIds(tenderId, block);
  1186. if (!copyNodes || copyNodes.length <= 0) {
  1187. throw '复制数据错误';
  1188. }
  1189. let bSameParent = true;
  1190. for (const node of copyNodes) {
  1191. if (node.ledger_pid !== copyNodes[0].ledger_pid) {
  1192. bSameParent = false;
  1193. break;
  1194. }
  1195. }
  1196. if (!bSameParent) {
  1197. throw '复制数据错误:仅可操作同层节点';
  1198. }
  1199. const orgParentPath = copyNodes[0].full_path.replace(copyNodes[0].ledger_id, '');
  1200. let incre = 0;
  1201. this.transaction = await this.db.beginTransaction();
  1202. try {
  1203. // 选中节点的所有后兄弟节点,order+粘贴节点个数
  1204. await this._updateSelectNextsOrder(selectData, copyNodes.length);
  1205. // 数据库创建新增节点数据
  1206. for (const node of copyNodes) {
  1207. incre += node.total_price ? node.total_price : 0;
  1208. const datas = await this.getDataByFullPath(tenderId, node.full_path + '%');
  1209. const cacheKey = 'tender_node_maxId:' + tenderId;
  1210. let maxId = parseInt(await this.cache.get(cacheKey));
  1211. if (!maxId) {
  1212. maxId = await this._getMaxNodeId(tenderId);
  1213. }
  1214. this.cache.set(cacheKey, maxId + datas.length, 'EX', this.ctx.app.config.cacheTime);
  1215. // 计算粘贴数据中需更新部分
  1216. for (let index = 0; index < datas.length; index++) {
  1217. const data = datas[index];
  1218. const newId = maxId + index + 1;
  1219. delete data.id;
  1220. if (!data.is_leaf) {
  1221. for (const children of datas) {
  1222. children.full_path = children.full_path.replace('.' + data.ledger_id, '.' + newId);
  1223. if (children.ledger_pid === data.ledger_id) {
  1224. children.ledger_pid = newId;
  1225. }
  1226. }
  1227. } else {
  1228. data.full_path = data.full_path.replace('.' + data.ledger_id, '.' + newId);
  1229. }
  1230. data.ledger_id = newId;
  1231. data.full_path = data.full_path.replace(orgParentPath, newParentPath);
  1232. if (data.ledger_pid === copyNodes[0].ledger_pid) {
  1233. data.ledger_pid = selectData.ledger_pid;
  1234. data.order = selectData.order + index + 1;
  1235. }
  1236. data.level = data.level + selectData.level - copyNodes[0].level;
  1237. }
  1238. // 插入粘贴数据
  1239. await this.transaction.insert(this.tableName, datas);
  1240. }
  1241. // 更新父节点金额
  1242. if (this.ctx.helper.checkZero(incre)) {
  1243. const updateMap = {};
  1244. updateMap[newParentPath] = incre;
  1245. await this._increCalcParent(tenderId, updateMap);
  1246. }
  1247. await this.transaction.commit();
  1248. } catch (err) {
  1249. await this.transaction.rollback();
  1250. throw err;
  1251. }
  1252. // 查询应返回的结果
  1253. const order = [];
  1254. for (let i = 1; i <= copyNodes.length; i++) {
  1255. order.push(selectData.order + i);
  1256. }
  1257. const createData = await this.getDataByParentAndOrder(selectData.tender_id, selectData.ledger_pid, order);
  1258. const updateData = await this.getNextsData(selectData.tender_id, selectData.ledger_pid, selectData.order + copyNodes.length);
  1259. if (this.ctx.helper.checkZero(incre)) {
  1260. const updateData1 = await this.getFullLevelDataByFullPath(selectData.tender_id, newParentPath);
  1261. return { create: createData, update: updateData.concat(updateData1) };
  1262. } else {
  1263. return { create: createData, update: updateData };
  1264. }
  1265. }
  1266. /**
  1267. * 增量更新父项金额
  1268. * @param {Number} tenderId - 标段id
  1269. * @param {Object} updateMap - 增量更新数,使用更新父项的full_path为索引
  1270. * e.g: {'1.2.6.8': 30, '1.2.6.10': 40}表示'1.2.6.8'增量30,'1.2.6.10'增量40(此处同步更新'1.2.6', '1.2', '1')
  1271. * @returns {Promise<void>}
  1272. * @private
  1273. */
  1274. async _increCalcParent(tenderId, updateMap) {
  1275. for (const prop in updateMap) {
  1276. this.initSqlBuilder();
  1277. this.sqlBuilder.setAndWhere('tender_id', {
  1278. value: tenderId,
  1279. operate: '='
  1280. });
  1281. const fullPath = this.ctx.helper.explodePath(prop);
  1282. this.sqlBuilder.setAndWhere('full_path', {
  1283. value: this.ctx.helper.explodePath(prop),
  1284. operate: 'in'
  1285. });
  1286. this.sqlBuilder.setUpdateData('total_price', {
  1287. value: updateMap[prop] > 0 ? updateMap[prop] : -updateMap[prop],
  1288. selfOperate: updateMap[prop] > 0 ? '+' : '-'
  1289. });
  1290. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  1291. await this.transaction.query(sql, sqlParam);
  1292. }
  1293. }
  1294. /**
  1295. * 提交数据 - 响应计算(增量方式计算)
  1296. * @param {Number} tenderId
  1297. * @param {Object} data
  1298. * @returns {Promise<*>}
  1299. */
  1300. async updateCalc(tenderId, data) {
  1301. const findData = function (id, datas) {
  1302. for (const d of datas) {
  1303. if (d.id === id) {
  1304. return d;
  1305. }
  1306. }
  1307. return undefined;
  1308. }
  1309. // 简单验证数据
  1310. if (tenderId <= 0) {
  1311. throw '标段不存在';
  1312. }
  1313. if (!data) {
  1314. throw '提交数据错误1';
  1315. }
  1316. const datas = data instanceof Array ? data : [data];
  1317. const ids = [];
  1318. for (const row of datas) {
  1319. if (tenderId !== row.tender_id) {
  1320. throw '提交数据错误2';
  1321. }
  1322. ids.push(row.id);
  1323. }
  1324. const updateMap = {}, updateFullPath = [];
  1325. this.transaction = await this.db.beginTransaction();
  1326. try {
  1327. for (const row of datas) {
  1328. const updateNode = await this.getDataById(row.id);
  1329. if (!updateNode || tenderId !== updateNode.tender_id || row.ledger_id !== updateNode.ledger_id) {
  1330. throw '提交数据错误3';
  1331. }
  1332. let updateData;
  1333. if (this._checkCalcField(row)) {
  1334. const calcData = this.ctx.helper.updateObj(updateNode, row);
  1335. if (updateNode.is_leaf) {
  1336. calcData.total_price = calcData.quantity * calcData.unit_price;
  1337. }
  1338. if (updateNode.total_price === undefined || this.ctx.helper.checkZero(calcData.total_price - updateNode.total_price)) {
  1339. const pfp = updateNode.full_path.replace('.' + updateNode.ledger_id, '');
  1340. if (updateMap[pfp]) {
  1341. updateMap[pfp] = updateMap[pfp] + calcData.total_price - updateNode.total_price;
  1342. } else {
  1343. updateMap[pfp] = calcData.total_price - updateNode.total_price;
  1344. updateFullPath.push(pfp);
  1345. }
  1346. }
  1347. const data1 = this._filterChangedField(updateNode, calcData);
  1348. updateData = this._filterUpdateInvalidField(updateNode.id, data1);
  1349. } else {
  1350. updateData = this._filterUpdateInvalidField(updateNode.id, row);
  1351. }
  1352. await this.transaction.update(this.tableName, updateData);
  1353. }
  1354. await this._increCalcParent(tenderId, updateMap);
  1355. this.transaction.commit();
  1356. } catch (err) {
  1357. this.transaction.rollback();
  1358. throw err;
  1359. }
  1360. const result1 = await this.getDataByIds(ids);
  1361. if (updateFullPath.length > 0) {
  1362. const result2 = await this.getFullLevelDataByFullPath(tenderId, updateFullPath);
  1363. return result1.concat(result2);
  1364. } else {
  1365. return result1;
  1366. }
  1367. }
  1368. }
  1369. return Ledger;
  1370. };