ledger.js 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652
  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. await this.transaction.commit();
  85. } catch (error) {
  86. await 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 = await 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. await 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 = await this.db.count(this.tableName, { tender_id: tenderId, 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 = await 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. await 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 '提交数据错误';
  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 '提交数据错误';
  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 '提交数据错误';
  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. *
  1372. * @param tenderId
  1373. * @param xmj
  1374. * @param order
  1375. * @param parentData
  1376. * @returns {Promise<*[]>}
  1377. * @private
  1378. */
  1379. async _sortBatchInsertData(tenderId, xmj, order, parentData) {
  1380. const result = [], newIds = [];
  1381. let tp = 0;
  1382. const cacheKey = 'tender_node_maxId:' + tenderId;
  1383. let maxId = parseInt(await this.cache.get(cacheKey));
  1384. if (!maxId) {
  1385. maxId = await this._getMaxNodeId(tenderId);
  1386. }
  1387. this.cache.set(cacheKey, maxId + xmj.children.length + 1, 'EX', this.ctx.app.config.cacheTime);
  1388. // 添加xmj数据
  1389. const parent = {
  1390. tender_id: tenderId,
  1391. ledger_id: maxId + 1,
  1392. ledger_pid: parentData.ledger_id,
  1393. is_leaf: false,
  1394. order: order,
  1395. level: parentData.level + 1,
  1396. name: xmj.name,
  1397. };
  1398. parent.full_path = parentData.full_path + '.' + parent.ledger_id;
  1399. // 添加gcl数据
  1400. for (let i = 0, iLen = xmj.children.length; i < iLen; i++) {
  1401. const gcl = xmj.children[i];
  1402. const child = {
  1403. tender_id: tenderId,
  1404. ledger_id: maxId + 1 + i + 1,
  1405. ledger_pid: parent.ledger_id,
  1406. is_leaf: true,
  1407. order: i+1,
  1408. level: parent.level + 1,
  1409. b_code: gcl.b_code,
  1410. name: gcl.name,
  1411. unit: gcl.unit,
  1412. unit_price: gcl.unit_price,
  1413. quantity: gcl.quantity,
  1414. };
  1415. child.full_path = parent.full_path + '.' + child.ledger_id;
  1416. child.total_price = child.unit_price * child.quantity;
  1417. tp = tp + child.total_price;
  1418. result.push(child);
  1419. newIds.push(child.ledger_id);
  1420. }
  1421. parent.total_price = tp;
  1422. result.push(parent);
  1423. newIds.push(parent.ledger_id);
  1424. return [result, tp, newIds];
  1425. }
  1426. /**
  1427. * 批量插入子项
  1428. * @param {Number} tenderId - 标段Id
  1429. * @param {Number} selectId - 选中节点Id
  1430. * @param {Object} data - 批量插入数据
  1431. * @returns {Promise<void>}
  1432. */
  1433. async batchInsertChild(tenderId, selectId, data) {
  1434. if ((tenderId <= 0) || (selectId <= 0)) {
  1435. return [];
  1436. }
  1437. const selectData = await this.getDataByNodeId(tenderId, selectId);
  1438. if (!selectData) {
  1439. throw '位置数据错误';
  1440. }
  1441. this.transaction = await this.db.beginTransaction();
  1442. let incre = 0, newIds = [];
  1443. try {
  1444. const lastChild = await this.getLastChildData(tenderId, selectId);
  1445. if (!lastChild) {
  1446. await this.transaction.update(this.tableName, {
  1447. id: selectData.id,
  1448. is_leaf: false,
  1449. });
  1450. }
  1451. const order = lastChild ? lastChild.order : 0;
  1452. // 数据库创建新增节点数据
  1453. for (let i = 0, iLen = data.length; i < iLen; i++) {
  1454. const xmj = data[i];
  1455. const [insertData, tp, ids] = await this._sortBatchInsertData(tenderId, xmj, order + i + 1, selectData);
  1456. incre = incre + tp;
  1457. newIds = newIds.concat(ids);
  1458. await this.transaction.insert(this.tableName, insertData);
  1459. }
  1460. // 更新父节点金额
  1461. if (this.ctx.helper.checkZero(incre)) {
  1462. const updateMap = {};
  1463. updateMap[selectData.full_path] = incre;
  1464. await this._increCalcParent(tenderId, updateMap);
  1465. }
  1466. await this.transaction.commit();
  1467. } catch(err) {
  1468. await this.transaction.rollback();
  1469. throw err;
  1470. }
  1471. // 查询应返回的结果
  1472. const createData = await this.getDataByNodeIds(selectData.tender_id, newIds);
  1473. if (this.ctx.helper.checkZero(incre) || selectData.is_leaf) {
  1474. const updateData = await this.getFullLevelDataByFullPath(selectData.tender_id, selectData.full_path);
  1475. return { create: createData, update: updateData };
  1476. } else {
  1477. return { create: createData };
  1478. }
  1479. }
  1480. /**
  1481. * 批量插入后项
  1482. * @param {Number} tenderId - 标段Id
  1483. * @param {Number} selectId - 选中节点Id
  1484. * @param {Object} data - 批量插入数据
  1485. * @returns {Promise<void>}
  1486. */
  1487. async batchInsertNext(tenderId, selectId, data) {
  1488. if ((tenderId <= 0) || (selectId <= 0)) {
  1489. return [];
  1490. }
  1491. const selectData = await this.getDataByNodeId(tenderId, selectId);
  1492. if (!selectData) {
  1493. throw '位置数据错误';
  1494. }
  1495. const parentData = await this.getDataByNodeId(tenderId, selectData.ledger_pid);
  1496. if (!parentData) {
  1497. throw '位置数据错误';
  1498. }
  1499. this.transaction = await this.db.beginTransaction();
  1500. let incre = 0, newIds = [];
  1501. try {
  1502. // 选中节点的所有后兄弟节点,order+粘贴节点个数
  1503. await this._updateSelectNextsOrder(selectData, data.length);
  1504. const order = selectData.order;
  1505. // 数据库创建新增节点数据
  1506. for (let i = 0, iLen = data.length; i < iLen; i++) {
  1507. const xmj = data[i];
  1508. const [insertData, tp, ids] = await this._sortBatchInsertData(tenderId, xmj, order + i + 1, parentData);
  1509. incre = incre + tp;
  1510. newIds = newIds.concat(ids);
  1511. await this.transaction.insert(this.tableName, insertData);
  1512. }
  1513. // 更新父节点金额
  1514. if (this.ctx.helper.checkZero(incre)) {
  1515. const updateMap = {};
  1516. updateMap[parentData.full_path] = incre;
  1517. await this._increCalcParent(tenderId, updateMap);
  1518. }
  1519. await this.transaction.commit();
  1520. } catch(err) {
  1521. await this.transaction.rollback();
  1522. throw err;
  1523. }
  1524. // 查询应返回的结果
  1525. const createData = await this.getDataByNodeIds(parentData.tender_id, newIds);
  1526. const updateData = await this.getNextsData(selectData.tender_id, selectData.ledger_pid, selectData.order + data.length);
  1527. if (this.ctx.helper.checkZero(incre)) {
  1528. const updateData1 = await this.getFullLevelDataByFullPath(tenderId, parentData.full_path);
  1529. return { create: createData, update: updateData.concat(updateData1) };
  1530. } else {
  1531. return { create: createData, update: updateData };
  1532. }
  1533. }
  1534. }
  1535. return Ledger;
  1536. };