ledger.js 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479
  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. if (selectData.ledger_pid !== rootId) {
  736. const updateData1 = await this.getDataByNodeId(tenderId, selectData.ledger_pid);
  737. if (this.ctx.helper.checkZero(selectData.total_price)) {
  738. const updateData2 = await this.getFullLevelDataByFullPath(tenderId, updateData1.full_path);
  739. updateData = updateData.concat(updateData2);
  740. } else if (updateData1.is_leaf !== parentData.is_leaf) {
  741. updateData.push(updateData1);
  742. }
  743. }
  744. }
  745. return { delete: deleteData, update: updateData };
  746. }
  747. /**
  748. * tenderId标段中, 选中节点selectId上移
  749. *
  750. * @param {Number} tenderId - 标段id
  751. * @param {Number} selectId - 选中节点id
  752. * @return {Array} - 发生改变的数据
  753. */
  754. async upMoveNode(tenderId, selectId) {
  755. if ((tenderId <= 0) || (selectId <= 0)) {
  756. return [];
  757. }
  758. const selectData = await this.getDataByNodeId(tenderId, selectId);
  759. if (!selectData) {
  760. throw '上移节点数据错误';
  761. }
  762. const preData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, selectData.order - 1);
  763. if (!preData) {
  764. throw '节点不可上移';
  765. }
  766. this.transaction = await this.db.beginTransaction();
  767. try {
  768. const sData = await this.transaction.update(this.tableName, { id: selectData.id, order: selectData.order - 1 });
  769. const pData = await this.transaction.update(this.tableName, { id: preData.id, order: preData.order + 1 });
  770. await this.transaction.commit();
  771. } catch (err) {
  772. await this.transaction.rollback();
  773. throw err;
  774. }
  775. const resultData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, [selectData.order, preData.order]);
  776. return { update: resultData };
  777. }
  778. /**
  779. * tenderId标段中, 选中节点selectId下移
  780. *
  781. * @param {Number} tenderId - 标段id
  782. * @param {Number} selectId - 选中节点id
  783. * @return {Array} - 发生改变的数据
  784. */
  785. async downMoveNode(tenderId, selectId) {
  786. if ((tenderId <= 0) || (selectId <= 0)) {
  787. return [];
  788. }
  789. const selectData = await this.getDataByNodeId(tenderId, selectId);
  790. if (!selectData) {
  791. throw '下移节点数据错误';
  792. }
  793. const nextData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, selectData.order + 1);
  794. if (!nextData) {
  795. throw '节点不可下移';
  796. }
  797. this.transaction = await this.db.beginTransaction();
  798. try {
  799. const sData = await this.transaction.update(this.tableName, { id: selectData.id, order: selectData.order + 1 });
  800. const pData = await this.transaction.update(this.tableName, { id: nextData.id, order: nextData.order - 1 });
  801. await this.transaction.commit();
  802. } catch (err) {
  803. await this.transaction.rollback();
  804. throw err;
  805. }
  806. const resultData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, [selectData.order, nextData.order]);
  807. return { update: resultData };
  808. }
  809. /**
  810. * 升级selectData, 同步修改所有子节点
  811. * @param {Object} selectData - 升级操作,选中节点
  812. * @return {Object}
  813. * @private
  814. */
  815. async _syncUplevelChildren(selectData) {
  816. this.initSqlBuilder();
  817. this.sqlBuilder.setAndWhere('tender_id', {
  818. value: selectData.tender_id,
  819. operate: '=',
  820. });
  821. this.sqlBuilder.setAndWhere('full_path', {
  822. value: this.db.escape(selectData.full_path + '.%'),
  823. operate: 'like',
  824. });
  825. this.sqlBuilder.setUpdateData('level', {
  826. value: 1,
  827. selfOperate: '-',
  828. });
  829. this.sqlBuilder.setUpdateData('full_path', {
  830. value: ['`full_path`', this.db.escape(selectData.ledger_pid + '.'), this.db.escape('')],
  831. literal: 'Replace',
  832. });
  833. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  834. const data = this.transaction.query(sql, sqlParam);
  835. return data;
  836. }
  837. /**
  838. * 选中节点的后兄弟节点,全部变为当前节点的子节点
  839. * @param {Object} selectData - 选中节点
  840. * @return {Object}
  841. * @private
  842. */
  843. async _syncUpLevelNexts(selectData) {
  844. // 查询selectData的lastChild
  845. const lastChildData = await this.getLastChildData(selectData.tender_id, selectData.ledger_id);
  846. const nextsData = await this.getNextsData(selectData.tender_id, selectData.ledger_pid, selectData.order);
  847. if (nextsData && nextsData.length > 0) {
  848. // 修改nextsData pid, 排序
  849. this.initSqlBuilder();
  850. this.sqlBuilder.setUpdateData('ledger_pid', {
  851. value: selectData.ledger_id,
  852. });
  853. const orderInc = lastChildData ? lastChildData.order - selectData.order : -selectData.order;
  854. this.sqlBuilder.setUpdateData('order', {
  855. value: Math.abs(orderInc),
  856. selfOperate: orderInc > 0 ? '+' : '-',
  857. });
  858. this.sqlBuilder.setAndWhere('ledger_pid', {
  859. value: selectData.ledger_pid,
  860. operate: '=',
  861. });
  862. this.sqlBuilder.setAndWhere('order', {
  863. value: selectData.order,
  864. operate: '>',
  865. });
  866. const [sql1, sqlParam1] = this.sqlBuilder.build(this.tableName, 'update');
  867. await this.transaction.query(sql1, sqlParam1);
  868. // 选中节点 is_leaf应为false
  869. if (selectData.is_leaf) {
  870. const updateData = { id: selectData.id,
  871. is_leaf: false,
  872. };
  873. await this.transaction.update(this.tableName, updateData);
  874. }
  875. // 修改nextsData及其子节点的full_path
  876. const oldSubStr = this.db.escape(selectData.ledger_pid + '.');
  877. const newSubStr = this.db.escape(selectData.ledger_id + '.');
  878. const sqlArr = [];
  879. sqlArr.push('Update ?? SET `full_path` = Replace(`full_path`,' + oldSubStr + ',' + newSubStr + ') Where');
  880. sqlArr.push('(`tender_id` = ' + selectData.tender_id + ')');
  881. sqlArr.push(' And (');
  882. for (const data of nextsData) {
  883. sqlArr.push('`full_path` Like ' + this.db.escape(data.full_path + '%'));
  884. if (nextsData.indexOf(data) < nextsData.length - 1) {
  885. sqlArr.push(' Or ');
  886. }
  887. }
  888. sqlArr.push(')');
  889. const sql = sqlArr.join('');
  890. const resultData = await this.transaction.query(sql, [this.tableName]);
  891. return resultData;
  892. }
  893. }
  894. /**
  895. * 升级节点
  896. *
  897. * @param {Number} tenderId - 标段id
  898. * @param {Number} selectId - 选中节点id
  899. * @return {Array} - 发生改变的数据
  900. */
  901. async upLevelNode(tenderId, selectId) {
  902. if ((tenderId <= 0) || (selectId <= 0)) {
  903. return [];
  904. }
  905. const selectData = await this.getDataByNodeId(tenderId, selectId);
  906. if (!selectData) {
  907. throw '升级节点数据错误';
  908. }
  909. const parentData = await this.getDataByNodeId(tenderId, selectData.ledger_pid);
  910. if (!parentData) {
  911. throw '升级节点数据错误';
  912. }
  913. this.transaction = await this.db.beginTransaction();
  914. const newFullPath = selectData.full_path.replace(selectData.ledger_pid + '.', '');
  915. try {
  916. // 选中节点--父节点 选中节点为firstChild时,修改is_leaf
  917. if (selectData.order === 1) {
  918. await this.transaction.update(this.tableName, {
  919. id: parentData.id,
  920. is_leaf: true,
  921. total_price: 0
  922. });
  923. } else {
  924. await this.transaction.update(this.tableName, {
  925. id: parentData.id,
  926. total_price: await this.addUpChildren(tenderId, selectData.ledger_pid, selectData.order, '<')
  927. });
  928. }
  929. // 选中节点--父节点--全部后兄弟节点 order+1
  930. await this._updateSelectNextsOrder(parentData);
  931. // 选中节点 修改pid, order, full_path
  932. let totalPrice = selectData.total_price ? selectData.total_price : 0;
  933. const plus = await this.addUpChildren(tenderId, selectData.ledger_pid, selectData.order, '>');
  934. totalPrice = plus ? totalPrice + plus : totalPrice;
  935. const updateData = { id: selectData.id,
  936. ledger_pid: parentData.ledger_pid,
  937. order: parentData.order + 1,
  938. level: selectData.level - 1,
  939. full_path: newFullPath,
  940. total_price: totalPrice
  941. };
  942. await this.transaction.update(this.tableName, updateData);
  943. // 选中节点--全部子节点(含孙) level-1, full_path变更
  944. await this._syncUplevelChildren(selectData);
  945. // 选中节点--全部后兄弟节点 收编为子节点 修改pid, order, full_path
  946. await this._syncUpLevelNexts(selectData);
  947. this.transaction.commit();
  948. } catch (err) {
  949. await this.transaction.rollback();
  950. throw err;
  951. }
  952. // 查询修改的数据
  953. const resultData1 = await this.getDataByFullPath(tenderId, newFullPath + '%');
  954. const resultData2 = await this.getNextsData(tenderId, parentData.ledger_pid, parentData.order + 1);
  955. // 默认原Parent被刷新过,不核对total_price修改
  956. const preParent = await this.getDataByNodeId(tenderId, parentData.ledger_id);
  957. resultData2.push(preParent);
  958. return { update: resultData1.concat(resultData2) };
  959. }
  960. /**
  961. * 降级selectData, 同步修改所有子节点
  962. * @param {Object} selectData - 选中节点
  963. * @param {Object} preData - 选中节点的前一节点(降级后为父节点)
  964. * @return {Promise<*>}
  965. * @private
  966. */
  967. async _syncDownlevelChildren(selectData, preData) {
  968. this.initSqlBuilder();
  969. this.sqlBuilder.setAndWhere('tender_id', {
  970. value: selectData.tender_id,
  971. operate: '=',
  972. });
  973. this.sqlBuilder.setAndWhere('full_path', {
  974. value: this.db.escape(selectData.full_path + '.%'),
  975. operate: 'like',
  976. });
  977. this.sqlBuilder.setUpdateData('level', {
  978. value: 1,
  979. selfOperate: '+',
  980. });
  981. this.sqlBuilder.setUpdateData('full_path', {
  982. value: ['`full_path`', this.db.escape('.' + selectData.ledger_id), this.db.escape('.' + preData.ledger_id + '.' + selectData.ledger_id)],
  983. literal: 'Replace',
  984. });
  985. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  986. const data = await this.transaction.query(sql, sqlParam);
  987. return data;
  988. }
  989. /**
  990. * 降级节点
  991. *
  992. * @param {Number} tenderId - 标段id
  993. * @param {Number} selectId - 选中节点id
  994. * @return {Array} - 发生改变的数据
  995. */
  996. async downLevelNode(tenderId, selectId) {
  997. if ((tenderId <= 0) || (selectId <= 0)) {
  998. return [];
  999. }
  1000. const selectData = await this.getDataByNodeId(tenderId, selectId);
  1001. if (!selectData) {
  1002. throw '降级节点数据错误';
  1003. }
  1004. const preData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, selectData.order - 1);
  1005. if (!preData) {
  1006. throw '节点不可降级';
  1007. }
  1008. const preLastChildData = await this.getLastChildData(tenderId, preData.ledger_id);
  1009. this.transaction = await this.db.beginTransaction();
  1010. const orgLastPath = selectData.level === 1 ? selectData.ledger_id : '.' + selectData.ledger_id;
  1011. const newLastPath = selectData.level === 1 ? preData.ledger_id + '.' + selectData.ledger_id : '.' + preData.ledger_id + '.' + selectData.ledger_id;
  1012. const newFullPath = selectData.full_path.replace(orgLastPath, newLastPath);
  1013. try {
  1014. // 选中节点--全部后节点 order--
  1015. await this._updateSelectNextsOrder(selectData, -1);
  1016. // 选中节点 修改pid, level, order, full_path
  1017. const updateData = {
  1018. id: selectData.id,
  1019. ledger_pid: preData.ledger_id,
  1020. order: preLastChildData ? preLastChildData.order + 1 : 1,
  1021. level: selectData.level + 1,
  1022. full_path: newFullPath,
  1023. };
  1024. await this.transaction.update(this.tableName, updateData);
  1025. // 选中节点--全部子节点(含孙) level++, full_path
  1026. await this._syncDownlevelChildren(selectData, preData);
  1027. // 选中节点--前兄弟节点 is_leaf应为false
  1028. if (preData.is_leaf || this.ctx.helper.checkZero(selectData.total_price)) {
  1029. const updateData2 = {
  1030. id: preData.id,
  1031. is_leaf: false
  1032. };
  1033. if (this.ctx.helper.checkZero(selectData.total_price)) {
  1034. updateData2['total_price'] = preData.total_price ? preData.total_price + selectData.total_price : selectData.total_price;
  1035. }
  1036. await this.transaction.update(this.tableName, updateData2);
  1037. }
  1038. await this.transaction.commit();
  1039. } catch (err) {
  1040. await this.transaction.rollback();
  1041. throw err;
  1042. }
  1043. // 查询修改的数据
  1044. // 选中节点及子节点
  1045. const resultData1 = await this.getDataByFullPath(tenderId, newFullPath + '%');
  1046. // 选中节点--原前兄弟节点&全部后兄弟节点
  1047. const queryOrder = (preData.is_leaf || this.ctx.helper.checkZero(selectData.total_price)) ? preData.order - 1 : preData.order;
  1048. const resultData2 = await this.getNextsData(tenderId, preData.ledger_pid, queryOrder);
  1049. return { update: resultData1.concat(resultData2) };
  1050. }
  1051. /**
  1052. * 过滤data中update方式不可提交的字段
  1053. * @param {Number} id - 主键key
  1054. * @param {Object} data
  1055. * @return {Object<{id: *}>}
  1056. * @private
  1057. */
  1058. _filterUpdateInvalidField(id, data) {
  1059. const result = {
  1060. id,
  1061. };
  1062. for (const prop in data) {
  1063. if (readOnlyFields.indexOf(prop) === -1) {
  1064. result[prop] = data[prop];
  1065. }
  1066. }
  1067. return result;
  1068. }
  1069. /**
  1070. * newData中,以orgData为基准,过滤掉orgData中未定义或值相等的部分
  1071. * @param {Object} orgData
  1072. * @param {Object} newData
  1073. * @private
  1074. */
  1075. _filterChangedField(orgData, newData) {
  1076. const result= {};
  1077. let bChanged = false;
  1078. for (const prop in orgData) {
  1079. if (newData[prop] && newData[prop] !== orgData[prop]) {
  1080. result[prop] = newData[prop];
  1081. bChanged = true;
  1082. }
  1083. }
  1084. return bChanged ? result : undefined;
  1085. }
  1086. /**
  1087. * 检查data中是否含有计算字段
  1088. * @param {Object} data
  1089. * @returns {boolean}
  1090. * @private
  1091. */
  1092. _checkCalcField(data) {
  1093. for (const prop in data) {
  1094. if (calcFields.indexOf(prop) >= 0) {
  1095. return true;
  1096. }
  1097. }
  1098. return false;
  1099. }
  1100. /**
  1101. * 提交数据 - 不影响计算等未提交项
  1102. * @param {Number} tenderId - 标段id
  1103. * @param {Object} data - 提交数据
  1104. * @return {Object} - 提交后的数据
  1105. */
  1106. async updateInfo(tenderId, data) {
  1107. // 简单校验数据
  1108. if (tenderId <= 0) {
  1109. throw '标段不存在';
  1110. }
  1111. if (tenderId !== data.tender_id) {
  1112. throw '提交数据错误';
  1113. }
  1114. try {
  1115. // 过滤不可提交字段
  1116. const updateNode = await this.getDataById(data.id);
  1117. if (!updateNode || tenderId !== updateNode.tender_id || data.ledger_id !== updateNode.ledger_id) {
  1118. throw '提交数据错误';
  1119. }
  1120. const updateData = this._filterUpdateInvalidField(updateNode.id, data);
  1121. await this.db.update(this.tableName, updateData);
  1122. } catch (err) {
  1123. throw err;
  1124. }
  1125. const result = await this.getDataByNodeId(tenderId, data.ledger_id);
  1126. return result;
  1127. }
  1128. /**
  1129. * 提交多条数据 - 不影响计算等未提交项
  1130. * @param {Number} tenderId - 标段id
  1131. * @param {Array} datas - 提交数据
  1132. * @return {Array} - 提交后的数据
  1133. */
  1134. async updateInfos(tenderId, datas) {
  1135. if (tenderId <= 0) {
  1136. throw '标段不存在';
  1137. }
  1138. for (const data of datas) {
  1139. if (tenderId !== data.tender_id) {
  1140. throw '提交数据错误';
  1141. }
  1142. }
  1143. this.transaction = await this.db.beginTransaction();
  1144. try {
  1145. for (const data of datas) {
  1146. const updateNode = await this.getDataById(data.id);
  1147. if (!updateNode || tenderId !== updateNode.tender_id || data.ledger_id !== updateNode.ledger_id) {
  1148. throw '提交数据错误';
  1149. }
  1150. const updateData = this._filterUpdateInvalidField(updateNode.id, data);
  1151. await this.transaction.update(this.tableName, updateData);
  1152. }
  1153. await this.transaction.commit();
  1154. } catch (err) {
  1155. await this.transaction.rollback();
  1156. throw err;
  1157. }
  1158. const filter = [];
  1159. for (const data of datas) {
  1160. filter.push(data.id);
  1161. }
  1162. this.initSqlBuilder();
  1163. this.sqlBuilder.setAndWhere('id', {
  1164. value: filter,
  1165. operate: 'in',
  1166. });
  1167. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  1168. const resultData = await this.db.query(sql, sqlParam);
  1169. return resultData;
  1170. }
  1171. /**
  1172. * 复制粘贴整块
  1173. * @param {Number} tenderId - 标段Id
  1174. * @param {Number} selectId - 选中几点Id
  1175. * @param {Array} block - 复制节点Id
  1176. * @return {Object} - 提价后的数据(其中新增粘贴数据,只返回第一层)
  1177. */
  1178. async pasteBlock(tenderId, selectId, block) {
  1179. if ((tenderId <= 0) || (selectId <= 0)) {
  1180. return [];
  1181. }
  1182. const selectData = await this.getDataByNodeId(tenderId, selectId);
  1183. if (!selectData) {
  1184. throw '位置数据错误';
  1185. }
  1186. const newParentPath = selectData.full_path.replace(selectData.ledger_id, '');
  1187. const copyNodes = await this.getDataByNodeIds(tenderId, block);
  1188. if (!copyNodes || copyNodes.length <= 0) {
  1189. throw '复制数据错误';
  1190. }
  1191. let bSameParent = true;
  1192. for (const node of copyNodes) {
  1193. if (node.ledger_pid !== copyNodes[0].ledger_pid) {
  1194. bSameParent = false;
  1195. break;
  1196. }
  1197. }
  1198. if (!bSameParent) {
  1199. throw '复制数据错误:仅可操作同层节点';
  1200. }
  1201. const orgParentPath = copyNodes[0].full_path.replace(copyNodes[0].ledger_id, '');
  1202. let incre = 0;
  1203. this.transaction = await this.db.beginTransaction();
  1204. try {
  1205. // 选中节点的所有后兄弟节点,order+粘贴节点个数
  1206. await this._updateSelectNextsOrder(selectData, copyNodes.length);
  1207. // 数据库创建新增节点数据
  1208. for (const node of copyNodes) {
  1209. incre += node.total_price ? node.total_price : 0;
  1210. const datas = await this.getDataByFullPath(tenderId, node.full_path + '%');
  1211. const cacheKey = 'tender_node_maxId:' + tenderId;
  1212. let maxId = parseInt(await this.cache.get(cacheKey));
  1213. if (!maxId) {
  1214. maxId = await this._getMaxNodeId(tenderId);
  1215. }
  1216. this.cache.set(cacheKey, maxId + datas.length, 'EX', this.ctx.app.config.cacheTime);
  1217. // 计算粘贴数据中需更新部分
  1218. for (let index = 0; index < datas.length; index++) {
  1219. const data = datas[index];
  1220. const newId = maxId + index + 1;
  1221. delete data.id;
  1222. if (!data.is_leaf) {
  1223. for (const children of datas) {
  1224. children.full_path = children.full_path.replace('.' + data.ledger_id, '.' + newId);
  1225. if (children.ledger_pid === data.ledger_id) {
  1226. children.ledger_pid = newId;
  1227. }
  1228. }
  1229. } else {
  1230. data.full_path = data.full_path.replace('.' + data.ledger_id, '.' + newId);
  1231. }
  1232. data.ledger_id = newId;
  1233. data.full_path = data.full_path.replace(orgParentPath, newParentPath);
  1234. if (data.ledger_pid === copyNodes[0].ledger_pid) {
  1235. data.ledger_pid = selectData.ledger_pid;
  1236. data.order = selectData.order + index + 1;
  1237. }
  1238. data.level = data.level + selectData.level - copyNodes[0].level;
  1239. }
  1240. // 插入粘贴数据
  1241. await this.transaction.insert(this.tableName, datas);
  1242. }
  1243. // 更新父节点金额
  1244. if (this.ctx.helper.checkZero(incre)) {
  1245. const updateMap = {};
  1246. updateMap[newParentPath] = incre;
  1247. await this._increCalcParent(tenderId, updateMap);
  1248. }
  1249. await this.transaction.commit();
  1250. } catch (err) {
  1251. await this.transaction.rollback();
  1252. throw err;
  1253. }
  1254. // 查询应返回的结果
  1255. const order = [];
  1256. for (let i = 1; i <= copyNodes.length; i++) {
  1257. order.push(selectData.order + i);
  1258. }
  1259. const createData = await this.getDataByParentAndOrder(selectData.tender_id, selectData.ledger_pid, order);
  1260. const updateData = await this.getNextsData(selectData.tender_id, selectData.ledger_pid, selectData.order + copyNodes.length);
  1261. if (this.ctx.helper.checkZero(incre)) {
  1262. const updateData1 = await this.getFullLevelDataByFullPath(selectData.tender_id, newParentPath);
  1263. return { create: createData, update: updateData.concat(updateData1) };
  1264. } else {
  1265. return { create: createData, update: updateData };
  1266. }
  1267. }
  1268. /**
  1269. * 增量更新父项金额
  1270. * @param {Number} tenderId - 标段id
  1271. * @param {Object} updateMap - 增量更新数,使用更新父项的full_path为索引
  1272. * 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')
  1273. * @returns {Promise<void>}
  1274. * @private
  1275. */
  1276. async _increCalcParent(tenderId, updateMap) {
  1277. for (const prop in updateMap) {
  1278. this.initSqlBuilder();
  1279. this.sqlBuilder.setAndWhere('tender_id', {
  1280. value: tenderId,
  1281. operate: '='
  1282. });
  1283. const fullPath = this.ctx.helper.explodePath(prop);
  1284. this.sqlBuilder.setAndWhere('full_path', {
  1285. value: this.ctx.helper.explodePath(prop),
  1286. operate: 'in'
  1287. });
  1288. this.sqlBuilder.setUpdateData('total_price', {
  1289. value: updateMap[prop] > 0 ? updateMap[prop] : -updateMap[prop],
  1290. selfOperate: updateMap[prop] > 0 ? '+' : '-'
  1291. });
  1292. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  1293. await this.transaction.query(sql, sqlParam);
  1294. }
  1295. }
  1296. /**
  1297. * 提交数据 - 响应计算(增量方式计算)
  1298. * @param {Number} tenderId
  1299. * @param {Object} data
  1300. * @returns {Promise<*>}
  1301. */
  1302. async updateCalc(tenderId, data) {
  1303. const findData = function (id, datas) {
  1304. for (const d of datas) {
  1305. if (d.id === id) {
  1306. return d;
  1307. }
  1308. }
  1309. return undefined;
  1310. }
  1311. // 简单验证数据
  1312. if (tenderId <= 0) {
  1313. throw '标段不存在';
  1314. }
  1315. if (!data) {
  1316. throw '提交数据错误1';
  1317. }
  1318. const datas = data instanceof Array ? data : [data];
  1319. const ids = [];
  1320. for (const row of datas) {
  1321. if (tenderId !== row.tender_id) {
  1322. throw '提交数据错误2';
  1323. }
  1324. ids.push(row.id);
  1325. }
  1326. const updateMap = {}, updateFullPath = [];
  1327. this.transaction = await this.db.beginTransaction();
  1328. try {
  1329. for (const row of datas) {
  1330. const updateNode = await this.getDataById(row.id);
  1331. if (!updateNode || tenderId !== updateNode.tender_id || row.ledger_id !== updateNode.ledger_id) {
  1332. throw '提交数据错误3';
  1333. }
  1334. let updateData;
  1335. if (this._checkCalcField(row)) {
  1336. const calcData = this.ctx.helper.updateObj(updateNode, row);
  1337. if (updateNode.is_leaf) {
  1338. calcData.total_price = calcData.quantity * calcData.unit_price;
  1339. }
  1340. if (updateNode.total_price === undefined || this.ctx.helper.checkZero(calcData.total_price - updateNode.total_price)) {
  1341. const pfp = updateNode.full_path.replace('.' + updateNode.ledger_id, '');
  1342. if (updateMap[pfp]) {
  1343. updateMap[pfp] = updateMap[pfp] + calcData.total_price - updateNode.total_price;
  1344. } else {
  1345. updateMap[pfp] = calcData.total_price - updateNode.total_price;
  1346. updateFullPath.push(pfp);
  1347. }
  1348. }
  1349. const data1 = this._filterChangedField(updateNode, calcData);
  1350. updateData = this._filterUpdateInvalidField(updateNode.id, data1);
  1351. } else {
  1352. updateData = this._filterUpdateInvalidField(updateNode.id, row);
  1353. }
  1354. await this.transaction.update(this.tableName, updateData);
  1355. }
  1356. await this._increCalcParent(tenderId, updateMap);
  1357. await this.transaction.commit();
  1358. } catch (err) {
  1359. await this.transaction.rollback();
  1360. throw err;
  1361. }
  1362. const result1 = await this.getDataByIds(ids);
  1363. if (updateFullPath.length > 0) {
  1364. const result2 = await this.getFullLevelDataByFullPath(tenderId, updateFullPath);
  1365. return result1.concat(result2);
  1366. } else {
  1367. return result1;
  1368. }
  1369. }
  1370. }
  1371. return Ledger;
  1372. };