ledger.js 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001
  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. module.exports = app => {
  24. class Ledger extends app.BaseService {
  25. /**
  26. * 构造函数
  27. *
  28. * @param {Object} ctx - egg全局变量
  29. * @return {void}
  30. */
  31. constructor(ctx) {
  32. super(ctx);
  33. this.tableName = 'ledger';
  34. }
  35. /**
  36. * 新增数据
  37. *
  38. * @param {Object} data - 新增的数据(可批量)
  39. * @param {Number} tenderId - 标段id
  40. * @return {Boolean} - 返回新增的结果
  41. */
  42. async add(data, tenderId) {
  43. this.transaction = await this.db.beginTransaction();
  44. let result = false;
  45. try {
  46. if (tenderId <= 0) {
  47. throw '标段id错误';
  48. }
  49. if (data instanceof Array) {
  50. // 数组则为批量插入
  51. if (data.length <= 0) {
  52. throw '插入数据为空';
  53. }
  54. // 整理数据
  55. const insertData = [];
  56. for (const tmp of data) {
  57. tmp.ledger_id = tmp.id;
  58. tmp.ledger_pid = tmp.pid;
  59. tmp.tender_id = tenderId;
  60. delete tmp.id;
  61. delete tmp.pid;
  62. insertData.push(tmp);
  63. }
  64. const operate = await this.transaction.insert(this.tableName, insertData);
  65. this.transaction.commit();
  66. result = operate.affectedRows > 0;
  67. } else {
  68. // 对象则单个插入
  69. }
  70. } catch (error) {
  71. result = false;
  72. }
  73. return result;
  74. }
  75. /**
  76. * 根据层级获取数据
  77. *
  78. * @param {Number} tenderId - 标段id
  79. * @param {Number} showLevel - 显示层数
  80. * @return {Array} - 返回数据
  81. */
  82. async getDataByTenderId(tenderId, showLevel = 4) {
  83. if (tenderId <= 0) {
  84. return [];
  85. }
  86. this.initSqlBuilder();
  87. this.sqlBuilder.setAndWhere('tender_id', {
  88. value: tenderId,
  89. operate: '=',
  90. });
  91. if (showLevel > 0) {
  92. this.sqlBuilder.setAndWhere('level', {
  93. value: showLevel,
  94. operate: '<=',
  95. });
  96. }
  97. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  98. const data = await this.db.query(sql, sqlParam);
  99. return data;
  100. }
  101. /**
  102. * 根据节点Id获取数据
  103. *
  104. * @param {Number} tenderId - 标段id
  105. * @param {Number} nodeId - 项目节/工程量清单节点id
  106. * @return {Object} - 返回查询到的节点数据
  107. */
  108. async getDataByNodeId(tenderId, nodeId) {
  109. if ((nodeId <= 0) || (tenderId <= 0)) {
  110. return undefined;
  111. }
  112. this.initSqlBuilder();
  113. this.sqlBuilder.setAndWhere('tender_id', {
  114. value: tenderId,
  115. operate: '=',
  116. });
  117. this.sqlBuilder.setAndWhere('ledger_id', {
  118. value: nodeId,
  119. operate: '=',
  120. });
  121. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  122. const data = await this.db.queryOne(sql, sqlParam);
  123. return data;
  124. }
  125. /**
  126. * 根据节点Id获取数据
  127. * @param {Number} tenderId - 标段Id
  128. * @param {Array} nodesIds - 节点Id
  129. * @return {Array}
  130. */
  131. async getDataByNodeIds(tenderId, nodesIds) {
  132. if (tenderId <= 0) {
  133. return [];
  134. }
  135. this.initSqlBuilder();
  136. this.sqlBuilder.setAndWhere('tender_id', {
  137. value: tenderId,
  138. operate: '=',
  139. });
  140. this.sqlBuilder.setAndWhere('ledger_id', {
  141. value: nodesIds,
  142. operate: 'in',
  143. });
  144. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  145. const data = await this.db.query(sql, sqlParam);
  146. return data;
  147. }
  148. /**
  149. * 获取最末的子节点
  150. * @param {Number} tenderId - 标段id
  151. * @param {Number} pid - 父节点id
  152. * @return {Object}
  153. */
  154. async getLastChildData(tenderId, pid) {
  155. this.initSqlBuilder();
  156. this.sqlBuilder.setAndWhere('tender_id', {
  157. value: tenderId,
  158. operate: '=',
  159. });
  160. this.sqlBuilder.setAndWhere('ledger_pid', {
  161. value: pid,
  162. operate: '=',
  163. });
  164. this.sqlBuilder.orderBy = [['order', 'DESC']];
  165. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  166. const resultData = this.db.queryOne(sql, sqlParam);
  167. return resultData;
  168. }
  169. /**
  170. * 根据 父节点id 和 节点排序order 获取数据
  171. *
  172. * @param {Number} tenderId - 标段id
  173. * @param {Number} pid - 父节点id
  174. * @param {Number|Array} order - 排序
  175. * @return {Object|Array} - 查询结果
  176. */
  177. async getDataByParentAndOrder(tenderId, pid, order) {
  178. if ((tenderId <= 0) || (pid <= 0) || (order <= 0)) {
  179. return undefined;
  180. }
  181. this.initSqlBuilder();
  182. this.sqlBuilder.setAndWhere('tender_id', {
  183. value: tenderId,
  184. operate: '=',
  185. });
  186. this.sqlBuilder.setAndWhere('ledger_pid', {
  187. value: pid,
  188. operate: '=',
  189. });
  190. if (order instanceof Array) {
  191. this.sqlBuilder.setAndWhere('order', {
  192. value: order,
  193. operate: 'in',
  194. });
  195. } else {
  196. this.sqlBuilder.setAndWhere('order', {
  197. value: order,
  198. operate: '=',
  199. });
  200. }
  201. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  202. let data;
  203. if (order instanceof Array) {
  204. data = await this.db.query(sql, sqlParam);
  205. } else {
  206. data = await this.db.queryOne(sql, sqlParam);
  207. }
  208. return data;
  209. }
  210. /**
  211. * 根据 父节点id 获取子节点
  212. * @param tenderId
  213. * @param nodeId
  214. * @return {Promise<*>}
  215. */
  216. async getChildrenByParentId(tenderId, nodeId) {
  217. if ((nodeId <= 0) || (tenderId <= 0)) {
  218. return undefined;
  219. }
  220. this.initSqlBuilder();
  221. this.sqlBuilder.setAndWhere('tender_id', {
  222. value: tenderId,
  223. operate: '=',
  224. });
  225. this.sqlBuilder.setAndWhere('ledger_pid', {
  226. value: nodeId,
  227. operate: '=',
  228. });
  229. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  230. const data = await this.db.query(sql, sqlParam);
  231. return data;
  232. }
  233. /**
  234. * 根据full_path获取数据 full_path Like ‘1.2.3%’(传参full_path = '1.2.3%')
  235. * @param {Number} tenderId - 标段id
  236. * @param {String} full_path - 路径
  237. * @return {Promise<void>}
  238. */
  239. async getDataByFullPath(tenderId, full_path) {
  240. this.initSqlBuilder();
  241. this.sqlBuilder.setAndWhere('tender_id', {
  242. value: tenderId,
  243. operate: '=',
  244. });
  245. this.sqlBuilder.setAndWhere('full_path', {
  246. value: this.db.escape(full_path),
  247. operate: 'Like',
  248. });
  249. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  250. const resultData = await this.db.query(sql, sqlParam);
  251. return resultData;
  252. }
  253. /**
  254. * 根据 父节点ID 和 节点排序order 获取全部后节点数据
  255. * @param {Number} tenderId - 标段id
  256. * @param {Number} pid - 父节点id
  257. * @param {Number} order - 排序
  258. * @return {Array}
  259. */
  260. async getNextsData(tenderId, pid, order) {
  261. if ((tenderId <= 0) || (pid <= 0) || (order <= 0)) {
  262. return undefined;
  263. }
  264. this.initSqlBuilder();
  265. this.sqlBuilder.setAndWhere('tender_id', {
  266. value: tenderId,
  267. operate: '=',
  268. });
  269. this.sqlBuilder.setAndWhere('ledger_pid', {
  270. value: pid,
  271. operate: '=',
  272. });
  273. this.sqlBuilder.setAndWhere('order', {
  274. value: order,
  275. operate: '>',
  276. });
  277. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  278. const data = await this.db.query(sql, sqlParam);
  279. return data;
  280. }
  281. /**
  282. * select的全部后兄弟节点,Order自增
  283. *
  284. * @param {Object} select - 选中的节点
  285. * @param {Number} incre - 自增值
  286. * @return {Array} - 自增后的数据
  287. * @private
  288. */
  289. async _updateSelectNextsOrder(select, incre = 1) {
  290. this.initSqlBuilder();
  291. this.sqlBuilder.setAndWhere('tender_id', {
  292. value: select.tender_id,
  293. operate: '=',
  294. });
  295. this.sqlBuilder.setAndWhere('order', {
  296. value: select.order + 1,
  297. operate: '>=',
  298. });
  299. this.sqlBuilder.setAndWhere('ledger_pid', {
  300. value: select.ledger_pid,
  301. operate: '=',
  302. });
  303. this.sqlBuilder.setUpdateData('order', {
  304. value: Math.abs(incre),
  305. selfOperate: incre > 0 ? '+' : '-',
  306. });
  307. // sql = update this.tableName set order = order + 1 where (tender_id = select.tender_id) && (pid = select.pid) && (order >= select.order+1)
  308. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  309. const data = await this.transaction.query(sql, sqlParam);
  310. return data;
  311. }
  312. /**
  313. * 从数据库获取标段的最大节点id
  314. *
  315. * @param {Number} tenderId - 标段id
  316. * @return {Number}
  317. * @private
  318. */
  319. async _getMaxNodeId(tenderId) {
  320. const sql = 'SELECT Max(??) As max_id FROM ?? Where tender_id = ' + tenderId;
  321. const sqlParam = ['ledger_id', this.tableName];
  322. const queryResult = await this.db.queryOne(sql, sqlParam);
  323. return queryResult.max_id;
  324. }
  325. /**
  326. * 根据selectData, data 新增数据
  327. *
  328. * @param {Number} tenderId - 标段id
  329. * @param {Object} selectData - 选中节点的数据
  330. * @param {Object} data - 新增节点的初始数据
  331. * @return {Object} - 新增结果
  332. * @private
  333. */
  334. async _addNodeData(tenderId, selectData, data) {
  335. if (tenderId <= 0) {
  336. return undefined;
  337. }
  338. if (!data) {
  339. data = {};
  340. }
  341. const cacheKey = 'tender_node_maxId:' + tenderId;
  342. let maxId = parseInt(await this.cache.get(cacheKey));
  343. if (!maxId) {
  344. maxId = await this._getMaxNodeId(tenderId);
  345. this.cache.set(cacheKey, maxId, 'EX', this.ctx.app.config.cacheTime);
  346. }
  347. data.tender_id = tenderId;
  348. data.ledger_id = maxId + 1;
  349. data.ledger_pid = selectData.ledger_pid;
  350. data.level = selectData.level;
  351. data.order = selectData.order + 1;
  352. data.full_path = selectData.full_path.replace(selectData.ledger_id, data.ledger_id);
  353. data.is_leaf = true;
  354. const result = await this.transaction.insert(this.tableName, data);
  355. this.cache.set(cacheKey, maxId + 1, 'EX', this.ctx.app.config.cacheTime);
  356. return result;
  357. }
  358. /**
  359. * tenderId标段中, 在selectId后新增一个节点
  360. *
  361. * @param {Number} tenderId - 标段id
  362. * @param {Number} selectId - 选中节点id
  363. * @param {Object} data - 新增节点初始化数据
  364. * @return {Array} 新增后的数据,其他被修改的数据
  365. */
  366. async addNode(tenderId, selectId, data) {
  367. if ((tenderId <= 0) || (selectId <= 0)) {
  368. return [];
  369. }
  370. const selectData = await this.getDataByNodeId(tenderId, selectId);
  371. if (!selectData) {
  372. throw '新增节点数据错误';
  373. }
  374. this.transaction = await this.db.beginTransaction();
  375. try {
  376. // 选中节点的所有后兄弟节点,order+1
  377. await this._updateSelectNextsOrder(selectData);
  378. // 数据库创建新增节点数据
  379. await this._addNodeData(tenderId, selectData, data);
  380. await this.transaction.commit();
  381. } catch (err) {
  382. await this.transaction.rollback();
  383. throw err;
  384. }
  385. // 查询应返回的结果
  386. const createData = await this.getDataByParentAndOrder(selectData.tender_id, selectData.ledger_pid, [selectData.order + 1]);
  387. const updateData = await this.getNextsData(selectData.tender_id, selectData.ledger_pid, selectData.order + 1);
  388. return { create: createData, update: updateData };
  389. }
  390. /**
  391. * tenderId标段中, 删除选中节点及其子节点
  392. *
  393. * @param {Number} tenderId - 标段id
  394. * @param {Number} selectId - 选中节点id
  395. * @return {Array} - 被删除的数据
  396. */
  397. async deleteNode(tenderId, selectId) {
  398. if ((tenderId <= 0) || (selectId <= 0)) {
  399. return [];
  400. }
  401. const selectData = await this.getDataByNodeId(tenderId, selectId);
  402. if (!selectData) {
  403. throw '删除节点数据错误';
  404. }
  405. const parentData = await this.getDataByNodeId(tenderId, selectData.ledger_pid);
  406. this.transaction = await this.db.beginTransaction();
  407. let deleteData = [];
  408. try {
  409. // 获取将要被删除的数据
  410. deleteData = await this.getDataByFullPath(tenderId, selectData.full_path + '%');
  411. // 删除
  412. this.initSqlBuilder();
  413. this.sqlBuilder.setAndWhere('tender_id', {
  414. value: tenderId,
  415. operate: '=',
  416. });
  417. this.sqlBuilder.setAndWhere('full_path', {
  418. value: this.db.escape(selectData.full_path + '%'),
  419. operate: 'Like',
  420. });
  421. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'delete');
  422. const operate = await this.transaction.query(sql, sqlParam);
  423. // 选中节点--父节点 只有一个子节点时,应升级is_leaf
  424. if (parentData) {
  425. const count = this.db.count(this.tableName, { ledger_pid: selectData.ledger_pid });
  426. if (count === 1) {
  427. await this.transaction.update({
  428. id: parentData.id,
  429. is_leaf: true,
  430. });
  431. }
  432. }
  433. // 选中节点--全部后节点 order--
  434. await this._updateSelectNextsOrder(selectData, -1);
  435. await this.transaction.commit();
  436. } catch (err) {
  437. deleteData = [];
  438. await this.transaction.rollback();
  439. throw err;
  440. }
  441. // 查询结果
  442. let updateData = [];
  443. if (deleteData.length > 0) {
  444. updateData = await this.getNextsData(tenderId, selectData.ledger_pid, selectData.order - 1);
  445. updateData = updateData ? updateData : [];
  446. const updateData2 = await this.getDataByNodeId(tenderId, selectData.ledger_pid);
  447. if (updateData2.is_leaf === parentData.is_leaf) {
  448. updateData.push(updateData2);
  449. }
  450. }
  451. return { delete: deleteData, update: updateData };
  452. }
  453. /**
  454. * tenderId标段中, 选中节点selectId上移
  455. *
  456. * @param {Number} tenderId - 标段id
  457. * @param {Number} selectId - 选中节点id
  458. * @return {Array} - 发生改变的数据
  459. */
  460. async upMoveNode(tenderId, selectId) {
  461. if ((tenderId <= 0) || (selectId <= 0)) {
  462. return [];
  463. }
  464. const selectData = await this.getDataByNodeId(tenderId, selectId);
  465. if (!selectData) {
  466. throw '上移节点数据错误';
  467. }
  468. const preData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, selectData.order - 1);
  469. if (!preData) {
  470. throw '节点不可上移';
  471. }
  472. this.transaction = await this.db.beginTransaction();
  473. try {
  474. const sData = await this.transaction.update(this.tableName, { id: selectData.id, order: selectData.order - 1 });
  475. const pData = await this.transaction.update(this.tableName, { id: preData.id, order: preData.order + 1 });
  476. this.transaction.commit();
  477. } catch (err) {
  478. await this.transaction.rollback();
  479. throw err;
  480. }
  481. const resultData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, [selectData.order, preData.order]);
  482. return { update: resultData };
  483. }
  484. /**
  485. * tenderId标段中, 选中节点selectId下移
  486. *
  487. * @param {Number} tenderId - 标段id
  488. * @param {Number} selectId - 选中节点id
  489. * @return {Array} - 发生改变的数据
  490. */
  491. async downMoveNode(tenderId, selectId) {
  492. if ((tenderId <= 0) || (selectId <= 0)) {
  493. return [];
  494. }
  495. const selectData = await this.getDataByNodeId(tenderId, selectId);
  496. if (!selectData) {
  497. throw '下移节点数据错误';
  498. }
  499. const nextData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, selectData.order + 1);
  500. if (!nextData) {
  501. throw '节点不可下移';
  502. }
  503. this.transaction = await this.db.beginTransaction();
  504. try {
  505. const sData = await this.transaction.update(this.tableName, { id: selectData.id, order: selectData.order + 1 });
  506. const pData = await this.transaction.update(this.tableName, { id: nextData.id, order: nextData.order - 1 });
  507. this.transaction.commit();
  508. } catch (err) {
  509. await this.transaction.rollback();
  510. throw err;
  511. }
  512. const resultData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, [selectData.order, nextData.order]);
  513. return { update: resultData };
  514. }
  515. /**
  516. * 升级selectData, 同步修改所有子节点
  517. * @param {Object} selectData - 升级操作,选中节点
  518. * @return {Object}
  519. * @private
  520. */
  521. async _syncUplevelChildren(selectData) {
  522. this.initSqlBuilder();
  523. this.sqlBuilder.setAndWhere('tender_id', {
  524. value: selectData.tender_id,
  525. operate: '=',
  526. });
  527. this.sqlBuilder.setAndWhere('full_path', {
  528. value: this.db.escape(selectData.full_path + '.%'),
  529. operate: 'like',
  530. });
  531. this.sqlBuilder.setUpdateData('level', {
  532. value: 1,
  533. selfOperate: '-',
  534. });
  535. this.sqlBuilder.setUpdateData('full_path', {
  536. value: ['`full_path`', this.db.escape(selectData.ledger_pid + '.'), this.db.escape('')],
  537. literal: 'Replace',
  538. });
  539. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  540. const data = this.transaction.query(sql, sqlParam);
  541. return data;
  542. }
  543. /**
  544. * 选中节点的后兄弟节点,全部变为当前节点的子节点
  545. * @param {Object} selectData - 选中节点
  546. * @return {Object}
  547. * @private
  548. */
  549. async _syncUpLevelNexts(selectData) {
  550. // 查询selectData的lastChild
  551. const lastChildData = await this.getLastChildData(selectData.tender_id, selectData.ledger_id);
  552. const nextsData = await this.getNextsData(selectData.tender_id, selectData.ledger_pid, selectData.order);
  553. if (nextsData && nextsData.length > 0) {
  554. // 修改nextsData pid, 排序
  555. this.initSqlBuilder();
  556. this.sqlBuilder.setUpdateData('ledger_pid', {
  557. value: selectData.ledger_id,
  558. });
  559. const orderInc = lastChildData ? lastChildData.order - selectData.order : -selectData.order;
  560. this.sqlBuilder.setUpdateData('order', {
  561. value: Math.abs(orderInc),
  562. selfOperate: orderInc > 0 ? '+' : '-',
  563. });
  564. this.sqlBuilder.setAndWhere('ledger_pid', {
  565. value: selectData.ledger_pid,
  566. operate: '=',
  567. });
  568. this.sqlBuilder.setAndWhere('order', {
  569. value: selectData.order,
  570. operate: '>',
  571. });
  572. const [sql1, sqlParam1] = this.sqlBuilder.build(this.tableName, 'update');
  573. await this.transaction.query(sql1, sqlParam1);
  574. // 选中节点 is_leaf应为false
  575. if (selectData.is_leaf) {
  576. const updateData = { id: selectData.id,
  577. is_leaf: false,
  578. };
  579. await this.transaction.update(this.tableName, updateData);
  580. }
  581. // 修改nextsData及其子节点的full_path
  582. const oldSubStr = this.db.escape(selectData.ledger_pid + '.');
  583. const newSubStr = this.db.escape(selectData.ledger_id + '.');
  584. const sqlArr = [];
  585. sqlArr.push('Update ?? SET `full_path` = Replace(`full_path`,' + oldSubStr + ',' + newSubStr + ') Where');
  586. sqlArr.push('(`tender_id` = ' + selectData.tender_id + ')');
  587. sqlArr.push(' And (');
  588. for (const data of nextsData) {
  589. sqlArr.push('`full_path` Like ' + this.db.escape(data.full_path + '%'));
  590. if (nextsData.indexOf(data) < nextsData.length - 1) {
  591. sqlArr.push(' Or ');
  592. }
  593. }
  594. sqlArr.push(')');
  595. const sql = sqlArr.join('');
  596. const resultData = await this.transaction.query(sql, [this.tableName]);
  597. return resultData;
  598. }
  599. }
  600. /**
  601. * 升级节点
  602. *
  603. * @param {Number} tenderId - 标段id
  604. * @param {Number} selectId - 选中节点id
  605. * @return {Array} - 发生改变的数据
  606. */
  607. async upLevelNode(tenderId, selectId) {
  608. if ((tenderId <= 0) || (selectId <= 0)) {
  609. return [];
  610. }
  611. const selectData = await this.getDataByNodeId(tenderId, selectId);
  612. if (!selectData) {
  613. throw '升级节点数据错误';
  614. }
  615. const parentData = await this.getDataByNodeId(tenderId, selectData.ledger_pid);
  616. if (!parentData) {
  617. throw '升级节点数据错误';
  618. }
  619. this.transaction = await this.db.beginTransaction();
  620. const newFullPath = selectData.full_path.replace(selectData.ledger_pid + '.', '');
  621. try {
  622. // 选中节点--父节点 选中节点为firstChild时,修改is_leaf
  623. if (selectData.order === 1) {
  624. this.transaction.update(this.tableName, {
  625. id: parentData.id,
  626. is_leaf: true,
  627. });
  628. }
  629. // 选中节点--父节点--全部后兄弟节点 order+1
  630. await this._updateSelectNextsOrder(parentData);
  631. // 选中节点 修改pid, order, full_path
  632. const updateData = { id: selectData.id,
  633. ledger_pid: parentData.ledger_pid,
  634. order: parentData.order + 1,
  635. level: selectData.level - 1,
  636. full_path: newFullPath,
  637. };
  638. await this.transaction.update(this.tableName, updateData);
  639. // 选中节点--全部子节点(含孙) level-1, full_path变更
  640. await this._syncUplevelChildren(selectData);
  641. // 选中节点--全部后兄弟节点 收编为子节点 修改pid, order, full_path
  642. await this._syncUpLevelNexts(selectData);
  643. this.transaction.commit();
  644. } catch (err) {
  645. await this.transaction.rollback();
  646. throw err;
  647. }
  648. // 查询修改的数据
  649. const resultData1 = await this.getDataByFullPath(tenderId, newFullPath + '%');
  650. const resultData2 = await this.getNextsData(tenderId, parentData.ledger_pid, parentData.order + 1);
  651. if (selectData.order === 1) {
  652. const preParent = await this.getDataByNodeId(tenderId, parentData.ledger_id);
  653. resultData2.push(preParent);
  654. }
  655. return { update: resultData1.concat(resultData2) };
  656. }
  657. /**
  658. * 降级selectData, 同步修改所有子节点
  659. * @param {Object} selectData - 选中节点
  660. * @param {Object} preData - 选中节点的前一节点(降级后为父节点)
  661. * @return {Promise<*>}
  662. * @private
  663. */
  664. async _syncDownlevelChildren(selectData, preData) {
  665. this.initSqlBuilder();
  666. this.sqlBuilder.setAndWhere('tender_id', {
  667. value: selectData.tender_id,
  668. operate: '=',
  669. });
  670. this.sqlBuilder.setAndWhere('full_path', {
  671. value: this.db.escape(selectData.full_path + '.%'),
  672. operate: 'like',
  673. });
  674. this.sqlBuilder.setUpdateData('level', {
  675. value: 1,
  676. selfOperate: '+',
  677. });
  678. this.sqlBuilder.setUpdateData('full_path', {
  679. value: ['`full_path`', this.db.escape('.' + selectData.ledger_id), this.db.escape('.' + preData.ledger_id + '.' + selectData.ledger_id)],
  680. literal: 'Replace',
  681. });
  682. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  683. const data = this.transaction.query(sql, sqlParam);
  684. return data;
  685. }
  686. /**
  687. * 降级节点
  688. *
  689. * @param {Number} tenderId - 标段id
  690. * @param {Number} selectId - 选中节点id
  691. * @return {Array} - 发生改变的数据
  692. */
  693. async downLevelNode(tenderId, selectId) {
  694. if ((tenderId <= 0) || (selectId <= 0)) {
  695. return [];
  696. }
  697. const selectData = await this.getDataByNodeId(tenderId, selectId);
  698. if (!selectData) {
  699. throw '降级节点数据错误';
  700. }
  701. const preData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, selectData.order - 1);
  702. if (!preData) {
  703. throw '节点不可降级';
  704. }
  705. const preLastChildData = await this.getLastChildData(tenderId, preData.ledger_id);
  706. this.transaction = await this.db.beginTransaction();
  707. const orgLastPath = selectData.level === 1 ? selectData.ledger_id : '.' + selectData.ledger_id;
  708. const newLastPath = selectData.level === 1 ? preData.ledger_id + '.' + selectData.ledger_id : '.' + preData.ledger_id + '.' + selectData.ledger_id;
  709. const newFullPath = selectData.full_path.replace(orgLastPath, newLastPath);
  710. try {
  711. // 选中节点--全部后节点 order--
  712. await this._updateSelectNextsOrder(selectData, -1);
  713. // 选中节点 修改pid, level, order, full_path
  714. const updateData = {
  715. id: selectData.id,
  716. ledger_pid: preData.ledger_id,
  717. order: preLastChildData ? preLastChildData.order + 1 : 1,
  718. level: selectData.level + 1,
  719. full_path: newFullPath,
  720. };
  721. await this.transaction.update(this.tableName, updateData);
  722. // 选中节点--全部子节点(含孙) level++, full_path
  723. await this._syncDownlevelChildren(selectData, preData);
  724. // 选中节点--前兄弟节点 is_leaf应为false
  725. if (preData.is_leaf) {
  726. const updateData2 = {
  727. id: preData.id,
  728. is_leaf: false,
  729. };
  730. await this.transaction.update(this.tableName, updateData);
  731. }
  732. this.transaction.commit();
  733. } catch (err) {
  734. this.transaction.rollback();
  735. throw err;
  736. }
  737. // 查询修改的数据
  738. // 选中节点及子节点
  739. const resultData1 = await this.getDataByFullPath(tenderId, newFullPath + '%');
  740. // 选中节点--原前兄弟节点&全部后兄弟节点
  741. const queryOrder = preData.is_leaf ? preData.order - 1 : preData.order;
  742. const resultData2 = await this.getNextsData(tenderId, preData.ledger_pid, queryOrder);
  743. return { update: resultData1.concat(resultData2) };
  744. }
  745. /**
  746. * 过滤data中update方式不可提交的字段
  747. * @param {Number} id - 主键key
  748. * @param {Object} data
  749. * @return {Object<{id: *}>}
  750. * @private
  751. */
  752. _filterUpdateInvalidField(id, data) {
  753. const result = {
  754. id,
  755. };
  756. for (const prop in data) {
  757. if (readOnlyFields.indexOf(prop) === -1) {
  758. result[prop] = data[prop];
  759. }
  760. }
  761. return result;
  762. }
  763. /**
  764. * 提交数据 - 不影响计算等未提交项
  765. * @param {Number} tenderId - 标段id
  766. * @param {Object} data - 提交数据
  767. * @return {Object} - 提交后的数据
  768. */
  769. async updateInfo(tenderId, data) {
  770. // 简单校验数据
  771. if (tenderId <= 0) {
  772. throw '标段不存在';
  773. }
  774. if (tenderId !== data.tender_id) {
  775. throw '提交数据错误';
  776. }
  777. try {
  778. // 过滤不可提交字段
  779. const updateNode = await this.getDataById(data.id);
  780. if (!updateNode || tenderId !== updateNode.tender_id || data.ledger_id !== updateNode.ledger_id) {
  781. throw '提交数据错误';
  782. }
  783. const updateData = this._filterUpdateInvalidField(updateNode.id, data);
  784. await this.db.update(this.tableName, updateData);
  785. } catch (err) {
  786. throw err;
  787. }
  788. const result = await this.getDataByNodeId(tenderId, data.ledger_id);
  789. return result;
  790. }
  791. /**
  792. * 提交多条数据 - 不影响计算等未提交项
  793. * @param {Number} tenderId - 标段id
  794. * @param {Array} datas - 提交数据
  795. * @return {Array} - 提交后的数据
  796. */
  797. async updateInfos(tenderId, datas) {
  798. if (tenderId <= 0) {
  799. throw '标段不存在';
  800. }
  801. for (const data of datas) {
  802. if (tenderId !== data.tender_id) {
  803. throw '提交数据错误1';
  804. }
  805. }
  806. this.transaction = await this.db.beginTransaction();
  807. try {
  808. for (const data of datas) {
  809. const updateNode = await this.getDataById(data.id);
  810. if (!updateNode || tenderId !== updateNode.tender_id || data.ledger_id !== updateNode.ledger_id) {
  811. throw '提交数据错误2';
  812. }
  813. const updateData = this._filterUpdateInvalidField(updateNode.id, data);
  814. await this.transaction.update(this.tableName, updateData);
  815. }
  816. this.transaction.commit();
  817. } catch (err) {
  818. this.transaction.rollback();
  819. throw err;
  820. }
  821. const filter = [];
  822. for (const data of datas) {
  823. filter.push(data.id);
  824. }
  825. this.initSqlBuilder();
  826. this.sqlBuilder.setAndWhere('id', {
  827. value: filter,
  828. operate: 'in',
  829. });
  830. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  831. const resultData = await this.db.query(sql, sqlParam);
  832. return resultData;
  833. }
  834. /**
  835. * 复制粘贴整块
  836. * @param {Number} tenderId - 标段Id
  837. * @param {Number} selectId - 选中几点Id
  838. * @param {Array} block - 复制节点Id
  839. * @return {Object} - 提价后的数据(其中新增粘贴数据,只返回第一层)
  840. */
  841. async pasteBlock(tenderId, selectId, block) {
  842. if ((tenderId <= 0) || (selectId <= 0)) {
  843. return [];
  844. }
  845. const selectData = await this.getDataByNodeId(tenderId, selectId);
  846. if (!selectData) {
  847. throw '位置数据错误';
  848. }
  849. const newParentPath = selectData.full_path.replace(selectData.ledger_id, '');
  850. const copyNodes = await this.getDataByNodeIds(tenderId, block);
  851. if (!copyNodes || copyNodes.length <= 0) {
  852. throw '复制数据错误';
  853. }
  854. let bSameParent = true;
  855. for (const node of copyNodes) {
  856. if (node.ledger_pid !== copyNodes[0].ledger_pid) {
  857. bSameParent = false;
  858. break;
  859. }
  860. }
  861. if (!bSameParent) {
  862. throw '复制数据错误:仅可操作同层节点';
  863. }
  864. const orgParentPath = copyNodes[0].full_path.replace(copyNodes[0].ledger_id, '');
  865. this.transaction = await this.db.beginTransaction();
  866. try {
  867. // 选中节点的所有后兄弟节点,order+粘贴节点个数
  868. await this._updateSelectNextsOrder(selectData, copyNodes.length);
  869. // 数据库创建新增节点数据
  870. for (const node of copyNodes) {
  871. const datas = await this.getDataByFullPath(tenderId, node.full_path + '%');
  872. const cacheKey = 'tender_node_maxId:' + tenderId;
  873. let maxId = parseInt(await this.cache.get(cacheKey));
  874. if (!maxId) {
  875. maxId = await this._getMaxNodeId(tenderId);
  876. }
  877. this.cache.set(cacheKey, maxId + datas.length, 'EX', this.ctx.app.config.cacheTime);
  878. // 计算粘贴数据中需更新部分
  879. for (let index = 0; index < datas.length; index++) {
  880. const data = datas[index];
  881. const newId = maxId + index + 1;
  882. delete data.id;
  883. if (!data.is_leaf) {
  884. for (const children of datas) {
  885. children.full_path = children.full_path.replace('.' + data.ledger_id, '.' + newId);
  886. if (children.ledger_pid === data.ledger_id) {
  887. children.ledger_pid = newId;
  888. }
  889. }
  890. } else {
  891. data.full_path = data.full_path.replace('.' + data.ledger_id, '.' + newId);
  892. }
  893. data.ledger_id = newId;
  894. data.full_path = data.full_path.replace(orgParentPath, newParentPath);
  895. if (data.ledger_pid === copyNodes[0].ledger_pid) {
  896. data.ledger_pid = selectData.ledger_pid;
  897. data.order = selectData.order + index + 1;
  898. }
  899. data.level = data.level + selectData.level - copyNodes[0].level;
  900. }
  901. // 插入粘贴数据
  902. await this.transaction.insert(this.tableName, datas);
  903. }
  904. await this.transaction.commit();
  905. } catch (err) {
  906. await this.transaction.rollback();
  907. throw err;
  908. }
  909. // 查询应返回的结果
  910. const order = [];
  911. for (let i = 1; i <= copyNodes.length; i++) {
  912. order.push(selectData.order + i);
  913. }
  914. const createData = await this.getDataByParentAndOrder(selectData.tender_id, selectData.ledger_pid, order);
  915. const updateData = await this.getNextsData(selectData.tender_id, selectData.ledger_pid, selectData.order + copyNodes.length);
  916. return { create: createData, update: updateData };
  917. }
  918. }
  919. return Ledger;
  920. };